http://packetstorm.tacticalflex.com/UNIX/admin/xscreensaver-3.27.tar.gz
[xscreensaver] / utils / erase.c
1 /* erase.c: Erase the screen in various more or less interesting ways.
2  * (c) 1997 by Johannes Keukelaar <johannes@nada.kth.se>
3  * Permission to use in any way granted. Provided "as is" without expressed
4  * or implied warranty. NO WARRANTY, NO EXPRESSION OF SUITABILITY FOR ANY
5  * PURPOSE. (I.e.: Use in any way, but at your own risk!)
6  */
7
8 #include "utils.h"
9 #include "yarandom.h"
10 #include "usleep.h"
11 #include "resources.h"
12
13 #undef countof
14 #define countof(x) (sizeof(x)/sizeof(*(x)))
15
16 typedef void (*Eraser) (Display *dpy, Window window, GC gc,
17                         int width, int height, int delay, int granularity);
18
19
20 static void
21 random_lines (Display *dpy, Window window, GC gc,
22               int width, int height, int delay, int granularity)
23 {
24   Bool horiz_p = (random() & 1);
25   int max = (horiz_p ? height : width);
26   int *lines = (int *) calloc(max, sizeof(*lines));
27   int i;
28
29   for (i = 0; i < max; i++)
30     lines[i] = i;
31
32   for (i = 0; i < max; i++)
33     {
34       int t, r;
35       t = lines[i];
36       r = random() % max;
37       lines[i] = lines[r];
38       lines[r] = t;
39     }
40
41   for (i = 0; i < max; i++)
42     { 
43       if (horiz_p)
44         XDrawLine (dpy, window, gc, 0, lines[i], width, lines[i]);
45       else
46         XDrawLine (dpy, window, gc, lines[i], 0, lines[i], height);
47
48       XSync (dpy, False);
49       if (delay > 0 && ((i % granularity) == 0))
50         usleep (delay * granularity);
51     }
52   free(lines);
53 }
54
55
56 static void
57 venetian (Display *dpy, Window window, GC gc,
58           int width, int height, int delay, int granularity)
59 {
60   Bool horiz_p = (random() & 1);
61   Bool flip_p = (random() & 1);
62   int max = (horiz_p ? height : width);
63   int *lines = (int *) calloc(max, sizeof(*lines));
64   int i, j;
65
66   granularity /= 6;
67
68   j = 0;
69   for (i = 0; i < max*2; i++)
70     {
71       int line = ((i / 16) * 16) - ((i % 16) * 15);
72       if (line >= 0 && line < max)
73         lines[j++] = (flip_p ? max - line : line);
74     }
75
76   for (i = 0; i < max; i++)
77     { 
78       if (horiz_p)
79         XDrawLine (dpy, window, gc, 0, lines[i], width, lines[i]);
80       else
81         XDrawLine (dpy, window, gc, lines[i], 0, lines[i], height);
82
83       XSync (dpy, False);
84       if (delay > 0 && ((i % granularity) == 0))
85         usleep (delay * granularity);
86     }
87   free(lines);
88 }
89
90
91 static void
92 triple_wipe (Display *dpy, Window window, GC gc,
93              int width, int height, int delay, int granularity)
94 {
95   Bool flip_x = random() & 1;
96   Bool flip_y = random() & 1;
97   int max = width + (height / 2);
98   int *lines = (int *)calloc(max, sizeof(int));
99   int i;
100
101   for(i = 0; i < width/2; i++)
102     lines[i] = i*2+height;
103   for(i = 0; i < height/2; i++)
104     lines[i+width/2] = i*2;
105   for(i = 0; i < width/2; i++)
106     lines[i+width/2+height/2] = width-i*2-(width%2?0:1)+height;
107
108   granularity /= 6;
109
110   for (i = 0; i < max; i++)
111     { 
112       int x, y, x2, y2;
113       if (lines[i] < height)
114         x = 0, y = lines[i], x2 = width, y2 = y;
115       else
116         x = lines[i]-height, y = 0, x2 = x, y2 = height;
117
118       if (flip_x)
119         x = width-x, x2 = width-x2;
120       if (flip_y)
121         y = height-y, y2 = height-y2;
122
123       XDrawLine (dpy, window, gc, x, y, x2, y2);
124       XSync (dpy, False);
125       if (delay > 0 && ((i % granularity) == 0))
126         usleep (delay*granularity);
127     }
128   free(lines);
129 }
130
131
132 static void
133 quad_wipe (Display *dpy, Window window, GC gc,
134            int width, int height, int delay, int granularity)
135 {
136   Bool flip_x = random() & 1;
137   Bool flip_y = random() & 1;
138   int max = width + height;
139   int *lines = (int *)calloc(max, sizeof(int));
140   int i;
141
142   granularity /= 3;
143
144   for (i = 0; i < max/4; i++)
145     {
146       lines[i*4]   = i*2;
147       lines[i*4+1] = height-i*2-(height%2?0:1);
148       lines[i*4+2] = height+i*2;
149       lines[i*4+3] = height+width-i*2-(width%2?0:1);
150     }
151
152   for (i = 0; i < max; i++)
153     { 
154       int x, y, x2, y2;
155       if (lines[i] < height)
156         x = 0, y = lines[i], x2 = width, y2 = y;
157       else
158         x = lines[i]-height, y = 0, x2 = x, y2 = height;
159
160       if (flip_x)
161         x = width-x, x2 = width-x2;
162       if (flip_y)
163         y = height-y, y2 = height-y2;
164
165       XDrawLine (dpy, window, gc, x, y, x2, y2);
166       XSync (dpy, False);
167       if (delay > 0 && ((i % granularity) == 0))
168         usleep (delay*granularity);
169     }
170   free(lines);
171 }
172
173
174
175 static void
176 circle_wipe (Display *dpy, Window window, GC gc,
177              int width, int height, int delay, int granularity)
178 {
179   int full = 360 * 64;
180   int inc = full / 64;
181   int start = random() % full;
182   int rad = (width > height ? width : height);
183   int i;
184   if (random() & 1)
185     inc = -inc;
186   for (i = (inc > 0 ? 0 : full);
187        (inc > 0 ? i < full : i > 0);
188        i += inc)
189     {
190       XFillArc(dpy, window, gc,
191                (width/2)-rad, (height/2)-rad, rad*2, rad*2,
192                (i+start) % full, inc);
193       XFlush (dpy);
194       usleep (delay*granularity);
195     }
196 }
197
198
199 static void
200 three_circle_wipe (Display *dpy, Window window, GC gc,
201                    int width, int height, int delay, int granularity)
202 {
203   int i;
204   int full = 360 * 64;
205   int q = full / 6;
206   int q2 = q * 2;
207   int inc = full / 240;
208   int start = random() % q;
209   int rad = (width > height ? width : height);
210
211   for (i = 0; i < q; i += inc)
212     {
213       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
214                (start+i) % full, inc);
215       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
216                (start-i) % full, -inc);
217
218       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
219                (start+q2+i) % full, inc);
220       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
221                (start+q2-i) % full, -inc);
222
223       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
224                (start+q2+q2+i) % full, inc);
225       XFillArc(dpy, window, gc, (width/2)-rad, (height/2)-rad, rad*2, rad*2,
226                (start+q2+q2-i) % full, -inc);
227
228       XSync (dpy, False);
229       usleep (delay*granularity);
230     }
231 }
232
233
234 static void
235 squaretate (Display *dpy, Window window, GC gc,
236             int width, int height, int delay, int granularity)
237 {
238   int steps = (((width > height ? width : width) * 2) / granularity);
239   int i;
240   Bool flip = random() & 1;
241
242 #define DRAW() \
243       if (flip) { \
244         points[0].x = width-points[0].x; \
245         points[1].x = width-points[1].x; \
246         points[2].x = width-points[2].x; } \
247       XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin)
248
249   for (i = 0; i < steps; i++)
250     {
251       XPoint points [3];
252       points[0].x = 0;
253       points[0].y = 0;
254       points[1].x = width;
255       points[1].y = 0;
256       points[2].x = 0;
257       points[2].y = points[0].y + ((i * height) / steps);
258       DRAW();
259
260       points[0].x = 0;
261       points[0].y = 0;
262       points[1].x = 0;
263       points[1].y = height;
264       points[2].x = ((i * width) / steps);
265       points[2].y = height;
266       DRAW();
267
268       points[0].x = width;
269       points[0].y = height;
270       points[1].x = 0;
271       points[1].y = height;
272       points[2].x = width;
273       points[2].y = height - ((i * height) / steps);
274       DRAW();
275
276       points[0].x = width;
277       points[0].y = height;
278       points[1].x = width;
279       points[1].y = 0;
280       points[2].x = width - ((i * width) / steps);
281       points[2].y = 0;
282       DRAW();
283
284       XSync (dpy, True);
285       if (delay > 0)
286         usleep (delay * granularity);
287    }
288 #undef DRAW
289 }
290
291
292 /* from Frederick Roeber <roeber@netscape.com> */
293 static void
294 fizzle (Display *dpy, Window window, GC gc,
295             int width, int height, int delay, int granularity)
296 {
297   /* These dimensions must be prime numbers.  They should be roughly the
298      square root of the width and height. */
299 # define BX 31
300 # define BY 31
301 # define SIZE (BX*BY)
302
303   int array[SIZE];
304   int i, j;
305   XPoint *skews;
306   int nx, ny;
307
308   /* Distribute the numbers [0,SIZE) randomly in the array */
309   {
310     int indices[SIZE];
311
312     for( i = 0; i < SIZE; i++ ) {
313       array[i] = -1;
314       indices[i] = i;
315     } 
316
317     for( i = 0; i < SIZE; i++ ) {
318       j = random()%(SIZE-i);
319       array[indices[j]] = i;
320       indices[j] = indices[SIZE-i-1];
321     }
322   }
323
324   /* nx, ny are the number of cells across and down, rounded up */
325   nx = width  / BX + (0 == (width %BX) ? 0 : 1);
326   ny = height / BY + (0 == (height%BY) ? 0 : 1);
327   skews = (XPoint *)malloc(sizeof(XPoint) * (nx*ny));
328   if( (XPoint *)0 != skews ) {
329     for( i = 0; i < nx; i++ ) {
330       for( j = 0; j < ny; j++ ) {
331         skews[j * nx + i].x = random()%BX;
332         skews[j * nx + i].y = random()%BY;
333       }
334     }
335   }
336
337 # define SKEWX(cx, cy) (((XPoint *)0 == skews)?0:skews[cy*nx + cx].x)
338 # define SKEWY(cx, cy) (((XPoint *)0 == skews)?0:skews[cy*nx + cx].y)
339
340   for( i = 0; i < SIZE; i++ ) {
341     int x = array[i] % BX;
342     int y = array[i] / BX;
343
344     {
345       int iy, cy;
346       for( iy = 0, cy = 0; iy < height; iy += BY, cy++ ) {
347         int ix, cx;
348         for( ix = 0, cx = 0; ix < width; ix += BX, cx++ ) {
349           int xx = ix + (SKEWX(cx, cy) + x*((cx%(BX-1))+1))%BX;
350           int yy = iy + (SKEWY(cx, cy) + y*((cy%(BY-1))+1))%BY;
351           if (xx < width && yy < height)
352             XDrawPoint(dpy, window, gc, xx, yy);
353         }
354       }
355     }
356
357     if( (BX-1) == (i%BX) ) {
358       XSync (dpy, False);
359       usleep (delay*granularity);
360     }
361   }
362
363 # undef SKEWX
364 # undef SKEWY
365
366   if( (XPoint *)0 != skews ) {
367     free(skews);
368   }
369
370 # undef BX
371 # undef BY
372 # undef SIZE
373 }
374
375
376 /* from Rick Campbell <rick@campbellcentral.org> */
377 static void
378 spiral (Display *display, Window window, GC context,
379         int width, int height, int delay, int granularity)
380 {
381 # define SPIRAL_ERASE_PI_2 (M_PI + M_PI)
382 # define SPIRAL_ERASE_LOOP_COUNT (10)
383 # define SPIRAL_ERASE_ARC_COUNT (360.0)
384 # define SPIRAL_ERASE_ANGLE_INCREMENT (SPIRAL_ERASE_PI_2 /     \
385 SPIRAL_ERASE_ARC_COUNT)
386 # define SPIRAL_ERASE_DELAY (0)
387
388   double angle;
389   int arc_limit;
390   int arc_max_limit;
391   int length_step;
392   XPoint points [3];
393
394   angle = 0.0;
395   arc_limit = 1;
396   arc_max_limit = (int) (ceil (sqrt ((width * width) + (height * height)))
397                          / 2.0);
398   length_step = ((arc_max_limit + SPIRAL_ERASE_LOOP_COUNT - 1) /
399                  SPIRAL_ERASE_LOOP_COUNT);
400   arc_max_limit += length_step;
401   points [0].x = width / 2;
402   points [0].y = height / 2;
403   points [1].x = points [0].x + length_step;
404   points [1].y = points [0].y;
405   points [2].x = points [1].x;
406   points [2].y = points [1].y;
407
408   for (arc_limit = length_step;
409        arc_limit < arc_max_limit;
410        arc_limit += length_step)
411     {
412       int arc_length = length_step;
413       int length_base = arc_limit;
414       for (angle = 0.0; angle < SPIRAL_ERASE_PI_2;
415            angle += SPIRAL_ERASE_ANGLE_INCREMENT)
416         {
417           arc_length = length_base + ((length_step * angle) /
418                                       SPIRAL_ERASE_PI_2);
419           points [1].x = points [2].x;
420           points [1].y = points [2].y;
421           points [2].x = points [0].x + (int)(cos (angle) * arc_length);
422           points [2].y = points [0].y + (int)(sin (angle) * arc_length);
423           XFillPolygon (display, window, context, points, 3, Convex,
424                         CoordModeOrigin);
425 # if (SPIRAL_ERASE_DELAY != 0)
426           usleep (SPIRAL_ERASE_DELAY);
427 # endif /* (SPIRAL_ERASE_DELAY != 0) */
428         }
429     }
430 # undef SPIRAL_ERASE_DELAY
431 # undef SPIRAL_ERASE_ANGLE_INCREMENT
432 # undef SPIRAL_ERASE_ARC_COUNT
433 # undef SPIRAL_ERASE_LOOP_COUNT
434 # undef SPIRAL_ERASE_PI_2
435 }
436
437
438 #undef MAX
439 #undef MIN
440 #define MAX(a,b) ((a)>(b)?(a):(b))
441 #define MIN(a,b) ((a)<(b)?(a):(b))
442
443 /* from David Bagley <bagleyd@tux.org> */
444 static void
445 random_squares(Display * dpy, Window window, GC gc,
446                int width, int height, int delay, int granularity)
447 {
448   int randsize = MAX(1, MIN(width, height) / (16 + (random() % 32)));
449   int max = (height / randsize + 1) * (width / randsize + 1);
450   int *squares = (int *) calloc(max, sizeof (*squares));
451   int i;
452   int columns = width / randsize + 1;  /* Add an extra for roundoff */
453
454   for (i = 0; i < max; i++)
455     squares[i] = i;
456
457   for (i = 0; i < max; i++)
458     {
459       int t, r;
460       t = squares[i];
461       r = random() % max;
462       squares[i] = squares[r];
463       squares[r] = t;
464     }
465
466   for (i = 0; i < max; i++)
467     {
468       XFillRectangle(dpy, window, gc,
469                      (squares[i] % columns) * randsize,
470                      (squares[i] / columns) * randsize,
471                      randsize, randsize);
472
473       XSync(dpy, False);
474       if (delay > 0 && ((i % granularity) == 0))
475       usleep(delay * granularity);
476     }
477   free(squares);
478 }
479
480 /* I first saw something like this, albeit in reverse, in an early Tetris
481    implementation for the Mac.
482     -- Torbjörn Andersson <torbjorn@dev.eurotime.se>
483  */
484
485 static void
486 slide_lines (Display * dpy, Window window, GC gc, int width, int height,
487              int delay, int granularity)
488 {
489   int slide_old_x, slide_new_x, clear_x;
490   int x, y, dx, dy;
491
492   /* This might need some tuning. The idea is to get sensible values no
493      matter what the size of the window.
494
495      Everything moves at constant speed. Should it accelerate instead? */
496
497   granularity *= 2;
498
499   dy = MAX (1, height / granularity);
500   dx = MAX (1, width / 100);
501
502   for (x = 0; x < width; x += dx)
503     {
504       for (y = 0; y < height; y += dy)
505         {
506           if ((y / dy) & 1)
507             {
508               slide_old_x = x;
509               slide_new_x = x + dx;
510               clear_x = x;
511             }
512           else
513             {
514               slide_old_x = dx;
515               slide_new_x = 0;
516               clear_x = width - x - dx;
517             }
518
519           XCopyArea (dpy, window, window, gc, slide_old_x, y, width - x - dx,
520                      dy, slide_new_x, y);
521           XClearArea (dpy, window, clear_x, y, dx, dy, False);
522         }
523
524       XSync(dpy, False);
525       usleep(delay * 3);
526     }
527 }
528
529 static Eraser erasers[] = {
530   random_lines,
531   venetian,
532   triple_wipe,
533   quad_wipe,
534   circle_wipe,
535   three_circle_wipe,
536   squaretate,
537   fizzle,
538   random_squares,
539   spiral,
540   slide_lines,
541 };
542
543
544 void
545 erase_window(Display *dpy, Window window, GC gc,
546              int width, int height, int mode, int delay)
547 {
548   int granularity = 25;
549
550   if (mode < 0 || mode >= countof(erasers))
551     mode = random() % countof(erasers);
552   (*(erasers[mode])) (dpy, window, gc, width, height, delay, granularity);
553   XClearWindow (dpy, window);
554   XSync(dpy, False);
555 }
556
557
558 void
559 erase_full_window(Display *dpy, Window window)
560 {
561   XWindowAttributes xgwa;
562   XGCValues gcv;
563   GC erase_gc;
564   XColor black;
565   int erase_speed, erase_mode;
566   char *s;
567
568   s = get_string_resource("eraseSpeed", "Integer");
569   if (s && *s)
570     erase_speed = get_integer_resource("eraseSpeed", "Integer");
571   else
572     erase_speed = 400;
573   if (s) free(s);
574
575   s = get_string_resource("eraseMode", "Integer");
576   if (s && *s)
577     erase_mode = get_integer_resource("eraseMode", "Integer");
578   else
579     erase_mode = -1;
580   if (s) free(s);
581
582   XGetWindowAttributes (dpy, window, &xgwa);
583   black.flags = DoRed|DoGreen|DoBlue;
584   black.red = black.green = black.blue = 0;
585   XAllocColor(dpy, xgwa.colormap, &black);
586   gcv.foreground = black.pixel;
587   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
588   erase_window (dpy, window, erase_gc, xgwa.width, xgwa.height,
589                 erase_mode, erase_speed);
590   XFreeColors(dpy, xgwa.colormap, &black.pixel, 1, 0);
591   XFreeGC(dpy, erase_gc);
592 }
593
594
595 \f
596 #if 0
597 #include "screenhack.h"
598
599 char *progclass = "Erase";
600 char *defaults [] = {
601   0
602 };
603
604 XrmOptionDescRec options [] = {{0}};
605 int options_size = 0;
606
607 void
608 screenhack (dpy, window)
609      Display *dpy;
610      Window window;
611 {
612   int delay = 500000;
613   XGCValues gcv;
614   GC gc;
615   XColor white;
616   XWindowAttributes xgwa;
617   XGetWindowAttributes (dpy, window, &xgwa);
618   white.flags = DoRed|DoGreen|DoBlue;
619   white.red = white.green = white.blue = 0xFFFF;
620   XAllocColor(dpy, xgwa.colormap, &white);
621   gcv.foreground = white.pixel;
622   gc = XCreateGC (dpy, window, GCForeground, &gcv);
623
624   while (1)
625     {
626       XFillRectangle(dpy, window, gc, 0, 0, 1280, 1024);
627       XSync (dpy, False);
628       usleep (delay);
629       erase_full_window(dpy, window);
630       XSync (dpy, False);
631       usleep (delay);
632
633     }
634 }
635
636 #endif