# To unbundle, run this file echo mkfile sed 's/^X//' >mkfile <<'!' Xgetscr.c <<'!' X#include X#include X#include 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 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 X#include X#include X#include 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} !