1 /* xscreensaver, Copyright (c) 1992, 1995, 1997, 1998, 1999, 2003
2 * Jamie Zawinski <jwz@jwz.org>
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
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
17 * And remember: X Windows is to graphics hacking as roman numerals are to
18 * the square root of pi.
23 #include "screenhack.h"
24 #include <X11/Xutil.h>
26 #ifdef HAVE_XSHM_EXTENSION
28 #endif /* HAVE_XSHM_EXTENSION */
31 #define dither_when_mapped 1
34 static int ncolors = 0;
35 static XColor *colors = 0;
36 static Display *display;
37 static Visual *visual;
38 #if dither_when_mapped
39 static unsigned char *mc = 0;
41 static Colormap cmap = 0;
45 static void random_colors(void);
47 /* -----------------------------------------------------------
48 pixel hack, 8-bit pixel grid, first/next frame interface
50 pixack_init(int *size_h, int *size_v)
51 pixack_frame(char *pix_buf)
56 #define mx ((1<<16)-1)
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)
64 #define R (ya_random()&((1<<30)-1))
66 static int frame = 0, epoch_time;
67 static ushort *r1, *r2, *r1b, *r2b;
68 static int width, height, npix;
70 static int reaction = 0;
71 static int diffusion = 0;
73 /* returns number of pixels that the pixack produces. called once. */
75 pixack_init(int *size_h, int *size_v)
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);
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... */
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);
99 if (!r1 || !r2 || !r1b || !r2b) {
100 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
108 #define test_pattern_hyper 0
111 /* returns the pixels. called many times. */
113 pixack_frame(char *pix_buf)
118 #if test_pattern_hyper
127 #ifdef GETTIMEOFDAY_TWO_ARGS
129 gettimeofday(&tp, &tzp);
133 tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
135 printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
139 if (!(frame%epoch_time)) {
142 int tt = epoch_time / 500;
148 for (i = 0; i < npix; i++) {
156 XSetWindowBackground(display, window, colors[255 % ncolors].pixel);
157 XClearWindow(display, window);
159 s = w2 * (height/2) + width/2;
160 radius = get_integer_resource ("radius", "Integer");
162 int maxr = width/2-2;
163 int maxr2 = height/2-2;
164 if (maxr2 < maxr) maxr = maxr2;
167 radius = 1 + ((R%10) ? (R%5) : (R % maxr));
168 if (radius > maxr) radius = maxr;
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;
182 printf("reaction = %d\ndiffusion = %d\nradius = %d\n",
183 reaction, diffusion, radius);
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];
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];
197 for (i = 0; i < height; i++) {
199 char *q = pix_buf + width * i;
200 short *qq = ((short *) pix_buf) + width * i;
201 /* long *qqq = ((long *) pix_buf) + width * i; -- crashes on Alpha */
202 int *qqq = ((int *) pix_buf) + width * i;
203 ushort *i1 = r1 + 1 + w2 * ii;
204 ushort *i2 = r2 + 1 + w2 * ii;
205 ushort *o1 = r1b + 1 + w2 * ii;
206 ushort *o2 = r2b + 1 + w2 * ii;
207 for (j = 0; j < width; j++) {
208 #if test_pattern_hyper
209 int r1 = (i * j + (frame&127)*frame)&65535;
211 int uvv, r1 = 0, r2 = 0;
214 r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
216 r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
220 r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
222 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
226 r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
228 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
233 /* John E. Pearson "Complex Patterns in a Simple System"
234 Science, July 1993 */
236 uvv = (((r1 * r2) >> bps) * r2) >> bps;
237 switch (reaction) { /* costs 4% */
239 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
240 r2 += 4 * (uvv - ((80 * r2) >> 10));
243 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
244 r2 += 3 * (uvv - ((80 * r2) >> 10));
247 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
248 r2 += 3 * (uvv - ((80 * r2) >> 10));
251 if (r1 > mx) r1 = mx;
252 if (r2 > mx) r2 = mx;
259 /* this is terrible. here i want to assume ncolors = 256.
260 should lose double indirection */
263 #if dither_when_mapped
264 q[j] = colors[mc[r1] % ncolors].pixel;
266 q[j] = colors[(r1>>8) % ncolors].pixel;
268 else if (pdepth == 8)
269 q[j] = colors[(r1>>8) % ncolors].pixel;
270 else if (pdepth == 16)
271 #if dither_when_mapped
272 qq[j] = colors[mc[r1] % ncolors].pixel;
274 qq[j] = colors[(r1>>8) % ncolors].pixel;
276 else if (pdepth == 32)
277 #if dither_when_mapped
278 qqq[j] = colors[mc[r1] % ncolors].pixel;
280 qqq[j] = colors[(r1>>8) % ncolors].pixel;
286 t = r1; r1 = r1b; r1b = t;
287 t = r2; r2 = r2b; r2b = t;
291 /* ------------- xscreensaver rendering -------------- */
295 char *progclass = "RD";
298 char *defaults [] = {
299 ".background: black",
300 ".foreground: white",
301 "*width: 0", /* tried to use -1 but it complained */
312 #ifdef HAVE_XSHM_EXTENSION
314 #endif /* HAVE_XSHM_EXTENSION */
318 XrmOptionDescRec options [] = {
319 { "-width", ".width", XrmoptionSepArg, 0 },
320 { "-height", ".height", XrmoptionSepArg, 0 },
321 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
322 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
323 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
324 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
325 { "-radius", ".radius", XrmoptionSepArg, 0 },
326 { "-speed", ".speed", XrmoptionSepArg, 0 },
327 { "-size", ".size", XrmoptionSepArg, 0 },
328 { "-delay", ".delay", XrmoptionSepArg, 0 },
329 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
330 #ifdef HAVE_XSHM_EXTENSION
331 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
332 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
333 #endif /* HAVE_XSHM_EXTENSION */
341 memset(colors, 0, ncolors*sizeof(*colors));
342 make_smooth_colormap (display, visual, cmap, colors, &ncolors,
347 colors[0].flags = DoRed|DoGreen|DoBlue;
348 colors[0].red = colors[0].green = colors[0].blue = 0;
349 XAllocColor(display, cmap, &colors[0]);
350 colors[1].flags = DoRed|DoGreen|DoBlue;
351 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
352 XAllocColor(display, cmap, &colors[1]);
355 /* Scale it up so that there are exactly 255 colors -- that keeps the
356 animation speed consistent, even when there aren't many allocatable
357 colors, and prevents the -mono mode from looking like static. */
358 if (ncolors != 255) {
360 double scale = (double) ncolors / (double) (n+1);
361 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
362 for (i = 0; i < n; i++)
363 c2[i] = colors[(int) (i * scale)];
371 /* should factor into RD-specfic and compute-every-pixel general */
373 screenhack (Display *dpy, Window win)
377 XWindowAttributes xgwa;
379 int array_width, array_height;
380 double array_x, array_y;
381 double array_dx, array_dy;
386 #ifdef HAVE_XSHM_EXTENSION
387 Bool use_shm = get_boolean_resource("useSHM", "Boolean");
388 XShmSegmentInfo shm_info;
391 double delay = get_float_resource ("delay", "Float");
397 XGetWindowAttributes (dpy, win, &xgwa);
398 visual = xgwa.visual;
399 pixack_init(&width, &height);
401 double s = get_float_resource ("size", "Float");
402 double p = get_float_resource ("speed", "Float");
403 if (s < 0.0 || s > 1.0)
406 array_width = xgwa.width * s;
407 array_height = xgwa.height * s;
409 array_width = (array_width / width) * width;
410 array_height = (array_height / height) * height;
412 if (array_width < width) array_width = width;
413 if (array_height < height) array_height = height;
414 array_x = (xgwa.width - array_width)/2;
415 array_y = (xgwa.height - array_height)/2;
417 array_dy = .31415926 * p;
419 /* start in a random direction */
420 if (random() & 1) array_dx = -array_dx;
421 if (random() & 1) array_dy = -array_dy;
424 verbose = get_boolean_resource ("verbose", "Boolean");
425 npix = (width + 2) * (height + 2);
427 gcv.function = GXcopy;
428 gc = XCreateGC(dpy, win, GCFunction, &gcv);
429 vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
431 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
432 Therefore, we assume that those depths will be supported by the
433 coresponding visual depths (that depth-24 displays accept depth-32
434 pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
435 pdepth = (vdepth == 1 ? 1 :
440 /* Ok, this like, sucks and stuff. There are some XFree86 systems
441 that have depth-24 visuals, that do not accept depth-32 XImages!
442 Which if you ask me is just absurd, since all it would take is
443 for the server to truncate the bits in that case. So, this crap
444 here detects the specific case of: we have chosen depth 32;
445 and the server does not support depth 32. In that case, we
446 try and use depth 16 instead.
448 The real fix would be to rewrite this program to deal with
449 depth 24 directly (or even better, arbitrary depths, but that
450 would mean going through the XImage routines instead of messing
451 with the XImage->data directly.)
453 jwz, 18-Mar-99: well, the X servers I have access to these days do
454 support 32-deep images on deep visuals, so I no longer have the
455 ability to test this code -- but it was causing problems on the
456 visuals that I do have, and I think that's because I mistakenly
457 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
458 The symptom I was seeing was that the grid was 64x64, but the
459 images were being drawn 32x32 -- so there was a black stripe on
460 every other row. Wow, this code sucks so much.
466 XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
467 for (i = 0; i < pfvc; i++)
468 if (pfv[i].bits_per_pixel == pdepth)
474 cmap = xgwa.colormap;
475 ncolors = get_integer_resource ("colors", "Integer");
484 if (mono_p || ncolors < 2) ncolors = 2;
485 if (ncolors <= 2) mono_p = True;
486 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
488 mapped = (vdepth <= 8 &&
489 has_writable_cells(xgwa.screen, xgwa.visual));
493 mc = (unsigned char *) malloc(1<<16);
494 for (i = 0; i < (1<<16); i++) {
495 di = (i + (random()&255))>>8;
496 if (di > 255) di = 255;
501 pd = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
503 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
509 #ifdef HAVE_XSHM_EXTENSION
512 image = create_xshm_image(dpy, xgwa.visual, vdepth,
513 ZPixmap, 0, &shm_info, width, height);
522 #endif /* HAVE_XSHM_EXTENSION */
526 image = XCreateImage(dpy, xgwa.visual, vdepth,
528 width, height, 8, 0);
536 for (i = 0; i < array_width; i += width)
537 for (j = 0; j < array_height; j += height)
538 #ifdef HAVE_XSHM_EXTENSION
540 XShmPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y,
541 width, height, False);
544 XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y,
551 array_dx = -array_dx;
553 } else if (array_x > (xgwa.width - array_width)) {
554 array_x = (xgwa.width - array_width);
555 array_dx = -array_dx;
560 array_dy = -array_dy;
562 } else if (array_y > (xgwa.height - array_height)) {
563 array_y = (xgwa.height - array_height);
564 array_dy = -array_dy;
570 double swap = array_dx;
579 screenhack_handle_events (dpy);
581 usleep(1000 * delay);