1 /* xscreensaver, Copyright (c) 1992-2013 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
313 "*ignoreRotation: True",
318 static XrmOptionDescRec rd_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 { "-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 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
330 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
336 random_colors(struct state *st)
338 memset(st->colors, 0, st->ncolors*sizeof(*st->colors));
339 make_smooth_colormap (st->xgwa.screen, st->visual, st->cmap,
340 st->colors, &st->ncolors,
342 if (st->ncolors <= 2) {
345 st->colors[0].flags = DoRed|DoGreen|DoBlue;
346 st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0;
347 XAllocColor(st->dpy, st->cmap, &st->colors[0]);
348 st->colors[1].flags = DoRed|DoGreen|DoBlue;
349 st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF;
350 XAllocColor(st->dpy, st->cmap, &st->colors[1]);
353 /* Scale it up so that there are exactly 255 colors -- that keeps the
354 animation speed consistent, even when there aren't many allocatable
355 colors, and prevents the -mono mode from looking like static. */
356 if (st->ncolors != 255) {
358 double scale = (double) st->ncolors / (double) (n+1);
359 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
360 for (i = 0; i < n; i++)
361 c2[i] = st->colors[(int) (i * scale)];
370 /* should factor into RD-specfic and compute-every-pixel general */
372 rd_init (Display *dpy, Window win)
374 struct state *st = (struct state *) calloc (1, sizeof(*st));
382 st->delay = get_integer_resource (st->dpy, "delay", "Float");
384 #ifdef HAVE_XSHM_EXTENSION
385 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
388 XGetWindowAttributes (st->dpy, win, &st->xgwa);
389 st->visual = st->xgwa.visual;
390 pixack_init(st, &st->width, &st->height);
392 double s = get_float_resource (st->dpy, "size", "Float");
393 double p = get_float_resource (st->dpy, "speed", "Float");
394 if (s < 0.0 || s > 1.0)
397 st->array_width = st->xgwa.width * s;
398 st->array_height = st->xgwa.height * s;
400 st->array_width = (st->array_width / st->width) * st->width;
401 st->array_height = (st->array_height / st->height) * st->height;
403 if (st->array_width < st->width) st->array_width = st->width;
404 if (st->array_height < st->height) st->array_height = st->height;
405 st->array_x = (st->xgwa.width - st->array_width)/2;
406 st->array_y = (st->xgwa.height - st->array_height)/2;
408 st->array_dy = .31415926 * p;
410 /* start in a random direction */
411 if (random() & 1) st->array_dx = -st->array_dx;
412 if (random() & 1) st->array_dy = -st->array_dy;
415 st->npix = (st->width + 2) * (st->height + 2);
417 /* gcv.function = GXcopy;*/
418 st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv);
419 vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
421 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
422 Therefore, we assume that those depths will be supported by the
423 coresponding visual depths (that depth-24 dpys accept depth-32
424 pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */
425 st->pdepth = (vdepth == 1 ? 1 :
430 /* Ok, this like, sucks and stuff. There are some XFree86 systems
431 that have depth-24 visuals, that do not accept depth-32 XImages!
432 Which if you ask me is just absurd, since all it would take is
433 for the server to truncate the bits in that case. So, this crap
434 here detects the specific case of: we have chosen depth 32;
435 and the server does not support depth 32. In that case, we
436 try and use depth 16 instead.
438 The real fix would be to rewrite this program to deal with
439 depth 24 directly (or even better, arbitrary depths, but that
440 would mean going through the XImage routines instead of messing
441 with the XImage->data directly.)
443 jwz, 18-Mar-99: well, the X servers I have access to these days do
444 support 32-deep images on deep visuals, so I no longer have the
445 ability to test this code -- but it was causing problems on the
446 visuals that I do have, and I think that's because I mistakenly
447 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
448 The symptom I was seeing was that the grid was 64x64, but the
449 images were being drawn 32x32 -- so there was a black stripe on
450 every other row. Wow, this code sucks so much.
452 if (st->pdepth == 32)
456 XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc);
457 for (i = 0; i < pfvc; i++)
458 if (pfv[i].bits_per_pixel == st->pdepth)
464 st->cmap = st->xgwa.colormap;
465 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
467 if (st->ncolors <= 0 || st->ncolors >= 255) {
474 if (mono_p || st->ncolors < 2) st->ncolors = 2;
475 if (st->ncolors <= 2) mono_p = True;
476 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
478 st->mapped = (vdepth <= 8 &&
479 has_writable_cells(st->xgwa.screen, st->xgwa.visual));
483 st->mc = (unsigned char *) malloc(1<<16);
484 for (i = 0; i < (1<<16); i++) {
485 di = (i + (random()&255))>>8;
486 if (di > 255) di = 255;
491 st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8)));
493 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
499 #ifdef HAVE_XSHM_EXTENSION
502 st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth,
503 ZPixmap, 0, &st->shm_info, st->width, st->height);
509 st->pd = st->image->data;
512 #endif /* HAVE_XSHM_EXTENSION */
516 st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth,
518 st->width, st->height, 8, 0);
525 rd_draw (Display *dpy, Window win, void *closure)
527 struct state *st = (struct state *) closure;
531 pixack_frame(st, st->pd);
532 for (i = 0; i < st->array_width; i += st->width)
533 for (j = 0; j < st->array_height; j += st->height)
534 #ifdef HAVE_XSHM_EXTENSION
536 XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
537 st->width, st->height, False);
540 XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
541 st->width, st->height);
543 st->array_x += st->array_dx;
544 st->array_y += st->array_dy;
545 if (st->array_x < 0) {
547 st->array_dx = -st->array_dx;
549 } else if (st->array_x > (st->xgwa.width - st->array_width)) {
550 st->array_x = (st->xgwa.width - st->array_width);
551 st->array_dx = -st->array_dx;
554 if (st->array_y < 0) {
556 st->array_dy = -st->array_dy;
558 } else if (st->array_y > (st->xgwa.height - st->array_height)) {
559 st->array_y = (st->xgwa.height - st->array_height);
560 st->array_dy = -st->array_dy;
566 double swap = st->array_dx;
567 st->array_dx = st->array_dy;
578 rd_reshape (Display *dpy, Window window, void *closure,
579 unsigned int w, unsigned int h)
584 rd_event (Display *dpy, Window window, void *closure, XEvent *event)
590 rd_free (Display *dpy, Window window, void *closure)
594 XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd)