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"
25 /* why doesn't this work??? */
26 #ifdef HAVE_XSHM_EXTENSION
29 #include <X11/extensions/XShm.h>
32 #define test_pattern_hyper 0
35 #define dither_when_mapped 1
37 char *progclass = "RD";
41 "RD.background: black", /* to placate SGI */
42 "RD.foreground: white",
58 XrmOptionDescRec options [] = {
59 { "-width", ".width", XrmoptionSepArg, 0 },
60 { "-height", ".height", XrmoptionSepArg, 0 },
61 { "-epoch", ".epoch", XrmoptionSepArg, 0 },
62 { "-palette", ".palette", XrmoptionSepArg, 0 },
63 { "-reaction", ".reaction", XrmoptionSepArg, 0 },
64 { "-diffusion", ".diffusion", XrmoptionSepArg, 0 },
65 { "-verbose", ".verbose", XrmoptionSepArg, 0 },
66 { "-radius", ".radius", XrmoptionSepArg, 0 },
67 { "-speed", ".speed", XrmoptionSepArg, 0 },
68 { "-size", ".size", XrmoptionSepArg, 0 },
69 { "-delay", ".delay", XrmoptionSepArg, 0 },
70 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
75 #define mx ((1<<16)-1)
77 /* you can replace integer mults wish shift/adds with these,
78 but it doesn't help on my 586 */
79 #define x5(n) ((n<<2)+n)
80 #define x7(n) ((n<<3)-n)
83 #define R (ya_random()&((1<<30)-1))
85 /* should factor into RD-specfic and compute-every-pixel general */
87 screenhack (Display *dpy, Window win)
91 XWindowAttributes xgwa;
94 int width, height, radius;
95 int array_width, array_height;
96 double array_x, array_y;
97 double array_dx, array_dy;
99 int frame = 0, epoch_time;
102 ushort *r1, *r2, *r1b, *r2b;
109 #if dither_when_mapped
110 unsigned char *mc = 0;
112 #ifdef HAVE_XSHM_EXTENSION
114 XShmSegmentInfo shm_info;
119 int delay = get_float_resource ("delay", "Integer");
121 XGetWindowAttributes (dpy, win, &xgwa);
122 width = get_integer_resource ("width", "Integer");
123 height = get_integer_resource ("height", "Integer");
125 double s = get_float_resource ("size", "Float");
126 double p = get_float_resource ("speed", "Float");
127 if (s < 0.0 || s > 1.0)
130 array_width = xgwa.width * s;
131 array_height = xgwa.height * s;
133 array_width = (array_width / width) * width;
134 array_height = (array_height / height) * height;
136 if (array_width < width) array_width = width;
137 if (array_height < height) array_height = height;
138 array_x = (xgwa.width - array_width)/2;
139 array_y = (xgwa.height - array_height)/2;
141 array_dy = .31415926 * p;
143 if (width < 10) width = 10;
144 if (height < 10) height = 10;
145 verbose = get_boolean_resource ("verbose", "Boolean");
146 npix = (width + 2) * (height + 2);
147 epoch_time = get_integer_resource ("epoch", "Integer");
149 gcv.function = GXcopy;
150 gc = XCreateGC(dpy, win, GCFunction, &gcv);
151 vdepth = visual_depth(DefaultScreenOfDisplay(dpy), xgwa.visual);
153 /* This code only deals with pixmap depths of 1, 8, 16, and 32.
154 Therefore, we assume that those depths will be supported by the
155 coresponding visual depths (that depth-24 displays accept depth-32
156 pixmaps, and that depth-12 displays accept depth-16 pixmaps.) */
157 pdepth = (vdepth == 1 ? 1 :
162 cmap = xgwa.colormap;
163 ncolors = get_integer_resource ("colors", "Integer");
172 if (mono_p || ncolors < 2) ncolors = 2;
173 if (ncolors <= 2) mono_p = True;
174 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
176 mapped = (vdepth <= 8 &&
177 has_writable_cells(xgwa.screen, xgwa.visual));
180 m = (int *) malloc(sizeof(int) * (1<<16));
181 #if dither_when_mapped
184 mc = (unsigned char *) malloc(1<<16);
185 for (i = 0; i < (1<<16); i++) {
186 di = (i + (ya_random()&255))>>8;
187 if (di > 255) di = 255;
192 p = malloc(npix * (pdepth == 1 ? 1 : (pdepth / 8)));
193 r1 = (ushort *) malloc(sizeof(ushort) * npix);
194 r2 = (ushort *) malloc(sizeof(ushort) * npix);
195 r1b = (ushort *) malloc(sizeof(ushort) * npix);
196 r2b = (ushort *) malloc(sizeof(ushort) * npix);
197 if (!p || !r1 || !r2 || !r1b || !r2b) {
198 fprintf(stderr, "not enough memory for %d pixels.\n", npix);
202 #ifdef HAVE_XSHM_EXTENSION
206 image = XShmCreateImage(dpy, xgwa.visual, vdepth,
207 ZPixmap, 0, &shm_info, width, height);
208 shm_info.shmid = shmget(IPC_PRIVATE,
209 image->bytes_per_line * image->height,
211 if (shm_info.shmid == -1)
212 printf ("shmget failed!");
213 shm_info.readOnly = False;
214 p = shmat(shm_info.shmid, 0, 0);
215 printf("p=%X %d\n", p, image->bytes_per_line);
216 XShmAttach(dpy, &shm_info);
220 image = XCreateImage(dpy, xgwa.visual, vdepth,
222 width, height, 8, 0);
227 #if test_pattern_hyper
237 gettimeofday(&tp, &tzp);
238 tm2 = tp.tv_sec + tp.tv_usec * 1e-6;
240 printf("fps = %2.4g\n", 100.0 / (tm2 - tm));
244 if (!(frame%epoch_time)) {
247 int t = epoch_time / 500;
253 for (i = 0; i < npix; i++) {
259 memset(colors, 0, ncolors*sizeof(*colors));
260 make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
265 colors[0].flags = DoRed|DoGreen|DoBlue;
266 colors[0].red = colors[0].green = colors[0].blue = 0;
267 XAllocColor(dpy, cmap, &colors[0]);
268 colors[1].flags = DoRed|DoGreen|DoBlue;
269 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
270 XAllocColor(dpy, cmap, &colors[1]);
273 /* Scale it up so that there are exactly 255 colors -- that keeps the
274 animation speed consistent, even when there aren't many allocatable
275 colors, and prevents the -mono mode from looking like static. */
276 if (ncolors != 255) {
278 double scale = (double) ncolors / (double) (n+1);
279 XColor *c2 = (XColor *) malloc(sizeof(*c2) * (n+1));
280 for (i = 0; i < n; i++)
281 c2[i] = colors[(int) (i * scale)];
288 XSetWindowBackground(dpy, win, colors[255 % ncolors].pixel);
289 XClearWindow(dpy, win);
291 s = w2 * height/2 + width/2;
292 radius = get_integer_resource ("radius", "Integer");
294 radius = 1 + ((R%10) ? (R%5) : (R % (width/2-2)));
295 for (i = -radius; i < (radius+1); i++)
296 for (j = -radius; j < (radius+1); j++)
297 r2[s + i + j*w2] = mx - (R&63);
298 reaction = get_integer_resource ("reaction", "Integer");
299 if (reaction < 0 || reaction > 2) reaction = R&1;
300 diffusion = get_integer_resource ("diffusion", "Integer");
301 if (diffusion < 0 || diffusion > 2)
302 diffusion = (R%5) ? ((R%3)?0:1) : 2;
303 if (2 == reaction && 2 == diffusion)
304 reaction = diffusion = 0;
307 printf("reaction = %d\ndiffusion = %d\n"
308 "palette = %d\nradius = %d\n",
309 reaction, diffusion, palette, radius);
312 for (i = 0; i <= width+1; i++) {
313 r1[i] = r1[i + w2 * height];
314 r2[i] = r2[i + w2 * height];
315 r1[i + w2 * (height + 1)] = r1[i + w2];
316 r2[i + w2 * (height + 1)] = r2[i + w2];
318 for (i = 0; i <= height+1; i++) {
319 r1[w2 * i] = r1[width + w2 * i];
320 r2[w2 * i] = r2[width + w2 * i];
321 r1[w2 * i + width + 1] = r1[w2 * i + 1];
322 r2[w2 * i + width + 1] = r2[w2 * i + 1];
324 for (i = 0; i < height; i++) {
326 char *q = p + width * i;
327 short *qq = ((short *) p) + width * i;
328 long *qqq = ((long *) p) + width * i;
329 ushort *i1 = r1 + 1 + w2 * ii;
330 ushort *i2 = r2 + 1 + w2 * ii;
331 ushort *o1 = r1b + 1 + w2 * ii;
332 ushort *o2 = r2b + 1 + w2 * ii;
333 for (j = 0; j < width; j++) {
334 #if test_pattern_hyper
335 int r1 = (i * j + (frame&127)*frame)&65535;
337 int uvv, r1 = 0, r2 = 0;
340 r1 = i1[j] + i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
342 r2 = (i2[j]<<3) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
346 r1 = i1[j+1] + i1[j-1] + i1[j+w2] + i1[j-w2];
348 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
352 r1 = (i1[j]<<1) + (i1[j+1]<<1) + (i1[j-1]<<1) + i1[j+w2] + i1[j-w2];
354 r2 = (i2[j]<<2) + i2[j+1] + i2[j-1] + i2[j+w2] + i2[j-w2];
358 uvv = (((r1 * r2) >> bps) * r2) >> bps;
359 switch (reaction) { /* costs 4% */
361 r1 += 4 * (((28 * (mx-r1)) >> 10) - uvv);
362 r2 += 4 * (uvv - ((80 * r2) >> 10));
365 r1 += 3 * (((27 * (mx-r1)) >> 10) - uvv);
366 r2 += 3 * (uvv - ((80 * r2) >> 10));
369 r1 += 2 * (((28 * (mx-r1)) >> 10) - uvv);
370 r2 += 3 * (uvv - ((80 * r2) >> 10));
373 if (r1 > mx) r1 = mx;
374 if (r2 > mx) r2 = mx;
382 #if dither_when_mapped
383 q[j] = colors[mc[r1] % ncolors].pixel;
385 q[j] = colors[(r1>>8) % ncolors].pixel;
387 else if (pdepth == 8)
388 q[j] = colors[(r1>>8) % ncolors].pixel;
389 else if (pdepth == 16)
390 qq[j] = colors[(r1>>8) % ncolors].pixel;
391 else if (pdepth == 32)
392 qqq[j] = colors[(r1>>8) % ncolors].pixel;
397 t = r1; r1 = r1b; r1b = t;
398 t = r2; r2 = r2b; r2b = t;
399 for (i = 0; i < array_width; i += width)
400 for (j = 0; j < array_height; j += height)
401 #ifdef HAVE_XSHM_EXTENSION
403 XShmPutImage(dpy, win, gc, image, 0, 0, i, j,
404 width, height, False);
407 XPutImage(dpy, win, gc, image, 0, 0, i+array_x, j+array_y, width, height);
413 array_dx = -array_dx;
414 } else if (array_x > (xgwa.width - array_width)) {
415 array_x = (xgwa.width - array_width);
416 array_dx = -array_dx;
420 array_dy = -array_dy;
421 } else if (array_y > (xgwa.height - array_height)) {
422 array_y = (xgwa.height - array_height);
423 array_dy = -array_dy;