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