1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* coral --- a coral reef */
3
4 #if 0
5 static const char sccsid[] = "@(#)coral.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8 /*
9 * Copyright (c) 1997 by "Frederick G.M. Roeber" <roeber@netscape.com>
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * Revision History:
24 * 01-Nov-2000: Allocation checks
25 * 29-Oct-1997: xlock version (David Bagley <bagleyd AT verizon.net>)
26 * 15-Jul-1997: xscreensaver version Frederick G.M. Roeber
27 * <roeber@netscape.com>
28 */
29
30 /*-
31 * original copyright
32 * Copyright (c) 1997 by "Frederick G.M. Roeber" <roeber@netscape.com>
33 *
34 * Permission to use, copy, modify, distribute, and sell this software and its
35 * documentation for any purpose is hereby granted without fee, provided that
36 * the above copyright notice appear in all copies and that both that
37 * copyright notice and this permission notice appear in supporting
38 * documentation. No representations are made about the suitability of this
39 * software for any purpose. It is provided "as is" without express or
40 * implied warranty.
41 */
42
43 #ifdef STANDALONE
44 #define MODE_coral
45 #define DEFAULTS "*delay: 60000 \n" \
46 "*batchcount: -3 \n" \
47 "*size: 35 \n" \
48 "*ncolors: 200 \n" \
49
50 # define free_coral 0
51 # define reshape_coral 0
52 # define coral_handle_event 0
53 #include "xlockmore.h" /* in xscreensaver distribution */
54 #else /* STANDALONE */
55 #include "xlock.h" /* in xlockmore distribution */
56 #endif /* STANDALONE */
57
58 #ifdef MODE_coral
59
60 ENTRYPOINT ModeSpecOpt coral_opts =
61 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
62
63 #ifdef USE_MODULES
64 ModStruct coral_description =
65 {"coral", "init_coral", "draw_coral", "release_coral",
66 "init_coral", "init_coral", (char *) NULL, &coral_opts,
67 60000, -3, 1, 35, 64, 0.6, "",
68 "Shows a coral reef", 0, NULL};
69
70 #endif
71
72 #define MINSIZE 1
73 #define MINSEEDS 1
74 #define MAXSIZE 99
75 #define MAXPOINTS 200
76 #define COLORTHRESH 512
77
78 typedef struct {
79 unsigned int default_fg_pixel;
80
81 XPoint *walkers;
82 XPoint *pointbuf;
83 unsigned int *reef;
84 int nwalkers;
85 int width, widthb;
86 int height;
87 int colorindex;
88 int density;
89 int seeds;
90 } coralstruct;
91
92 static coralstruct *reefs = (coralstruct *) NULL;
93
94 #define getdot(x,y) (cp->reef[(y*cp->widthb)+(x>>5)] & (1<<(x & 31)))
95 /* Avoid array bounds reads and writes */
96 #define setdot(x,y) (cp->reef[((y*cp->widthb)+(x>>5) >= 0 ? (y*cp->widthb)+(x>>5) : 0)] |= (1<<(x & 31)))
97
98 /*-
99 * returns 2 bits of randomness (conserving calls to LRAND()).
100 * This speeds things up a little, but not a lot (5-10% or so.)
101 */
102 static int
rand_2(void)103 rand_2(void)
104 {
105 static int i = 0;
106 static int r = 0;
107
108 if (i) {
109 i--;
110 } else {
111 i = 15;
112 r = (int) LRAND();
113 }
114
115 {
116 register int j = (r & 3);
117
118 r = r >> 2;
119 return j;
120 }
121 }
122
123 static void
free_coral_screen(coralstruct * cp)124 free_coral_screen(coralstruct *cp)
125 {
126 if (cp == NULL) {
127 return;
128 }
129 if (cp->reef != NULL) {
130 free(cp->reef);
131 cp->reef = (unsigned int *) NULL;
132 }
133 if (cp->walkers != NULL) {
134 free(cp->walkers);
135 cp->walkers = (XPoint *) NULL;
136 }
137 if (cp->pointbuf != NULL) {
138 free(cp->pointbuf);
139 cp->pointbuf = (XPoint *) NULL;
140 }
141 cp = NULL;
142 }
143
144 ENTRYPOINT void
init_coral(ModeInfo * mi)145 init_coral(ModeInfo * mi)
146 {
147 Display *display = MI_DISPLAY(mi);
148 Window window = MI_WINDOW(mi);
149 GC gc = MI_GC(mi);
150 coralstruct *cp;
151 int size = MI_SIZE(mi);
152 int i;
153
154 MI_INIT(mi, reefs);
155 cp = &reefs[MI_SCREEN(mi)];
156
157 cp->width = MAX(MI_WIDTH(mi), 4);
158 cp->height = MAX(MI_HEIGHT(mi), 4);
159
160 cp->widthb = ((cp->width + 31) >> 5);
161 if (cp->reef != NULL)
162 free(cp->reef);
163 if ((cp->reef = (unsigned int *) calloc((cp->widthb + 1) * cp->height,
164 sizeof (unsigned int))) == NULL) {
165 free_coral_screen(cp);
166 return;
167 }
168
169 if (size < -MINSIZE)
170 cp->density = NRAND(MIN(MAXSIZE, -size) - MINSIZE + 1) + MINSIZE;
171 else if (size < MINSIZE)
172 cp->density = MINSIZE;
173 else
174 cp->density = MIN(MAXSIZE, size);
175
176 cp->nwalkers = MAX((cp->width * cp->height * cp->density) / 100, 1);
177 if (cp->walkers != NULL)
178 free(cp->walkers);
179 if ((cp->walkers = (XPoint *) calloc(cp->nwalkers,
180 sizeof (XPoint))) == NULL) {
181 free_coral_screen(cp);
182 return;
183 }
184
185 cp->seeds = MI_COUNT(mi);
186 if (cp->seeds < -MINSEEDS)
187 cp->seeds = NRAND(-cp->seeds - MINSEEDS + 1) + MINSEEDS;
188 else if (cp->seeds < MINSEEDS)
189 cp->seeds = MINSEEDS;
190
191 MI_CLEARWINDOW(mi);
192
193 if (MI_NPIXELS(mi) > 2) {
194 cp->colorindex = NRAND(MI_NPIXELS(mi) * COLORTHRESH);
195 XSetForeground(display, gc, MI_PIXEL(mi, cp->colorindex / COLORTHRESH));
196 } else
197 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
198
199 for (i = 0; i < cp->seeds; i++) {
200 int x, y;
201
202 do {
203 x = NRAND(cp->width);
204 y = NRAND(cp->height);
205 } while (getdot(x, y));
206
207 setdot((x - 1), (y - 1));
208 setdot(x, (y - 1));
209 setdot((x + 1), (y - 1));
210 setdot((x - 1), y);
211 setdot(x, y);
212 setdot((x + 1), y);
213 setdot((x - 1), (y + 1));
214 setdot(x, (y + 1));
215 setdot((x + 1), (y + 1));
216 XDrawPoint(display, window, gc, x, y);
217 }
218
219 for (i = 0; i < cp->nwalkers; i++) {
220 cp->walkers[i].x = NRAND(cp->width - 2) + 1;
221 cp->walkers[i].y = NRAND(cp->height - 2) + 1;
222 }
223 if (cp->pointbuf) {
224 free(cp->pointbuf);
225 }
226 if ((cp->pointbuf = (XPoint *) calloc((MAXPOINTS + 2),
227 sizeof (XPoint))) == NULL) {
228 free_coral_screen(cp);
229 return;
230 }
231 }
232
233
234 ENTRYPOINT void
draw_coral(ModeInfo * mi)235 draw_coral(ModeInfo * mi)
236 {
237 Display *display = MI_DISPLAY(mi);
238 Window window = MI_WINDOW(mi);
239 GC gc = MI_GC(mi);
240 int npoints = 0;
241 int i;
242 coralstruct *cp;
243
244 if (reefs == NULL)
245 return;
246 cp = &reefs[MI_SCREEN(mi)];
247 if (cp->reef == NULL)
248 return;
249
250 MI_IS_DRAWN(mi) = True;
251 for (i = 0; i < cp->nwalkers; i++) {
252 int x = cp->walkers[i].x;
253 int y = cp->walkers[i].y;
254
255 if (getdot(x, y)) {
256
257 /* XDrawPoint(display, window, gc, x, y); */
258 cp->pointbuf[npoints].x = x;
259 cp->pointbuf[npoints].y = y;
260 npoints++;
261
262 /* Mark the surrounding area as "sticky" */
263 setdot((x - 1), (y - 1));
264 setdot(x, (y - 1));
265 setdot((x + 1), (y - 1));
266 setdot((x - 1), y);
267 setdot((x + 1), y);
268 setdot((x - 1), (y + 1));
269 setdot(x, (y + 1));
270 setdot((x + 1), (y + 1));
271 cp->nwalkers--;
272 cp->walkers[i].x = cp->walkers[cp->nwalkers].x;
273 cp->walkers[i].y = cp->walkers[cp->nwalkers].y;
274
275 if (0 == cp->nwalkers || npoints >= MAXPOINTS) {
276 XDrawPoints(display, window, gc, cp->pointbuf, npoints,
277 CoordModeOrigin);
278 npoints = 0;
279 }
280 if (MI_NPIXELS(mi) > 2) {
281 XSetForeground(display, gc, MI_PIXEL(mi, cp->colorindex / COLORTHRESH));
282 if (++cp->colorindex >= MI_NPIXELS(mi) * COLORTHRESH)
283 cp->colorindex = 0;
284 } else
285 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
286
287 if (0 == cp->nwalkers) {
288 if (cp->pointbuf)
289 free(cp->pointbuf);
290 cp->pointbuf = 0;
291 init_coral(mi);
292 return;
293 }
294 } else {
295 /* move it a notch */
296 switch (rand_2()) {
297 case 0:
298 if (1 == x)
299 continue;
300 cp->walkers[i].x--;
301 break;
302 case 1:
303 if (cp->width - 2 == x)
304 continue;
305 cp->walkers[i].x++;
306 break;
307 case 2:
308 if (1 == y)
309 continue;
310 cp->walkers[i].y--;
311 break;
312 default: /* case 3: */
313 if (cp->height - 2 == y)
314 continue;
315 cp->walkers[i].y++;
316 break;
317 }
318 }
319 }
320
321 if (npoints > 0) {
322 XDrawPoints(display, window, gc, cp->pointbuf, npoints,
323 CoordModeOrigin);
324 }
325 }
326
327 ENTRYPOINT void
release_coral(ModeInfo * mi)328 release_coral(ModeInfo * mi)
329 {
330 if (reefs != NULL) {
331 int screen;
332
333 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
334 free_coral_screen(&reefs[screen]);
335 free(reefs);
336 reefs = (coralstruct *) NULL;
337 }
338 }
339
340 XSCREENSAVER_MODULE ("Coral", coral)
341
342 #endif /* MODE_coral */
343