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)) {
149 for (i = 0; i < st->npix; i++) {
157 XSetWindowBackground(st->dpy, st->window, st->colors[255 % st->ncolors].pixel);
158 XClearWindow(st->dpy, st->window);
160 s = w2 * (st->height/2) + st->width/2;
161 st->radius = get_integer_resource (st->dpy, "radius", "Integer");
163 int maxr = st->width/2-2;
164 int maxr2 = st->height/2-2;
165 if (maxr2 < maxr) maxr = maxr2;
168 st->radius = 1 + ((R%10) ? (R%5) : (R % maxr));
169 if (st->radius > maxr) st->radius = maxr;
171 for (i = -st->radius; i < (st->radius+1); i++)
172 for (j = -st->radius; j < (st->radius+1); j++)
173 st->r2[s + i + j*w2] = mx - (R&63);
174 st->reaction = get_integer_resource (st->dpy, "reaction", "Integer");
175 if (st->reaction < 0 || st->reaction > 2) st->reaction = R&1;
176 st->diffusion = get_integer_resource (st->dpy, "diffusion", "Integer");
177 if (st->diffusion < 0 || st->diffusion > 2)
178 st->diffusion = (R%5) ? ((R%3)?0:1) : 2;
179 if (2 == st->reaction && 2 == st->diffusion)
180 st->reaction = st->diffusion = 0;
182 for (i = 0; i <= st->width+1; i++) {
183 st->r1[i] = st->r1[i + w2 * st->height];
184 st->r2[i] = st->r2[i + w2 * st->height];
185 st->r1[i + w2 * (st->height + 1)] = st->r1[i + w2];
186 st->r2[i + w2 * (st->height + 1)] = st->r2[i + w2];
188 for (i = 0; i <= st->height+1; i++) {
189 st->r1[w2 * i] = st->r1[st->width + w2 * i];
190 st->r2[w2 * i] = st->r2[st->width + w2 * i];
191 st->r1[w2 * i + st->width + 1] = st->r1[w2 * i + 1];
192 st->r2[w2 * i + st->width + 1] = st->r2[w2 * i + 1];
194 for (i = 0; i < st->height; i++) {
196 char *q = pix_buf + st->width * i;
197 short *qq = ((short *) pix_buf) + st->width * i;
198 /* long *qqq = ((long *) pix_buf) + st->width * i; -- crashes on Alpha */
199 int *qqq = ((int *) pix_buf) + st->width * i;
200 unsigned short *i1 = st->r1 + 1 + w2 * ii;
201 unsigned short *i2 = st->r2 + 1 + w2 * ii;
202 unsigned short *o1 = st->r1b + 1 + w2 * ii;
203 unsigned short *o2 = st->r2b + 1 + w2 * ii;
204 for (j = 0; j < st->width; j++) {
205 #if test_pattern_hyper
206 int r1 = (i * j + (st->frame&127)*frame)&65535;
208 int uvv, r1 = 0, r2 = 0;
209 switch (st->diffusion) {
211 r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
213 r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
217 r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
219 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
223 r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
225 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
230 /* John E. Pearson "Complex Patterns in a Simple System"
231 Science, July 1993 */
233 /* uvv = (((r1 * r2) >> bps) * r2) >> bps; */
234 /* avoid signed integer overflow */
235 uvv = ((((r1 >> 1)* r2) >> bps) * r2) >> (bps - 1);
236 switch (st->reaction) { /* costs 4% */
238 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
239 r2 += 4 * (uvv - ((80 * r2) >> 10));
242 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
243 r2 += 3 * (uvv - ((80 * r2) >> 10));
246 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
247 r2 += 3 * (uvv - ((80 * r2) >> 10));
250 if (r1 > mx) r1 = mx;
251 if (r2 > mx) r2 = mx;
258 /* this is terrible. here i want to assume ncolors = 256.
259 should lose double indirection */
262 #if dither_when_mapped
263 q[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
265 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
267 else if (st->pdepth == 8)
268 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
269 else if (st->pdepth == 16)
270 #if dither_when_mapped
271 qq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
273 qq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
275 else if (st->pdepth == 32)
276 #if dither_when_mapped
277 qqq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
279 qqq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
285 t = st->r1; st->r1 = st->r1b; st->r1b = t;
286 t = st->r2; st->r2 = st->r2b; st->r2b = t;
290 /* ------------- xscreensaver rendering -------------- */
292 static const char *rd_defaults [] = {
293 ".background: black",
294 ".foreground: white",
296 "*width: 0", /* tried to use -1 but it complained */
306 #ifdef HAVE_XSHM_EXTENSION
312 "*ignoreRotation: True",
317 static XrmOptionDescRec rd_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 { "-radius", ".radius", XrmoptionSepArg, 0 },
324 { "-speed", ".speed", XrmoptionSepArg, 0 },
325 { "-size", ".size", XrmoptionSepArg, 0 },
326 { "-delay", ".delay", XrmoptionSepArg, 0 },
327 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
328 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
329 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
335 random_colors(struct state *st)
337 memset(st->colors, 0, st->ncolors*sizeof(*st->colors));
338 make_smooth_colormap (st->xgwa.screen, st->visual, st->cmap,
339 st->colors, &st->ncolors,
341 if (st->ncolors <= 2) {
344 st->colors[0].flags = DoRed|DoGreen|DoBlue;
345 st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0;
346 XAllocColor(st->dpy, st->cmap, &st->colors[0]);
347 st->colors[1].flags = DoRed|DoGreen|DoBlue;
348 st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF;
349 XAllocColor(st->dpy, st->cmap, &st->colors[1]);
352 /* Scale it up so that there are exactly 255 colors -- that keeps the
353 animation speed consistent, even when there aren't many allocatable
354 colors, and prevents the -mono mode from looking like static. */
355 if (st->ncolors != 255) {
357 double scale = (double) st->ncolors / (double) (n+1);
358 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
359 for (i = 0; i < n; i++)
360 c2[i] = st->colors[(int) (i * scale)];
369 /* should factor into RD-specfic and compute-every-pixel general */
371 rd_init (Display *dpy, Window win)
373 struct state *st = (struct state *) calloc (1, sizeof(*st));
380 st->delay = get_integer_resource (st->dpy, "delay", "Float");
382 #ifdef HAVE_XSHM_EXTENSION
383 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
386 XGetWindowAttributes (st->dpy, win, &st->xgwa);
387 st->visual = st->xgwa.visual;
388 pixack_init(st, &st->width, &st->height);
390 double s = get_float_resource (st->dpy, "size", "Float");
391 double p = get_float_resource (st->dpy, "speed", "Float");
392 if (s < 0.0 || s > 1.0)
395 st->array_width = st->xgwa.width * s;
396 st->array_height = st->xgwa.height * s;
398 st->array_width = (st->array_width / st->width) * st->width;
399 st->array_height = (st->array_height / st->height) * st->height;
401 if (st->array_width < st->width) st->array_width = st->width;
402 if (st->array_height < st->height) st->array_height = st->height;
403 st->array_x = (st->xgwa.width - st->array_width)/2;
404 st->array_y = (st->xgwa.height - st->array_height)/2;
406 st->array_dy = .31415926 * p;
408 /* start in a random direction */
409 if (random() & 1) st->array_dx = -st->array_dx;
410 if (random() & 1) st->array_dy = -st->array_dy;
413 st->npix = (st->width + 2) * (st->height + 2);
414 /* gcv.function = GXcopy;*/
415 st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv);
416 vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
418 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
419 Therefore, we assume that those depths will be supported by the
420 coresponding visual depths (that depth-24 dpys accept depth-32
421 pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */
422 st->pdepth = (vdepth == 1 ? 1 :
427 /* Ok, this like, sucks and stuff. There are some XFree86 systems
428 that have depth-24 visuals, that do not accept depth-32 XImages!
429 Which if you ask me is just absurd, since all it would take is
430 for the server to truncate the bits in that case. So, this crap
431 here detects the specific case of: we have chosen depth 32;
432 and the server does not support depth 32. In that case, we
433 try and use depth 16 instead.
435 The real fix would be to rewrite this program to deal with
436 depth 24 directly (or even better, arbitrary depths, but that
437 would mean going through the XImage routines instead of messing
438 with the XImage->data directly.)
440 jwz, 18-Mar-99: well, the X servers I have access to these days do
441 support 32-deep images on deep visuals, so I no longer have the
442 ability to test this code -- but it was causing problems on the
443 visuals that I do have, and I think that's because I mistakenly
444 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
445 The symptom I was seeing was that the grid was 64x64, but the
446 images were being drawn 32x32 -- so there was a black stripe on
447 every other row. Wow, this code sucks so much.
449 if (st->pdepth == 32)
453 XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc);
454 for (i = 0; i < pfvc; i++)
455 if (pfv[i].bits_per_pixel == st->pdepth)
461 st->cmap = st->xgwa.colormap;
462 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
464 if (st->ncolors <= 0 || st->ncolors >= 255) {
471 if (mono_p || st->ncolors < 2) st->ncolors = 2;
472 if (st->ncolors <= 2) mono_p = True;
473 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
475 st->mapped = (vdepth <= 8 &&
476 has_writable_cells(st->xgwa.screen, st->xgwa.visual));
480 st->mc = (unsigned char *) malloc(1<<16);
481 for (i = 0; i < (1<<16); i++) {
482 di = (i + (random()&255))>>8;
483 if (di > 255) di = 255;
488 st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8)));
490 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
496 #ifdef HAVE_XSHM_EXTENSION
499 st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth,
500 ZPixmap, 0, &st->shm_info, st->width, st->height);
506 st->pd = st->image->data;
509 #endif /* HAVE_XSHM_EXTENSION */
513 st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth,
515 st->width, st->height, 8, 0);
522 rd_draw (Display *dpy, Window win, void *closure)
524 struct state *st = (struct state *) closure;
528 pixack_frame(st, st->pd);
529 for (i = 0; i < st->array_width; i += st->width)
530 for (j = 0; j < st->array_height; j += st->height)
531 #ifdef HAVE_XSHM_EXTENSION
533 XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
534 st->width, st->height, False);
537 XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
538 st->width, st->height);
540 st->array_x += st->array_dx;
541 st->array_y += st->array_dy;
542 if (st->array_x < 0) {
544 st->array_dx = -st->array_dx;
546 } else if (st->array_x > (st->xgwa.width - st->array_width)) {
547 st->array_x = (st->xgwa.width - st->array_width);
548 st->array_dx = -st->array_dx;
551 if (st->array_y < 0) {
553 st->array_dy = -st->array_dy;
555 } else if (st->array_y > (st->xgwa.height - st->array_height)) {
556 st->array_y = (st->xgwa.height - st->array_height);
557 st->array_dy = -st->array_dy;
563 double swap = st->array_dx;
564 st->array_dx = st->array_dy;
575 rd_reshape (Display *dpy, Window window, void *closure,
576 unsigned int w, unsigned int h)
581 rd_event (Display *dpy, Window window, void *closure, XEvent *event)
587 rd_free (Display *dpy, Window window, void *closure)
591 XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd)