ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / hacks / rotzoomer.c
1 /* rotzoomer - creates a collage of rotated and scaled portions of the screen
2  * Copyright (C) 2001 Claudio Matsuoka <claudio@helllabs.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or
10  * implied warranty.
11  */
12
13 /*
14  * Options:
15  *
16  * -shm         enable MIT shared memory extension
17  * -no-shm      disable MIT shared memory extension
18  * -n <num>     number of zoomboxes
19  * -move        enable mobile zoomboxes
20  * -sweep       enable sweep mode
21  * -anim        enable snapshot mode
22  * -no-anim     enable snapshot mode
23  * -delay       delay in milliseconds
24  */
25
26 #include <math.h>
27 #include "screenhack.h"
28
29 #ifdef HAVE_XSHM_EXTENSION
30 #include "xshm.h"
31 #endif
32
33 struct zoom_area {
34   int w, h;             /* rectangle width and height */
35   int inc1, inc2;       /* rotation and zoom angle increments */
36   int dx, dy;           /* translation increments */
37   int a1, a2;           /* rotation and zoom angular variables */
38   int ox, oy;           /* origin in the background copy */
39   int xx, yy;           /* left-upper corner position (* 256) */
40   int x, y;             /* left-upper corner position */
41   int ww, hh;           /* valid area to place left-upper corner */
42   int n;                /* number of iteractions */
43   int count;            /* current iteraction */
44 };
45
46 struct state {
47   Display *dpy;
48   Window window;
49
50   GC gc;
51   Visual *visual;
52   XImage *orig_map, *buffer_map;
53   Colormap colormap;
54
55   int width, height;
56   struct zoom_area **zoom_box;
57   int num_zoom;
58   int move;
59   int sweep;
60   int delay;
61   int anim;
62
63   async_load_state *img_loader;
64
65 #ifdef HAVE_XSHM_EXTENSION
66   Bool use_shm;
67   XShmSegmentInfo shm_info;
68 #endif
69 };
70
71
72 static void
73 rotzoom (struct state *st, struct zoom_area *za)
74 {
75   int x, y, c, s, zoom, z;
76   int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1;
77   int ox = 0, oy = 0;
78
79   z = 8100 * sin (M_PI * za->a2 / 8192);
80   zoom = 8192 + z;
81
82   c = zoom * cos (M_PI * za->a1 / 8192);
83   s = zoom * sin (M_PI * za->a1 / 8192);
84   for (y = za->y; y <= y2; y++) {
85     for (x = za->x; x <= x2; x++) {
86       ox = (x * c + y * s) >> 13;
87       oy = (-x * s + y * c) >> 13;
88
89       while (ox < 0)
90         ox += st->width;
91       while (oy < 0)
92         oy += st->height;
93       while (ox >= st->width)
94         ox -= st->width;
95       while (oy >= st->height)
96         oy -= st->height;
97
98       XPutPixel (st->buffer_map, x, y, XGetPixel (st->orig_map, ox, oy));
99     }
100   }
101
102   za->a1 += za->inc1;           /* Rotation angle */
103   za->a1 &= 0x3fff;;
104
105   za->a2 += za->inc2;           /* Zoom */
106   za->a2 &= 0x3fff;
107
108   za->ox = ox;                  /* Save state for next iteration */
109   za->oy = oy;
110
111   za->count++;
112 }
113
114
115 static void
116 reset_zoom (struct state *st, struct zoom_area *za)
117 {
118   if (st->sweep) {
119     int speed = random () % 100 + 100;
120     switch (random () % 4) {
121     case 0:
122       za->w = st->width;
123       za->h = 10;
124       za->x = 0;
125       za->y = 0;
126       za->dx = 0;
127       za->dy = speed;
128       za->n = (st->height - 10) * 256 / speed;
129       break;
130     case 1:
131       za->w = 10;
132       za->h = st->height;
133       za->x = st->width - 10;
134       za->y = 0;
135       za->dx = -speed;
136       za->dy = 0;
137       za->n = (st->width - 10) * 256 / speed;
138       break;
139     case 2:
140       za->w = st->width;
141       za->h = 10;
142       za->x = 0;
143       za->y = st->height - 10;
144       za->dx = 0;
145       za->dy = -speed;
146       za->n = (st->height - 10) * 256 / speed;
147       break;
148     case 3:
149       za->w = 10;
150       za->h = st->height;
151       za->x = 0;
152       za->y = 0;
153       za->dx = speed;
154       za->dy = 0;
155       za->n = (st->width - 10) * 256 / speed;
156       break;
157     }
158     za->ww = st->width - za->w;
159     za->hh = st->height - za->h;
160
161     /* We want smaller angle increments in sweep mode (looks better) */
162
163     za->a1 = 0;
164     za->a2 = 0;
165     za->inc1 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
166     za->inc2 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
167   } else {
168     za->w = 50 + random() % 300;
169     za->h = 50 + random() % 300;
170
171     if (za->w > st->width / 3)
172       za->w = st->width / 3;
173     if (za->h > st->height / 3)
174       za->h = st->height / 3;
175
176     za->ww = st->width - za->w;
177     za->hh = st->height - za->h;
178
179     za->x = (za->ww ? random() % za->ww : 0);
180     za->y = (za->hh ? random() % za->hh : 0);
181
182     za->dx = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
183     za->dy = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
184
185     if (st->anim) {
186       za->n = 50 + random() % 1000;
187       za->a1 = 0;
188       za->a2 = 0;
189     } else {
190       za->n = 5 + random() % 10;
191       za->a1 = random ();
192       za->a2 = random ();
193     }
194
195     za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
196     za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30);
197   }
198
199   za->xx = za->x * 256;
200   za->yy = za->y * 256;
201
202   za->count = 0;
203 }
204
205
206 static struct zoom_area *
207 create_zoom (struct state *st)
208 {
209   struct zoom_area *za;
210
211   za = malloc (sizeof (struct zoom_area));
212   reset_zoom (st, za);
213
214   return za;
215 }
216
217
218 static void
219 update_position (struct zoom_area *za)
220 {
221   za->xx += za->dx;
222   za->yy += za->dy;
223
224   za->x = za->xx >> 8;
225   za->y = za->yy >> 8;
226
227   if (za->x < 0) {
228     za->x = 0;
229     za->dx = 100 + random() % 100;
230   }
231                 
232   if (za->y < 0) {
233     za->y = 0;
234     za->dy = 100 + random() % 100;
235   }
236                 
237   if (za->x > za->ww) {
238     za->x = za->ww;
239     za->dx = -(100 + random() % 100);
240   }
241
242   if (za->y > za->hh) {
243     za->y = za->hh;
244     za->dy = -(100 + random() % 100);
245   }
246 }
247
248
249 static void
250 DisplayImage (struct state *st, int x, int y, int w, int h)
251 {
252 #ifdef HAVE_XSHM_EXTENSION
253   if (st->use_shm)
254     XShmPutImage (st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y,
255                   w, h, False);
256   else
257 #endif /* HAVE_XSHM_EXTENSION */
258     XPutImage(st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y, w, h);
259 }
260
261
262 static void
263 init_hack (struct state *st)
264 {
265   int i;
266
267   st->zoom_box = calloc (st->num_zoom, sizeof (struct zoom_area *));
268   for (i = 0; i < st->num_zoom; i++) {
269     st->zoom_box[i] = create_zoom (st);
270   }
271
272   if (st->height && st->orig_map->data)
273     memcpy (st->buffer_map->data, st->orig_map->data,
274             st->height * st->buffer_map->bytes_per_line);
275
276   DisplayImage(st, 0, 0, st->width, st->height);
277 }
278
279
280 static unsigned long
281 rotzoomer_draw (Display *disp, Window win, void *closure)
282 {
283   struct state *st = (struct state *) closure;
284   int delay = (st->delay * 1000);
285   int i;
286
287   if (st->img_loader)   /* still loading */
288     {
289       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
290       if (! st->img_loader) {  /* just finished */
291         st->orig_map = XGetImage (st->dpy, st->window, 0, 0, 
292                                   st->width, st->height, ~0L, ZPixmap);
293         init_hack (st);
294       }
295       return st->delay;
296     }
297
298   for (i = 0; i < st->num_zoom; i++) {
299     if (st->move || st->sweep)
300       update_position (st->zoom_box[i]);
301
302     if (st->zoom_box[i]->n > 0) {
303       if (st->anim || st->zoom_box[i]->count == 0) {
304         rotzoom (st, st->zoom_box[i]);
305       } else {
306         delay = 1000000;
307       }
308       st->zoom_box[i]->n--;
309     } else {
310       reset_zoom (st, st->zoom_box[i]);
311     }
312   }
313
314   for (i = 0; i < st->num_zoom; i++) {
315     DisplayImage(st, st->zoom_box[i]->x, st->zoom_box[i]->y,
316                  st->zoom_box[i]->w, st->zoom_box[i]->h);
317   }
318
319   return delay;
320 }
321
322
323 static void
324 setup_X (struct state *st)
325 {
326   XWindowAttributes xgwa;
327   int depth;
328   XGCValues gcv;
329   long gcflags;
330
331   XGetWindowAttributes (st->dpy, st->window, &xgwa);
332   depth = xgwa.depth;
333   st->colormap = xgwa.colormap;
334   st->width = xgwa.width;
335   st->height = xgwa.height;
336   st->visual = xgwa.visual;
337
338   if (st->width % 2)
339     st->width--;
340   if (st->height % 2)
341     st->height--;
342
343   gcv.function = GXcopy;
344   gcv.subwindow_mode = IncludeInferiors;
345   gcflags = GCFunction;
346   if (use_subwindow_mode_p (xgwa.screen, st->window))   /* see grabscreen.c */
347     gcflags |= GCSubwindowMode;
348   st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
349   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
350                                             st->window, 0, 0);
351
352   st->buffer_map = 0;
353
354 #ifdef HAVE_XSHM_EXTENSION
355   if (st->use_shm) {
356     st->buffer_map = create_xshm_image(st->dpy, xgwa.visual, depth,
357                                        ZPixmap, 0, &st->shm_info, st->width, st->height);
358     if (!st->buffer_map) {
359       st->use_shm = False;
360       fprintf(stderr, "create_xshm_image failed\n");
361     }
362   }
363 #endif /* HAVE_XSHM_EXTENSION */
364
365   if (!st->buffer_map) {
366     st->buffer_map = XCreateImage(st->dpy, xgwa.visual,
367                                   depth, ZPixmap, 0, 0, st->width, st->height, 8, 0);
368     st->buffer_map->data = (char *)calloc (st->buffer_map->height,
369                                            st->buffer_map->bytes_per_line);
370   }
371 }
372
373
374 static void *
375 rotzoomer_init (Display *dpy, Window window)
376 {
377   struct state *st = (struct state *) calloc (1, sizeof(*st));
378   char *s;
379   st->dpy = dpy;
380   st->window = window;
381 #ifdef HAVE_XSHM_EXTENSION
382   st->use_shm = get_boolean_resource (st->dpy, "useSHM", "Boolean");
383 #endif
384   st->num_zoom = get_integer_resource (st->dpy, "numboxes", "Integer");
385
386   s = get_string_resource (dpy, "mode", "Mode");
387   if (!s || !*s || !strcasecmp (s, "stationary"))
388     ;
389   else if (!strcasecmp (s, "move"))
390     st->move = True;
391   else if (!strcasecmp (s, "sweep"))
392     st->sweep = True;
393   else
394     fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s);
395
396   st->anim = get_boolean_resource (st->dpy, "anim", "Boolean");
397   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
398
399   /* In sweep or static mode, we want only one box */
400   if (st->sweep || !st->anim)
401     st->num_zoom = 1;
402
403   /* Can't have static sweep mode */
404   if (!st->anim)
405     st->sweep = 0;
406
407   setup_X (st);
408
409   return st;
410 }
411
412 static void
413 rotzoomer_reshape (Display *dpy, Window window, void *closure, 
414                  unsigned int w, unsigned int h)
415 {
416 }
417
418 static Bool
419 rotzoomer_event (Display *dpy, Window window, void *closure, XEvent *event)
420 {
421   return False;
422 }
423
424 static void
425 rotzoomer_free (Display *dpy, Window window, void *closure)
426 {
427   struct state *st = (struct state *) closure;
428   free (st);
429 }
430
431
432 static const char *rotzoomer_defaults[] = {
433   ".background: black",
434   ".foreground: white",
435 #ifdef HAVE_XSHM_EXTENSION
436   "*useSHM: True",
437 #else
438   "*useSHM: False",
439 #endif
440   "*anim: True",
441   "*mode: stationary",
442   "*numboxes: 2",
443   "*delay: 10",
444   0
445 };
446
447
448 static XrmOptionDescRec rotzoomer_options[] = {
449   { "-shm",     ".useSHM",      XrmoptionNoArg, "True"  },
450   { "-no-shm",  ".useSHM",      XrmoptionNoArg, "False" },
451   { "-mode",    ".mode",        XrmoptionSepArg, 0      },
452   { "-move",    ".mode",        XrmoptionNoArg, "move"  },
453   { "-sweep",   ".mode",        XrmoptionNoArg, "sweep" },
454   { "-anim",    ".anim",        XrmoptionNoArg, "True"  },
455   { "-no-anim", ".anim",        XrmoptionNoArg, "False" },
456   { "-delay",   ".delay",       XrmoptionSepArg, 0      },
457   { "-n",       ".numboxes",    XrmoptionSepArg, 0      },
458   { 0, 0, 0, 0 }
459 };
460
461
462 XSCREENSAVER_MODULE ("Rotzoomer", rotzoomer)