2 /* -*- Mode: C; tab-width: 4 -*- */
3 /* worm --- draw wiggly worms */
5 #if !defined( lint ) && !defined( SABER )
6 static const char sccsid[] = "@(#)worm.c 4.04 97/07/28 xlockmore";
11 * Copyright (c) 1991 by Patrick J. Naughton.
13 * Permission to use, copy, modify, and distribute this software and its
14 * documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appear in all copies and that
16 * both that copyright notice and this permission notice appear in
17 * supporting documentation.
19 * This file is provided AS IS with no warranties of any kind. The author
20 * shall have no liability with respect to the infringement of copyrights,
21 * trade secrets or any patents by this file or any part thereof. In no
22 * event will the author be liable for any lost revenue or profits or
23 * other special, indirect and consequential damages.
26 * 10-May-97: Compatible with xscreensaver
27 * 03-Sep-96: fixed bug in allocation of space for worms, added 3d support
28 * Henrik Theiling <theiling@coli.uni-sb.de>
29 * 27-Sep-95: put back malloc
30 * 23-Sep-93: got rid of "rint". (David Bagley)
31 * 27-Sep-91: got rid of all malloc calls since there were no calls to free().
32 * 25-Sep-91: Integrated into X11R5 contrib xlock.
34 * Adapted from a concept in the Dec 87 issue of Scientific American p. 142.
36 * SunView version: Brad Taylor <brad@sun.com>
37 * X11 version: Dave Lemke <lemke@ncd.com>
38 * xlock version: Boris Putanec <bp@cs.brown.edu>
42 # define PROGCLASS "Worm"
43 # define HACK_INIT init_worm
44 # define HACK_DRAW draw_worm
45 # define worm_opts xlockmore_opts
46 # define DEFAULTS "*delay: 17000 \n" \
55 "*both3d: magenta \n" \
57 # define SMOOTH_COLORS
58 # include "xlockmore.h" /* in xscreensaver distribution */
59 #else /* STANDALONE */
60 # include "xlock.h" /* in xlockmore distribution */
61 #endif /* STANDALONE */
63 ModeSpecOpt worm_opts =
64 {0, NULL, 0, NULL, NULL};
74 #define GETZDIFF(z) (MI_DELTA3D(mi)*20.0*(1.0-(SCREENZ)/((float)(z)+MINZ)))
75 #define IRINT(x) ((int)(((x)>0.0)?(x)+0.5:(x)-0.5))
77 /* How many segments to draw per cycle when redrawing */
86 int redrawing, redrawpos;
90 int xsize, ysize, zsize;
96 XRectangle *rects; /* [NUMCOLORS * batchcount/NUMCOLORS+1] */
102 static float sintab[SEGMENTS];
103 static float costab[SEGMENTS];
104 static int init_table = 0;
106 static wormstruct *worms = NULL;
109 worm_doit(ModeInfo * mi, int which, unsigned long color)
111 Display *display = MI_DISPLAY(mi);
112 Window window = MI_WINDOW(mi);
114 wormstruct *wp = &worms[MI_SCREEN(mi)];
115 wormstuff *ws = &wp->worm[which];
120 if (ws->tail == wp->wormlength)
123 x = ws->circ[ws->tail].x;
124 y = ws->circ[ws->tail].y;
126 if (MI_WIN_IS_USE3D(mi)) {
127 diff = ws->diffcirc[ws->tail];
128 if (MI_WIN_IS_INSTALL(mi)) {
129 XSetForeground(display, gc, MI_NONE_COLOR(mi));
130 XFillRectangle(display, window, gc, x - diff, y,
131 wp->circsize, wp->circsize);
132 XFillRectangle(display, window, gc, x + diff, y,
133 wp->circsize, wp->circsize);
135 XClearArea(display, window, x - diff, y,
136 wp->circsize, wp->circsize, False);
137 XClearArea(display, window, x + diff, y,
138 wp->circsize, wp->circsize, False);
141 XClearArea(display, window, x, y, wp->circsize, wp->circsize, False);
144 ws->dir = (ws->dir + 1) % SEGMENTS;
146 ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS;
148 x = (ws->x + IRINT((float) wp->circsize * costab[ws->dir]) +
149 wp->xsize) % wp->xsize;
150 y = (ws->y + IRINT((float) wp->circsize * sintab[ws->dir]) +
151 wp->ysize) % wp->ysize;
153 ws->circ[ws->tail].x = x;
154 ws->circ[ws->tail].y = y;
158 if (MI_WIN_IS_USE3D(mi)) {
160 ws->dir2 = (ws->dir2 + 1) % SEGMENTS;
162 ws->dir2 = (ws->dir2 + SEGMENTS - 1) % SEGMENTS;
163 /* for the z-axis the wrap-around looks bad, so worms should just turn around. */
164 z = (int) (ws->z + wp->circsize * sintab[ws->dir2]);
165 if (z < 0 || z >= wp->zsize)
166 z = (int) (ws->z - wp->circsize * sintab[ws->dir2]);
168 diff = (int) (GETZDIFF(z) + 0.5); /* ROUND */
169 ws->diffcirc[ws->tail] = diff;
175 wp->rects[color * wp->maxsize + wp->size[color]].x = x + diff;
176 wp->rects[color * wp->maxsize + wp->size[color]].y = y;
181 wp->rects[color * wp->maxsize + wp->size[color]].x = x - diff;
182 wp->rects[color * wp->maxsize + wp->size[color]].y = y;
186 if (ws->redrawing) { /* Too hard for now */
189 for (j = 0; j < REDRAWSTEP; j++) {
190 int k = (ws->tail - ws->redrawpos + wp->wormlength)
194 wp->rects[color * wp->maxsize + wp->size[color]].x =
195 ws->circ[k].x + ws->diffcirc[k];
196 wp->rects[color * wp->maxsize + wp->size[color]].y =
201 wp->rects[color * wp->maxsize + wp->size[color]].x =
202 ws->circ[k].x - ws->diffcirc[k];
203 wp->rects[color * wp->maxsize + wp->size[color]].y =
207 if (++(ws->redrawpos) >= wp->wormlength) {
217 wp->rects[color * wp->maxsize + wp->size[color]].x = x;
218 wp->rects[color * wp->maxsize + wp->size[color]].y = y;
224 /* Compensates for the changed ws->tail
225 since the last callback. */
227 for (j = 0; j < REDRAWSTEP; j++) {
228 int k = (ws->tail - ws->redrawpos + wp->wormlength)
231 wp->rects[color * wp->maxsize + wp->size[color]].x = ws->circ[k].x;
232 wp->rects[color * wp->maxsize + wp->size[color]].y = ws->circ[k].y;
235 if (++(ws->redrawpos) >= wp->wormlength) {
245 free_worms(wormstruct * wp)
250 for (wn = 0; wn < wp->nw; wn++) {
251 if (wp->worm[wn].circ)
252 (void) free((void *) wp->worm[wn].circ);
253 if (wp->worm[wn].diffcirc)
254 (void) free((void *) wp->worm[wn].diffcirc);
256 (void) free((void *) wp->worm);
260 (void) free((void *) wp->rects);
264 (void) free((void *) wp->size);
270 init_worm(ModeInfo * mi)
273 int size = MI_SIZE(mi);
277 if ((worms = (wormstruct *) calloc(MI_NUM_SCREENS(mi),
278 sizeof (wormstruct))) == NULL)
281 wp = &worms[MI_SCREEN(mi)];
282 if (MI_NPIXELS(mi) <= 2 || MI_WIN_IS_USE3D(mi))
285 wp->nc = MI_NPIXELS(mi);
286 if (wp->nc > NUMCOLORS)
290 wp->nw = MI_BATCHCOUNT(mi);
291 if (wp->nw < -MINWORMS)
292 wp->nw = NRAND(-wp->nw - MINWORMS + 1) + MINWORMS;
293 else if (wp->nw < MINWORMS)
296 wp->worm = (wormstuff *) malloc(wp->nw * sizeof (wormstuff));
299 wp->size = (int *) malloc(NUMCOLORS * sizeof (int));
301 wp->maxsize = (REDRAWSTEP + 1) * wp->nw; /* / wp->nc + 1; */
304 (XRectangle *) malloc(wp->maxsize * NUMCOLORS * sizeof (XRectangle));
309 for (i = 0; i < SEGMENTS; i++) {
310 sintab[i] = SINF(i * 2.0 * M_PI / SEGMENTS);
311 costab[i] = COSF(i * 2.0 * M_PI / SEGMENTS);
314 wp->xsize = MI_WIN_WIDTH(mi);
315 wp->ysize = MI_WIN_HEIGHT(mi);
316 wp->zsize = MAXZ - MINZ + 1;
317 if (MI_NPIXELS(mi) > 2)
318 wp->chromo = NRAND(MI_NPIXELS(mi));
321 wp->circsize = NRAND(-size - MINSIZE + 1) + MINSIZE;
322 else if (size < MINSIZE)
323 wp->circsize = MINSIZE;
327 for (i = 0; i < wp->nc; i++) {
328 for (j = 0; j < wp->maxsize; j++) {
329 wp->rects[i * wp->maxsize + j].width = wp->circsize;
330 wp->rects[i * wp->maxsize + j].height = wp->circsize;
334 (void) memset((char *) wp->size, 0, wp->nc * sizeof (int));
336 wp->wormlength = (int) sqrt(wp->xsize + wp->ysize) *
337 MI_CYCLES(mi) / 8; /* Fudge this to something reasonable */
338 for (i = 0; i < wp->nw; i++) {
339 wp->worm[i].circ = (XPoint *) malloc(wp->wormlength * sizeof (XPoint));
340 wp->worm[i].diffcirc = (int *) malloc(wp->wormlength * sizeof (int));
342 for (j = 0; j < wp->wormlength; j++) {
343 wp->worm[i].circ[j].x = wp->xsize / 2;
344 wp->worm[i].circ[j].y = wp->ysize / 2;
345 if (MI_WIN_IS_USE3D(mi))
346 wp->worm[i].diffcirc[j] = 0;
348 wp->worm[i].dir = NRAND(SEGMENTS);
349 wp->worm[i].dir2 = NRAND(SEGMENTS);
350 wp->worm[i].tail = 0;
351 wp->worm[i].x = wp->xsize / 2;
352 wp->worm[i].y = wp->ysize / 2;
353 wp->worm[i].z = SCREENZ - MINZ;
354 wp->worm[i].redrawing = 0;
357 if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) {
358 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi));
359 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
360 0, 0, wp->xsize, wp->ysize);
362 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
366 draw_worm(ModeInfo * mi)
368 Display *display = MI_DISPLAY(mi);
369 Window window = MI_WINDOW(mi);
371 wormstruct *wp = &worms[MI_SCREEN(mi)];
372 unsigned long wcolor;
375 (void) memset((char *) wp->size, 0, wp->nc * sizeof (int));
377 for (i = 0; i < wp->nw; i++) {
378 if (MI_NPIXELS(mi) > 2) {
379 wcolor = (i + wp->chromo) % wp->nc;
381 worm_doit(mi, i, wcolor);
383 worm_doit(mi, i, (unsigned long) 0);
386 if (MI_WIN_IS_USE3D(mi)) {
387 if (MI_WIN_IS_INSTALL(mi))
388 XSetFunction(display, gc, GXor);
389 XSetForeground(display, gc, MI_RIGHT_COLOR(mi));
390 XFillRectangles(display, window, gc, &(wp->rects[0]), wp->size[0]);
392 XSetForeground(display, gc, MI_LEFT_COLOR(mi));
393 XFillRectangles(display, window, gc, &(wp->rects[wp->maxsize]), wp->size[1]);
394 if (MI_WIN_IS_INSTALL(mi))
395 XSetFunction(display, gc, GXcopy);
396 } else if (MI_NPIXELS(mi) > 2) {
397 for (i = 0; i < wp->nc; i++) {
398 XSetForeground(display, gc, MI_PIXEL(mi, i));
399 XFillRectangles(display, window, gc, &(wp->rects[i * wp->maxsize]), wp->size[i]);
402 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
403 XFillRectangles(display, window, gc,
404 &(wp->rects[0]), wp->size[0]);
407 if (++wp->chromo == (unsigned long) wp->nc)
412 release_worm(ModeInfo * mi)
417 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
418 free_worms(&worms[screen]);
419 (void) free((void *) worms);
425 refresh_worm(ModeInfo * mi)
427 if (MI_WIN_IS_USE3D(mi))
428 /* The 3D code does drawing&clearing by XORing. We do not
429 want to go to too much trouble here to make it redraw
431 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
432 else if (worms != NULL) {
433 wormstruct *wp = &worms[MI_SCREEN(mi)];
436 for (i = 0; i < wp->nw; i++) {
437 wp->worm[i].redrawing = 1;
438 wp->worm[i].redrawpos = 0;