Plan 9 from Bell Labs’s /usr/web/sources/contrib/geoff/rotzoomer.bun

Copyright © 2009 Alcatel-Lucent.
Distributed under the Lucent Public License version 1.02.
Download the Plan 9 distribution.


# 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}
!

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2009 Alcatel-Lucent. All Rights Reserved.
Comments to webmaster@plan9.bell-labs.com.