From http://www.jwz.org/xscreensaver/xscreensaver-5.30.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 /* (circle-mode by jwz, 4-Jun-2014; not finished yet.) */
14
15 /*
16  * Options:
17  *
18  * -shm         enable MIT shared memory extension
19  * -no-shm      disable MIT shared memory extension
20  * -n <num>     number of zoomboxes
21  * -move        enable mobile zoomboxes
22  * -sweep       enable sweep mode
23  * -circle      enable circle mode
24  * -anim        enable snapshot mode
25  * -no-anim     enable snapshot mode
26  * -delay       delay in milliseconds
27  */
28
29 #include <math.h>
30 #include "screenhack.h"
31
32 #ifdef HAVE_XSHM_EXTENSION
33 #include "xshm.h"
34 #endif
35
36 struct zoom_area {
37   int w, h;             /* rectangle width and height */
38   int inc1, inc2;       /* rotation and zoom angle increments */
39   int dx, dy;           /* translation increments */
40   int a1, a2;           /* rotation and zoom angular variables */
41   int ox, oy;           /* origin in the background copy */
42   int xx, yy;           /* left-upper corner position (* 256) */
43   int x, y;             /* left-upper corner position */
44   int ww, hh;           /* valid area to place left-upper corner */
45   int n;                /* number of iteractions */
46   int count;            /* current iteraction */
47 };
48
49 struct state {
50   Display *dpy;
51   Window window;
52
53   GC gc;
54   Visual *visual;
55   XImage *orig_map, *buffer_map;
56   Colormap colormap;
57
58   int width, height;
59   struct zoom_area **zoom_box;
60   int num_zoom;
61   int move;
62   int sweep;
63   int circle;
64   int delay;
65   int anim;
66   int duration;
67   time_t start_time;
68
69   async_load_state *img_loader;
70
71 #ifdef HAVE_XSHM_EXTENSION
72   Bool use_shm;
73   XShmSegmentInfo shm_info;
74 #endif
75 };
76
77
78 static void
79 rotzoom (struct state *st, struct zoom_area *za)
80 {
81   int x, y, c, s, zoom, z;
82   int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1;
83   int ox = 0, oy = 0;
84   int w2 = (za->w/2) * (za->w/2);
85
86   z = 8100 * sin (M_PI * za->a2 / 8192);
87   zoom = 8192 + z;
88
89   for (y = za->y; y <= y2; y++) {
90     for (x = za->x; x <= x2; x++) {
91       c = zoom * cos (M_PI * za->a1 / 8192);
92       s = zoom * sin (M_PI * za->a1 / 8192);
93       if (st->circle) {
94         int cx = za->x + za->w / 2;
95         int cy = za->y + za->h / 2;
96         int dx = x - cx;
97         int dy = y - cy;
98         int d2 = (dx*dx) + (dy*dy);
99
100         ox = x;
101         oy = y;
102
103         if (d2 > w2) {
104           ox = x;
105           oy = y;
106         } else {
107           double r = sqrt ((double) d2);
108           double th = atan ((double)dy / (double) (dx == 0 ? 1 : dx));
109           th += M_PI * (za->a1 / 300.0);
110           ox = 10 + cx + (int) (r * cos(th));
111           oy = 10 + cy + (int) (r * sin(th));
112         }
113       } else {
114         ox = (x * c + y * s) >> 13;
115         oy = (-x * s + y * c) >> 13;
116       }
117
118       while (ox < 0)
119         ox += st->width;
120       while (oy < 0)
121         oy += st->height;
122       while (ox >= st->width)
123         ox -= st->width;
124       while (oy >= st->height)
125         oy -= st->height;
126
127       XPutPixel (st->buffer_map, x, y, XGetPixel (st->orig_map, ox, oy));
128     }
129   }
130
131   za->a1 += za->inc1;           /* Rotation angle */
132   za->a1 &= 0x3fff;
133
134   za->a2 += za->inc2;           /* Zoom */
135   za->a2 &= 0x3fff;
136
137   za->ox = ox;                  /* Save state for next iteration */
138   za->oy = oy;
139
140   za->count++;
141 }
142
143
144 static void
145 reset_zoom (struct state *st, struct zoom_area *za)
146 {
147   if (st->sweep) {
148     int speed = random () % 100 + 100;
149     switch (random () % 4) {
150     case 0:
151       za->w = st->width;
152       za->h = 10;
153       za->x = 0;
154       za->y = 0;
155       za->dx = 0;
156       za->dy = speed;
157       za->n = (st->height - 10) * 256 / speed;
158       break;
159     case 1:
160       za->w = 10;
161       za->h = st->height;
162       za->x = st->width - 10;
163       za->y = 0;
164       za->dx = -speed;
165       za->dy = 0;
166       za->n = (st->width - 10) * 256 / speed;
167       break;
168     case 2:
169       za->w = st->width;
170       za->h = 10;
171       za->x = 0;
172       za->y = st->height - 10;
173       za->dx = 0;
174       za->dy = -speed;
175       za->n = (st->height - 10) * 256 / speed;
176       break;
177     case 3:
178       za->w = 10;
179       za->h = st->height;
180       za->x = 0;
181       za->y = 0;
182       za->dx = speed;
183       za->dy = 0;
184       za->n = (st->width - 10) * 256 / speed;
185       break;
186     }
187     za->ww = st->width - za->w;
188     za->hh = st->height - za->h;
189
190     /* We want smaller angle increments in sweep mode (looks better) */
191
192     za->a1 = 0;
193     za->a2 = 0;
194     za->inc1 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
195     za->inc2 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
196   } else if (st->circle) {
197
198     za->w = 50 + random() % 300;
199     if (za->w > st->width / 3)
200       za->w = st->width / 3;
201     if (za->w > st->height / 3)
202       za->w = st->height / 3;
203     za->h = za->w;
204
205     za->ww = st->width - za->w;
206     za->hh = st->height - za->h;
207
208     za->x = (za->ww ? random() % za->ww : 0);
209     za->y = (za->hh ? random() % za->hh : 0);
210
211     za->dx = 0;
212     za->dy = 0;
213     za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
214
215     if (st->anim) {
216       za->n = 50 + random() % 1000;
217       za->a1 = 0;
218       za->a2 = 0;
219     } else {
220       za->n = 5 + random() % 10;
221       za->a1 = random ();
222       za->a2 = random ();
223     }
224
225     za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
226     za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30);
227
228   } else {
229     za->w = 50 + random() % 300;
230     za->h = 50 + random() % 300;
231
232     if (za->w > st->width / 3)
233       za->w = st->width / 3;
234     if (za->h > st->height / 3)
235       za->h = st->height / 3;
236
237     za->ww = st->width - za->w;
238     za->hh = st->height - za->h;
239
240     za->x = (za->ww ? random() % za->ww : 0);
241     za->y = (za->hh ? random() % za->hh : 0);
242
243     za->dx = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
244     za->dy = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
245
246     if (st->anim) {
247       za->n = 50 + random() % 1000;
248       za->a1 = 0;
249       za->a2 = 0;
250     } else {
251       za->n = 5 + random() % 10;
252       za->a1 = random ();
253       za->a2 = random ();
254     }
255
256     za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
257     za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30);
258   }
259
260   za->xx = za->x * 256;
261   za->yy = za->y * 256;
262
263   za->count = 0;
264 }
265
266
267 static struct zoom_area *
268 create_zoom (struct state *st)
269 {
270   struct zoom_area *za;
271
272   za = malloc (sizeof (struct zoom_area));
273   reset_zoom (st, za);
274
275   return za;
276 }
277
278
279 static void
280 update_position (struct zoom_area *za)
281 {
282   za->xx += za->dx;
283   za->yy += za->dy;
284
285   za->x = za->xx >> 8;
286   za->y = za->yy >> 8;
287
288   if (za->x < 0) {
289     za->x = 0;
290     za->dx = 100 + random() % 100;
291   }
292                 
293   if (za->y < 0) {
294     za->y = 0;
295     za->dy = 100 + random() % 100;
296   }
297                 
298   if (za->x > za->ww) {
299     za->x = za->ww;
300     za->dx = -(100 + random() % 100);
301   }
302
303   if (za->y > za->hh) {
304     za->y = za->hh;
305     za->dy = -(100 + random() % 100);
306   }
307 }
308
309
310 static void
311 DisplayImage (struct state *st, int x, int y, int w, int h)
312 {
313 #ifdef HAVE_XSHM_EXTENSION
314   if (st->use_shm)
315     XShmPutImage (st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y,
316                   w, h, False);
317   else
318 #endif /* HAVE_XSHM_EXTENSION */
319     XPutImage(st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y, w, h);
320 }
321
322
323 static void
324 init_hack (struct state *st)
325 {
326   int i;
327
328   st->start_time = time ((time_t) 0);
329   st->zoom_box = calloc (st->num_zoom, sizeof (struct zoom_area *));
330   for (i = 0; i < st->num_zoom; i++) {
331     st->zoom_box[i] = create_zoom (st);
332   }
333
334   if (st->height && st->orig_map->data)
335     memcpy (st->buffer_map->data, st->orig_map->data,
336             st->height * st->buffer_map->bytes_per_line);
337
338   DisplayImage(st, 0, 0, st->width, st->height);
339 }
340
341
342 static unsigned long
343 rotzoomer_draw (Display *disp, Window win, void *closure)
344 {
345   struct state *st = (struct state *) closure;
346   int delay = st->delay;
347   int i;
348
349   if (st->img_loader)   /* still loading */
350     {
351       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
352       if (! st->img_loader) {  /* just finished */
353         st->orig_map = XGetImage (st->dpy, st->window, 0, 0, 
354                                   st->width, st->height, ~0L, ZPixmap);
355         init_hack (st);
356       }
357       return st->delay;
358     }
359
360   if (!st->img_loader &&
361       st->start_time + st->duration < time ((time_t) 0)) {
362     XWindowAttributes xgwa;
363     XGetWindowAttributes(st->dpy, st->window, &xgwa);
364     st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
365                                               st->window, 0, 0);
366     st->start_time = time ((time_t) 0);
367     return st->delay;
368   }
369
370   for (i = 0; i < st->num_zoom; i++) {
371     if (st->move || st->sweep)
372       update_position (st->zoom_box[i]);
373
374     if (st->zoom_box[i]->n > 0) {
375       if (st->anim || st->zoom_box[i]->count == 0) {
376         rotzoom (st, st->zoom_box[i]);
377       } else {
378         delay = 1000000;
379       }
380       st->zoom_box[i]->n--;
381     } else {
382       reset_zoom (st, st->zoom_box[i]);
383     }
384   }
385
386   for (i = 0; i < st->num_zoom; i++) {
387     DisplayImage(st, st->zoom_box[i]->x, st->zoom_box[i]->y,
388                  st->zoom_box[i]->w, st->zoom_box[i]->h);
389   }
390
391   return delay;
392 }
393
394
395 static void
396 setup_X (struct state *st)
397 {
398   XWindowAttributes xgwa;
399   int depth;
400   XGCValues gcv;
401   long gcflags;
402
403   XGetWindowAttributes (st->dpy, st->window, &xgwa);
404   depth = xgwa.depth;
405   st->colormap = xgwa.colormap;
406   st->width = xgwa.width;
407   st->height = xgwa.height;
408   st->visual = xgwa.visual;
409
410   if (st->width % 2)
411     st->width--;
412   if (st->height % 2)
413     st->height--;
414
415   gcv.function = GXcopy;
416   gcv.subwindow_mode = IncludeInferiors;
417   gcflags = GCFunction;
418   if (use_subwindow_mode_p (xgwa.screen, st->window))   /* see grabscreen.c */
419     gcflags |= GCSubwindowMode;
420   st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
421   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
422                                             st->window, 0, 0);
423
424   st->buffer_map = 0;
425
426 #ifdef HAVE_XSHM_EXTENSION
427   if (st->use_shm) {
428     st->buffer_map = create_xshm_image(st->dpy, xgwa.visual, depth,
429                                        ZPixmap, 0, &st->shm_info, st->width, st->height);
430     if (!st->buffer_map) {
431       st->use_shm = False;
432       fprintf(stderr, "create_xshm_image failed\n");
433     }
434   }
435 #endif /* HAVE_XSHM_EXTENSION */
436
437   if (!st->buffer_map) {
438     st->buffer_map = XCreateImage(st->dpy, xgwa.visual,
439                                   depth, ZPixmap, 0, 0, st->width, st->height, 8, 0);
440     st->buffer_map->data = (char *)calloc (st->buffer_map->height,
441                                            st->buffer_map->bytes_per_line);
442   }
443 }
444
445
446 static void *
447 rotzoomer_init (Display *dpy, Window window)
448 {
449   struct state *st = (struct state *) calloc (1, sizeof(*st));
450   char *s;
451   st->dpy = dpy;
452   st->window = window;
453 #ifdef HAVE_XSHM_EXTENSION
454   st->use_shm = get_boolean_resource (st->dpy, "useSHM", "Boolean");
455 #endif
456   st->num_zoom = get_integer_resource (st->dpy, "numboxes", "Integer");
457
458   s = get_string_resource (dpy, "mode", "Mode");
459   if (!s || !*s || !strcasecmp (s, "stationary"))
460     ;
461   else if (!strcasecmp (s, "move"))
462     st->move = True;
463   else if (!strcasecmp (s, "sweep"))
464     st->sweep = True;
465   else if (!strcasecmp (s, "circle"))
466     st->circle = True;
467   else
468     fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s);
469
470   st->anim = get_boolean_resource (st->dpy, "anim", "Boolean");
471   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
472   st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
473   if (st->delay < 0) st->delay = 0;
474   if (st->duration < 1) st->duration = 1;
475
476   /* In sweep or static mode, we want only one box */
477   if (st->sweep || !st->anim)
478     st->num_zoom = 1;
479
480   /* Can't have static sweep mode */
481   if (!st->anim)
482     st->sweep = 0;
483
484   if (st->circle) {
485     st->move = 0;
486     st->sweep = 0;
487   }
488
489   st->start_time = time ((time_t) 0);
490
491   setup_X (st);
492
493   return st;
494 }
495
496 static void
497 rotzoomer_reshape (Display *dpy, Window window, void *closure, 
498                  unsigned int w, unsigned int h)
499 {
500 }
501
502 static Bool
503 rotzoomer_event (Display *dpy, Window window, void *closure, XEvent *event)
504 {
505   struct state *st = (struct state *) closure;
506   if (screenhack_event_helper (dpy, window, event))
507     {
508       st->start_time = 0;
509       return True;
510     }
511   return False;
512 }
513
514 static void
515 rotzoomer_free (Display *dpy, Window window, void *closure)
516 {
517   struct state *st = (struct state *) closure;
518   free (st);
519 }
520
521
522 static const char *rotzoomer_defaults[] = {
523   ".background: black",
524   ".foreground: white",
525   "*fpsSolid:   true",
526 #ifdef HAVE_XSHM_EXTENSION
527   "*useSHM: True",
528 #else
529   "*useSHM: False",
530 #endif
531   "*anim: True",
532   "*mode: stationary",
533   "*numboxes: 2",
534   "*delay: 10000",
535   "*duration: 120",
536 #ifdef USE_IPHONE
537   "*ignoreRotation: True",
538   "*rotateImages:   True",
539 #endif
540   0
541 };
542
543
544 static XrmOptionDescRec rotzoomer_options[] = {
545   { "-shm",     ".useSHM",      XrmoptionNoArg, "True"  },
546   { "-no-shm",  ".useSHM",      XrmoptionNoArg, "False" },
547   { "-mode",    ".mode",        XrmoptionSepArg, 0      },
548   { "-move",    ".mode",        XrmoptionNoArg, "move"  },
549   { "-sweep",   ".mode",        XrmoptionNoArg, "sweep" },
550   { "-circle",  ".mode",        XrmoptionNoArg, "circle"},
551   { "-anim",    ".anim",        XrmoptionNoArg, "True"  },
552   { "-no-anim", ".anim",        XrmoptionNoArg, "False" },
553   { "-delay",   ".delay",       XrmoptionSepArg, 0      },
554   {"-duration", ".duration",    XrmoptionSepArg, 0      },
555   { "-n",       ".numboxes",    XrmoptionSepArg, 0      },
556   { 0, 0, 0, 0 }
557 };
558
559
560 XSCREENSAVER_MODULE ("RotZoomer", rotzoomer)