1 | |
---|
2 | /* -*- Mode: C; tab-width: 4 -*- */ |
---|
3 | /* worm --- draw wiggly worms */ |
---|
4 | |
---|
5 | #if 0 |
---|
6 | static const char sccsid[] = "@(#)worm.c 4.04 97/07/28 xlockmore"; |
---|
7 | #endif |
---|
8 | |
---|
9 | /*- |
---|
10 | * Copyright (c) 1991 by Patrick J. Naughton. |
---|
11 | * |
---|
12 | * Permission to use, copy, modify, and distribute this software and its |
---|
13 | * documentation for any purpose and without fee is hereby granted, |
---|
14 | * provided that the above copyright notice appear in all copies and that |
---|
15 | * both that copyright notice and this permission notice appear in |
---|
16 | * supporting documentation. |
---|
17 | * |
---|
18 | * This file is provided AS IS with no warranties of any kind. The author |
---|
19 | * shall have no liability with respect to the infringement of copyrights, |
---|
20 | * trade secrets or any patents by this file or any part thereof. In no |
---|
21 | * event will the author be liable for any lost revenue or profits or |
---|
22 | * other special, indirect and consequential damages. |
---|
23 | * |
---|
24 | * Revision History: |
---|
25 | * 10-May-97: Compatible with xscreensaver |
---|
26 | * 03-Sep-96: fixed bug in allocation of space for worms, added 3d support |
---|
27 | * Henrik Theiling <theiling@coli.uni-sb.de> |
---|
28 | * 27-Sep-95: put back malloc |
---|
29 | * 23-Sep-93: got rid of "rint". (David Bagley) |
---|
30 | * 27-Sep-91: got rid of all malloc calls since there were no calls to free(). |
---|
31 | * 25-Sep-91: Integrated into X11R5 contrib xlock. |
---|
32 | * |
---|
33 | * Adapted from a concept in the Dec 87 issue of Scientific American p. 142. |
---|
34 | * |
---|
35 | * SunView version: Brad Taylor <brad@sun.com> |
---|
36 | * X11 version: Dave Lemke <lemke@ncd.com> |
---|
37 | * xlock version: Boris Putanec <bp@cs.brown.edu> |
---|
38 | */ |
---|
39 | |
---|
40 | #ifdef STANDALONE |
---|
41 | # define PROGCLASS "Worm" |
---|
42 | # define HACK_INIT init_worm |
---|
43 | # define HACK_DRAW draw_worm |
---|
44 | # define worm_opts xlockmore_opts |
---|
45 | # define DEFAULTS "*delay: 17000 \n" \ |
---|
46 | "*count: -20 \n" \ |
---|
47 | "*cycles: 10 \n" \ |
---|
48 | "*size: -3 \n" \ |
---|
49 | "*ncolors: 150 \n" \ |
---|
50 | "*use3d: False \n" \ |
---|
51 | "*delta3d: 1.5 \n" \ |
---|
52 | "*right3d: red \n" \ |
---|
53 | "*left3d: blue \n" \ |
---|
54 | "*both3d: magenta \n" \ |
---|
55 | "*none3d: black \n " |
---|
56 | # define SMOOTH_COLORS |
---|
57 | # include "xlockmore.h" /* in xscreensaver distribution */ |
---|
58 | #else /* STANDALONE */ |
---|
59 | # include "xlock.h" /* in xlockmore distribution */ |
---|
60 | #endif /* STANDALONE */ |
---|
61 | |
---|
62 | ModeSpecOpt worm_opts = |
---|
63 | {0, NULL, 0, NULL, NULL}; |
---|
64 | |
---|
65 | #define MINSIZE 1 |
---|
66 | |
---|
67 | #define SEGMENTS 36 |
---|
68 | #define MINWORMS 1 |
---|
69 | |
---|
70 | #define MAXZ 750 |
---|
71 | #define MINZ 100 |
---|
72 | #define SCREENZ 200 |
---|
73 | #define GETZDIFF(z) (MI_DELTA3D(mi)*20.0*(1.0-(SCREENZ)/((float)(z)+MINZ))) |
---|
74 | #define IRINT(x) ((int)(((x)>0.0)?(x)+0.5:(x)-0.5)) |
---|
75 | |
---|
76 | /* How many segments to draw per cycle when redrawing */ |
---|
77 | #define REDRAWSTEP 3 |
---|
78 | |
---|
79 | typedef struct { |
---|
80 | XPoint *circ; |
---|
81 | int *diffcirc; |
---|
82 | int dir, dir2; |
---|
83 | int tail; |
---|
84 | int x, y, z; |
---|
85 | int redrawing, redrawpos; |
---|
86 | } wormstuff; |
---|
87 | |
---|
88 | typedef struct { |
---|
89 | int xsize, ysize, zsize; |
---|
90 | int wormlength; |
---|
91 | int nc; |
---|
92 | int nw; |
---|
93 | int circsize; |
---|
94 | wormstuff *worm; |
---|
95 | XRectangle *rects; /* [NUMCOLORS * batchcount/NUMCOLORS+1] */ |
---|
96 | int maxsize; |
---|
97 | int *size; |
---|
98 | unsigned int chromo; |
---|
99 | } wormstruct; |
---|
100 | |
---|
101 | static float sintab[SEGMENTS]; |
---|
102 | static float costab[SEGMENTS]; |
---|
103 | static int init_table = 0; |
---|
104 | |
---|
105 | static wormstruct *worms = NULL; |
---|
106 | |
---|
107 | static void |
---|
108 | worm_doit(ModeInfo * mi, int which, unsigned long color) |
---|
109 | { |
---|
110 | Display *display = MI_DISPLAY(mi); |
---|
111 | Window window = MI_WINDOW(mi); |
---|
112 | GC gc = MI_GC(mi); |
---|
113 | wormstruct *wp = &worms[MI_SCREEN(mi)]; |
---|
114 | wormstuff *ws = &wp->worm[which]; |
---|
115 | int x, y, z; |
---|
116 | int diff; |
---|
117 | |
---|
118 | ws->tail++; |
---|
119 | if (ws->tail == wp->wormlength) |
---|
120 | ws->tail = 0; |
---|
121 | |
---|
122 | x = ws->circ[ws->tail].x; |
---|
123 | y = ws->circ[ws->tail].y; |
---|
124 | |
---|
125 | if (MI_WIN_IS_USE3D(mi)) { |
---|
126 | diff = ws->diffcirc[ws->tail]; |
---|
127 | if (MI_WIN_IS_INSTALL(mi)) { |
---|
128 | XSetForeground(display, gc, MI_NONE_COLOR(mi)); |
---|
129 | XFillRectangle(display, window, gc, x - diff, y, |
---|
130 | wp->circsize, wp->circsize); |
---|
131 | XFillRectangle(display, window, gc, x + diff, y, |
---|
132 | wp->circsize, wp->circsize); |
---|
133 | } else { |
---|
134 | XClearArea(display, window, x - diff, y, |
---|
135 | wp->circsize, wp->circsize, False); |
---|
136 | XClearArea(display, window, x + diff, y, |
---|
137 | wp->circsize, wp->circsize, False); |
---|
138 | } |
---|
139 | } else |
---|
140 | XClearArea(display, window, x, y, wp->circsize, wp->circsize, False); |
---|
141 | |
---|
142 | if (LRAND() & 1) |
---|
143 | ws->dir = (ws->dir + 1) % SEGMENTS; |
---|
144 | else |
---|
145 | ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS; |
---|
146 | |
---|
147 | x = (ws->x + IRINT((float) wp->circsize * costab[ws->dir]) + |
---|
148 | wp->xsize) % wp->xsize; |
---|
149 | y = (ws->y + IRINT((float) wp->circsize * sintab[ws->dir]) + |
---|
150 | wp->ysize) % wp->ysize; |
---|
151 | |
---|
152 | ws->circ[ws->tail].x = x; |
---|
153 | ws->circ[ws->tail].y = y; |
---|
154 | ws->x = x; |
---|
155 | ws->y = y; |
---|
156 | |
---|
157 | if (MI_WIN_IS_USE3D(mi)) { |
---|
158 | if (LRAND() & 1) |
---|
159 | ws->dir2 = (ws->dir2 + 1) % SEGMENTS; |
---|
160 | else |
---|
161 | ws->dir2 = (ws->dir2 + SEGMENTS - 1) % SEGMENTS; |
---|
162 | /* for the z-axis the wrap-around looks bad, so worms should just turn around. */ |
---|
163 | z = (int) (ws->z + wp->circsize * sintab[ws->dir2]); |
---|
164 | if (z < 0 || z >= wp->zsize) |
---|
165 | z = (int) (ws->z - wp->circsize * sintab[ws->dir2]); |
---|
166 | |
---|
167 | diff = (int) (GETZDIFF(z) + 0.5); /* ROUND */ |
---|
168 | ws->diffcirc[ws->tail] = diff; |
---|
169 | |
---|
170 | ws->z = z; |
---|
171 | |
---|
172 | /* right eye */ |
---|
173 | color = 0; |
---|
174 | wp->rects[color * wp->maxsize + wp->size[color]].x = x + diff; |
---|
175 | wp->rects[color * wp->maxsize + wp->size[color]].y = y; |
---|
176 | wp->size[color]++; |
---|
177 | |
---|
178 | /* left eye */ |
---|
179 | color = 1; |
---|
180 | wp->rects[color * wp->maxsize + wp->size[color]].x = x - diff; |
---|
181 | wp->rects[color * wp->maxsize + wp->size[color]].y = y; |
---|
182 | wp->size[color]++; |
---|
183 | |
---|
184 | #if 0 |
---|
185 | if (ws->redrawing) { /* Too hard for now */ |
---|
186 | int j; |
---|
187 | |
---|
188 | for (j = 0; j < REDRAWSTEP; j++) { |
---|
189 | int k = (ws->tail - ws->redrawpos + wp->wormlength) |
---|
190 | % wp->wormlength; |
---|
191 | |
---|
192 | color = 0; |
---|
193 | wp->rects[color * wp->maxsize + wp->size[color]].x = |
---|
194 | ws->circ[k].x + ws->diffcirc[k]; |
---|
195 | wp->rects[color * wp->maxsize + wp->size[color]].y = |
---|
196 | ws->circ[k].y; |
---|
197 | wp->size[color]++; |
---|
198 | |
---|
199 | color = 1; |
---|
200 | wp->rects[color * wp->maxsize + wp->size[color]].x = |
---|
201 | ws->circ[k].x - ws->diffcirc[k]; |
---|
202 | wp->rects[color * wp->maxsize + wp->size[color]].y = |
---|
203 | ws->circ[k].y; |
---|
204 | wp->size[color]++; |
---|
205 | |
---|
206 | if (++(ws->redrawpos) >= wp->wormlength) { |
---|
207 | ws->redrawing = 0; |
---|
208 | break; |
---|
209 | } |
---|
210 | } |
---|
211 | } |
---|
212 | #endif |
---|
213 | |
---|
214 | } else { |
---|
215 | |
---|
216 | wp->rects[color * wp->maxsize + wp->size[color]].x = x; |
---|
217 | wp->rects[color * wp->maxsize + wp->size[color]].y = y; |
---|
218 | wp->size[color]++; |
---|
219 | if (ws->redrawing) { |
---|
220 | int j; |
---|
221 | |
---|
222 | ws->redrawpos++; |
---|
223 | /* Compensates for the changed ws->tail |
---|
224 | since the last callback. */ |
---|
225 | |
---|
226 | for (j = 0; j < REDRAWSTEP; j++) { |
---|
227 | int k = (ws->tail - ws->redrawpos + wp->wormlength) |
---|
228 | % wp->wormlength; |
---|
229 | |
---|
230 | wp->rects[color * wp->maxsize + wp->size[color]].x = ws->circ[k].x; |
---|
231 | wp->rects[color * wp->maxsize + wp->size[color]].y = ws->circ[k].y; |
---|
232 | wp->size[color]++; |
---|
233 | |
---|
234 | if (++(ws->redrawpos) >= wp->wormlength) { |
---|
235 | ws->redrawing = 0; |
---|
236 | break; |
---|
237 | } |
---|
238 | } |
---|
239 | } |
---|
240 | } |
---|
241 | } |
---|
242 | |
---|
243 | static void |
---|
244 | free_worms(wormstruct * wp) |
---|
245 | { |
---|
246 | int wn; |
---|
247 | |
---|
248 | if (wp->worm) { |
---|
249 | for (wn = 0; wn < wp->nw; wn++) { |
---|
250 | if (wp->worm[wn].circ) |
---|
251 | (void) free((void *) wp->worm[wn].circ); |
---|
252 | if (wp->worm[wn].diffcirc) |
---|
253 | (void) free((void *) wp->worm[wn].diffcirc); |
---|
254 | } |
---|
255 | (void) free((void *) wp->worm); |
---|
256 | wp->worm = NULL; |
---|
257 | } |
---|
258 | if (wp->rects) { |
---|
259 | (void) free((void *) wp->rects); |
---|
260 | wp->rects = NULL; |
---|
261 | } |
---|
262 | if (wp->size) { |
---|
263 | (void) free((void *) wp->size); |
---|
264 | wp->size = NULL; |
---|
265 | } |
---|
266 | } |
---|
267 | |
---|
268 | void |
---|
269 | init_worm(ModeInfo * mi) |
---|
270 | { |
---|
271 | wormstruct *wp; |
---|
272 | int size = MI_SIZE(mi); |
---|
273 | int i, j; |
---|
274 | |
---|
275 | if (worms == NULL) { |
---|
276 | if ((worms = (wormstruct *) calloc(MI_NUM_SCREENS(mi), |
---|
277 | sizeof (wormstruct))) == NULL) |
---|
278 | return; |
---|
279 | } |
---|
280 | wp = &worms[MI_SCREEN(mi)]; |
---|
281 | if (MI_NPIXELS(mi) <= 2 || MI_WIN_IS_USE3D(mi)) |
---|
282 | wp->nc = 2; |
---|
283 | else |
---|
284 | wp->nc = MI_NPIXELS(mi); |
---|
285 | if (wp->nc > NUMCOLORS) |
---|
286 | wp->nc = NUMCOLORS; |
---|
287 | |
---|
288 | free_worms(wp); |
---|
289 | wp->nw = MI_BATCHCOUNT(mi); |
---|
290 | if (wp->nw < -MINWORMS) |
---|
291 | wp->nw = NRAND(-wp->nw - MINWORMS + 1) + MINWORMS; |
---|
292 | else if (wp->nw < MINWORMS) |
---|
293 | wp->nw = MINWORMS; |
---|
294 | if (!wp->worm) |
---|
295 | wp->worm = (wormstuff *) malloc(wp->nw * sizeof (wormstuff)); |
---|
296 | |
---|
297 | if (!wp->size) |
---|
298 | wp->size = (int *) malloc(NUMCOLORS * sizeof (int)); |
---|
299 | |
---|
300 | wp->maxsize = (REDRAWSTEP + 1) * wp->nw; /* / wp->nc + 1; */ |
---|
301 | if (!wp->rects) |
---|
302 | wp->rects = |
---|
303 | (XRectangle *) malloc(wp->maxsize * NUMCOLORS * sizeof (XRectangle)); |
---|
304 | |
---|
305 | |
---|
306 | if (!init_table) { |
---|
307 | init_table = 1; |
---|
308 | for (i = 0; i < SEGMENTS; i++) { |
---|
309 | sintab[i] = SINF(i * 2.0 * M_PI / SEGMENTS); |
---|
310 | costab[i] = COSF(i * 2.0 * M_PI / SEGMENTS); |
---|
311 | } |
---|
312 | } |
---|
313 | wp->xsize = MI_WIN_WIDTH(mi); |
---|
314 | wp->ysize = MI_WIN_HEIGHT(mi); |
---|
315 | wp->zsize = MAXZ - MINZ + 1; |
---|
316 | if (MI_NPIXELS(mi) > 2) |
---|
317 | wp->chromo = NRAND(MI_NPIXELS(mi)); |
---|
318 | |
---|
319 | if (size < -MINSIZE) |
---|
320 | wp->circsize = NRAND(-size - MINSIZE + 1) + MINSIZE; |
---|
321 | else if (size < MINSIZE) |
---|
322 | wp->circsize = MINSIZE; |
---|
323 | else |
---|
324 | wp->circsize = size; |
---|
325 | |
---|
326 | for (i = 0; i < wp->nc; i++) { |
---|
327 | for (j = 0; j < wp->maxsize; j++) { |
---|
328 | wp->rects[i * wp->maxsize + j].width = wp->circsize; |
---|
329 | wp->rects[i * wp->maxsize + j].height = wp->circsize; |
---|
330 | |
---|
331 | } |
---|
332 | } |
---|
333 | (void) memset((char *) wp->size, 0, wp->nc * sizeof (int)); |
---|
334 | |
---|
335 | wp->wormlength = (int) sqrt(wp->xsize + wp->ysize) * |
---|
336 | MI_CYCLES(mi) / 8; /* Fudge this to something reasonable */ |
---|
337 | for (i = 0; i < wp->nw; i++) { |
---|
338 | wp->worm[i].circ = (XPoint *) malloc(wp->wormlength * sizeof (XPoint)); |
---|
339 | wp->worm[i].diffcirc = (int *) malloc(wp->wormlength * sizeof (int)); |
---|
340 | |
---|
341 | for (j = 0; j < wp->wormlength; j++) { |
---|
342 | wp->worm[i].circ[j].x = wp->xsize / 2; |
---|
343 | wp->worm[i].circ[j].y = wp->ysize / 2; |
---|
344 | if (MI_WIN_IS_USE3D(mi)) |
---|
345 | wp->worm[i].diffcirc[j] = 0; |
---|
346 | } |
---|
347 | wp->worm[i].dir = NRAND(SEGMENTS); |
---|
348 | wp->worm[i].dir2 = NRAND(SEGMENTS); |
---|
349 | wp->worm[i].tail = 0; |
---|
350 | wp->worm[i].x = wp->xsize / 2; |
---|
351 | wp->worm[i].y = wp->ysize / 2; |
---|
352 | wp->worm[i].z = SCREENZ - MINZ; |
---|
353 | wp->worm[i].redrawing = 0; |
---|
354 | } |
---|
355 | |
---|
356 | if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) { |
---|
357 | XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi)); |
---|
358 | XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), |
---|
359 | 0, 0, wp->xsize, wp->ysize); |
---|
360 | } else |
---|
361 | XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); |
---|
362 | } |
---|
363 | |
---|
364 | void |
---|
365 | draw_worm(ModeInfo * mi) |
---|
366 | { |
---|
367 | Display *display = MI_DISPLAY(mi); |
---|
368 | Window window = MI_WINDOW(mi); |
---|
369 | GC gc = MI_GC(mi); |
---|
370 | wormstruct *wp = &worms[MI_SCREEN(mi)]; |
---|
371 | unsigned long wcolor; |
---|
372 | int i; |
---|
373 | |
---|
374 | (void) memset((char *) wp->size, 0, wp->nc * sizeof (int)); |
---|
375 | |
---|
376 | for (i = 0; i < wp->nw; i++) { |
---|
377 | if (MI_NPIXELS(mi) > 2) { |
---|
378 | wcolor = (i + wp->chromo) % wp->nc; |
---|
379 | |
---|
380 | worm_doit(mi, i, wcolor); |
---|
381 | } else |
---|
382 | worm_doit(mi, i, (unsigned long) 0); |
---|
383 | } |
---|
384 | |
---|
385 | if (MI_WIN_IS_USE3D(mi)) { |
---|
386 | if (MI_WIN_IS_INSTALL(mi)) |
---|
387 | XSetFunction(display, gc, GXor); |
---|
388 | XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); |
---|
389 | XFillRectangles(display, window, gc, &(wp->rects[0]), wp->size[0]); |
---|
390 | |
---|
391 | XSetForeground(display, gc, MI_LEFT_COLOR(mi)); |
---|
392 | XFillRectangles(display, window, gc, &(wp->rects[wp->maxsize]), wp->size[1]); |
---|
393 | if (MI_WIN_IS_INSTALL(mi)) |
---|
394 | XSetFunction(display, gc, GXcopy); |
---|
395 | } else if (MI_NPIXELS(mi) > 2) { |
---|
396 | for (i = 0; i < wp->nc; i++) { |
---|
397 | XSetForeground(display, gc, MI_PIXEL(mi, i)); |
---|
398 | XFillRectangles(display, window, gc, &(wp->rects[i * wp->maxsize]), wp->size[i]); |
---|
399 | } |
---|
400 | } else { |
---|
401 | XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi)); |
---|
402 | XFillRectangles(display, window, gc, |
---|
403 | &(wp->rects[0]), wp->size[0]); |
---|
404 | } |
---|
405 | |
---|
406 | if (++wp->chromo == (unsigned long) wp->nc) |
---|
407 | wp->chromo = 0; |
---|
408 | } |
---|
409 | |
---|
410 | void |
---|
411 | release_worm(ModeInfo * mi) |
---|
412 | { |
---|
413 | if (worms != NULL) { |
---|
414 | int screen; |
---|
415 | |
---|
416 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) |
---|
417 | free_worms(&worms[screen]); |
---|
418 | (void) free((void *) worms); |
---|
419 | worms = NULL; |
---|
420 | } |
---|
421 | } |
---|
422 | |
---|
423 | void |
---|
424 | refresh_worm(ModeInfo * mi) |
---|
425 | { |
---|
426 | if (MI_WIN_IS_USE3D(mi)) |
---|
427 | /* The 3D code does drawing&clearing by XORing. We do not |
---|
428 | want to go to too much trouble here to make it redraw |
---|
429 | correctly. */ |
---|
430 | XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); |
---|
431 | else if (worms != NULL) { |
---|
432 | wormstruct *wp = &worms[MI_SCREEN(mi)]; |
---|
433 | int i; |
---|
434 | |
---|
435 | for (i = 0; i < wp->nw; i++) { |
---|
436 | wp->worm[i].redrawing = 1; |
---|
437 | wp->worm[i].redrawpos = 0; |
---|
438 | } |
---|
439 | } |
---|
440 | } |
---|