ftp://ftp.demon.nl/disk1/redhat-contrib/libc5/SRPMS/xscreensaver-2.14-1.src.rpm
[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   "*reaction:   -1",
47   "*diffusion:  -1",
48   "*verbose:    off",
49   "*radius:     -1",
50   "*speed:      0.0",
51   "*size:       0.66",
52   "*delay:      1000",
53   "*colors:     -1",
54   0
55 };
56
57 XrmOptionDescRec options [] = {
58   { "-width",           ".width",       XrmoptionSepArg, 0 },
59   { "-height",          ".height",      XrmoptionSepArg, 0 },
60   { "-epoch",           ".epoch",       XrmoptionSepArg, 0 },
61   { "-reaction",        ".reaction",    XrmoptionSepArg, 0 },
62   { "-diffusion",       ".diffusion",   XrmoptionSepArg, 0 },
63   { "-verbose",         ".verbose",     XrmoptionNoArg, "True" },
64   { "-radius",          ".radius",      XrmoptionSepArg, 0 },
65   { "-speed",           ".speed",       XrmoptionSepArg, 0 },
66   { "-size",            ".size",        XrmoptionSepArg, 0 },
67   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
68   { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
69   { 0, 0, 0, 0 }
70 };
71
72 #define bps 16
73 #define mx ((1<<16)-1)
74
75 /* you can replace integer mults wish shift/adds with these,
76    but it doesn't help on my 586 */
77 #define x5(n) ((n<<2)+n)
78 #define x7(n) ((n<<3)-n)
79
80 /* why strip bit? */
81 #define R (ya_random()&((1<<30)-1))
82
83 /* should factor into RD-specfic and compute-every-pixel general */
84 void
85 screenhack (Display *dpy, Window win)
86 {
87   GC gc;
88   XGCValues gcv;
89   XWindowAttributes xgwa;
90   Colormap cmap = 0;
91   XImage *image;
92   int width, height, radius;
93   int array_width, array_height;
94   double array_x, array_y;
95   double array_dx, array_dy;
96   int w2;
97   int frame = 0, epoch_time;
98   char *p;
99   int vdepth, pdepth;
100   ushort *r1, *r2, *r1b, *r2b;
101   int npix;
102   int reaction = 0;
103   int diffusion = 0;
104   int verbose;
105   int mapped;
106   int *m = 0;
107 #if dither_when_mapped
108   unsigned char *mc = 0;
109 #endif
110 #ifdef HAVE_XSHM_EXTENSION
111   int use_shm = 0;
112   XShmSegmentInfo shm_info;
113 #endif
114   int ncolors = 0;
115   XColor *colors = 0;
116
117   int delay = get_float_resource ("delay", "Integer");
118
119   XGetWindowAttributes (dpy, win, &xgwa);
120   width = get_integer_resource ("width", "Integer");
121   height = get_integer_resource ("height", "Integer");
122   {
123     double s = get_float_resource ("size", "Float");
124     double p = get_float_resource ("speed", "Float");
125     if (s < 0.0 || s > 1.0)
126       s = 1.0;
127     s = sqrt(s);
128     array_width = xgwa.width * s;
129     array_height = xgwa.height * s;
130     if (s < 0.99) {
131       array_width = (array_width / width) * width;
132       array_height = (array_height / height) * height;
133     }
134     if (array_width < width) array_width = width;
135     if (array_height < height) array_height = height;
136     array_x = (xgwa.width - array_width)/2;
137     array_y = (xgwa.height - array_height)/2;
138     array_dx = p;
139     array_dy = .31415926 * p;
140   }
141   if (width < 10) width = 10;
142   if (height < 10) height = 10;
143   verbose = get_boolean_resource ("verbose", "Boolean");
144   npix = (width + 2) * (height + 2);
145   epoch_time = get_integer_resource ("epoch", "Integer");
146   w2 = width + 2;
147   gcv.function = GXcopy;
148   gc = XCreateGC(dpy, win, GCFunction, &gcv);
149   vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
150
151   /* This code only deals with pixmap depths of 1, 8, 16, and 32.
152      Therefore, we assume that those depths will be supported by the
153      coresponding visual depths (that depth-24 displays accept depth-32
154      pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
155   pdepth = (vdepth == 1 ? 1 :
156             vdepth <= 8 ? 8 :
157             vdepth <= 16 ? 16 :
158             32);
159
160   cmap = xgwa.colormap;
161   ncolors = get_integer_resource ("colors", "Integer");
162
163   if (ncolors <= 0) {
164     if (vdepth > 8)
165       ncolors = 2047;
166     else
167       ncolors = 255;
168   }
169
170   if (mono_p || ncolors < 2) ncolors = 2;
171   if (ncolors <= 2) mono_p = True;
172   colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
173
174   mapped = (vdepth <= 8 &&
175             has_writable_cells(xgwa.screen, xgwa.visual));
176
177   if (!mapped)
178     m = (int *) malloc(sizeof(int) * (1<<16));
179 #if dither_when_mapped
180   else {
181     int i, di;
182     mc = (unsigned char *) malloc(1<<16);
183     for (i = 0; i < (1<<16); i++) {
184       di = (i + (ya_random()&255))>>8;
185       if (di > 255) di = 255;
186       mc[i] = di;
187     }
188   }
189 #endif
190   p = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
191   r1 = (ushort *) malloc(sizeof(ushort) * npix);
192   r2 = (ushort *) malloc(sizeof(ushort) * npix);
193   r1b = (ushort *) malloc(sizeof(ushort) * npix);
194   r2b = (ushort *) malloc(sizeof(ushort) * npix);
195   if (!p || !r1 || !r2 || !r1b || !r2b) {
196     fprintf(stderr, "not enough memory for %d pixels.\n", npix);
197     exit(1);
198   }
199
200 #ifdef HAVE_XSHM_EXTENSION
201   if (use_shm) {
202     printf("p=%X\n", p);
203     free(p);
204     image = XShmCreateImage(dpy, xgwa.visual, vdepth,
205                             ZPixmap, 0, &shm_info, width, height);
206     shm_info.shmid = shmget(IPC_PRIVATE,
207                             image->bytes_per_line * image->height,
208                             IPC_CREAT | 0777);
209     if (shm_info.shmid == -1)
210       printf ("shmget failed!");
211     shm_info.readOnly = False;
212     p = shmat(shm_info.shmid, 0, 0);
213     printf("p=%X %d\n", p, image->bytes_per_line);
214     XShmAttach(dpy, &shm_info);
215     XSync(dpy, False);
216   } else
217 #endif
218   image = XCreateImage(dpy, xgwa.visual, vdepth,
219                        ZPixmap, 0, p,
220                        width, height, 8, 0);
221
222   while (1) {
223     int i, j;
224     ushort *t;
225 #if test_pattern_hyper
226     if (frame&0x100)
227       sleep(1);
228 #endif
229     if (verbose) {
230       double tm = 0;
231       struct timeval tp;
232       if (!(frame%100)) {
233         double tm2;
234 #ifdef GETTIMEOFDAY_TWO_ARGS
235         struct timezone tzp;
236         gettimeofday(&tp, &tzp);
237 #else
238         gettimeofday(&tp);
239 #endif
240         tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
241         if (frame > 0)
242           printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
243         tm = tm2;
244       }
245     }
246     if (!(frame%epoch_time)) {
247       int s;
248       if (0 != frame) {
249         int t = epoch_time / 500;
250         if (t > 15)
251           t = 15;
252         sleep(t);
253       }
254           
255       for (i = 0; i < npix; i++) {
256         /* equilibrium */
257         r1[i] = 65500;
258         r2[i] = 11;
259       }
260
261       memset(colors, 0, ncolors*sizeof(*colors));
262       make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
263                             True, 0, True);
264       if (ncolors <= 2) {
265         mono_p = True;
266         ncolors = 2;
267         colors[0].flags = DoRed|DoGreen|DoBlue;
268         colors[0].red = colors[0].green = colors[0].blue = 0;
269         XAllocColor(dpy, cmap, &colors[0]);
270         colors[1].flags = DoRed|DoGreen|DoBlue;
271         colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
272         XAllocColor(dpy, cmap, &colors[1]);
273       }
274
275       /* Scale it up so that there are exactly 255 colors -- that keeps the
276          animation speed consistent, even when there aren't many allocatable
277          colors, and prevents the -mono mode from looking like static. */
278       if (ncolors != 255) {
279         int i, n = 255;
280         double scale = (double) ncolors / (double) (n+1);
281         XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
282         for (i = 0; i < n; i++)
283           c2[i] = colors[(int) (i * scale)];
284         free(colors);
285         colors = c2;
286         ncolors = n;
287       }
288
289
290       XSetWindowBackground(dpy, win, colors[255 % ncolors].pixel);
291       XClearWindow(dpy, win);
292
293       s = w2 * height/2 + width/2;
294       radius = get_integer_resource ("radius", "Integer");
295       if (radius < 0)
296         radius = 1 + ((R%10) ? (R%5) : (R % (width/2-2)));
297       for (i = -radius; i < (radius+1); i++)
298         for (j = -radius; j < (radius+1); j++)
299           r2[s + i + j*w2] = mx - (R&63);
300       reaction = get_integer_resource ("reaction", "Integer");
301       if (reaction < 0 || reaction > 2) reaction = R&1;
302       diffusion = get_integer_resource ("diffusion", "Integer");
303       if (diffusion < 0 || diffusion > 2)
304         diffusion = (R%5) ? ((R%3)?0:1) : 2;
305       if (2 == reaction && 2 == diffusion)
306         reaction = diffusion = 0;
307       
308       if (verbose)
309         printf("reaction = %d\ndiffusion = %d\nradius = %d\n",
310                reaction, diffusion, radius);
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 }