ftp://ftp.sunet.se/pub/os/Linux/distributions/ultrapenguin/ultrapenguin-1.1/SRPMS...
[xscreensaver] / hacks / rd-bomb.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1997
2  *  Jamie Zawinski <jwz@netscape.com>
3  *
4  *  reaction/diffusion textures
5  *  Copyright (c) 1997 Scott Draves spot@transmeta.com
6  *  this code is derived from Bomb
7  *  see http://www.cs.cmu.edu/~spot/bomb.html
8  *
9  * Permission to use, copy, modify, distribute, and sell this software and its
10  * documentation for any purpose is hereby granted without fee, provided that
11  * the above copyright notice appear in all copies and that both that
12  * copyright notice and this permission notice appear in supporting
13  * documentation.  No representations are made about the suitability of this
14  * software for any purpose.  It is provided "as is" without express or 
15  * implied warranty.
16  *
17  * And remember: X Windows is to graphics hacking as roman numerals are to
18  * the square root of pi.
19  */
20
21 #include <math.h>
22
23 #include "screenhack.h"
24
25 /* why doesn't this work??? */
26 #ifdef HAVE_XSHM_EXTENSION
27 #include <sys/ipc.h>
28 #include <sys/shm.h>
29 #include <X11/extensions/XShm.h>
30 #endif
31
32 #define test_pattern_hyper 0
33
34 /* costs ~6% speed */
35 #define dither_when_mapped 1
36
37 char *progclass = "RD";
38
39
40 char *defaults [] = {
41   "RD.background:       black",         /* to placate SGI */
42   "RD.foreground:       white",
43   "*width:      100",
44   "*height:     100",
45   "*epoch:      40000",
46   "*palette:    -1",
47   "*reaction:   -1",
48   "*diffusion:  -1",
49   "*verbose:    off",
50   "*radius:     -1",
51   "*speed:      0.0",
52   "*size:       0.66",
53   "*delay:      1000",
54   "*colors:     -1",
55   0
56 };
57
58 XrmOptionDescRec options [] = {
59   { "-width",           ".width",       XrmoptionSepArg, 0 },
60   { "-height",          ".height",      XrmoptionSepArg, 0 },
61   { "-epoch",           ".epoch",       XrmoptionSepArg, 0 },
62   { "-palette",         ".palette",     XrmoptionSepArg, 0 },
63   { "-reaction",        ".reaction",    XrmoptionSepArg, 0 },
64   { "-diffusion",       ".diffusion",   XrmoptionSepArg, 0 },
65   { "-verbose",         ".verbose",     XrmoptionSepArg, 0 },
66   { "-radius",          ".radius",      XrmoptionSepArg, 0 },
67   { "-speed",           ".speed",       XrmoptionSepArg, 0 },
68   { "-size",            ".size",        XrmoptionSepArg, 0 },
69   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
70   { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
71   { 0, 0, 0, 0 }
72 };
73
74 #define bps 16
75 #define mx ((1<<16)-1)
76
77 /* you can replace integer mults wish shift/adds with these,
78    but it doesn't help on my 586 */
79 #define x5(n) ((n<<2)+n)
80 #define x7(n) ((n<<3)-n)
81
82 /* why strip bit? */
83 #define R (ya_random()&((1<<30)-1))
84
85 /* should factor into RD-specfic and compute-every-pixel general */
86 void
87 screenhack (Display *dpy, Window win)
88 {
89   GC gc;
90   XGCValues gcv;
91   XWindowAttributes xgwa;
92   Colormap cmap = 0;
93   XImage *image;
94   int width, height, radius;
95   int array_width, array_height;
96   double array_x, array_y;
97   double array_dx, array_dy;
98   int w2;
99   int frame = 0, epoch_time;
100   char *p;
101   int vdepth, pdepth;
102   ushort *r1, *r2, *r1b, *r2b;
103   int npix;
104   int reaction = 0;
105   int diffusion = 0;
106   int verbose;
107   int mapped;
108   int *m = 0;
109 #if dither_when_mapped
110   unsigned char *mc = 0;
111 #endif
112 #ifdef HAVE_XSHM_EXTENSION
113   int use_shm = 0;
114   XShmSegmentInfo shm_info;
115 #endif
116   int ncolors = 0;
117   XColor *colors = 0;
118
119   int delay = get_float_resource ("delay", "Integer");
120
121   XGetWindowAttributes (dpy, win, &xgwa);
122   width = get_integer_resource ("width", "Integer");
123   height = get_integer_resource ("height", "Integer");
124   {
125     double s = get_float_resource ("size", "Float");
126     double p = get_float_resource ("speed", "Float");
127     if (s < 0.0 || s > 1.0)
128       s = 1.0;
129     s = sqrt(s);
130     array_width = xgwa.width * s;
131     array_height = xgwa.height * s;
132     if (s < 0.99) {
133       array_width = (array_width / width) * width;
134       array_height = (array_height / height) * height;
135     }
136     if (array_width < width) array_width = width;
137     if (array_height < height) array_height = height;
138     array_x = (xgwa.width - array_width)/2;
139     array_y = (xgwa.height - array_height)/2;
140     array_dx = p;
141     array_dy = .31415926 * p;
142   }
143   if (width < 10) width = 10;
144   if (height < 10) height = 10;
145   verbose = get_boolean_resource ("verbose", "Boolean");
146   npix = (width + 2) * (height + 2);
147   epoch_time = get_integer_resource ("epoch", "Integer");
148   w2 = width + 2;
149   gcv.function = GXcopy;
150   gc = XCreateGC(dpy, win, GCFunction, &gcv);
151   vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
152
153   /* This code only deals with pixmap depths of 1, 8, 16, and 32.
154      Therefore, we assume that those depths will be supported by the
155      coresponding visual depths (that depth-24 displays accept depth-32
156      pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
157   pdepth = (vdepth == 1 ? 1 :
158             vdepth <= 8 ? 8 :
159             vdepth <= 16 ? 16 :
160             32);
161
162   cmap = xgwa.colormap;
163   ncolors = get_integer_resource ("colors", "Integer");
164
165   if (ncolors <= 0) {
166     if (vdepth > 8)
167       ncolors = 2047;
168     else
169       ncolors = 255;
170   }
171
172   if (mono_p || ncolors < 2) ncolors = 2;
173   if (ncolors <= 2) mono_p = True;
174   colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
175
176   mapped = (vdepth <= 8 &&
177             has_writable_cells(xgwa.screen, xgwa.visual));
178
179   if (!mapped)
180     m = (int *) malloc(sizeof(int) * (1<<16));
181 #if dither_when_mapped
182   else {
183     int i, di;
184     mc = (unsigned char *) malloc(1<<16);
185     for (i = 0; i < (1<<16); i++) {
186       di = (i + (ya_random()&255))>>8;
187       if (di > 255) di = 255;
188       mc[i] = di;
189     }
190   }
191 #endif
192   p = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
193   r1 = (ushort *) malloc(sizeof(ushort) * npix);
194   r2 = (ushort *) malloc(sizeof(ushort) * npix);
195   r1b = (ushort *) malloc(sizeof(ushort) * npix);
196   r2b = (ushort *) malloc(sizeof(ushort) * npix);
197   if (!p || !r1 || !r2 || !r1b || !r2b) {
198     fprintf(stderr, "not enough memory for %d pixels.\n", npix);
199     exit(1);
200   }
201
202 #ifdef HAVE_XSHM_EXTENSION
203   if (use_shm) {
204     printf("p=%X\n", p);
205     free(p);
206     image = XShmCreateImage(dpy, xgwa.visual, vdepth,
207                             ZPixmap, 0, &shm_info, width, height);
208     shm_info.shmid = shmget(IPC_PRIVATE,
209                             image->bytes_per_line * image->height,
210                             IPC_CREAT | 0777);
211     if (shm_info.shmid == -1)
212       printf ("shmget failed!");
213     shm_info.readOnly = False;
214     p = shmat(shm_info.shmid, 0, 0);
215     printf("p=%X %d\n", p, image->bytes_per_line);
216     XShmAttach(dpy, &shm_info);
217     XSync(dpy, False);
218   } else
219 #endif
220   image = XCreateImage(dpy, xgwa.visual, vdepth,
221                        ZPixmap, 0, p,
222                        width, height, 8, 0);
223
224   while (1) {
225     int i, j;
226     ushort *t;
227 #if test_pattern_hyper
228     if (frame&0x100)
229       sleep(1);
230 #endif
231     if (verbose) {
232       double tm = 0;
233       struct timeval tp;
234       struct timezone tzp;
235       if (!(frame%100)) {
236         double tm2;
237         gettimeofday(&tp, &tzp);
238         tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
239         if (frame > 0)
240           printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
241         tm = tm2;
242       }
243     }
244     if (!(frame%epoch_time)) {
245       int s;
246       if (0 != frame) {
247         int t = epoch_time / 500;
248         if (t > 15)
249           t = 15;
250         sleep(t);
251       }
252           
253       for (i = 0; i < npix; i++) {
254         /* equilibrium */
255         r1[i] = 65500;
256         r2[i] = 11;
257       }
258
259       memset(colors, 0, ncolors*sizeof(*colors));
260       make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
261                             True, 0, True);
262       if (ncolors <= 2) {
263         mono_p = True;
264         ncolors = 2;
265         colors[0].flags = DoRed|DoGreen|DoBlue;
266         colors[0].red = colors[0].green = colors[0].blue = 0;
267         XAllocColor(dpy, cmap, &colors[0]);
268         colors[1].flags = DoRed|DoGreen|DoBlue;
269         colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
270         XAllocColor(dpy, cmap, &colors[1]);
271       }
272
273       /* Scale it up so that there are exactly 255 colors -- that keeps the
274          animation speed consistent, even when there aren't many allocatable
275          colors, and prevents the -mono mode from looking like static. */
276       if (ncolors != 255) {
277         int i, n = 255;
278         double scale = (double) ncolors / (double) (n+1);
279         XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
280         for (i = 0; i < n; i++)
281           c2[i] = colors[(int) (i * scale)];
282         free(colors);
283         colors = c2;
284         ncolors = n;
285       }
286
287
288       XSetWindowBackground(dpy, win, colors[255 % ncolors].pixel);
289       XClearWindow(dpy, win);
290
291       s = w2 * height/2 + width/2;
292       radius = get_integer_resource ("radius", "Integer");
293       if (radius < 0)
294         radius = 1 + ((R%10) ? (R%5) : (R % (width/2-2)));
295       for (i = -radius; i < (radius+1); i++)
296         for (j = -radius; j < (radius+1); j++)
297           r2[s + i + j*w2] = mx - (R&63);
298       reaction = get_integer_resource ("reaction", "Integer");
299       if (reaction < 0 || reaction > 2) reaction = R&1;
300       diffusion = get_integer_resource ("diffusion", "Integer");
301       if (diffusion < 0 || diffusion > 2)
302         diffusion = (R%5) ? ((R%3)?0:1) : 2;
303       if (2 == reaction && 2 == diffusion)
304         reaction = diffusion = 0;
305       
306 /*      if (verbose)
307         printf("reaction = %d\ndiffusion = %d\n"
308                "palette = %d\nradius = %d\n",
309                reaction, diffusion, palette, radius);
310 */
311     }
312     for (i = 0; i <= width+1; i++) {
313       r1[i] = r1[i + w2 * height];
314       r2[i] = r2[i + w2 * height];
315       r1[i + w2 * (height + 1)] = r1[i + w2];
316       r2[i + w2 * (height + 1)] = r2[i + w2];
317     }
318     for (i = 0; i <= height+1; i++) {
319       r1[w2 * i] = r1[width + w2 * i];
320       r2[w2 * i] = r2[width + w2 * i];
321       r1[w2 * i + width + 1] = r1[w2 * i + 1];
322       r2[w2 * i + width + 1] = r2[w2 * i + 1];
323     }
324     for (i = 0; i < height; i++) {
325       int ii = i + 1;
326       char *q = p + width * i;
327       short *qq = ((short *) p) + width * i;
328       long  *qqq = ((long *) p) + width * i;
329       ushort *i1 = r1 + 1 + w2 * ii;
330       ushort *i2 = r2 + 1 + w2 * ii;
331       ushort *o1 = r1b + 1 + w2 * ii;
332       ushort *o2 = r2b + 1 + w2 * ii;
333       for (j = 0; j < width; j++) {
334 #if test_pattern_hyper
335         int r1 = (i * j + (frame&127)*frame)&65535;
336 #else
337         int uvv, r1 = 0, r2 = 0;
338         switch (diffusion) {
339         case 0:
340           r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
341           r1 = r1 / 5;
342           r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
343           r2 = r2 / 12;
344           break;
345         case 1:
346           r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
347           r1 = r1 >> 2;
348           r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
349           r2 = r2 >> 3;
350           break;
351         case 2:
352           r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
353           r1 = r1 >> 3;
354           r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
355           r2 = r2 >> 3;
356           break;
357         }
358         uvv = (((r1 * r2) >> bps) * r2) >> bps;
359         switch (reaction) {  /* costs 4% */
360         case 0:
361           r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
362           r2 += 4 * (uvv - ((80 * r2) >> 10));
363           break;
364         case 1:
365           r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
366           r2 += 3 * (uvv - ((80 * r2) >> 10));
367           break;
368         case 2:
369           r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
370           r2 += 3 * (uvv - ((80 * r2) >> 10));
371           break;
372         }
373         if (r1 > mx) r1 = mx;
374         if (r2 > mx) r2 = mx;
375         if (r1 < 0) r1 = 0;
376         if (r2 < 0) r2 = 0;
377         o1[j] = r1;
378         o2[j] = r2;
379 #endif
380
381         if (mapped)
382 #if dither_when_mapped
383           q[j] = colors[mc[r1]  % ncolors].pixel;
384 #else
385           q[j] = colors[(r1>>8) % ncolors].pixel;
386 #endif
387         else if (pdepth == 8)
388           q[j] = colors[(r1>>8) % ncolors].pixel;
389         else if (pdepth == 16)
390           qq[j] = colors[(r1>>8) % ncolors].pixel;
391         else if (pdepth == 32)
392           qqq[j] = colors[(r1>>8) % ncolors].pixel;
393         else
394           abort();
395       }
396     }
397     t = r1; r1 = r1b; r1b = t;
398     t = r2; r2 = r2b; r2b = t;
399     for (i = 0; i < array_width; i += width)
400       for (j = 0; j < array_height; j += height)
401 #ifdef HAVE_XSHM_EXTENSION
402         if (use_shm)
403           XShmPutImage(dpy, win, gc, image, 0, 0, i, j,
404                        width, height, False);
405         else
406 #endif
407           XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y, width, height);
408
409     array_x += array_dx;
410     array_y += array_dy;
411     if (array_x < 0) {
412       array_x = 0;
413       array_dx = -array_dx;
414     } else if (array_x > (xgwa.width - array_width)) {
415       array_x = (xgwa.width - array_width);
416       array_dx = -array_dx;
417     }
418     if (array_y < 0) {
419       array_y = 0;
420       array_dy = -array_dy;
421     } else if (array_y > (xgwa.height - array_height)) {
422       array_y = (xgwa.height - array_height);
423       array_dy = -array_dy;
424     }
425     frame++;
426
427     XSync(dpy, False);
428     if (delay > 0)
429       usleep(delay);
430   }
431 }