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 = 48 + BELLRAND(256);
100 if (st->width <= 0) st->width = 48 + BELLRAND(256);
101 if (st->height <= 0) st->height = 48 + BELLRAND(256);
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 switch (st->reaction) { /* costs 4% */
242 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
243 r2 += 4 * (uvv - ((80 * r2) >> 10));
246 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
247 r2 += 3 * (uvv - ((80 * r2) >> 10));
250 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
251 r2 += 3 * (uvv - ((80 * r2) >> 10));
254 if (r1 > mx) r1 = mx;
255 if (r2 > mx) r2 = mx;
262 /* this is terrible. here i want to assume ncolors = 256.
263 should lose double indirection */
266 #if dither_when_mapped
267 q[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
269 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
271 else if (st->pdepth == 8)
272 q[j] = st->colors[(r1>>8) % st->ncolors].pixel;
273 else if (st->pdepth == 16)
274 #if dither_when_mapped
275 qq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
277 qq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
279 else if (st->pdepth == 32)
280 #if dither_when_mapped
281 qqq[j] = st->colors[st->mc[r1] % st->ncolors].pixel;
283 qqq[j] = st->colors[(r1>>8) % st->ncolors].pixel;
289 t = st->r1; st->r1 = st->r1b; st->r1b = t;
290 t = st->r2; st->r2 = st->r2b; st->r2b = t;
294 /* ------------- xscreensaver rendering -------------- */
296 static const char *rd_defaults [] = {
297 ".background: black",
298 ".foreground: white",
300 "*width: 0", /* tried to use -1 but it complained */
310 #ifdef HAVE_XSHM_EXTENSION
316 "*ignoreRotation: True",
321 static XrmOptionDescRec rd_options [] = {
322 { "-width", ".width", XrmoptionSepArg, 0 },
323 { "-height", ".height", XrmoptionSepArg, 0 },
324 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
325 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
326 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
327 { "-radius", ".radius", XrmoptionSepArg, 0 },
328 { "-speed", ".speed", XrmoptionSepArg, 0 },
329 { "-size", ".size", XrmoptionSepArg, 0 },
330 { "-delay", ".delay", XrmoptionSepArg, 0 },
331 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
332 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
333 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
339 random_colors(struct state *st)
341 memset(st->colors, 0, st->ncolors*sizeof(*st->colors));
342 make_smooth_colormap (st->xgwa.screen, st->visual, st->cmap,
343 st->colors, &st->ncolors,
345 if (st->ncolors <= 2) {
348 st->colors[0].flags = DoRed|DoGreen|DoBlue;
349 st->colors[0].red = st->colors[0].green = st->colors[0].blue = 0;
350 XAllocColor(st->dpy, st->cmap, &st->colors[0]);
351 st->colors[1].flags = DoRed|DoGreen|DoBlue;
352 st->colors[1].red = st->colors[1].green = st->colors[1].blue = 0xFFFF;
353 XAllocColor(st->dpy, st->cmap, &st->colors[1]);
356 /* Scale it up so that there are exactly 255 colors -- that keeps the
357 animation speed consistent, even when there aren't many allocatable
358 colors, and prevents the -mono mode from looking like static. */
359 if (st->ncolors != 255) {
361 double scale = (double) st->ncolors / (double) (n+1);
362 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
363 for (i = 0; i < n; i++)
364 c2[i] = st->colors[(int) (i * scale)];
373 /* should factor into RD-specfic and compute-every-pixel general */
375 rd_init (Display *dpy, Window win)
377 struct state *st = (struct state *) calloc (1, sizeof(*st));
385 st->delay = get_integer_resource (st->dpy, "delay", "Float");
387 #ifdef HAVE_XSHM_EXTENSION
388 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
391 XGetWindowAttributes (st->dpy, win, &st->xgwa);
392 st->visual = st->xgwa.visual;
393 pixack_init(st, &st->width, &st->height);
395 double s = get_float_resource (st->dpy, "size", "Float");
396 double p = get_float_resource (st->dpy, "speed", "Float");
397 if (s < 0.0 || s > 1.0)
400 st->array_width = st->xgwa.width * s;
401 st->array_height = st->xgwa.height * s;
403 st->array_width = (st->array_width / st->width) * st->width;
404 st->array_height = (st->array_height / st->height) * st->height;
406 if (st->array_width < st->width) st->array_width = st->width;
407 if (st->array_height < st->height) st->array_height = st->height;
408 st->array_x = (st->xgwa.width - st->array_width)/2;
409 st->array_y = (st->xgwa.height - st->array_height)/2;
411 st->array_dy = .31415926 * p;
413 /* start in a random direction */
414 if (random() & 1) st->array_dx = -st->array_dx;
415 if (random() & 1) st->array_dy = -st->array_dy;
418 st->npix = (st->width + 2) * (st->height + 2);
420 /* gcv.function = GXcopy;*/
421 st->gc = XCreateGC(st->dpy, win, 0 /*GCFunction*/, &gcv);
422 vdepth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
424 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
425 Therefore, we assume that those depths will be supported by the
426 coresponding visual depths (that depth-24 dpys accept depth-32
427 pixmaps, and that depth-12 dpys accept depth-16 pixmaps.) */
428 st->pdepth = (vdepth == 1 ? 1 :
433 /* Ok, this like, sucks and stuff. There are some XFree86 systems
434 that have depth-24 visuals, that do not accept depth-32 XImages!
435 Which if you ask me is just absurd, since all it would take is
436 for the server to truncate the bits in that case. So, this crap
437 here detects the specific case of: we have chosen depth 32;
438 and the server does not support depth 32. In that case, we
439 try and use depth 16 instead.
441 The real fix would be to rewrite this program to deal with
442 depth 24 directly (or even better, arbitrary depths, but that
443 would mean going through the XImage routines instead of messing
444 with the XImage->data directly.)
446 jwz, 18-Mar-99: well, the X servers I have access to these days do
447 support 32-deep images on deep visuals, so I no longer have the
448 ability to test this code -- but it was causing problems on the
449 visuals that I do have, and I think that's because I mistakenly
450 wrote `pfv[i].depth' when I meant to write `pfv[i].bits_per_pixel'.
451 The symptom I was seeing was that the grid was 64x64, but the
452 images were being drawn 32x32 -- so there was a black stripe on
453 every other row. Wow, this code sucks so much.
455 if (st->pdepth == 32)
459 XPixmapFormatValues *pfv = XListPixmapFormats (st->dpy, &pfvc);
460 for (i = 0; i < pfvc; i++)
461 if (pfv[i].bits_per_pixel == st->pdepth)
467 st->cmap = st->xgwa.colormap;
468 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
470 if (st->ncolors <= 0 || st->ncolors >= 255) {
477 if (mono_p || st->ncolors < 2) st->ncolors = 2;
478 if (st->ncolors <= 2) mono_p = True;
479 st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1));
481 st->mapped = (vdepth <= 8 &&
482 has_writable_cells(st->xgwa.screen, st->xgwa.visual));
486 st->mc = (unsigned char *) malloc(1<<16);
487 for (i = 0; i < (1<<16); i++) {
488 di = (i + (random()&255))>>8;
489 if (di > 255) di = 255;
494 st->pd = malloc(st->npix * (st->pdepth == 1 ? 1 : (st->pdepth / 8)));
496 fprintf(stderr, "not enough memory for %d pixels.\n", st->npix);
502 #ifdef HAVE_XSHM_EXTENSION
505 st->image = create_xshm_image(st->dpy, st->xgwa.visual, vdepth,
506 ZPixmap, 0, &st->shm_info, st->width, st->height);
512 st->pd = st->image->data;
515 #endif /* HAVE_XSHM_EXTENSION */
519 st->image = XCreateImage(st->dpy, st->xgwa.visual, vdepth,
521 st->width, st->height, 8, 0);
528 rd_draw (Display *dpy, Window win, void *closure)
530 struct state *st = (struct state *) closure;
534 pixack_frame(st, st->pd);
535 for (i = 0; i < st->array_width; i += st->width)
536 for (j = 0; j < st->array_height; j += st->height)
537 #ifdef HAVE_XSHM_EXTENSION
539 XShmPutImage(st->dpy, st->window, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
540 st->width, st->height, False);
543 XPutImage(st->dpy, win, st->gc, st->image, 0, 0, i+st->array_x, j+st->array_y,
544 st->width, st->height);
546 st->array_x += st->array_dx;
547 st->array_y += st->array_dy;
548 if (st->array_x < 0) {
550 st->array_dx = -st->array_dx;
552 } else if (st->array_x > (st->xgwa.width - st->array_width)) {
553 st->array_x = (st->xgwa.width - st->array_width);
554 st->array_dx = -st->array_dx;
557 if (st->array_y < 0) {
559 st->array_dy = -st->array_dy;
561 } else if (st->array_y > (st->xgwa.height - st->array_height)) {
562 st->array_y = (st->xgwa.height - st->array_height);
563 st->array_dy = -st->array_dy;
569 double swap = st->array_dx;
570 st->array_dx = st->array_dy;
581 rd_reshape (Display *dpy, Window window, void *closure,
582 unsigned int w, unsigned int h)
587 rd_event (Display *dpy, Window window, void *closure, XEvent *event)
593 rd_free (Display *dpy, Window window, void *closure)
597 XSCREENSAVER_MODULE_2 ("RDbomb", rdbomb, rd)