source: trunk/third/xscreensaver/hacks/rd-bomb.c @ 20148

Revision 20148, 15.5 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1992, 1995, 1997, 1998, 1999, 2003
2 *  Jamie Zawinski <jwz@jwz.org>
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#include <X11/Xutil.h>
25
26#ifdef HAVE_XSHM_EXTENSION
27# include "xshm.h"
28#endif /* HAVE_XSHM_EXTENSION */
29
30/* costs ~6% speed */
31#define dither_when_mapped 1
32
33static int verbose;
34static int ncolors = 0;
35static XColor *colors = 0;
36static Display *display;
37static Visual *visual;
38#if dither_when_mapped
39static unsigned char *mc = 0;
40#endif
41static Colormap cmap = 0;
42static Window window;
43static int mapped;
44static int pdepth;
45static void random_colors(void);
46
47/* -----------------------------------------------------------
48   pixel hack, 8-bit pixel grid, first/next frame interface
49
50   pixack_init(int *size_h, int *size_v)
51   pixack_frame(char *pix_buf)
52   */
53
54
55#define bps 16
56#define mx ((1<<16)-1)
57
58/* you can replace integer mults wish shift/adds with these,
59   but it doesn't help on my 586 */
60#define x5(n) ((n<<2)+n)
61#define x7(n) ((n<<3)-n)
62
63/* why strip bit? */
64#define R (ya_random()&((1<<30)-1))
65
66static int frame = 0, epoch_time;
67static ushort *r1, *r2, *r1b, *r2b;
68static int width, height, npix;
69static int radius;
70static int reaction = 0;
71static int diffusion = 0;
72
73/* returns number of pixels that the pixack produces.  called once. */
74static void
75pixack_init(int *size_h, int *size_v)
76{
77  int sz_base;
78  width = get_integer_resource ("width", "Integer");
79  height = get_integer_resource ("height", "Integer");
80  sz_base = 80 + (R%40);
81  if (width <= 0) width = (R%20) ? sz_base : (28 + R%10);
82  if (height <= 0) height = (R%20) ? sz_base : (28 + R%10);
83
84  /* jwz: when (and only when) XSHM is in use on an SGI 8-bit visual,
85     we get shear unless width is a multiple of 4.  I don't understand
86     why.  This is undoubtedly the wrong fix... */
87  width &= ~0x7;
88
89  /* don't go there */
90  if (width < 10) width = 10;
91  if (height < 10) height = 10;
92  epoch_time = get_integer_resource ("epoch", "Integer");
93  npix = (width + 2) * (height + 2);
94  r1 = (ushort *) malloc(sizeof(ushort) * npix);
95  r2 = (ushort *) malloc(sizeof(ushort) * npix);
96  r1b = (ushort *) malloc(sizeof(ushort) * npix);
97  r2b = (ushort *) malloc(sizeof(ushort) * npix);
98
99  if (!r1 || !r2 || !r1b || !r2b) {
100    fprintf(stderr, "not enough memory for %d pixels.\n", npix);
101    exit(1);
102  }
103
104  *size_h = width;
105  *size_v = height;
106}
107
108#define test_pattern_hyper 0
109
110
111/* returns the pixels.  called many times. */
112static void
113pixack_frame(char *pix_buf)
114{
115  int i, j;
116  int w2 = width + 2;
117  ushort *t;
118#if test_pattern_hyper
119  if (frame&0x100)
120    sleep(1);
121#endif
122  if (verbose) {
123    double tm = 0;
124    struct timeval tp;
125    if (!(frame%100)) {
126      double tm2;
127#ifdef GETTIMEOFDAY_TWO_ARGS
128      struct timezone tzp;
129      gettimeofday(&tp, &tzp);
130#else
131      gettimeofday(&tp);
132#endif
133      tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
134      if (frame > 0)
135        printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
136      tm = tm2;
137    }
138  }
139  if (!(frame%epoch_time)) {
140    int s;
141    if (0 != frame) {
142      int tt = epoch_time / 500;
143      if (tt > 15)
144        tt = 15;
145      sleep(tt);
146    }
147         
148    for (i = 0; i < npix; i++) {
149      /* equilibrium */
150      r1[i] = 65500;
151      r2[i] = 11;
152    }
153
154    random_colors();
155
156    XSetWindowBackground(display, window, colors[255 % ncolors].pixel);
157    XClearWindow(display, window);
158
159    s = w2 * (height/2) + width/2;
160    radius = get_integer_resource ("radius", "Integer");
161    {
162      int maxr = width/2-2;
163      int maxr2 = height/2-2;
164      if (maxr2 < maxr) maxr = maxr2;
165
166      if (radius < 0)
167        radius = 1 + ((R%10) ? (R%5) : (R % maxr));
168      if (radius > maxr) radius = maxr;
169    }
170    for (i = -radius; i < (radius+1); i++)
171      for (j = -radius; j < (radius+1); j++)
172        r2[s + i + j*w2] = mx - (R&63);
173    reaction = get_integer_resource ("reaction", "Integer");
174    if (reaction < 0 || reaction > 2) reaction = R&1;
175    diffusion = get_integer_resource ("diffusion", "Integer");
176    if (diffusion < 0 || diffusion > 2)
177      diffusion = (R%5) ? ((R%3)?0:1) : 2;
178    if (2 == reaction && 2 == diffusion)
179      reaction = diffusion = 0;
180     
181    if (verbose)
182      printf("reaction = %d\ndiffusion = %d\nradius = %d\n",
183             reaction, diffusion, radius);
184  }
185  for (i = 0; i <= width+1; i++) {
186    r1[i] = r1[i + w2 * height];
187    r2[i] = r2[i + w2 * height];
188    r1[i + w2 * (height + 1)] = r1[i + w2];
189    r2[i + w2 * (height + 1)] = r2[i + w2];
190  }
191  for (i = 0; i <= height+1; i++) {
192    r1[w2 * i] = r1[width + w2 * i];
193    r2[w2 * i] = r2[width + w2 * i];
194    r1[w2 * i + width + 1] = r1[w2 * i + 1];
195    r2[w2 * i + width + 1] = r2[w2 * i + 1];
196  }
197  for (i = 0; i < height; i++) {
198    int ii = i + 1;
199    char *q = pix_buf + width * i;
200    short *qq = ((short *) pix_buf) + width * i;
201    long  *qqq = ((long *) pix_buf) + width * i;
202    ushort *i1 = r1 + 1 + w2 * ii;
203    ushort *i2 = r2 + 1 + w2 * ii;
204    ushort *o1 = r1b + 1 + w2 * ii;
205    ushort *o2 = r2b + 1 + w2 * ii;
206    for (j = 0; j < width; j++) {
207#if test_pattern_hyper
208      int r1 = (i * j + (frame&127)*frame)&65535;
209#else
210      int uvv, r1 = 0, r2 = 0;
211      switch (diffusion) {
212      case 0:
213        r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
214        r1 = r1 / 5;
215        r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
216        r2 = r2 / 12;
217        break;
218      case 1:
219        r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
220        r1 = r1 >> 2;
221        r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
222        r2 = r2 >> 3;
223        break;
224      case 2:
225        r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
226        r1 = r1 >> 3;
227        r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
228        r2 = r2 >> 3;
229        break;
230      }
231
232      /* John E. Pearson "Complex Patterns in a Simple System"
233         Science, July 1993 */
234
235      uvv = (((r1 * r2) >> bps) * r2) >> bps;
236      switch (reaction) {  /* costs 4% */
237      case 0:
238        r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
239        r2 += 4 * (uvv - ((80 * r2) >> 10));
240        break;
241      case 1:
242        r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
243        r2 += 3 * (uvv - ((80 * r2) >> 10));
244        break;
245      case 2:
246        r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
247        r2 += 3 * (uvv - ((80 * r2) >> 10));
248        break;
249      }
250      if (r1 > mx) r1 = mx;
251      if (r2 > mx) r2 = mx;
252      if (r1 < 0) r1 = 0;
253      if (r2 < 0) r2 = 0;
254      o1[j] = r1;
255      o2[j] = r2;
256#endif
257
258      /* this is terrible.  here i want to assume ncolors = 256.
259         should lose double indirection */
260
261      if (mapped)
262#if dither_when_mapped
263        q[j] = colors[mc[r1]  % ncolors].pixel;
264#else
265      q[j] = colors[(r1>>8) % ncolors].pixel;
266#endif
267      else if (pdepth == 8)
268        q[j] = colors[(r1>>8) % ncolors].pixel;
269      else if (pdepth == 16)
270#if dither_when_mapped
271        qq[j] = colors[mc[r1] % ncolors].pixel;
272#else
273        qq[j] = colors[(r1>>8) % ncolors].pixel;
274#endif
275      else if (pdepth == 32)
276#if dither_when_mapped
277        qqq[j] = colors[mc[r1] % ncolors].pixel;
278#else
279        qqq[j] = colors[(r1>>8) % ncolors].pixel;
280#endif
281      else
282        abort();
283    }
284  }
285  t = r1; r1 = r1b; r1b = t;
286  t = r2; r2 = r2b; r2b = t; 
287}
288
289
290/* ------------- xscreensaver rendering -------------- */
291
292
293
294char *progclass = "RD";
295
296
297char *defaults [] = {
298  ".background: black",
299  ".foreground: white",
300  "*width:      0",                     /* tried to use -1 but it complained */
301  "*height:     0",
302  "*epoch:      40000",
303  "*reaction:   -1",
304  "*diffusion:  -1",
305  "*verbose:    off",
306  "*radius:     -1",
307  "*speed:      0.0",
308  "*size:       1.0",
309  "*delay:      1",
310  "*colors:     -1",
311#ifdef HAVE_XSHM_EXTENSION
312  "*useSHM:     True",
313#endif /* HAVE_XSHM_EXTENSION */
314  0
315};
316
317XrmOptionDescRec options [] = {
318  { "-width",           ".width",       XrmoptionSepArg, 0 },
319  { "-height",          ".height",      XrmoptionSepArg, 0 },
320  { "-epoch",           ".epoch",       XrmoptionSepArg, 0 },
321  { "-reaction",        ".reaction",    XrmoptionSepArg, 0 },
322  { "-diffusion",       ".diffusion",   XrmoptionSepArg, 0 },
323  { "-verbose",         ".verbose",     XrmoptionNoArg, "True" },
324  { "-radius",          ".radius",      XrmoptionSepArg, 0 },
325  { "-speed",           ".speed",       XrmoptionSepArg, 0 },
326  { "-size",            ".size",        XrmoptionSepArg, 0 },
327  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
328  { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
329#ifdef HAVE_XSHM_EXTENSION
330  { "-shm",             ".useSHM",      XrmoptionNoArg, "True" },
331  { "-no-shm",          ".useSHM",      XrmoptionNoArg, "False" },
332#endif /* HAVE_XSHM_EXTENSION */
333  { 0, 0, 0, 0 }
334};
335
336
337static void
338random_colors(void)
339{
340  memset(colors, 0, ncolors*sizeof(*colors));
341  make_smooth_colormap (display, visual, cmap, colors, &ncolors,
342                        True, 0, True);
343  if (ncolors <= 2) {
344    mono_p = True;
345    ncolors = 2;
346    colors[0].flags = DoRed|DoGreen|DoBlue;
347    colors[0].red = colors[0].green = colors[0].blue = 0;
348    XAllocColor(display, cmap, &colors[0]);
349    colors[1].flags = DoRed|DoGreen|DoBlue;
350    colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
351    XAllocColor(display, cmap, &colors[1]);
352  }
353
354  /* Scale it up so that there are exactly 255 colors -- that keeps the
355     animation speed consistent, even when there aren't many allocatable
356     colors, and prevents the -mono mode from looking like static. */
357  if (ncolors != 255) {
358    int i, n = 255;
359    double scale = (double) ncolors / (double) (n+1);
360    XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
361    for (i = 0; i < n; i++)
362      c2[i] = colors[(int) (i * scale)];
363    free(colors);
364    colors = c2;
365    ncolors = n;
366  }
367
368}
369
370/* should factor into RD-specfic and compute-every-pixel general */
371void
372screenhack (Display *dpy, Window win)
373{
374  GC gc;
375  XGCValues gcv;
376  XWindowAttributes xgwa;
377  XImage *image;
378  int array_width, array_height;
379  double array_x, array_y;
380  double array_dx, array_dy;
381  int w2;
382  char *pd;
383  int vdepth;
384  int npix;
385#ifdef HAVE_XSHM_EXTENSION
386  Bool use_shm = get_boolean_resource("useSHM", "Boolean");
387  XShmSegmentInfo shm_info;
388#endif
389
390  double delay = get_float_resource ("delay", "Float");
391
392  display = dpy;
393  window = win;
394
395
396  XGetWindowAttributes (dpy, win, &xgwa);
397  visual = xgwa.visual;
398  pixack_init(&width, &height);
399  {
400    double s = get_float_resource ("size", "Float");
401    double p = get_float_resource ("speed", "Float");
402    if (s < 0.0 || s > 1.0)
403      s = 1.0;
404    s = sqrt(s);
405    array_width = xgwa.width * s;
406    array_height = xgwa.height * s;
407    if (s < 0.99) {
408      array_width = (array_width / width) * width;
409      array_height = (array_height / height) * height;
410    }
411    if (array_width < width) array_width = width;
412    if (array_height < height) array_height = height;
413    array_x = (xgwa.width - array_width)/2;
414    array_y = (xgwa.height - array_height)/2;
415    array_dx = p;
416    array_dy = .31415926 * p;
417
418    /* start in a random direction */
419    if (random() & 1) array_dx = -array_dx;
420    if (random() & 1) array_dy = -array_dy;
421
422  }
423  verbose = get_boolean_resource ("verbose", "Boolean");
424  npix = (width + 2) * (height + 2);
425  w2 = width + 2;
426  gcv.function = GXcopy;
427  gc = XCreateGC(dpy, win, GCFunction, &gcv);
428  vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
429
430  /* This code only deals with pixmap depths of 1, 8, 16, and 32.
431     Therefore, we assume that those depths will be supported by the
432     coresponding visual depths (that depth-24 displays accept depth-32
433     pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
434  pdepth = (vdepth == 1 ? 1 :
435            vdepth <= 8 ? 8 :
436            vdepth <= 16 ? 16 :
437            32);
438
439  /* Ok, this like, sucks and stuff.  There are some XFree86 systems
440     that have depth-24 visuals, that do not accept depth-32 XImages!
441     Which if you ask me is just absurd, since all it would take is
442     for the server to truncate the bits in that case.  So, this crap
443     here detects the specific case of: we have chosen depth 32;
444     and the server does not support depth 32.  In that case, we
445     try and use depth 16 instead.
446
447     The real fix would be to rewrite this program to deal with
448     depth 24 directly (or even better, arbitrary depths, but that
449     would mean going through the XImage routines instead of messing
450     with the XImage->data directly.)
451
452     jwz, 18-Mar-99: well, the X servers I have access to these days do
453     support 32-deep images on deep visuals, so I no longer have the
454     ability to test this code -- but it was causing problems on the
455     visuals that I do have, and I think that's because I mistakenly
456     wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
457     The symptom I was seeing was that the grid was 64x64, but the
458     images were being drawn 32x32 -- so there was a black stripe on
459     every other row.  Wow, this code sucks so much.
460   */
461  if (pdepth == 32)
462    {
463      int i, pfvc = 0;
464      Bool ok = False;
465      XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
466      for (i = 0; i < pfvc; i++)
467        if (pfv[i].bits_per_pixel == pdepth)
468          ok = True;
469      if (!ok)
470        pdepth = 16;
471    }
472
473  cmap = xgwa.colormap;
474  ncolors = get_integer_resource ("colors", "Integer");
475
476  if (ncolors <= 0) {
477    if (vdepth > 8)
478      ncolors = 2047;
479    else
480      ncolors = 255;
481  }
482
483  if (mono_p || ncolors < 2) ncolors = 2;
484  if (ncolors <= 2) mono_p = True;
485  colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
486
487  mapped = (vdepth <= 8 &&
488            has_writable_cells(xgwa.screen, xgwa.visual));
489
490  {
491    int i, di;
492    mc = (unsigned char *) malloc(1<<16);
493    for (i = 0; i < (1<<16); i++) {
494      di = (i + (random()&255))>>8;
495      if (di > 255) di = 255;
496      mc[i] = di;
497    }
498  }
499
500  pd = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
501  if (!pd) {
502    fprintf(stderr, "not enough memory for %d pixels.\n", npix);
503    exit(1);
504  }
505
506  image = 0;
507
508#ifdef HAVE_XSHM_EXTENSION
509  if (use_shm)
510    {
511      image = create_xshm_image(dpy, xgwa.visual, vdepth,
512                                ZPixmap, 0, &shm_info, width, height);
513      if (!image)
514        use_shm = False;
515      else
516        {
517          free(pd);
518          pd = image->data;
519        }
520    }
521#endif /* HAVE_XSHM_EXTENSION */
522
523  if (!image)
524    {
525      image = XCreateImage(dpy, xgwa.visual, vdepth,
526                           ZPixmap, 0, pd,
527                           width, height, 8, 0);
528    }
529
530  while (1) {
531    Bool bump = False;
532
533    int i, j;
534    pixack_frame(pd);
535    for (i = 0; i < array_width; i += width)
536      for (j = 0; j < array_height; j += height)
537#ifdef HAVE_XSHM_EXTENSION
538        if (use_shm)
539          XShmPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y,
540                       width, height, False);
541        else
542#endif
543          XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y,
544                    width, height);
545
546    array_x += array_dx;
547    array_y += array_dy;
548    if (array_x < 0) {
549      array_x = 0;
550      array_dx = -array_dx;
551      bump = True;
552    } else if (array_x > (xgwa.width - array_width)) {
553      array_x = (xgwa.width - array_width);
554      array_dx = -array_dx;
555      bump = True;
556    }
557    if (array_y < 0) {
558      array_y = 0;
559      array_dy = -array_dy;
560      bump = True;
561    } else if (array_y > (xgwa.height - array_height)) {
562      array_y = (xgwa.height - array_height);
563      array_dy = -array_dy;
564      bump = True;
565    }
566
567    if (bump) {
568      if (random() & 1) {
569        double swap = array_dx;
570        array_dx = array_dy;
571        array_dy = swap;
572      }
573    }
574
575    frame++;
576
577    XSync(dpy, False);
578    screenhack_handle_events (dpy);
579    if (delay > 0)
580      usleep(1000 * delay);
581  }
582}
Note: See TracBrowser for help on using the repository browser.