7621d5eee4818b4b8b830547f9c77fc24535cf46
[xscreensaver] / hacks / coral.c
1 /* coral, by "Frederick G.M. Roeber" <roeber@netscape.com>, 15-jul-97.
2  *
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 
9  * implied warranty.
10  */
11
12 #include "screenhack.h"
13 #include "colors.h"
14 #include "erase.h"
15
16 static GC draw_gc, erase_gc;
17 static unsigned int default_fg_pixel;
18 #define NCOLORSMAX 200
19 static XColor colors[NCOLORSMAX];
20 static int ncolors = 0;
21 static int colorindex = 0;
22 static int colorsloth;
23
24 static XPoint *walkers = 0;
25 static int nwalkers;
26 static int width, widthb;
27 static int height;
28
29 static unsigned int *board = 0;
30 #define getdot(x,y) (board[(y*widthb)+(x>>5)] &  (1<<(x & 31)))
31 #define setdot(x,y) (board[(y*widthb)+(x>>5)] |= (1<<(x & 31)))
32
33
34 static void
35 init_coral(Display *dpy, Window window)
36 {
37     XGCValues gcv;
38     Colormap cmap;
39     XWindowAttributes xgwa;
40     Bool writeable = False;
41     int seeds;
42     int density;
43     int i;
44
45     XClearWindow(dpy, window);
46     XGetWindowAttributes(dpy, window, &xgwa);
47     width = xgwa.width;
48     widthb = ((xgwa.width + 31) >> 5);
49     height = xgwa.height;
50     if (board) free(board);
51     board = (unsigned int *)calloc(widthb * xgwa.height, sizeof(unsigned int));
52     if(!board) exit(1);
53     cmap = xgwa.colormap;
54     if( ncolors ) {
55         free_colors(dpy, cmap, colors, ncolors);
56         ncolors = 0;
57     }
58     gcv.foreground = default_fg_pixel = get_pixel_resource("foreground", "Foreground", dpy, cmap);
59     draw_gc = XCreateGC(dpy, window, GCForeground, &gcv);
60     gcv.foreground = get_pixel_resource ("background", "Background",dpy, cmap);
61     erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
62     ncolors = NCOLORSMAX;
63     make_uniform_colormap(dpy, xgwa.visual, cmap, colors, &ncolors, True, &writeable, False);
64     if (ncolors <= 0) {
65       ncolors = 2;
66       colors[0].red = colors[0].green = colors[0].blue = 0;
67       colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
68       XAllocColor(dpy, cmap, &colors[0]);
69       XAllocColor(dpy, cmap, &colors[1]);
70    }
71     colorindex = random()%ncolors;
72     
73     density = get_integer_resource("density", "Integer");
74     if( density < 1 ) density = 1;
75     if( density > 100 ) density = 90; /* more like mold than coral */
76     nwalkers = (width*height*density)/100;
77     if (walkers) free(walkers);
78     walkers = (XPoint *)calloc(nwalkers, sizeof(XPoint));
79     if( (XPoint *)0 == walkers ) exit(1);
80
81     seeds = get_integer_resource("seeds", "Integer");
82     if( seeds < 1 ) seeds = 1;
83     if( seeds > 1000 ) seeds = 1000;
84
85     colorsloth = nwalkers*2/ncolors;
86     XSetForeground(dpy, draw_gc, colors[colorindex].pixel);
87
88     for( i = 0; i < seeds; i++ ) {
89         int x, y;
90         do {
91             x = random() % width;
92             y = random() % height;
93         } while( getdot(x, y) );
94
95         setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1));
96         setdot((x-1),  y   ); setdot(x,  y   ); setdot((x+1),  y   );
97         setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1));
98         XDrawPoint(dpy, window, draw_gc, x, y);
99     }
100
101     for( i = 0; i < nwalkers; i++ ) {
102         walkers[i].x = (random() % (width-2)) + 1;
103         walkers[i].y = (random() % (height-2)) + 1;
104     }
105 }
106
107
108 /* returns 2 bits of randomness (conserving calls to random()).
109    This speeds things up a little, but not a lot (5-10% or so.)
110  */
111 static int 
112 rand_2(void)
113 {
114   static int i = 0;
115   static int r = 0;
116   if (i != 0) {
117     i--;
118   } else {
119     i = 15;
120     r = random();
121   }
122
123   {
124     register int j = (r & 3);
125     r = r >> 2;
126     return j;
127   }
128 }
129
130
131 static void
132 coral(Display *dpy, Window window)
133 {
134     int delay2 = get_integer_resource ("delay2", "Integer");
135
136     int max_points = 200;
137     int npoints = 0;
138     XPoint *pointbuf = (XPoint *) calloc(sizeof(XPoint), max_points+2);
139     if (!pointbuf) exit(-1);
140
141     while( 1 ) {
142         int i;
143
144         for( i = 0; i < nwalkers; i++ ) {
145             int x = walkers[i].x;
146             int y = walkers[i].y;
147
148             if( getdot(x, y) ) {
149
150                 Bool flush = False;
151                 Bool color = False;
152
153                 /* XDrawPoint(dpy, window, draw_gc, x, y); */
154                 pointbuf[npoints].x = x;
155                 pointbuf[npoints].y = y;
156                 npoints++;
157
158                 /* Mark the surrounding area as "sticky" */
159                 setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1));
160                 setdot((x-1),  y   );                   setdot((x+1),  y   );
161                 setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1));
162                 nwalkers--;
163                 walkers[i].x = walkers[nwalkers].x;
164                 walkers[i].y = walkers[nwalkers].y;
165                 if( 0 == (nwalkers%colorsloth) ) {
166                   color = True;
167                 }
168                   
169                 if (flush || color || 0 == nwalkers || npoints >= max_points) {
170                   XDrawPoints(dpy, window, draw_gc, pointbuf, npoints,
171                               CoordModeOrigin);
172                   npoints = 0;
173                   XSync(dpy, False);
174                 }
175
176                 if (color) {
177                     colorindex++;
178                     if( colorindex == ncolors )
179                         colorindex = 0;
180                     XSetForeground(dpy, draw_gc, colors[colorindex].pixel);
181                 }
182
183                 if( 0 == nwalkers ) {
184                     XSync(dpy, False);
185                     free(pointbuf);
186                     return;
187                 }
188             } else {
189                 /* move it a notch */
190                 do {
191                     switch(rand_2()) {
192                     case 0:
193                         if( 1 == x ) continue;
194                         walkers[i].x--;
195                         break;
196                     case 1:
197                         if( width-2 == x ) continue;
198                         walkers[i].x++;
199                         break;
200                     case 2:
201                         if( 1 == y ) continue;
202                         walkers[i].y--;
203                         break;
204                     default: /* case 3: */
205                         if( height-2 == y ) continue;
206                         walkers[i].y++;
207                         break;
208                     /* default:
209                       abort(); */
210                     }
211                 } while(0);
212             }
213         }
214
215         if (delay2 > 0) {
216           if (npoints > 0) {
217             XDrawPoints(dpy, window, draw_gc, pointbuf, npoints,
218                         CoordModeOrigin);
219             npoints = 0;
220             XSync(dpy, False);
221           }
222           screenhack_handle_events (dpy);
223           usleep(delay2);
224         }
225     }
226 }
227
228 char *progclass = "Coral";
229
230 char *defaults[] = {
231   ".background: black",
232   ".foreground: white",
233   "*density:    25",
234   "*seeds:      20", /* too many for 640x480, too few for 1280x1024 */
235   "*delay:      5",
236   "*delay2:     1000",
237   0
238 };
239
240 XrmOptionDescRec options[] = {
241     { "-density", ".density", XrmoptionSepArg, 0 },
242     { "-seeds", ".seeds", XrmoptionSepArg, 0 },
243     { "-delay", ".delay", XrmoptionSepArg, 0 },
244     { "-delay2", ".delay2", XrmoptionSepArg, 0 },
245     { 0, 0, 0, 0 }
246 };
247
248 void
249 screenhack(dpy, window)
250 Display *dpy;
251 Window window;
252 {
253     int delay = get_integer_resource ("delay", "Integer");
254     while( 1 ) {
255         init_coral(dpy, window);
256         coral(dpy, window);
257         screenhack_handle_events (dpy);
258         if( delay ) sleep(delay);
259         erase_full_window(dpy, window);
260     }
261 }