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