1 /* xscreensaver, Copyright (c) 1992, 1995, 1997
2 * Jamie Zawinski <jwz@netscape.com>
4 * reaction/diffusion textures
5 * Copyright (c) 1997 Scott Draves spot@transmeta.com
6 * this code is derived from Bomb
7 * see http://www.cs.cmu.edu/~spot/bomb.html
9 * Permission to use, copy, modify, distribute, and sell this software and its
10 * documentation for any purpose is hereby granted without fee, provided that
11 * the above copyright notice appear in all copies and that both that
12 * copyright notice and this permission notice appear in supporting
13 * documentation. No representations are made about the suitability of this
14 * software for any purpose. It is provided "as is" without express or
17 * And remember: X Windows is to graphics hacking as roman numerals are to
18 * the square root of pi.
23 #include "screenhack.h"
26 #define dither_when_mapped 1
33 #if dither_when_mapped
34 unsigned char *mc = 0;
40 void random_colors(void);
42 /* -----------------------------------------------------------
43 pixel hack, 8-bit pixel grid, first/next frame interface
45 pixack_init(int *size_h, int *size_v)
46 pixack_frame(char *pix_buf)
51 #define mx ((1<<16)-1)
53 /* you can replace integer mults wish shift/adds with these,
54 but it doesn't help on my 586 */
55 #define x5(n) ((n<<2)+n)
56 #define x7(n) ((n<<3)-n)
59 #define R (ya_random()&((1<<30)-1))
61 int frame = 0, epoch_time;
62 ushort *r1, *r2, *r1b, *r2b;
63 int width, height, npix;
68 /* returns number of pixels that the pixack produces. called once. */
70 pixack_init(int *size_h, int *size_v) {
72 width = get_integer_resource ("width", "Integer");
73 height = get_integer_resource ("height", "Integer");
74 sz_base = 80 + (R%40);
75 if (width <= 0) width = (R%20) ? sz_base : (28 + R%10);
76 if (height <= 0) height = (R%20) ? sz_base : (28 + R%10);
78 if (width < 10) width = 10;
79 if (height < 10) height = 10;
80 epoch_time = get_integer_resource ("epoch", "Integer");
81 npix = (width + 2) * (height + 2);
82 r1 = (ushort *) malloc(sizeof(ushort) * npix);
83 r2 = (ushort *) malloc(sizeof(ushort) * npix);
84 r1b = (ushort *) malloc(sizeof(ushort) * npix);
85 r2b = (ushort *) malloc(sizeof(ushort) * npix);
87 if (!r1 || !r2 || !r1b || !r2b) {
88 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
96 #define test_pattern_hyper 0
99 /* returns the pixels. called many times. */
101 pixack_frame(char *pix_buf) {
105 #if test_pattern_hyper
114 #ifdef GETTIMEOFDAY_TWO_ARGS
116 gettimeofday(&tp, &tzp);
120 tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
122 printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
126 if (!(frame%epoch_time)) {
129 int t = epoch_time / 500;
135 for (i = 0; i < npix; i++) {
143 XSetWindowBackground(display, window, colors[255 % ncolors].pixel);
144 XClearWindow(display, window);
146 s = w2 * (height/2) + width/2;
147 radius = get_integer_resource ("radius", "Integer");
149 int maxr = width/2-2;
150 int maxr2 = height/2-2;
151 if (maxr2 < maxr) maxr = maxr2;
154 radius = 1 + ((R%10) ? (R%5) : (R % maxr));
155 if (radius > maxr) radius = maxr;
157 for (i = -radius; i < (radius+1); i++)
158 for (j = -radius; j < (radius+1); j++)
159 r2[s + i + j*w2] = mx - (R&63);
160 reaction = get_integer_resource ("reaction", "Integer");
161 if (reaction < 0 || reaction > 2) reaction = R&1;
162 diffusion = get_integer_resource ("diffusion", "Integer");
163 if (diffusion < 0 || diffusion > 2)
164 diffusion = (R%5) ? ((R%3)?0:1) : 2;
165 if (2 == reaction && 2 == diffusion)
166 reaction = diffusion = 0;
169 printf("reaction = %d\ndiffusion = %d\nradius = %d\n",
170 reaction, diffusion, radius);
172 for (i = 0; i <= width+1; i++) {
173 r1[i] = r1[i + w2 * height];
174 r2[i] = r2[i + w2 * height];
175 r1[i + w2 * (height + 1)] = r1[i + w2];
176 r2[i + w2 * (height + 1)] = r2[i + w2];
178 for (i = 0; i <= height+1; i++) {
179 r1[w2 * i] = r1[width + w2 * i];
180 r2[w2 * i] = r2[width + w2 * i];
181 r1[w2 * i + width + 1] = r1[w2 * i + 1];
182 r2[w2 * i + width + 1] = r2[w2 * i + 1];
184 for (i = 0; i < height; i++) {
186 char *q = pix_buf + width * i;
187 short *qq = ((short *) pix_buf) + width * i;
188 long *qqq = ((long *) pix_buf) + width * i;
189 ushort *i1 = r1 + 1 + w2 * ii;
190 ushort *i2 = r2 + 1 + w2 * ii;
191 ushort *o1 = r1b + 1 + w2 * ii;
192 ushort *o2 = r2b + 1 + w2 * ii;
193 for (j = 0; j < width; j++) {
194 #if test_pattern_hyper
195 int r1 = (i * j + (frame&127)*frame)&65535;
197 int uvv, r1 = 0, r2 = 0;
200 r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
202 r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
206 r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
208 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
212 r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
214 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
219 /* John E. Pearson "Complex Patterns in a Simple System"
220 Science, July 1993 */
222 uvv = (((r1 * r2) >> bps) * r2) >> bps;
223 switch (reaction) { /* costs 4% */
225 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
226 r2 += 4 * (uvv - ((80 * r2) >> 10));
229 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
230 r2 += 3 * (uvv - ((80 * r2) >> 10));
233 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
234 r2 += 3 * (uvv - ((80 * r2) >> 10));
237 if (r1 > mx) r1 = mx;
238 if (r2 > mx) r2 = mx;
245 /* this is terrible. here i want to assume ncolors = 256.
246 should lose double indirection */
249 #if dither_when_mapped
250 q[j] = colors[mc[r1] % ncolors].pixel;
252 q[j] = colors[(r1>>8) % ncolors].pixel;
254 else if (pdepth == 8)
255 q[j] = colors[(r1>>8) % ncolors].pixel;
256 else if (pdepth == 16)
257 #if dither_when_mapped
258 qq[j] = colors[mc[r1] % ncolors].pixel;
260 qq[j] = colors[(r1>>8) % ncolors].pixel;
262 else if (pdepth == 32)
263 #if dither_when_mapped
264 qqq[j] = colors[mc[r1] % ncolors].pixel;
266 qqq[j] = colors[(r1>>8) % ncolors].pixel;
272 t = r1; r1 = r1b; r1b = t;
273 t = r2; r2 = r2b; r2b = t;
277 /* ------------- xscreensaver rendering -------------- */
281 char *progclass = "RD";
284 char *defaults [] = {
285 "RD.background: black", /* to placate SGI */
286 "RD.foreground: white",
287 "*width: 0", /* tried to use -1 but it complained */
301 XrmOptionDescRec options [] = {
302 { "-width", ".width", XrmoptionSepArg, 0 },
303 { "-height", ".height", XrmoptionSepArg, 0 },
304 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
305 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
306 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
307 { "-verbose", ".verbose", XrmoptionNoArg, "True" },
308 { "-radius", ".radius", XrmoptionSepArg, 0 },
309 { "-speed", ".speed", XrmoptionSepArg, 0 },
310 { "-size", ".size", XrmoptionSepArg, 0 },
311 { "-delay", ".delay", XrmoptionSepArg, 0 },
312 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
317 /* why doesn't this work??? and more importantly, do i really still have
320 #ifdef HAVE_XSHM_EXTENSION
323 #include <X11/extensions/XShm.h>
329 memset(colors, 0, ncolors*sizeof(*colors));
330 make_smooth_colormap (display, visual, cmap, colors, &ncolors,
335 colors[0].flags = DoRed|DoGreen|DoBlue;
336 colors[0].red = colors[0].green = colors[0].blue = 0;
337 XAllocColor(display, cmap, &colors[0]);
338 colors[1].flags = DoRed|DoGreen|DoBlue;
339 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
340 XAllocColor(display, cmap, &colors[1]);
343 /* Scale it up so that there are exactly 255 colors -- that keeps the
344 animation speed consistent, even when there aren't many allocatable
345 colors, and prevents the -mono mode from looking like static. */
346 if (ncolors != 255) {
348 double scale = (double) ncolors / (double) (n+1);
349 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
350 for (i = 0; i < n; i++)
351 c2[i] = colors[(int) (i * scale)];
359 /* should factor into RD-specfic and compute-every-pixel general */
361 screenhack (Display *dpy, Window win)
365 XWindowAttributes xgwa;
367 int array_width, array_height;
368 double array_x, array_y;
369 double array_dx, array_dy;
375 #ifdef HAVE_XSHM_EXTENSION
377 XShmSegmentInfo shm_info;
380 double delay = get_float_resource ("delay", "Float");
386 XGetWindowAttributes (dpy, win, &xgwa);
387 visual = xgwa.visual;
388 pixack_init(&width, &height);
390 double s = get_float_resource ("size", "Float");
391 double p = get_float_resource ("speed", "Float");
392 if (s < 0.0 || s > 1.0)
395 array_width = xgwa.width * s;
396 array_height = xgwa.height * s;
398 array_width = (array_width / width) * width;
399 array_height = (array_height / height) * height;
401 if (array_width < width) array_width = width;
402 if (array_height < height) array_height = height;
403 array_x = (xgwa.width - array_width)/2;
404 array_y = (xgwa.height - array_height)/2;
406 array_dy = .31415926 * p;
408 verbose = get_boolean_resource ("verbose", "Boolean");
409 npix = (width + 2) * (height + 2);
411 gcv.function = GXcopy;
412 gc = XCreateGC(dpy, win, GCFunction, &gcv);
413 vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
415 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
416 Therefore, we assume that those depths will be supported by the
417 coresponding visual depths (that depth-24 displays accept depth-32
418 pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
419 pdepth = (vdepth == 1 ? 1 :
424 cmap = xgwa.colormap;
425 ncolors = get_integer_resource ("colors", "Integer");
434 if (mono_p || ncolors < 2) ncolors = 2;
435 if (ncolors <= 2) mono_p = True;
436 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
438 mapped = (vdepth <= 8 &&
439 has_writable_cells(xgwa.screen, xgwa.visual));
443 mc = (unsigned char *) malloc(1<<16);
444 for (i = 0; i < (1<<16); i++) {
445 di = (i + (ya_random()&255))>>8;
446 if (di > 255) di = 255;
451 p = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
453 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
457 #ifdef HAVE_XSHM_EXTENSION
461 image = XShmCreateImage(dpy, xgwa.visual, vdepth,
462 ZPixmap, 0, &shm_info, width, height);
463 shm_info.shmid = shmget(IPC_PRIVATE,
464 image->bytes_per_line * image->height,
466 if (shm_info.shmid == -1)
467 printf ("shmget failed!");
468 shm_info.readOnly = False;
469 p = shmat(shm_info.shmid, 0, 0);
470 printf("p=%X %d\n", p, image->bytes_per_line);
471 XShmAttach(dpy, &shm_info);
475 image = XCreateImage(dpy, xgwa.visual, vdepth,
477 width, height, 8, 0);
482 for (i = 0; i < array_width; i += width)
483 for (j = 0; j < array_height; j += height)
484 #ifdef HAVE_XSHM_EXTENSION
486 XShmPutImage(dpy, win, gc, image, 0, 0, i, j,
487 width, height, False);
490 XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y, width, height);
496 array_dx = -array_dx;
497 } else if (array_x > (xgwa.width - array_width)) {
498 array_x = (xgwa.width - array_width);
499 array_dx = -array_dx;
503 array_dy = -array_dy;
504 } else if (array_y > (xgwa.height - array_height)) {
505 array_y = (xgwa.height - array_height);
506 array_dy = -array_dy;
512 usleep(1000 * delay);