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 /* ------------------------------------------- */
109 grey = ncolors * abs(grey) / (SPLASH/4);
119 draw_ripple(short *src)
122 char *dirty = dirty_buffer;
124 for (down = 0; down < height - 1; down++, src += 1, dirty += 1)
125 for (across = 0; across < width - 1; across++, src++, dirty++) {
128 v2 = (int)*(src + 1);
129 v3 = (int)*(src + width);
130 v4 = (int)*(src + width + 1);
131 if ((v1 == 0 && v2 == 0 && v3 == 0 && v4 == 0)) {
140 dx = ((v3 - v1) + (v4 - v2)) << light; /* light from top */
143 XPutPixel(buffer_map,(across<<1), (down<<1), map_color(dx + v1));
144 XPutPixel(buffer_map,(across<<1)+1,(down<<1), map_color(dx + ((v1 + v2) >> 1)));
145 XPutPixel(buffer_map,(across<<1), (down<<1)+1,map_color(dx + ((v1 + v3) >> 1)));
146 XPutPixel(buffer_map,(across<<1)+1,(down<<1)+1,map_color(dx + ((v1 + v4) >> 1)));
152 /* ------------------------------------------- */
155 /* Uses the horizontal gradient as an offset to create a warp effect */
157 draw_transparent_vanilla(short *src)
159 int across, down, pixel;
160 char *dirty = dirty_buffer;
163 for (down = 0; down < height - 2; down++, pixel += 2)
164 for (across = 0; across < width-2; across++, pixel++) {
165 int gradx, grady, gradx1, grady1;
166 int x0, x1, x2, y1, y2;
171 y1 = src[pixel + width];
172 y2 = src[pixel + 2*width];
178 gradx1 = 1 + (gradx + gradx1) / 2;
179 grady1 = 1 + (grady + grady1) / 2;
181 if ((2*across+MIN(gradx,gradx1) < 0) ||
182 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
186 if ((2*down+MIN(grady,grady1) < 0) ||
187 (2*down+MAX(grady,grady1) >= bigheight)) {
192 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
193 if (dirty[pixel] > 0)
196 dirty[pixel] = DIRTY;
198 if (dirty[pixel] > 0) {
199 XPutPixel(buffer_map, (across<<1), (down<<1),
200 XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady));
201 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
202 XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady));
203 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
204 XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1));
205 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
206 XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1));
212 /* ------------------------------------------- */
215 /* This builds on the above warp effect by adding in a lighting effect: */
216 /* brighten pixels by an amount corresponding to the vertical gradient */
217 static unsigned long rmask;
218 static unsigned long gmask;
219 static unsigned long bmask;
226 set_mask(unsigned long color, unsigned long *mask, int *shift)
229 while (color != 0 && (color & 1) == 0) {
238 cadd(unsigned long color, int dx, unsigned long mask, int shift)
245 else if (x > (int)mask) x = mask;
247 return color << shift;
252 bright(int dx, unsigned long color)
254 return (cadd(color, dx, rmask, rshift) |
255 cadd(color, dx, gmask, gshift) |
256 cadd(color, dx, bmask, bshift));
261 draw_transparent_light(short *src)
263 int across, down, pixel;
264 char *dirty = dirty_buffer;
267 for (down = 0; down < height - 2; down++, pixel += 2)
268 for (across = 0; across < width-2; across++, pixel++) {
269 int gradx, grady, gradx1, grady1;
270 int x0, x1, x2, y1, y2;
275 y1 = src[pixel + width];
276 y2 = src[pixel + 2*width];
282 gradx1 = 1 + (gradx + gradx1) / 2;
283 grady1 = 1 + (grady + grady1) / 2;
285 if ((2*across+MIN(gradx,gradx1) < 0) ||
286 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
290 if ((2*down+MIN(grady,grady1) < 0) ||
291 (2*down+MAX(grady,grady1) >= bigheight)) {
296 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
297 if (dirty[pixel] > 0)
300 dirty[pixel] = DIRTY;
302 if (dirty[pixel] > 0) {
307 dx = (grady + (src[pixel+width+1]-x1)) >> (4-light);
309 dx = (grady + (src[pixel+width+1]-x1)) << (light-4);
312 XPutPixel(buffer_map, (across<<1), (down<<1),
313 bright(dx, XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady)));
314 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
315 bright(dx, XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady)));
316 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
317 bright(dx, XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1)));
318 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
319 bright(dx, XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1)));
321 /* Could use XCopyArea, but XPutPixel is faster */
322 XPutPixel(buffer_map, (across<<1), (down<<1),
323 XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady));
324 XPutPixel(buffer_map, (across<<1)+1,(down<<1),
325 XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady));
326 XPutPixel(buffer_map, (across<<1), (down<<1)+1,
327 XGetPixel(orig_map, (across<<1) + gradx, (down<<1) + grady1));
328 XPutPixel(buffer_map, (across<<1)+1,(down<<1)+1,
329 XGetPixel(orig_map, (across<<1) + gradx1,(down<<1) + grady1));
336 /* ------------------------------------------- */
340 /* Doesn't go any faster and doesn't work at all colour depths */
342 draw_transparent16l(short *src)
344 int across, down, bigpix, pixel;
345 char *dirty = dirty_buffer;
346 unsigned short *buffer, *orig;
348 buffer = (unsigned short *) buffer_map->data;
349 orig = (unsigned short *) orig_map->data;
351 for (pixel = bigpix = down = 0;
353 down++, pixel += 2, bigpix += bigwidth+4)
354 for (across = 0; across < width-2; across++, pixel++, bigpix+=2) {
355 int gradx, grady, gradx1, grady1;
356 int x0, x1, x2, y1, y2;
361 y1 = src[pixel + width];
362 y2 = src[pixel + 2*width];
368 gradx1 = 1 + (gradx + gradx1) / 2;
369 grady1 = 1 + (grady + grady1) / 2;
371 if ((2*across+MIN(gradx,gradx1) < 0) ||
372 (2*across+MAX(gradx,gradx1) >= bigwidth)) {
376 if ((2*down+MIN(grady,grady1) < 0) ||
377 (2*down+MAX(grady,grady1) >= bigheight)) {
382 if ((gradx == 0 && gradx1 == 1 && grady == 0 && grady1 == 1)) {
383 if (dirty[pixel] > 0)
386 dirty[pixel] = DIRTY;
388 if (dirty[pixel] > 0) {
389 unsigned short *dest = buffer + bigpix;
390 unsigned short *image = orig + bigpix;
395 dx = (grady + (src[pixel+width+1]-x1)) >> (4-light);
397 dx = (grady + (src[pixel+width+1]-x1)) << (light-4);
403 *dest++ = dobright(dx, *(image + gradx + grady));
404 *dest = dobright(dx, *(image + gradx1 + grady));
405 dest += bigwidth - 1;
406 *dest++ = dobright(dx, *(image + gradx + grady1));
407 *dest = dobright(dx, *(image + gradx1 + grady1));
409 *dest++ = *(image + gradx + grady);
410 *dest = *(image + gradx1 + grady);
411 dest += bigwidth - 1;
412 *dest++ = *(image + gradx + grady1);
413 *dest = *(image + gradx1 + grady1);
421 /* ------------------------------------------- */
425 setup_X(Display * disp, Window win)
427 XWindowAttributes xwa;
430 XGetWindowAttributes(disp, win, &xwa);
434 colormap = xwa.colormap;
435 bigwidth = xwa.width;
436 bigheight = xwa.height;
440 /* This causes buffer_map to be 1 pixel taller and wider than orig_map,
441 which can cause the two XImages to have different bytes-per-line,
442 which causes stair-stepping. So this better not be necessary...
445 #if 0 /* I'm not entirely sure if I need this */
453 width = bigwidth / 2;
454 height = bigheight / 2;
460 gcv.function = GXcopy;
461 gcv.subwindow_mode = IncludeInferiors;
463 gcflags = GCForeground | GCFunction;
464 if (use_subwindow_mode_p(xwa.screen, window)) /* see grabscreen.c */
465 gcflags |= GCSubwindowMode;
467 gc = XCreateGC(display, window, gcflags, &gcv);
469 grab_screen_image(xwa.screen, window);
471 orig_map = XGetImage(display, window, 0, 0, xwa.width, xwa.height,
476 gc = XCreateGC(display, window, 0, &gcv);
481 fprintf(stderr, "XCreateGC failed\n");
487 #ifdef HAVE_XSHM_EXTENSION
489 buffer_map = create_xshm_image(display, xwa.visual, depth,
490 ZPixmap, 0, &shm_info, bigwidth, bigheight);
493 fprintf(stderr, "create_xshm_image failed\n");
496 #endif /* HAVE_XSHM_EXTENSION */
499 buffer_map = XCreateImage(display, xwa.visual,
500 depth, ZPixmap, 0, 0,
501 bigwidth, bigheight, 8, 0);
502 buffer_map->data = (char *)
503 calloc(buffer_map->height, buffer_map->bytes_per_line);
511 #ifdef HAVE_XSHM_EXTENSION
513 XShmPutImage(display, window, gc, buffer_map, 0, 0, 0, 0,
514 bigwidth, bigheight, False);
516 #endif /* HAVE_XSHM_EXTENSION */
517 XPutImage(display, window, gc, buffer_map, 0, 0, 0, 0,
518 bigwidth, bigheight);
520 XSync(display,False);
521 screenhack_handle_events(display);
525 /* ------------------------------------------- */
529 cinterp(double a, int bg, int fg)
532 result = (int)((1-a) * bg + a * fg + 0.5);
533 if (result < 0) result = 0;
534 if (result > 255) result = 255;
539 /* Interpolate the ripple colours between the background colour and
542 init_linear_colors(void)
544 int i, j, red, green, blue, bred, bgreen, bblue;
547 if (ncolors < 2 || mono_p)
552 /* Make it possible to set the color of the ripples,
553 Based on work by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
555 fg.pixel = get_pixel_resource("foreground", "Foreground",
557 XQueryColor(display, colormap, &fg);
559 green = (fg.green >> 8);
560 blue = (fg.blue >> 8);
562 bg.pixel = get_pixel_resource("background", "Background",
564 XQueryColor(display, colormap, &bg);
565 bred = (bg.red >> 8);
566 bgreen = (bg.green >> 8);
567 bblue = (bg.blue >> 8);
570 for (i = 0; i < ncolors+1; i++) {
572 double a = (double)i / ncolors;
573 int r = cinterp(a, bred, red);
574 int g = cinterp(a, bgreen, green);
575 int b = cinterp(a, bblue, blue);
577 xcl.red = (unsigned short) ((r << 8) | r);
578 xcl.green = (unsigned short) ((g << 8) | g);
579 xcl.blue = (unsigned short) ((b << 8) | b);
580 xcl.flags = DoRed | DoGreen | DoBlue;
582 XAllocColor(display, colormap, &xcl);
584 ctab[j++] = (int) xcl.pixel;
590 init_oily_colors(void)
592 XColor *colors = NULL;
594 if (ncolors < 2 || mono_p)
601 colors = (XColor *)malloc(sizeof(*colors) * (ncolors+1));
602 make_smooth_colormap(display, visual, colormap, colors, &ncolors,
604 False, /* not writable */
605 True); /* verbose (complain about failure) */
615 for (i = 0; i < ncolors+1; i++) {
616 XAllocColor(display, colormap, colors+i);
617 ctab[j++] = (int) colors[i].pixel;
622 ctab[1] = get_pixel_resource("foreground", "Foreground", display, colormap);
623 ctab[0] = get_pixel_resource("background", "Background", display, colormap);
628 /* ------------------------------------------- */
635 for (i = 0; i < TABLE; i++)
636 cos_tab[i] = cos(i * M_PI/2 / TABLE);
640 /* Shape of drop to add */
647 i = (int)(x * TABLE + 0.5);
648 if (i >= TABLE) i = (TABLE-1) - (i-(TABLE-1));
651 return cos(x * M_PI/2);
662 add_circle_drop(int x, int y, int radius, int dheight)
665 short *buf = (random()&1) ? bufferA : bufferB;
668 r2 = radius * radius;
670 for (cy = -radius; cy <= radius; cy++)
671 for (cx = -radius; cx <= radius; cx++) {
672 int r = cx*cx + cy*cy;
674 buf[i + cx + cy*width] =
675 (short)(dheight * sinc(sqrt(r)/radius));
682 add_drop(ripple_mode mode, int drop)
684 int newx, newy, dheight;
685 int radius = MIN(width, height) / 50;
686 /* Don't put drops too near the edge of the screen or they get stuck */
694 dheight = 1 + (random() % drop);
695 newx = border + (random() % (width - 2*border));
696 newy = border + (random() % (height - 2*border));
697 x = newy * width + newx;
698 bufferA[x + 1] = bufferA[x] = bufferA[x + width] = bufferA[x + width + 1] =
699 bufferB[x + 1] = bufferB[x] = bufferB[x + width] = bufferB[x + width + 1] =
706 power = drop_dist[random() % (sizeof(drop_dist)/sizeof(drop_dist[0]))]; /* clumsy */
707 dheight = (int)(drop * (power + 0.01));
708 newx = radius + border + (random() % (int)(width - 2*border - 2*radius*power));
709 newy = radius + border + (random() % (int)(height - 2*border - 2*radius*power));
710 add_circle_drop(newx, newy, radius, dheight);
713 /* Adding too many boxes too quickly (-box 1) doesn't give the waves time
714 to disperse and the waves build up (and overflow) */
718 short *buf = (random()&1) ? bufferA : bufferB;
720 radius = (1 + (random() % 5)) * (1 + (random() % 5));
721 dheight = drop / 128;
722 if (random() & 1) dheight = -dheight;
723 newx = radius + border + (random() % (width - 2*border - 2*radius));
724 newy = radius + border + (random() % (height - 2*border - 2*radius));
725 x = newy * width + newx;
726 for (cy = -radius; cy <= radius; cy++)
727 for (cx = -radius; cx <= radius; cx++)
728 buf[x + cx + cy*width] = (short)(dheight);
732 static double ang = 0;
734 newx = border + (int)((width-2*border) * (1+cos(3*ang)) / 2);
735 newy = border + (int)((height-2*border) * (1+sin(2*ang)) / 2);
736 add_circle_drop(newx, newy, radius, drop / 10);
738 if (ang > 12*M_PI) ang = 0;
746 init_ripples(int ndrops, int splash)
750 bufferA = (short *)calloc(width * height, sizeof(*bufferA));
751 bufferB = (short *)calloc(width * height, sizeof(*bufferB));
752 temp = (short *)calloc(width * height, sizeof(*temp));
754 dirty_buffer = (char *)calloc(width * height, sizeof(*dirty_buffer));
756 for (i = 0; i < ndrops; i++)
757 add_drop(ripple_blob, splash);
760 /* There's got to be a better way of doing this XCopyArea? */
761 memcpy(buffer_map->data, orig_map->data,
762 bigheight * buffer_map->bytes_per_line);
764 int across, down, color;
766 color = map_color(0); /* background colour */
767 for (down = 0; down < bigheight; down++)
768 for (across = 0; across < bigwidth; across++)
769 XPutPixel(buffer_map,across, down, color);
777 Explanation from hq_water.zip (Arturo R Montesinos (ARM) arami@fi.upm.es)
779 Differential equation is: u = a ( u + u )
782 Where a = tension * gravity / surface_density.
784 Approximating second derivatives by central differences:
786 [ u(t+1)-2u(t)+u(t-1) ] / dt = a [ u(x+1)+u(x-1)+u(y+1)+u(y-1)-4u ] / h
788 where dt = time step squared, h = dx*dy = mesh resolution squared.
790 From where u(t+1) may be calculated as:
793 u(t+1) = a -- | 1 0 1 |u - u(t-1) + (2-4a --)u
796 When a*dt/h = 1/2 last term vanishes, giving:
799 u(t+1) = - | 1 0 1 |u - u(t-1)
802 (note that u(t-1,x,y) is only used to calculate u(t+1,x,y) so
803 we can use the same array for both t-1 and t+1, needing only
804 two arrays, U[0] and U[1])
806 Dampening is simulated by subtracting 1/2^n of result.
807 n=4 gives best-looking result
808 n<4 (eg 2 or 3) thicker consistency, waves die out immediately
809 n>4 (eg 8 or 12) more fluid, waves die out slowly
815 int across, down, pixel;
832 pixel = 1 * width + 1;
833 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
834 for (across = 1; across < width - 1; across++, pixel++) {
836 (((src[pixel - 1] + src[pixel + 1] +
837 src[pixel - width] + src[pixel + width]) / 2)) - dest[pixel];
840 /* Smooth the output */
841 pixel = 1 * width + 1;
842 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
843 for (across = 1; across < width - 1; across++, pixel++) {
844 if (temp[pixel] != 0) { /* Close enough for government work */
846 (temp[pixel - 1] + temp[pixel + 1] +
847 temp[pixel - width] + temp[pixel + width] +
848 temp[pixel - width - 1] + temp[pixel - width + 1] +
849 temp[pixel + width - 1] + temp[pixel + width + 1] +
851 dest[pixel] = damp - (damp >> fluidity);
857 pixel = 1 * width + 1;
858 for (down = 1; down < height - 1; down++, pixel += 2 * 1)
859 for (across = 1; across < width - 1; across++, pixel++) {
861 (((src[pixel - 1] + src[pixel + 1] +
862 src[pixel - width] + src[pixel + width]) / 2)) - dest[pixel];
863 dest[pixel] = damp - (damp >> fluidity);
867 if (++count > 3) count = 0;
870 draw_transparent(dest);
876 /* ------------------------------------------- */
879 char *progclass = "Ripples";
883 ".background: black",
884 ".foreground: #FFAF5F",
886 "*dontClearRoot: True",
895 #ifdef HAVE_XSHM_EXTENSION
897 #endif /* HAVE_XSHM_EXTENSION */
901 XrmOptionDescRec options[] =
903 { "-colors", ".colors", XrmoptionSepArg, 0},
904 { "-colours", ".colors", XrmoptionSepArg, 0},
905 {"-delay", ".delay", XrmoptionSepArg, 0},
906 {"-rate", ".rate", XrmoptionSepArg, 0},
907 {"-box", ".box", XrmoptionSepArg, 0},
908 {"-water", ".water", XrmoptionNoArg, "True"},
909 {"-oily", ".oily", XrmoptionNoArg, "True"},
910 {"-stir", ".stir", XrmoptionNoArg, "True"},
911 {"-fluidity", ".fluidity", XrmoptionSepArg, 0},
912 {"-light", ".light", XrmoptionSepArg, 0},
913 #ifdef HAVE_XSHM_EXTENSION
914 {"-shm", ".useSHM", XrmoptionNoArg, "True"},
915 {"-no-shm", ".useSHM", XrmoptionNoArg, "False"},
916 #endif /* HAVE_XSHM_EXTENSION */
921 void screenhack(Display *disp, Window win)
924 int delay = get_integer_resource("delay", "Integer");
925 int rate = get_integer_resource("rate", "Integer");
926 int box = get_integer_resource("box", "Integer");
927 int oily = get_boolean_resource("oily", "Boolean");
928 int stir = get_boolean_resource("stir", "Boolean");
929 int fluidity = get_integer_resource("fluidity", "Integer");
930 transparent = get_boolean_resource("water", "Boolean");
931 #ifdef HAVE_XSHM_EXTENSION
932 use_shm = get_boolean_resource("useSHM", "Boolean");
933 #endif /* HAVE_XSHM_EXTENSION */
934 light = get_integer_resource("light", "Integer");
936 if (fluidity <= 1) fluidity = 1;
937 if (fluidity > 16) fluidity = 16; /* 16 = sizeof(short) */
938 if (light < 0) light = 0;
943 ncolors = get_integer_resource ("colors", "Colors");
944 if (0 == ncolors) /* English spelling? */
945 ncolors = get_integer_resource ("colours", "Colors");
947 if (ncolors > sizeof(ctab)/sizeof(*ctab))
948 ncolors = sizeof(ctab)/sizeof(*ctab);
953 init_linear_colors();
955 if (transparent && light > 0) {
957 draw_transparent = draw_transparent_light;
958 set_mask(visual->red_mask, &rmask, &rshift);
959 set_mask(visual->green_mask, &gmask, &gshift);
960 set_mask(visual->blue_mask, &bmask, &bshift);
961 if (rmask == 0) draw_transparent = draw_transparent_vanilla;
963 /* Adjust the shift value "light" when we don't have 8 bits per colour */
964 maxbits = MIN(MIN(BITCOUNT(rmask), BITCOUNT(gmask)), BITCOUNT(bmask));
966 if (light < 0) light = 0;
968 draw_transparent = draw_transparent_vanilla;
970 init_ripples(0, -SPLASH); /* Start off without any drops */
972 /* Main drawing loop */
974 if (rate > 0 && (iterations % rate) == 0)
975 add_drop(ripple_blob, -SPLASH);
977 add_drop(ripple_stir, -SPLASH);
978 if (box > 0 && (random() % box) == 0)
979 add_drop(ripple_box, -SPLASH);