1 /* ripples, Copyright (c) 1999 Ian McConnell <ian@emit.demon.co.uk>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
13 * "Water" ripples that can cross and interfere with each other.
15 * I can't remember where I got this idea from, but it's been around for a
16 * while in various demos. Some inspiration from
17 * water.txt by Tom Hammersley,tomh@globalnet.co.uk
20 * -delay usleep every iteration
21 * -rate Add one drop every "rate" iterations
22 * -box Add big square splash every "box" iters (not very good)
23 * -water Ripples on a grabbed background image
24 * -foreground Interpolate ripples between these two colors
26 * -oily Psychedelic colours like man
27 * -stir Add a regular pattern of drops
28 * -fluidity Between 0 and 16. 16 = big drops
29 * -light Hack to add lighting effect
31 * Code mainly hacked from xflame and decayscreen.
35 * 13 Oct 1999: Initial hack
36 * 30 Oct 1999: Speeded up graphics with dirty buffer. Returned to using
37 * putpixel for greater portability
38 * Added a variety of methods for splashing screen.
39 * 31 Oct 1999: Added in lighting hack
40 * 13 Nov 1999: Speed up tweaks
41 * Adjust "light" for different bits per colour (-water only)
47 #include "screenhack.h"
48 #include <X11/Xutil.h>
50 typedef enum {ripple_drop, ripple_blob, ripple_box, ripple_stir} ripple_mode;
52 #ifdef HAVE_XSHM_EXTENSION
55 static XShmSegmentInfo shm_info;
56 #endif /* HAVE_XSHM_EXTENSION */
59 static Display *display;
61 static Visual *visual;
63 static XImage *orig_map, *buffer_map;
65 static Colormap colormap;
69 static int width, height; /* ripple size */
70 static int bigwidth, bigheight; /* screen size */
72 static Bool transparent;
73 static short *bufferA, *bufferB, *temp;
74 static char *dirty_buffer;
77 static double cos_tab[TABLE];
79 /* Distribution of drops: many little ones and a few big ones. */
80 static double drop_dist[] =
81 {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.6};
83 static void (*draw_transparent)(short *src);
85 /* How hard to hit the water */
88 #define MIN(x, y) ((x) < (y) ? (x) : (y))
90 #define MAX(x, y) ((x) > (y) ? (x) : (y))
92 #define DIRTY 3 /* dirty >= 2, 1 = restore original pixel, 0 = leave alone */
95 /* -- really weird C code to count the number of bits in a word */
96 #define BITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255)
97 #define BX_(x) ((x) - (((x)>>1)&0x77777777) \
98 - (((x)>>2)&0x33333333) \
99 - (((x)>>3)&0x11111111))
102 static Bool grayscale_p;
103 static unsigned long grayscale(unsigned long color);
105 /* ------------------------------------------- */
112 grey = ncolors * abs(grey) / (SPLASH/4);
122 draw_ripple(short *src)
125 char *dirty = dirty_buffer;
127 for (down = 0; down < height - 1; down++, src += 1, dirty += 1)
128 for (across = 0; across < width - 1; across++, src++, dirty++) {
131 v2 = (int)*(src + 1);
132 v3 = (int)*(src + width);
133 v4 = (int)*(src + width + 1);
134 if ((v1 == 0 && v2 == 0 && v3 == 0 && v4 == 0)) {
143 dx = ((v3 - v1) + (v4 - v2)) << light; /* light from top */
146 XPutPixel(buffer_map,(across<<1), (down<<1), map_color(dx + v1));
147 XPutPixel(buffer_map,(across<<1)+1,(down<<1), map_color(dx + ((v1 + v2) >> 1)));
148 XPutPixel(buffer_map,(across<<1), (down<<1)+1,map_color(dx + ((v1 + v3) >> 1)));
149 XPutPixel(buffer_map,(across<<1)+1,(down<<1)+1,map_color(dx + ((v1 + v4) >> 1)));
155 /* ------------------------------------------- */
158 /* Uses the horizontal gradient as an offset to create a warp effect */
160 draw_transparent_vanilla(short *src)
162 int across, down, pixel;
163 char *dirty = dirty_buffer;
166 for (down = 0; down < height - 2; down++, pixel += 2)
167 for (across = 0; across < width-2; across++, pixel++) {
168 int gradx, grady, gradx1, grady1;
169 int x0, x1, x2, y1, y2;
174 y1 = src[pixel + width];
175 y2 = src[pixel + 2*width];
181 gradx1 = 1 + (gradx + gradx1) / 2;
182 grady1 = 1 + (grady + grady1) / 2;
184 if ((2*across+MIN(gradx,gradx1) < 0) ||
185 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
189 if ((2*down+MIN(grady,grady1) < 0) ||
190 (2*down+MAX(grady,grady1) >= bigheight)) {
195 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
196 if (dirty[pixel] > 0)
199 dirty[pixel] = DIRTY;
201 if (dirty[pixel] > 0) {
202 XPutPixel(buffer_map, (across<<1), (down<<1),
203 grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady)));
204 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
205 grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady)));
206 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
207 grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1)));
208 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
209 grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1)));
215 /* ------------------------------------------- */
218 /* This builds on the above warp effect by adding in a lighting effect: */
219 /* brighten pixels by an amount corresponding to the vertical gradient */
220 static unsigned long rmask;
221 static unsigned long gmask;
222 static unsigned long bmask;
229 set_mask(unsigned long color, unsigned long *mask, int *shift)
232 while (color != 0 && (color & 1) == 0) {
241 cadd(unsigned long color, int dx, unsigned long mask, int shift)
248 else if (x > (int)mask) x = mask;
250 return color << shift;
255 bright(int dx, unsigned long color)
257 return (cadd(color, dx, rmask, rshift) |
258 cadd(color, dx, gmask, gshift) |
259 cadd(color, dx, bmask, bshift));
264 grayscale(unsigned long color)
278 if ((rmask == 0) || (gmask == 0) || (bmask == 0))
281 red = ((color >> rshift) & rmask);
282 green = ((color >> gshift) & gmask);
283 blue = ((color >> bshift) & bmask);
284 total = red * gmask * bmask + green * rmask * bmask + blue * rmask * gmask;
286 gray_r = total / (3 * gmask * bmask);
292 gray_g = total / (3 * rmask * bmask);
298 gray_b = total / (3 * rmask * gmask);
304 return ((unsigned long)
305 ((gray_r << rshift) | (gray_g << gshift) | (gray_b << bshift)));
310 draw_transparent_light(short *src)
312 int across, down, pixel;
313 char *dirty = dirty_buffer;
316 for (down = 0; down < height - 2; down++, pixel += 2)
317 for (across = 0; across < width-2; across++, pixel++) {
318 int gradx, grady, gradx1, grady1;
319 int x0, x1, x2, y1, y2;
324 y1 = src[pixel + width];
325 y2 = src[pixel + 2*width];
331 gradx1 = 1 + (gradx + gradx1) / 2;
332 grady1 = 1 + (grady + grady1) / 2;
334 if ((2*across+MIN(gradx,gradx1) < 0) ||
335 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
339 if ((2*down+MIN(grady,grady1) < 0) ||
340 (2*down+MAX(grady,grady1) >= bigheight)) {
345 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
346 if (dirty[pixel] > 0)
349 dirty[pixel] = DIRTY;
351 if (dirty[pixel] > 0) {
356 dx = (grady + (src[pixel+width+1]-x1)) >> (4-light);
358 dx = (grady + (src[pixel+width+1]-x1)) << (light-4);
361 XPutPixel(buffer_map, (across<<1), (down<<1),
362 bright(dx, grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady))));
363 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
364 bright(dx, grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady))));
365 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
366 bright(dx, grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1))));
367 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
368 bright(dx, grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1))));
370 /* Could use XCopyArea, but XPutPixel is faster */
371 XPutPixel(buffer_map, (across<<1), (down<<1),
372 grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady)));
373 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
374 grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady)));
375 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
376 grayscale(XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1)));
377 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
378 grayscale(XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1)));
385 /* ------------------------------------------- */
389 /* Doesn't go any faster and doesn't work at all colour depths */
391 draw_transparent16l(short *src)
393 int across, down, bigpix, pixel;
394 char *dirty = dirty_buffer;
395 unsigned short *buffer, *orig;
397 buffer = (unsigned short *) buffer_map->data;
398 orig = (unsigned short *) orig_map->data;
400 for (pixel = bigpix = down = 0;
402 down++, pixel += 2, bigpix += bigwidth+4)
403 for (across = 0; across < width-2; across++, pixel++, bigpix+=2) {
404 int gradx, grady, gradx1, grady1;
405 int x0, x1, x2, y1, y2;
410 y1 = src[pixel + width];
411 y2 = src[pixel + 2*width];
417 gradx1 = 1 + (gradx + gradx1) / 2;
418 grady1 = 1 + (grady + grady1) / 2;
420 if ((2*across+MIN(gradx,gradx1) < 0) ||
421 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
425 if ((2*down+MIN(grady,grady1) < 0) ||
426 (2*down+MAX(grady,grady1) >= bigheight)) {
431 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
432 if (dirty[pixel] > 0)
435 dirty[pixel] = DIRTY;
437 if (dirty[pixel] > 0) {
438 unsigned short *dest = buffer + bigpix;
439 unsigned short *image = orig + bigpix;
444 dx = (grady + (src[pixel+width+1]-x1)) >> (4-light);
446 dx = (grady + (src[pixel+width+1]-x1)) << (light-4);
452 *dest++ = dobright(dx, *(image + gradx + grady));
453 *dest = dobright(dx, *(image + gradx1 + grady));
454 dest += bigwidth - 1;
455 *dest++ = dobright(dx, *(image + gradx + grady1));
456 *dest = dobright(dx, *(image + gradx1 + grady1));
458 *dest++ = *(image + gradx + grady);
459 *dest = *(image + gradx1 + grady);
460 dest += bigwidth - 1;
461 *dest++ = *(image + gradx + grady1);
462 *dest = *(image + gradx1 + grady1);
470 /* ------------------------------------------- */
474 setup_X(Display * disp, Window win)
476 XWindowAttributes xwa;
479 XGetWindowAttributes(disp, win, &xwa);
483 colormap = xwa.colormap;
484 bigwidth = xwa.width;
485 bigheight = xwa.height;
489 /* This causes buffer_map to be 1 pixel taller and wider than orig_map,
490 which can cause the two XImages to have different bytes-per-line,
491 which causes stair-stepping. So this better not be necessary...
494 #if 0 /* I'm not entirely sure if I need this */
502 width = bigwidth / 2;
503 height = bigheight / 2;
509 gcv.function = GXcopy;
510 gcv.subwindow_mode = IncludeInferiors;
512 gcflags = GCForeground | GCFunction;
513 if (use_subwindow_mode_p(xwa.screen, window)) /* see grabscreen.c */
514 gcflags |= GCSubwindowMode;
516 gc = XCreateGC(display, window, gcflags, &gcv);
518 load_random_image (xwa.screen, window, window, NULL, NULL);
520 orig_map = XGetImage(display, window, 0, 0, xwa.width, xwa.height,
525 gc = XCreateGC(display, window, 0, &gcv);
530 fprintf(stderr, "XCreateGC failed\n");
536 #ifdef HAVE_XSHM_EXTENSION
538 buffer_map = create_xshm_image(display, xwa.visual, depth,
539 ZPixmap, 0, &shm_info, bigwidth, bigheight);
542 fprintf(stderr, "create_xshm_image failed\n");
545 #endif /* HAVE_XSHM_EXTENSION */
548 buffer_map = XCreateImage(display, xwa.visual,
549 depth, ZPixmap, 0, 0,
550 bigwidth, bigheight, 8, 0);
551 buffer_map->data = (char *)
552 calloc(buffer_map->height, buffer_map->bytes_per_line);
560 #ifdef HAVE_XSHM_EXTENSION
562 XShmPutImage(display, window, gc, buffer_map, 0, 0, 0, 0,
563 bigwidth, bigheight, False);
565 #endif /* HAVE_XSHM_EXTENSION */
566 XPutImage(display, window, gc, buffer_map, 0, 0, 0, 0,
567 bigwidth, bigheight);
569 XSync(display,False);
570 screenhack_handle_events(display);
574 /* ------------------------------------------- */
578 cinterp(double a, int bg, int fg)
581 result = (int)((1-a) * bg + a * fg + 0.5);
582 if (result < 0) result = 0;
583 if (result > 255) result = 255;
588 /* Interpolate the ripple colours between the background colour and
591 init_linear_colors(void)
593 int i, j, red, green, blue, bred, bgreen, bblue;
596 if (ncolors < 2 || mono_p)
601 /* Make it possible to set the color of the ripples,
602 Based on work by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
604 fg.pixel = get_pixel_resource("foreground", "Foreground",
606 XQueryColor(display, colormap, &fg);
608 green = (fg.green >> 8);
609 blue = (fg.blue >> 8);
611 bg.pixel = get_pixel_resource("background", "Background",
613 XQueryColor(display, colormap, &bg);
614 bred = (bg.red >> 8);
615 bgreen = (bg.green >> 8);
616 bblue = (bg.blue >> 8);
619 for (i = 0; i < ncolors+1; i++) {
621 double a = (double)i / ncolors;
622 int r = cinterp(a, bred, red);
623 int g = cinterp(a, bgreen, green);
624 int b = cinterp(a, bblue, blue);
626 xcl.red = (unsigned short) ((r << 8) | r);
627 xcl.green = (unsigned short) ((g << 8) | g);
628 xcl.blue = (unsigned short) ((b << 8) | b);
629 xcl.flags = DoRed | DoGreen | DoBlue;
631 XAllocColor(display, colormap, &xcl);
633 ctab[j++] = (int) xcl.pixel;
639 init_oily_colors(void)
641 XColor *colors = NULL;
643 if (ncolors < 2 || mono_p)
650 colors = (XColor *)malloc(sizeof(*colors) * (ncolors+1));
651 make_smooth_colormap(display, visual, colormap, colors, &ncolors,
653 False, /* not writable */
654 True); /* verbose (complain about failure) */
664 for (i = 0; i < ncolors+1; i++) {
665 XAllocColor(display, colormap, colors+i);
666 ctab[j++] = (int) colors[i].pixel;
671 ctab[1] = get_pixel_resource("foreground", "Foreground", display, colormap);
672 ctab[0] = get_pixel_resource("background", "Background", display, colormap);
677 /* ------------------------------------------- */
684 for (i = 0; i < TABLE; i++)
685 cos_tab[i] = cos(i * M_PI/2 / TABLE);
689 /* Shape of drop to add */
696 i = (int)(x * TABLE + 0.5);
697 if (i >= TABLE) i = (TABLE-1) - (i-(TABLE-1));
700 return cos(x * M_PI/2);
711 add_circle_drop(int x, int y, int radius, int dheight)
714 short *buf = (random()&1) ? bufferA : bufferB;
717 r2 = radius * radius;
719 for (cy = -radius; cy <= radius; cy++)
720 for (cx = -radius; cx <= radius; cx++) {
721 int r = cx*cx + cy*cy;
723 buf[i + cx + cy*width] =
724 (short)(dheight * sinc(sqrt(r)/radius));
731 add_drop(ripple_mode mode, int drop)
733 int newx, newy, dheight;
734 int radius = MIN(width, height) / 50;
735 /* Don't put drops too near the edge of the screen or they get stuck */
743 dheight = 1 + (random() % drop);
744 newx = border + (random() % (width - 2*border));
745 newy = border + (random() % (height - 2*border));
746 x = newy * width + newx;
747 bufferA[x + 1] = bufferA[x] = bufferA[x + width] = bufferA[x + width + 1] =
748 bufferB[x + 1] = bufferB[x] = bufferB[x + width] = bufferB[x + width + 1] =
755 power = drop_dist[random() % (sizeof(drop_dist)/sizeof(drop_dist[0]))]; /* clumsy */
756 dheight = (int)(drop * (power + 0.01));
757 newx = radius + border + (random() % (int)(width - 2*border - 2*radius*power));
758 newy = radius + border + (random() % (int)(height - 2*border - 2*radius*power));
759 add_circle_drop(newx, newy, radius, dheight);
762 /* Adding too many boxes too quickly (-box 1) doesn't give the waves time
763 to disperse and the waves build up (and overflow) */
767 short *buf = (random()&1) ? bufferA : bufferB;
769 radius = (1 + (random() % 5)) * (1 + (random() % 5));
770 dheight = drop / 128;
771 if (random() & 1) dheight = -dheight;
772 newx = radius + border + (random() % (width - 2*border - 2*radius));
773 newy = radius + border + (random() % (height - 2*border - 2*radius));
774 x = newy * width + newx;
775 for (cy = -radius; cy <= radius; cy++)
776 for (cx = -radius; cx <= radius; cx++)
777 buf[x + cx + cy*width] = (short)(dheight);
781 static double ang = 0;
783 newx = border + (int)((width-2*border) * (1+cos(3*ang)) / 2);
784 newy = border + (int)((height-2*border) * (1+sin(2*ang)) / 2);
785 add_circle_drop(newx, newy, radius, drop / 10);
787 if (ang > 12*M_PI) ang = 0;
795 init_ripples(int ndrops, int splash)
799 bufferA = (short *)calloc(width * height, sizeof(*bufferA));
800 bufferB = (short *)calloc(width * height, sizeof(*bufferB));
801 temp = (short *)calloc(width * height, sizeof(*temp));
803 dirty_buffer = (char *)calloc(width * height, sizeof(*dirty_buffer));
805 for (i = 0; i < ndrops; i++)
806 add_drop(ripple_blob, splash);
812 for (down = 0; down < bigheight; down++)
813 for (across = 0; across < bigwidth; across++)
814 XPutPixel(buffer_map, across, down,
815 grayscale(XGetPixel(orig_map, across, down)));
819 /* There's got to be a better way of doing this XCopyArea? */
820 memcpy(buffer_map->data, orig_map->data,
821 bigheight * buffer_map->bytes_per_line);
824 int across, down, color;
826 color = map_color(0); /* background colour */
827 for (down = 0; down < bigheight; down++)
828 for (across = 0; across < bigwidth; across++)
829 XPutPixel(buffer_map,across, down, color);
837 Explanation from hq_water.zip (Arturo R Montesinos (ARM) arami@fi.upm.es)
839 Differential equation is: u = a ( u + u )
842 Where a = tension * gravity / surface_density.
844 Approximating second derivatives by central differences:
846 [ u(t+1)-2u(t)+u(t-1) ] / dt = a [ u(x+1)+u(x-1)+u(y+1)+u(y-1)-4u ] / h
848 where dt = time step squared, h = dx*dy = mesh resolution squared.
850 From where u(t+1) may be calculated as:
853 u(t+1) = a -- | 1 0 1 |u - u(t-1) + (2-4a --)u
856 When a*dt/h = 1/2 last term vanishes, giving:
859 u(t+1) = - | 1 0 1 |u - u(t-1)
862 (note that u(t-1,x,y) is only used to calculate u(t+1,x,y) so
863 we can use the same array for both t-1 and t+1, needing only
864 two arrays, U[0] and U[1])
866 Dampening is simulated by subtracting 1/2^n of result.
867 n=4 gives best-looking result
868 n<4 (eg 2 or 3) thicker consistency, waves die out immediately
869 n>4 (eg 8 or 12) more fluid, waves die out slowly
875 int across, down, pixel;
892 pixel = 1 * width + 1;
893 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
894 for (across = 1; across < width - 1; across++, pixel++) {
896 (((src[pixel - 1] + src[pixel + 1] +
897 src[pixel - width] + src[pixel + width]) / 2)) - dest[pixel];
900 /* Smooth the output */
901 pixel = 1 * width + 1;
902 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
903 for (across = 1; across < width - 1; across++, pixel++) {
904 if (temp[pixel] != 0) { /* Close enough for government work */
906 (temp[pixel - 1] + temp[pixel + 1] +
907 temp[pixel - width] + temp[pixel + width] +
908 temp[pixel - width - 1] + temp[pixel - width + 1] +
909 temp[pixel + width - 1] + temp[pixel + width + 1] +
911 dest[pixel] = damp - (damp >> fluidity);
917 pixel = 1 * width + 1;
918 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
919 for (across = 1; across < width - 1; across++, pixel++) {
921 (((src[pixel - 1] + src[pixel + 1] +
922 src[pixel - width] + src[pixel + width]) / 2)) - dest[pixel];
923 dest[pixel] = damp - (damp >> fluidity);
927 if (++count > 3) count = 0;
930 draw_transparent(dest);
936 /* ------------------------------------------- */
939 char *progclass = "Ripples";
943 ".background: black",
944 ".foreground: #FFAF5F",
946 "*dontClearRoot: True",
956 #ifdef HAVE_XSHM_EXTENSION
958 #endif /* HAVE_XSHM_EXTENSION */
962 XrmOptionDescRec options[] =
964 { "-colors", ".colors", XrmoptionSepArg, 0},
965 { "-colours", ".colors", XrmoptionSepArg, 0},
966 {"-delay", ".delay", XrmoptionSepArg, 0},
967 {"-rate", ".rate", XrmoptionSepArg, 0},
968 {"-box", ".box", XrmoptionSepArg, 0},
969 {"-water", ".water", XrmoptionNoArg, "True"},
970 {"-oily", ".oily", XrmoptionNoArg, "True"},
971 {"-stir", ".stir", XrmoptionNoArg, "True"},
972 {"-fluidity", ".fluidity", XrmoptionSepArg, 0},
973 {"-light", ".light", XrmoptionSepArg, 0},
974 {"-grayscale", ".grayscale", XrmoptionNoArg, "True"},
975 #ifdef HAVE_XSHM_EXTENSION
976 {"-shm", ".useSHM", XrmoptionNoArg, "True"},
977 {"-no-shm", ".useSHM", XrmoptionNoArg, "False"},
978 #endif /* HAVE_XSHM_EXTENSION */
983 void screenhack(Display *disp, Window win)
986 int delay = get_integer_resource("delay", "Integer");
987 int rate = get_integer_resource("rate", "Integer");
988 int box = get_integer_resource("box", "Integer");
989 int oily = get_boolean_resource("oily", "Boolean");
990 int stir = get_boolean_resource("stir", "Boolean");
991 int fluidity = get_integer_resource("fluidity", "Integer");
992 transparent = get_boolean_resource("water", "Boolean");
993 grayscale_p = get_boolean_resource("grayscale", "Boolean");
994 #ifdef HAVE_XSHM_EXTENSION
995 use_shm = get_boolean_resource("useSHM", "Boolean");
996 #endif /* HAVE_XSHM_EXTENSION */
997 light = get_integer_resource("light", "Integer");
999 if (fluidity <= 1) fluidity = 1;
1000 if (fluidity > 16) fluidity = 16; /* 16 = sizeof(short) */
1001 if (light < 0) light = 0;
1006 ncolors = get_integer_resource ("colors", "Colors");
1007 if (0 == ncolors) /* English spelling? */
1008 ncolors = get_integer_resource ("colours", "Colors");
1010 if (ncolors > sizeof(ctab)/sizeof(*ctab))
1011 ncolors = sizeof(ctab)/sizeof(*ctab);
1016 init_linear_colors();
1018 if (transparent && light > 0) {
1020 draw_transparent = draw_transparent_light;
1021 set_mask(visual->red_mask, &rmask, &rshift);
1022 set_mask(visual->green_mask, &gmask, &gshift);
1023 set_mask(visual->blue_mask, &bmask, &bshift);
1024 if (rmask == 0) draw_transparent = draw_transparent_vanilla;
1026 /* Adjust the shift value "light" when we don't have 8 bits per colour */
1027 maxbits = MIN(MIN(BITCOUNT(rmask), BITCOUNT(gmask)), BITCOUNT(bmask));
1029 if (light < 0) light = 0;
1033 set_mask(visual->red_mask, &rmask, &rshift);
1034 set_mask(visual->green_mask, &gmask, &gshift);
1035 set_mask(visual->blue_mask, &bmask, &bshift);
1037 draw_transparent = draw_transparent_vanilla;
1040 init_ripples(0, -SPLASH); /* Start off without any drops */
1042 /* Main drawing loop */
1044 if (rate > 0 && (iterations % rate) == 0)
1045 add_drop(ripple_blob, -SPLASH);
1047 add_drop(ripple_stir, -SPLASH);
1048 if (box > 0 && (random() % box) == 0)
1049 add_drop(ripple_box, -SPLASH);