# To unbundle, run this file
echo mkfile
sed 's/^X//' >mkfile <<'!'
X</$objtype/mkfile
TARG=rotzoomer
OFILES=\
X getscr.$O\
X rotzoomer.$O
HFILES=getscr.h
BIN=$home/bin/$objtype
X</sys/src/cmd/mkone
X# LDFLAGS=-p
!
echo getscr.c
sed 's/^X//' >getscr.c <<'!'
X#include <u.h>
X#include <libc.h>
X#include <draw.h>
X#include "getscr.h"
X/*
X * allocates temporary storage for and reads
X * /dev/screen... modified from of lens.c
X */
uchar *
getscr(void)
X{
X char buf[5*12];
X ulong chan;
X uchar *screenbuf;
X int d, screenfd;
X screenfd = open("/dev/screen", OREAD);
X if(screenfd < 0)
X sysfatal("can't open /dev/screen: %r");
X if(read(screenfd, buf, sizeof buf) != sizeof buf)
X sysfatal("can't read /dev/screen: %r");
X chan = strtochan(buf);
X d = chantodepth(chan);
X if(d < 8)
X sysfatal("can't handle screen format %11.11s", buf);
X bypp = d/8;
X screenr.min.x = atoi(buf+1*12);
X screenr.min.y = atoi(buf+2*12);
X screenr.max.x = atoi(buf+3*12);
X screenr.max.y = atoi(buf+4*12);
X screenbuf = malloc(bypp*Dx(screenr)*Dy(screenr));
X if(screenbuf == nil)
X sysfatal("screen buffer malloc failed: %r");
X if(readn(screenfd, screenbuf, bypp*Dx(screenr)*Dy(screenr)) != bypp*Dx(screenr)*Dy(screenr))
X sysfatal("can't read screen: %r");
X return screenbuf;
X}
X/*
X * squeeze the screenshot to fit in the current window
X */
Image *
squeeze(uchar *buf)
X{
X int x, y, dxim, dyim, yydxsc;
X float dx, dy;
X Image *im;
X uchar *out, *src, *dst;
X if(buf == nil)
X return nil;
X im = allocimage(display, screen->r, screen->chan, 0, DBlack);
X if(im == nil)
X sysfatal("can't allocate temp image");
X dxim = Dx(im->r);
X dyim = Dy(im->r);
X dx = (float)Dx(screenr)/dxim;
X dy = (float)Dy(screenr)/dyim;
X out = (uchar *)malloc(bypp*dxim*dyim);
X if(out == nil)
X sysfatal("can't allocate temp memory");
X dst = out;
X for (y=0; y < dyim; y++) {
X yydxsc = ((int)(dy*y))*Dx(screenr);
X src = &buf[bypp*yydxsc];
X for (x=0; x < dxim; x++) {
X memmove(dst, src, bypp);
X dst += bypp;
X /*
X * ensure that src remains on a pixel boundary.
X * it's important that dx*x be computed in floating point
X * and rounded down, then multiplied by bypp.
X */
X src = &buf[bypp*(yydxsc + (int)(dx*x))];
X }
X }
X if(loadimage(im, im->r, out, bypp*dxim*dyim) != bypp*dxim*dyim)
X sysfatal("loadimage");
X free(out);
X return im;
X}
!
echo getscr.h
sed 's/^X//' >getscr.h <<'!'
uchar* getscr(void);
Image* squeeze(uchar *);
Rectangle screenr;
int bypp;
!
echo rotzoomer.c
sed 's/^X//' >rotzoomer.c <<'!'
X/*
X * rotzoomer - creates a collage of rotated and scaled portions of the screen
X * Copyright (C) 2001 Claudio Matsuoka <claudio@helllabs.org>
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation. No representations are made about the suitability of this
X * software for any purpose. It is provided "as is" without express or
X * implied warranty.
X */
X/*
X * ported to Plan 9 by mirtchov@cpsc.ucalgary.ca, 01/03
X */
X/* plan9-related stuff */
X#include <u.h>
X#include <libc.h>
X#include <draw.h>
X#include <event.h>
X/* screenshot-related stuff */
X#include "getscr.h"
static uchar *scrbuf;
static Image *scrimg;
static Image *bufimg;
X/* other defines */
X#define NULL nil
X#define XPoint Point
X#define NRAND nrand
X#define LRAND lrand
X#define random lrand
X#define MAXRAND ((2<<31)-1)
X#define MAX(a, b) (((a) > (b))?(a):(b))
X#define MIN(a, b) (((a) < (b))?(a):(b))
X#define RAND_MAX MAXRAND
X#define ABS abs
Image *colors[256];
X#define M_PI PI
X#define Bool int
X#define False 0
X#define True 1
X#define CYCLES 50000
char *buttons[] = {
X "sweep on/off",
X "exit",
X 0
X};
Menu menu = {
X buttons
X};
Mouse m;
X/* end of plan9-related defines */
typedef struct {
X int w, h; /* rectangle width and height */
X int inc1, inc2; /* rotation and zoom angle increments */
X int dx, dy; /* translation increments */
X int a1, a2; /* rotation and zoom angular variables */
X int ox, oy; /* origin in the background copy */
X int xx, yy; /* left-upper corner position (* 256) */
X int x, y; /* left-upper corner position */
X int ww, hh; /* valid area to place left-upper corner */
X int n; /* # of iteractions */
X int count; /* current iteraction */
X} Zoom;
static int width, height;
static Zoom **zoom_box = nil;
static int num_zoom = 2;
static int move = 0;
static int sweep = 0;
static int delay = 10;
static int anim = 1;
typedef struct {
X Rectangle r;
X} Screendim;
static Screendim scrdim;
static void
rotzoom(Zoom *za)
X{
X int x, y, c, s, zoom, z;
X int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1;
X int ox = 0, oy = 0, ys, yc;
X Rectangle r;
X z = 8100 * sin(M_PI * za->a2 / 8192);
X zoom = 8192 + z;
X c = zoom * cos(M_PI * za->a1 / 8192);
X s = zoom * sin(M_PI * za->a1 / 8192);
X ys = za->y * s;
X yc = za->y * c;
X for (y = za->y; y <= y2; y++) {
X int oxbig = za->x*c + ys;
X int oybig = -za->x*s + yc;
X ys += s;
X yc += c;
X for (x = za->x; x <= x2; x++) {
X ox = oxbig >> 13;
X if (ox < 0)
X do {
X ox += width;
X } while (ox < 0);
X else
X while (ox >= width)
X ox -= width;
X oxbig += c;
X oy = oybig >> 13;
X if (oy < 0)
X do {
X oy += height;
X } while (oy < 0);
X else
X while (oy >= height)
X oy -= height;
X oybig -= s;
X // XPutPixel(buffer_map, x, y, XGetPixel(scrbuf, ox, oy));
X r.max.x = (r.min.x = scrdim.r.min.x + x) + 2;
X r.max.y = (r.min.y = scrdim.r.min.y + y) + 2;
X /* we call draw way too much */
X draw(screen, r, scrimg, nil,
X (Point){scrdim.r.min.x + ox, scrdim.r.min.y + oy});
X }
X }
X za->a1 += za->inc1; /* Rotation angle */
X za->a1 &= 0x3fff;;
X za->a2 += za->inc2; /* Zoom */
X za->a2 &= 0x3fff;
X za->ox = ox; /* Save state for next iteration */
X za->oy = oy;
X za->count++;
X}
static void
reset_zoom(Zoom *za)
X{
X if (sweep) {
X int speed = random()%100 + 100;
X switch ((ulong)random()%4) {
X case 0:
X za->w = width;
X za->h = 10;
X za->x = za->y = za->dx = 0;
X za->dy = speed;
X za->n = height - 10;
X break;
X case 1:
X za->w = 10;
X za->h = height;
X za->x = width - 10;
X za->y = 0;
X za->dx = -speed;
X za->dy = 0;
X za->n = width - 10;
X break;
X case 2:
X za->w = width;
X za->h = 10;
X za->x = 0;
X za->y = height - 10;
X za->dx = 0;
X za->dy = -speed;
X za->n = height - 10;
X break;
X case 3:
X za->w = 10;
X za->h = height;
X za->x = 0;
X za->y = 0;
X za->dx = speed;
X za->dy = 0;
X za->n = width - 10;
X break;
X }
X za->n = (za->n * 256) / speed;
X za->ww = width - za->w;
X za->hh = height - za->h;
X /* We want smaller angle increments in sweep mode (looks better) */
X za->a1 = za->a2 = 0;
X za->inc1 = (2*(random() & 1) - 1) * (1 + random()%7);
X za->inc2 = (2*(random() & 1) - 1) * (1 + random()%7);
X } else {
X za->w = 50 + random()%300;
X za->h = 50 + random()%300;
X if (za->w > width / 3)
X za->w = width / 3;
X if (za->h > height / 3)
X za->h = height / 3;
X za->ww = width - za->w;
X za->hh = height - za->h;
X za->x = random() % za->ww;
X za->y = random() % za->hh;
X za->dx = (2*(random() & 1) - 1) * (100 + random()%300);
X za->dy = (2*(random() & 1) - 1) * (100 + random()%300);
X if (anim) {
X za->n = 50 + random()%1000;
X za->a1 = za->a2 = 0;
X } else {
X za->n = 5 + random()%10;
X za->a1 = random();
X za->a2 = random();
X }
X za->inc1 = (2*(random() & 1) - 1) * (random() % 30);
X za->inc2 = (2*(random() & 1) - 1) * (random() % 30);
X }
X za->xx = za->x * 256;
X za->yy = za->y * 256;
X za->count = 0;
X}
static Zoom *
create_zoom(void)
X{
X Zoom *za = malloc(sizeof(Zoom));
X reset_zoom(za);
X return za;
X}
static void
update_position(Zoom *za)
X{
X za->xx += za->dx;
X za->yy += za->dy;
X za->x = za->xx >> 8;
X za->y = za->yy >> 8;
X if (za->x < 0) {
X za->x = 0;
X za->dx = 100 + random() % 100;
X }
X if (za->y < 0) {
X za->y = 0;
X za->dy = 100 + random() % 100;
X }
X if (za->x > za->ww) {
X za->x = za->ww;
X za->dx = -(100 + random() % 100);
X }
X if (za->y > za->hh) {
X za->y = za->hh;
X za->dy = -(100 + random() % 100);
X }
X}
static void
hack_main(void)
X{
X int i;
X for (i = 0; i < num_zoom; i++) {
X if (move || sweep)
X update_position (zoom_box[i]);
X if (zoom_box[i]->n > 0) {
X if (anim || zoom_box[i]->count == 0)
X rotzoom(zoom_box[i]);
X else
X sleep(1);
X zoom_box[i]->n--;
X } else
X reset_zoom(zoom_box[i]);
X }
X flushimage(display, 1);
X if(ecanmouse()) {
X m = emouse();
X if(m.buttons&4)
X switch(emenuhit(3, &m, &menu)) {
X case 0:
X sweep = !sweep;
X for(i = 0; i < num_zoom; i++)
X reset_zoom(zoom_box[i]);
X break;
X case 1:
X exits(0);
X default:
X sysfatal("no such button in menu choice!");
X }
X }
X}
void
eresized(int new)
X{
X int i;
X if(new && getwindow(display, Refnone) < 0)
X sysfatal("can't reattach to window: %r");
X scrdim.r = screen->r;
X width = Dx(scrdim.r);
X height = Dy(scrdim.r);
X if (width & 1)
X width--;
X if (height & 1)
X height--;
X if(scrimg != nil)
X freeimage(scrimg);
X scrimg = squeeze(scrbuf);
X if(scrimg == nil)
X sysfatal("unable to fit screenshot to window: %r");
X if(zoom_box == nil) {
X zoom_box = calloc(num_zoom, sizeof(Zoom *));
X for(i = 0; i < num_zoom; i++)
X zoom_box[i] = create_zoom();
X } else
X for (i = 0; i < num_zoom; i++)
X reset_zoom(zoom_box[i]);
X draw(screen, scrdim.r, display->black, nil, ZP);
X}
void
screenhack(void)
X{
X /* In sweep or static mode, we want only one box */
X if (sweep || !anim)
X num_zoom = 1;
X /* Can't have static sweep mode */
X if (!anim)
X sweep = 0;
X /* Main drawing loop */
X for (; ; ) {
X hack_main();
X sleep(delay);
X }
X}
void
main(int argc, char **argv)
X{
X USED(argc, argv);
X srand(time(0));
X num_zoom = 2;
X move = delay = 0;
X sweep = anim = 1;
X scrbuf = getscr();
X if(scrbuf == nil)
X sysfatal("could not obtain screenshot: %r");
X if(initdraw(nil, nil, "rotzoomer") < 0)
X sysfatal("initdraw failed: %r");
X einit(Emouse);
X eresized(0);
X screenhack();
X}
!
|