source: trunk/third/xscreensaver/hacks/worm.c @ 20148

Revision 20148, 11.5 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1
2/* -*- Mode: C; tab-width: 4 -*- */
3/* worm --- draw wiggly worms */
4
5#if 0
6static 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
62ModeSpecOpt 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
79typedef 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
88typedef 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
101static float sintab[SEGMENTS];
102static float costab[SEGMENTS];
103static int  init_table = 0;
104
105static wormstruct *worms = NULL;
106
107static void
108worm_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
243static void
244free_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
268void
269init_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
364void
365draw_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
410void
411release_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
423void
424refresh_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}
Note: See TracBrowser for help on using the repository browser.