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 "*background: black",
286 "*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;
374 #ifdef HAVE_XSHM_EXTENSION
376 XShmSegmentInfo shm_info;
379 double delay = get_float_resource ("delay", "Float");
385 XGetWindowAttributes (dpy, win, &xgwa);
386 visual = xgwa.visual;
387 pixack_init(&width, &height);
389 double s = get_float_resource ("size", "Float");
390 double p = get_float_resource ("speed", "Float");
391 if (s < 0.0 || s > 1.0)
394 array_width = xgwa.width * s;
395 array_height = xgwa.height * s;
397 array_width = (array_width / width) * width;
398 array_height = (array_height / height) * height;
400 if (array_width < width) array_width = width;
401 if (array_height < height) array_height = height;
402 array_x = (xgwa.width - array_width)/2;
403 array_y = (xgwa.height - array_height)/2;
405 array_dy = .31415926 * p;
407 verbose = get_boolean_resource ("verbose", "Boolean");
408 npix = (width + 2) * (height + 2);
410 gcv.function = GXcopy;
411 gc = XCreateGC(dpy, win, GCFunction, &gcv);
412 vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
414 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
415 Therefore, we assume that those depths will be supported by the
416 coresponding visual depths (that depth-24 displays accept depth-32
417 pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
418 pdepth = (vdepth == 1 ? 1 :
423 cmap = xgwa.colormap;
424 ncolors = get_integer_resource ("colors", "Integer");
433 if (mono_p || ncolors < 2) ncolors = 2;
434 if (ncolors <= 2) mono_p = True;
435 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
437 mapped = (vdepth <= 8 &&
438 has_writable_cells(xgwa.screen, xgwa.visual));
442 mc = (unsigned char *) malloc(1<<16);
443 for (i = 0; i < (1<<16); i++) {
444 di = (i + (random()&255))>>8;
445 if (di > 255) di = 255;
450 p = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
452 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
456 #ifdef HAVE_XSHM_EXTENSION
460 image = XShmCreateImage(dpy, xgwa.visual, vdepth,
461 ZPixmap, 0, &shm_info, width, height);
462 shm_info.shmid = shmget(IPC_PRIVATE,
463 image->bytes_per_line * image->height,
465 if (shm_info.shmid == -1)
466 printf ("shmget failed!");
467 shm_info.readOnly = False;
468 p = shmat(shm_info.shmid, 0, 0);
469 printf("p=%X %d\n", p, image->bytes_per_line);
470 XShmAttach(dpy, &shm_info);
474 image = XCreateImage(dpy, xgwa.visual, vdepth,
476 width, height, 8, 0);
481 for (i = 0; i < array_width; i += width)
482 for (j = 0; j < array_height; j += height)
483 #ifdef HAVE_XSHM_EXTENSION
485 XShmPutImage(dpy, win, gc, image, 0, 0, i, j,
486 width, height, False);
489 XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y, width, height);
495 array_dx = -array_dx;
496 } else if (array_x > (xgwa.width - array_width)) {
497 array_x = (xgwa.width - array_width);
498 array_dx = -array_dx;
502 array_dy = -array_dy;
503 } else if (array_y > (xgwa.height - array_height)) {
504 array_y = (xgwa.height - array_height);
505 array_dy = -array_dy;
511 usleep(1000 * delay);