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