62df14cda924e0d08202ed9a61b4b98e269d9a7b
[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     if ((st->width <= 2) || (st->height <= 2)) return;
104
105     for( i = 0; i < seeds; i++ ) {
106         int x, y;
107         int max_repeat = 10;
108         do {
109           x = 1 + random() % (st->width - 2);
110           y = 1 + random() % (st->height - 2);
111         } while( getdot(x, y) && max_repeat--);
112
113         setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1));
114         setdot((x-1),  y   ); setdot(x,  y   ); setdot((x+1),  y   );
115         setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1));
116         XDrawPoint(st->dpy, st->window, st->draw_gc, x, y);
117     }
118
119     for( i = 0; i < st->nwalkers; i++ ) {
120         st->walkers[i].x = (random() % (st->width-2)) + 1;
121         st->walkers[i].y = (random() % (st->height-2)) + 1;
122     }
123 }
124
125
126 /* returns 2 bits of randomness (conserving calls to random()).
127    This speeds things up a little, but not a lot (5-10% or so.)
128  */
129 static int 
130 rand_2(void)
131 {
132   static int i = 0;
133   static int r = 0;
134   if (i != 0) {
135     i--;
136   } else {
137     i = 15;
138     r = random();
139   }
140
141   {
142     register int j = (r & 3);
143     r = r >> 2;
144     return j;
145   }
146 }
147
148
149 static int
150 coral(struct state *st)
151 {
152   int i = 0;
153
154   for( i = 0; i < st->nwalkers; i++ ) {
155     int x = st->walkers[i].x;
156     int y = st->walkers[i].y;
157
158     if( getdot(x, y) ) {
159
160       Bool flush = False;
161       Bool color = False;
162
163       /* XDrawPoint(dpy, window, draw_gc, x, y); */
164       st->pointbuf[st->npoints].x = x;
165       st->pointbuf[st->npoints].y = y;
166       st->npoints++;
167
168       /* Mark the surrounding area as "sticky" */
169       setdot((x-1), (y-1)); setdot(x, (y-1)); setdot((x+1), (y-1));
170       setdot((x-1),  y   );                   setdot((x+1),  y   );
171       setdot((x-1), (y+1)); setdot(x, (y+1)); setdot((x+1), (y+1));
172       st->nwalkers--;
173       st->walkers[i].x = st->walkers[st->nwalkers].x;
174       st->walkers[i].y = st->walkers[st->nwalkers].y;
175       if( 0 == 
176           ((st->colorsloth ? st->nwalkers%st->colorsloth : 0)) ) {
177         color = True;
178       }
179                   
180       if (flush || color || 0 == st->nwalkers || st->npoints >= st->max_points) {
181         XDrawPoints(st->dpy, st->window, st->draw_gc, st->pointbuf, st->npoints,
182                     CoordModeOrigin);
183         st->npoints = 0;
184       }
185
186       if (color) {
187         st->colorindex++;
188         if( st->colorindex == st->ncolors )
189           st->colorindex = 0;
190         XSetForeground(st->dpy, st->draw_gc, st->colors[st->colorindex].pixel);
191       }
192     } else {
193       /* move it a notch */
194       do {
195         switch(rand_2()) {
196         case 0:
197           if( 1 == x ) continue;
198           st->walkers[i].x--;
199           break;
200         case 1:
201           if( st->width-2 == x ) continue;
202           st->walkers[i].x++;
203           break;
204         case 2:
205           if( 1 == y ) continue;
206           st->walkers[i].y--;
207           break;
208         default: /* case 3: */
209           if( st->height-2 == y ) continue;
210           st->walkers[i].y++;
211           break;
212           /* default:
213              abort(); */
214         }
215       } while(0);
216     }
217   }
218
219  return (0 == st->nwalkers);
220 }
221
222 static void *
223 coral_init (Display *dpy, Window window)
224 {
225   struct state *st = (struct state *) calloc (1, sizeof(*st));
226   st->dpy = dpy;
227   st->window = window;
228   st->max_points = 200;
229   st->pointbuf = (XPoint *) calloc(sizeof(XPoint), st->max_points+2);
230   if (!st->pointbuf) exit(-1);
231
232   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
233   st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
234   st->reset = 1;
235   return st;
236 }
237
238
239 static unsigned long
240 coral_draw (Display *dpy, Window window, void *closure)
241 {
242   struct state *st = (struct state *) closure;
243
244   if (st->eraser || st->done)
245     {
246       st->done = 0;
247       st->eraser = erase_window (st->dpy, st->window, st->eraser);
248       return st->delay2;
249     }
250
251   if (st->reset)
252     init_coral(st);
253   st->reset = st->done = coral(st);
254
255   return (st->reset
256           ? (st->delay * 1000000)
257           : st->delay2);
258 }
259
260 static void
261 coral_reshape (Display *dpy, Window window, void *closure, 
262                  unsigned int w, unsigned int h)
263 {
264   struct state *st = (struct state *) closure;
265   init_coral(st);
266 }
267
268 static Bool
269 coral_event (Display *dpy, Window window, void *closure, XEvent *event)
270 {
271   return False;
272 }
273
274 static void
275 coral_free (Display *dpy, Window window, void *closure)
276 {
277   struct state *st = (struct state *) closure;
278   free (st->pointbuf);
279   if (st->walkers) free (st->walkers);
280   if (st->board) free (st->board);
281   free (st);
282 }
283
284 static const char *coral_defaults[] = {
285   ".background: black",
286   ".foreground: white",
287   "*fpsSolid:   true",
288   "*density:    25",
289   "*seeds:      20", /* too many for 640x480, too few for 1280x1024 */
290   "*delay:      5",
291   "*delay2:     20000",
292   0
293 };
294
295 static XrmOptionDescRec coral_options[] = {
296     { "-density", ".density", XrmoptionSepArg, 0 },
297     { "-seeds", ".seeds", XrmoptionSepArg, 0 },
298     { "-delay", ".delay", XrmoptionSepArg, 0 },
299     { "-delay2", ".delay2", XrmoptionSepArg, 0 },
300     { 0, 0, 0, 0 }
301 };
302
303 XSCREENSAVER_MODULE ("Coral", coral)