1 /* xscreensaver, Copyright (c) 1992-2014 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 = 64 + BELLRAND(512);
100 if (st->width <= 0) st->width = 64 + BELLRAND(512);
101 if (st->height <= 0) st->height = 64 + BELLRAND(512);
103 if (st->width > st->xgwa.width) st->width = st->xgwa.width;
104 if (st->height > st->xgwa.height) st->height = st->xgwa.height;
106 /* jwz: when (and only when) XSHM is in use on an SGI 8-bit visual,
107 we get shear unless st->width is a multiple of 4. I don't understand
108 why. This is undoubtedly the wrong fix... */
109 if (visual_depth (st->xgwa.screen, st->xgwa.visual) == 8)
113 if (st->width < 10) st->width = 10;
114 if (st->height < 10) st->height = 10;
115 st->epoch_time = get_integer_resource (st->dpy, "epoch", "Integer");
116 st->npix = (st->width + 2) * (st->height + 2);
117 st->r1 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
118 st->r2 = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
119 st->r1b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
120 st->r2b = (unsigned short *) malloc(sizeof(unsigned short) * st->npix);
122 if (!st->r1 || !st->r2 || !st->r1b || !st->r2b) {
123 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
128 *size_v = st->height;
131 #define test_pattern_hyper 0
134 /* returns the pixels. called many times. */
136 pixack_frame(struct state *st, char *pix_buf)
139 int w2 = st->width + 2;
141 #if test_pattern_hyper
146 if (!(st->frame%st->epoch_time)) {
148 if (0 != st->frame) {
149 int tt = st->epoch_time / 500;
155 for (i = 0; i < st->npix; i++) {
163 XSetWindowBackground(st->dpy, st->window, st->colors[255 % st->ncolors].pixel);
164 XClearWindow(st->dpy, st->window);
166 s = w2 * (st->height/2) + st->width/2;
167 st->radius = get_integer_resource (st->dpy, "radius", "Integer");
169 int maxr = st->width/2-2;
170 int maxr2 = st->height/2-2;
171 if (maxr2 < maxr) maxr = maxr2;
174 st->radius = 1 + ((R%10) ? (R%5) : (R % maxr));
175 if (st->radius > maxr) st->radius = maxr;
177 for (i = -st->radius; i < (st->radius+1); i++)
178 for (j = -st->radius; j < (st->radius+1); j++)
179 st->r2[s + i + j*w2] = mx - (R&63);
180 st->reaction = get_integer_resource (st->dpy, "reaction", "Integer");
181 if (st->reaction < 0 || st->reaction > 2) st->reaction = R&1;
182 st->diffusion = get_integer_resource (st->dpy, "diffusion", "Integer");
183 if (st->diffusion < 0 || st->diffusion > 2)
184 st->diffusion = (R%5) ? ((R%3)?0:1) : 2;
185 if (2 == st->reaction && 2 == st->diffusion)
186 st->reaction = st->diffusion = 0;
188 for (i = 0; i <= st->width+1; i++) {
189 st->r1[i] = st->r1[i + w2 * st->height];
190 st->r2[i] = st->r2[i + w2 * st->height];
191 st->r1[i + w2 * (st->height + 1)] = st->r1[i + w2];
192 st->r2[i + w2 * (st->height + 1)] = st->r2[i + w2];
194 for (i = 0; i <= st->height+1; i++) {
195 st->r1[w2 * i] = st->r1[st->width + w2 * i];
196 st->r2[w2 * i] = st->r2[st->width + w2 * i];
197 st->r1[w2 * i + st->width + 1] = st->r1[w2 * i + 1];
198 st->r2[w2 * i + st->width + 1] = st->r2[w2 * i + 1];
200 for (i = 0; i < st->height; i++) {
202 char *q = pix_buf + st->width * i;
203 short *qq = ((short *) pix_buf) + st->width * i;
204 /* long *qqq = ((long *) pix_buf) + st->width * i; -- crashes on Alpha */
205 int *qqq = ((int *) pix_buf) + st->width * i;
206 unsigned short *i1 = st->r1 + 1 + w2 * ii;
207 unsigned short *i2 = st->r2 + 1 + w2 * ii;
208 unsigned short *o1 = st->r1b + 1 + w2 * ii;
209 unsigned short *o2 = st->r2b + 1 + w2 * ii;
210 for (j = 0; j < st->width; j++) {
211 #if test_pattern_hyper
212 int r1 = (i * j + (st->frame&127)*frame)&65535;
214 int uvv, r1 = 0, r2 = 0;
215 switch (st->diffusion) {
217 r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
219 r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
223 r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
225 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
229 r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
231 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
236 /* John E. Pearson "Complex Patterns in a Simple System"
237 Science, July 1993 */
239 /* uvv = (((r1 * r2) >> bps) * r2) >> bps; */
240 /* avoid signed integer overflow */
241 uvv = ((((r1 >> 1)* r2) >> bps) * r2) >> (bps - 1);
242 switch (st->reaction) { /* costs 4% */
244 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
245 r2 += 4 * (uvv - ((80 * r2) >> 10));
248 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
249 r2 += 3 * (uvv - ((80 * r2) >> 10));
252 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
253 r2 += 3 * (uvv - ((80 * r2) >> 10));
256 if (r1 > mx) r1 = mx;
257 if (r2 > mx) r2 = mx;
264 /* this is terrible. here i want to assume ncolors = 256.
265 should lose double indirection */
268 #if dither_when_mapped
269 q[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
271 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
273 else if (st->pdepth == 8)
274 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
275 else if (st->pdepth == 16)
276 #if dither_when_mapped
277 qq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
279 qq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
281 else if (st->pdepth == 32)
282 #if dither_when_mapped
283 qqq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
285 qqq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
291 t = st->r1; st->r1 = st->r1b; st->r1b = t;
292 t = st->r2; st->r2 = st->r2b; st->r2b = t;
296 /* ------------- xscreensaver rendering -------------- */
298 static const char *rd_defaults [] = {
299 ".background: black",
300 ".foreground: white",
302 "*width: 0", /* tried to use -1 but it complained */
312 #ifdef HAVE_XSHM_EXTENSION
318 "*ignoreRotation: True",
323 static XrmOptionDescRec rd_options [] = {
324 { "-width", ".width", XrmoptionSepArg, 0 },
325 { "-height", ".height", XrmoptionSepArg, 0 },
326 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
327 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
328 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
329 { "-radius", ".radius", XrmoptionSepArg, 0 },
330 { "-speed", ".speed", XrmoptionSepArg, 0 },
331 { "-size", ".size", XrmoptionSepArg, 0 },
332 { "-delay", ".delay", XrmoptionSepArg, 0 },
333 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
334 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
335 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
341 random_colors(struct state *st)
343 memset(st->colors, 0, st->ncolors*sizeof(*st->colors));
344 make_smooth_colormap (st->xgwa.screen, st->visual, st->cmap,
345 st->colors, &st->ncolors,
347 if (st->ncolors <= 2) {
350 st->colors[0].flags = DoRed|DoGreen|DoBlue;
351 st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0;
352 XAllocColor(st->dpy, st->cmap, &st->colors[0]);
353 st->colors[1].flags = DoRed|DoGreen|DoBlue;
354 st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF;
355 XAllocColor(st->dpy, st->cmap, &st->colors[1]);
358 /* Scale it up so that there are exactly 255 colors -- that keeps the
359 animation speed consistent, even when there aren't many allocatable
360 colors, and prevents the -mono mode from looking like static. */
361 if (st->ncolors != 255) {
363 double scale = (double) st->ncolors / (double) (n+1);
364 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
365 for (i = 0; i < n; i++)
366 c2[i] = st->colors[(int) (i * scale)];
375 /* should factor into RD-specfic and compute-every-pixel general */
377 rd_init (Display *dpy, Window win)
379 struct state *st = (struct state *) calloc (1, sizeof(*st));
387 st->delay = get_integer_resource (st->dpy, "delay", "Float");
389 #ifdef HAVE_XSHM_EXTENSION
390 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
393 XGetWindowAttributes (st->dpy, win, &st->xgwa);
394 st->visual = st->xgwa.visual;
395 pixack_init(st, &st->width, &st->height);
397 double s = get_float_resource (st->dpy, "size", "Float");
398 double p = get_float_resource (st->dpy, "speed", "Float");
399 if (s < 0.0 || s > 1.0)
402 st->array_width = st->xgwa.width * s;
403 st->array_height = st->xgwa.height * s;
405 st->array_width = (st->array_width / st->width) * st->width;
406 st->array_height = (st->array_height / st->height) * st->height;
408 if (st->array_width < st->width) st->array_width = st->width;
409 if (st->array_height < st->height) st->array_height = st->height;
410 st->array_x = (st->xgwa.width - st->array_width)/2;
411 st->array_y = (st->xgwa.height - st->array_height)/2;
413 st->array_dy = .31415926 * p;
415 /* start in a random direction */
416 if (random() & 1) st->array_dx = -st->array_dx;
417 if (random() & 1) st->array_dy = -st->array_dy;
420 st->npix = (st->width + 2) * (st->height + 2);
422 /* gcv.function = GXcopy;*/
423 st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv);
424 vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
426 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
427 Therefore, we assume that those depths will be supported by the
428 coresponding visual depths (that depth-24 dpys accept depth-32
429 pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */
430 st->pdepth = (vdepth == 1 ? 1 :
435 /* Ok, this like, sucks and stuff. There are some XFree86 systems
436 that have depth-24 visuals, that do not accept depth-32 XImages!
437 Which if you ask me is just absurd, since all it would take is
438 for the server to truncate the bits in that case. So, this crap
439 here detects the specific case of: we have chosen depth 32;
440 and the server does not support depth 32. In that case, we
441 try and use depth 16 instead.
443 The real fix would be to rewrite this program to deal with
444 depth 24 directly (or even better, arbitrary depths, but that
445 would mean going through the XImage routines instead of messing
446 with the XImage->data directly.)
448 jwz, 18-Mar-99: well, the X servers I have access to these days do
449 support 32-deep images on deep visuals, so I no longer have the
450 ability to test this code -- but it was causing problems on the
451 visuals that I do have, and I think that's because I mistakenly
452 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
453 The symptom I was seeing was that the grid was 64x64, but the
454 images were being drawn 32x32 -- so there was a black stripe on
455 every other row. Wow, this code sucks so much.
457 if (st->pdepth == 32)
461 XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc);
462 for (i = 0; i < pfvc; i++)
463 if (pfv[i].bits_per_pixel == st->pdepth)
469 st->cmap = st->xgwa.colormap;
470 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
472 if (st->ncolors <= 0 || st->ncolors >= 255) {
479 if (mono_p || st->ncolors < 2) st->ncolors = 2;
480 if (st->ncolors <= 2) mono_p = True;
481 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
483 st->mapped = (vdepth <= 8 &&
484 has_writable_cells(st->xgwa.screen, st->xgwa.visual));
488 st->mc = (unsigned char *) malloc(1<<16);
489 for (i = 0; i < (1<<16); i++) {
490 di = (i + (random()&255))>>8;
491 if (di > 255) di = 255;
496 st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8)));
498 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
504 #ifdef HAVE_XSHM_EXTENSION
507 st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth,
508 ZPixmap, 0, &st->shm_info, st->width, st->height);
514 st->pd = st->image->data;
517 #endif /* HAVE_XSHM_EXTENSION */
521 st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth,
523 st->width, st->height, 8, 0);
530 rd_draw (Display *dpy, Window win, void *closure)
532 struct state *st = (struct state *) closure;
536 pixack_frame(st, st->pd);
537 for (i = 0; i < st->array_width; i += st->width)
538 for (j = 0; j < st->array_height; j += st->height)
539 #ifdef HAVE_XSHM_EXTENSION
541 XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
542 st->width, st->height, False);
545 XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
546 st->width, st->height);
548 st->array_x += st->array_dx;
549 st->array_y += st->array_dy;
550 if (st->array_x < 0) {
552 st->array_dx = -st->array_dx;
554 } else if (st->array_x > (st->xgwa.width - st->array_width)) {
555 st->array_x = (st->xgwa.width - st->array_width);
556 st->array_dx = -st->array_dx;
559 if (st->array_y < 0) {
561 st->array_dy = -st->array_dy;
563 } else if (st->array_y > (st->xgwa.height - st->array_height)) {
564 st->array_y = (st->xgwa.height - st->array_height);
565 st->array_dy = -st->array_dy;
571 double swap = st->array_dx;
572 st->array_dx = st->array_dy;
583 rd_reshape (Display *dpy, Window window, void *closure,
584 unsigned int w, unsigned int h)
589 rd_event (Display *dpy, Window window, void *closure, XEvent *event)
595 rd_free (Display *dpy, Window window, void *closure)
599 XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd)