1 /* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
3 * reaction/diffusion textures
4 * Copyright (c) 1997 Scott Draves spot@transmeta.com
5 * this code is derived from Bomb
6 * see http://www.cs.cmu.edu/~spot/bomb.html
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation. No representations are made about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
16 * And remember: X Windows is to graphics hacking as roman numerals are to
17 * the square root of pi.
22 #include "screenhack.h"
24 #ifdef HAVE_XSHM_EXTENSION
26 #endif /* HAVE_XSHM_EXTENSION */
29 #define dither_when_mapped 1
38 #if dither_when_mapped
45 int frame, epoch_time;
46 unsigned short *r1, *r2, *r1b, *r2b;
47 int width, height, npix;
53 int array_width, array_height;
55 #ifdef HAVE_XSHM_EXTENSION
57 XShmSegmentInfo shm_info;
62 double array_x, array_y;
63 double array_dx, array_dy;
64 XWindowAttributes xgwa;
68 static void random_colors(struct state *st);
70 /* -----------------------------------------------------------
71 pixel hack, 8-bit pixel grid, first/next frame interface
73 pixack_init(int *size_h, int *size_v)
74 pixack_frame(char *pix_buf)
79 #define mx ((1<<16)-1)
81 /* you can replace integer mults wish shift/adds with these,
82 but it doesn't help on my 586 */
83 #define x5(n) ((n<<2)+n)
84 #define x7(n) ((n<<3)-n)
87 #define R (random()&((1<<30)-1))
88 #define BELLRAND(x) (((random()%(x)) + (random()%(x)) + (random()%(x)))/3)
90 /* returns number of pixels that the pixack produces. called once. */
92 pixack_init(struct state *st, int *size_h, int *size_v)
94 st->width = get_integer_resource (st->dpy, "width", "Integer");
95 st->height = get_integer_resource (st->dpy, "height", "Integer");
97 if (st->width <= 0 && st->height <= 0 && (R & 1))
98 st->width = st->height = 48 + BELLRAND(256);
100 if (st->width <= 0) st->width = 48 + BELLRAND(256);
101 if (st->height <= 0) st->height = 48 + BELLRAND(256);
103 /* jwz: when (and only when) XSHM is in use on an SGI 8-bit visual,
104 we get shear unless st->width is a multiple of 4. I don't understand
105 why. This is undoubtedly the wrong fix... */
106 if (visual_depth (st->xgwa.screen, st->xgwa.visual) == 8)
110 if (st->width < 10) st->width = 10;
111 if (st->height < 10) st->height = 10;
112 st->epoch_time = get_integer_resource (st->dpy, "epoch", "Integer");
113 st->npix = (st->width + 2) * (st->height + 2);
114 st->r1 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
115 st->r2 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
116 st->r1b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
117 st->r2b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
119 if (!st->r1 || !st->r2 || !st->r1b || !st->r2b) {
120 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
125 *size_v = st->height;
128 #define test_pattern_hyper 0
131 /* returns the pixels. called many times. */
133 pixack_frame(struct state *st, char *pix_buf)
136 int w2 = st->width + 2;
138 #if test_pattern_hyper
143 if (!(st->frame%st->epoch_time)) {
145 if (0 != st->frame) {
146 int tt = st->epoch_time / 500;
152 for (i = 0; i < st->npix; i++) {
160 XSetWindowBackground(st->dpy, st->window, st->colors[255 % st->ncolors].pixel);
161 XClearWindow(st->dpy, st->window);
163 s = w2 * (st->height/2) + st->width/2;
164 st->radius = get_integer_resource (st->dpy, "radius", "Integer");
166 int maxr = st->width/2-2;
167 int maxr2 = st->height/2-2;
168 if (maxr2 < maxr) maxr = maxr2;
171 st->radius = 1 + ((R%10) ? (R%5) : (R % maxr));
172 if (st->radius > maxr) st->radius = maxr;
174 for (i = -st->radius; i < (st->radius+1); i++)
175 for (j = -st->radius; j < (st->radius+1); j++)
176 st->r2[s + i + j*w2] = mx - (R&63);
177 st->reaction = get_integer_resource (st->dpy, "reaction", "Integer");
178 if (st->reaction < 0 || st->reaction > 2) st->reaction = R&1;
179 st->diffusion = get_integer_resource (st->dpy, "diffusion", "Integer");
180 if (st->diffusion < 0 || st->diffusion > 2)
181 st->diffusion = (R%5) ? ((R%3)?0:1) : 2;
182 if (2 == st->reaction && 2 == st->diffusion)
183 st->reaction = st->diffusion = 0;
185 for (i = 0; i <= st->width+1; i++) {
186 st->r1[i] = st->r1[i + w2 * st->height];
187 st->r2[i] = st->r2[i + w2 * st->height];
188 st->r1[i + w2 * (st->height + 1)] = st->r1[i + w2];
189 st->r2[i + w2 * (st->height + 1)] = st->r2[i + w2];
191 for (i = 0; i <= st->height+1; i++) {
192 st->r1[w2 * i] = st->r1[st->width + w2 * i];
193 st->r2[w2 * i] = st->r2[st->width + w2 * i];
194 st->r1[w2 * i + st->width + 1] = st->r1[w2 * i + 1];
195 st->r2[w2 * i + st->width + 1] = st->r2[w2 * i + 1];
197 for (i = 0; i < st->height; i++) {
199 char *q = pix_buf + st->width * i;
200 short *qq = ((short *) pix_buf) + st->width * i;
201 /* long *qqq = ((long *) pix_buf) + st->width * i; -- crashes on Alpha */
202 int *qqq = ((int *) pix_buf) + st->width * i;
203 unsigned short *i1 = st->r1 + 1 + w2 * ii;
204 unsigned short *i2 = st->r2 + 1 + w2 * ii;
205 unsigned short *o1 = st->r1b + 1 + w2 * ii;
206 unsigned short *o2 = st->r2b + 1 + w2 * ii;
207 for (j = 0; j < st->width; j++) {
208 #if test_pattern_hyper
209 int r1 = (i * j + (st->frame&127)*frame)&65535;
211 int uvv, r1 = 0, r2 = 0;
212 switch (st->diffusion) {
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 (st->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] = st->colors[st->mc[r1] % st->ncolors].pixel;
266 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
268 else if (st->pdepth == 8)
269 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
270 else if (st->pdepth == 16)
271 #if dither_when_mapped
272 qq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
274 qq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
276 else if (st->pdepth == 32)
277 #if dither_when_mapped
278 qqq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
280 qqq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
286 t = st->r1; st->r1 = st->r1b; st->r1b = t;
287 t = st->r2; st->r2 = st->r2b; st->r2b = t;
291 /* ------------- xscreensaver rendering -------------- */
293 static const char *rd_defaults [] = {
294 ".background: black",
295 ".foreground: white",
297 "*width: 0", /* tried to use -1 but it complained */
307 #ifdef HAVE_XSHM_EXTENSION
315 static XrmOptionDescRec rd_options [] = {
316 { "-width", ".width", XrmoptionSepArg, 0 },
317 { "-height", ".height", XrmoptionSepArg, 0 },
318 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
319 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
320 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
321 { "-radius", ".radius", XrmoptionSepArg, 0 },
322 { "-speed", ".speed", XrmoptionSepArg, 0 },
323 { "-size", ".size", XrmoptionSepArg, 0 },
324 { "-delay", ".delay", XrmoptionSepArg, 0 },
325 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
326 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
327 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
333 random_colors(struct state *st)
335 memset(st->colors, 0, st->ncolors*sizeof(*st->colors));
336 make_smooth_colormap (st->dpy, st->visual, st->cmap, st->colors, &st->ncolors,
338 if (st->ncolors <= 2) {
341 st->colors[0].flags = DoRed|DoGreen|DoBlue;
342 st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0;
343 XAllocColor(st->dpy, st->cmap, &st->colors[0]);
344 st->colors[1].flags = DoRed|DoGreen|DoBlue;
345 st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF;
346 XAllocColor(st->dpy, st->cmap, &st->colors[1]);
349 /* Scale it up so that there are exactly 255 colors -- that keeps the
350 animation speed consistent, even when there aren't many allocatable
351 colors, and prevents the -mono mode from looking like static. */
352 if (st->ncolors != 255) {
354 double scale = (double) st->ncolors / (double) (n+1);
355 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
356 for (i = 0; i < n; i++)
357 c2[i] = st->colors[(int) (i * scale)];
366 /* should factor into RD-specfic and compute-every-pixel general */
368 rd_init (Display *dpy, Window win)
370 struct state *st = (struct state *) calloc (1, sizeof(*st));
378 st->delay = get_integer_resource (st->dpy, "delay", "Float");
380 #ifdef HAVE_XSHM_EXTENSION
381 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
384 XGetWindowAttributes (st->dpy, win, &st->xgwa);
385 st->visual = st->xgwa.visual;
386 pixack_init(st, &st->width, &st->height);
388 double s = get_float_resource (st->dpy, "size", "Float");
389 double p = get_float_resource (st->dpy, "speed", "Float");
390 if (s < 0.0 || s > 1.0)
393 st->array_width = st->xgwa.width * s;
394 st->array_height = st->xgwa.height * s;
396 st->array_width = (st->array_width / st->width) * st->width;
397 st->array_height = (st->array_height / st->height) * st->height;
399 if (st->array_width < st->width) st->array_width = st->width;
400 if (st->array_height < st->height) st->array_height = st->height;
401 st->array_x = (st->xgwa.width - st->array_width)/2;
402 st->array_y = (st->xgwa.height - st->array_height)/2;
404 st->array_dy = .31415926 * p;
406 /* start in a random direction */
407 if (random() & 1) st->array_dx = -st->array_dx;
408 if (random() & 1) st->array_dy = -st->array_dy;
411 st->npix = (st->width + 2) * (st->height + 2);
413 /* gcv.function = GXcopy;*/
414 st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv);
415 vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
417 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
418 Therefore, we assume that those depths will be supported by the
419 coresponding visual depths (that depth-24 dpys accept depth-32
420 pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */
421 st->pdepth = (vdepth == 1 ? 1 :
426 /* Ok, this like, sucks and stuff. There are some XFree86 systems
427 that have depth-24 visuals, that do not accept depth-32 XImages!
428 Which if you ask me is just absurd, since all it would take is
429 for the server to truncate the bits in that case. So, this crap
430 here detects the specific case of: we have chosen depth 32;
431 and the server does not support depth 32. In that case, we
432 try and use depth 16 instead.
434 The real fix would be to rewrite this program to deal with
435 depth 24 directly (or even better, arbitrary depths, but that
436 would mean going through the XImage routines instead of messing
437 with the XImage->data directly.)
439 jwz, 18-Mar-99: well, the X servers I have access to these days do
440 support 32-deep images on deep visuals, so I no longer have the
441 ability to test this code -- but it was causing problems on the
442 visuals that I do have, and I think that's because I mistakenly
443 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
444 The symptom I was seeing was that the grid was 64x64, but the
445 images were being drawn 32x32 -- so there was a black stripe on
446 every other row. Wow, this code sucks so much.
448 if (st->pdepth == 32)
452 XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc);
453 for (i = 0; i < pfvc; i++)
454 if (pfv[i].bits_per_pixel == st->pdepth)
460 st->cmap = st->xgwa.colormap;
461 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
463 if (st->ncolors <= 0 || st->ncolors >= 255) {
470 if (mono_p || st->ncolors < 2) st->ncolors = 2;
471 if (st->ncolors <= 2) mono_p = True;
472 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
474 st->mapped = (vdepth <= 8 &&
475 has_writable_cells(st->xgwa.screen, st->xgwa.visual));
479 st->mc = (unsigned char *) malloc(1<<16);
480 for (i = 0; i < (1<<16); i++) {
481 di = (i + (random()&255))>>8;
482 if (di > 255) di = 255;
487 st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8)));
489 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
495 #ifdef HAVE_XSHM_EXTENSION
498 st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth,
499 ZPixmap, 0, &st->shm_info, st->width, st->height);
505 st->pd = st->image->data;
508 #endif /* HAVE_XSHM_EXTENSION */
512 st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth,
514 st->width, st->height, 8, 0);
521 rd_draw (Display *dpy, Window win, void *closure)
523 struct state *st = (struct state *) closure;
527 pixack_frame(st, st->pd);
528 for (i = 0; i < st->array_width; i += st->width)
529 for (j = 0; j < st->array_height; j += st->height)
530 #ifdef HAVE_XSHM_EXTENSION
532 XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
533 st->width, st->height, False);
536 XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
537 st->width, st->height);
539 st->array_x += st->array_dx;
540 st->array_y += st->array_dy;
541 if (st->array_x < 0) {
543 st->array_dx = -st->array_dx;
545 } else if (st->array_x > (st->xgwa.width - st->array_width)) {
546 st->array_x = (st->xgwa.width - st->array_width);
547 st->array_dx = -st->array_dx;
550 if (st->array_y < 0) {
552 st->array_dy = -st->array_dy;
554 } else if (st->array_y > (st->xgwa.height - st->array_height)) {
555 st->array_y = (st->xgwa.height - st->array_height);
556 st->array_dy = -st->array_dy;
562 double swap = st->array_dx;
563 st->array_dx = st->array_dy;
574 rd_reshape (Display *dpy, Window window, void *closure,
575 unsigned int w, unsigned int h)
580 rd_event (Display *dpy, Window window, void *closure, XEvent *event)
586 rd_free (Display *dpy, Window window, void *closure)
590 XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd)