http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / lissie.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* lissie --- the Lissajous worm */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)lissie.c      5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10  * lissie.c - The Lissajous worm for xlock, the X Window System
11  *               lockscreen.
12  *
13  * Copyright (c) 1996 by Alexander Jolk <ub9x@rz.uni-karlsruhe.de>
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation.
20  *
21  * This file is provided AS IS with no warranties of any kind.  The author
22  * shall have no liability with respect to the infringement of copyrights,
23  * trade secrets or any patents by this file or any part thereof.  In no
24  * event will the author be liable for any lost revenue or profits or
25  * other special, indirect and consequential damages.
26  *
27  * Revision History:
28  * 01-Nov-2000: Allocation checks
29  * 10-May-1997: Compatible with xscreensaver
30  * 18-Aug-1996: added refresh-hook.
31  * 01-May-1996: written.
32  */
33
34 #ifdef STANDALONE
35 #define MODE_lissie
36 #define PROGCLASS "Lissie"
37 #define HACK_INIT init_lissie
38 #define HACK_DRAW draw_lissie
39 #define lissie_opts xlockmore_opts
40 #define DEFAULTS "*delay: 10000 \n" \
41  "*count: 1 \n" \
42  "*cycles: 20000 \n" \
43  "*size: -200 \n" \
44  "*ncolors: 200 \n"
45 #define SMOOTH_COLORS
46 #include "xlockmore.h"          /* in xscreensaver distribution */
47 #else /* STANDALONE */
48 #include "xlock.h"              /* in xlockmore distribution */
49 #endif /* STANDALONE */
50
51 #ifdef MODE_lissie
52
53 ModeSpecOpt lissie_opts =
54 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
55
56 #ifdef USE_MODULES
57 ModStruct   lissie_description =
58 {"lissie", "init_lissie", "draw_lissie", "release_lissie",
59  "refresh_lissie", "init_lissie", (char *) NULL, &lissie_opts,
60  10000, 1, 2000, -200, 64, 0.6, "",
61  "Shows lissajous worms", 0, NULL};
62
63 #endif
64
65 #define MINSIZE 1
66
67 #define Lissie(n)\
68         if (lissie->loc[(n)].x > 0 && lissie->loc[(n)].y > 0 &&\
69                 lissie->loc[(n)].x <= lp->width && lissie->loc[(n)].y <= lp->height) {\
70                 if (lissie->ri < 2)\
71                         XDrawPoint(display, MI_WINDOW(mi),\
72                                 gc, lissie->loc[(n)].x, lissie->loc[(n)].y);\
73                 else\
74                         XDrawArc(display, MI_WINDOW(mi), gc,\
75                                 lissie->loc[(n)].x - lissie->ri / 2,\
76                                 lissie->loc[(n)].y - lissie->ri / 2,\
77                                 lissie->ri, lissie->ri, 0, 23040);\
78         }
79
80 #define FLOATRAND(min,max)      ((min)+(LRAND()/MAXRAND)*((max)-(min)))
81 #define INTRAND(min,max)     ((min)+NRAND((max)-(min)+1))
82
83 #define MINDT  0.01
84 #define MAXDT  0.15
85
86 #define MAXLISSIELEN  100
87 #define MINLISSIELEN  10
88 #define MINLISSIES 1
89
90 /* How many segments to draw per cycle when redrawing */
91 #define REDRAWSTEP 3
92
93 typedef struct {
94         double      tx, ty, dtx, dty;
95         int         xi, yi, ri, rx, ry, len, pos;
96         int         redrawing, redrawpos;
97         XPoint      loc[MAXLISSIELEN];
98         unsigned long color;
99 } lissiestruct;
100
101 typedef struct {
102         Bool        painted;
103         int         width, height;
104         int         nlissies;
105         lissiestruct *lissie;
106         int         loopcount;
107 } lissstruct;
108
109 static lissstruct *lisses = (lissstruct *) NULL;
110
111
112 static void
113 drawlissie(ModeInfo * mi, lissiestruct * lissie)
114 {
115         Display    *display = MI_DISPLAY(mi);
116         GC          gc = MI_GC(mi);
117         lissstruct *lp = &lisses[MI_SCREEN(mi)];
118         int         p = (++lissie->pos) % MAXLISSIELEN;
119         int         oldp = (lissie->pos - lissie->len + MAXLISSIELEN) % MAXLISSIELEN;
120
121         /* Let time go by ... */
122         lissie->tx += lissie->dtx;
123         lissie->ty += lissie->dty;
124         if (lissie->tx > 2 * M_PI)
125                 lissie->tx -= 2 * M_PI;
126         if (lissie->ty > 2 * M_PI)
127                 lissie->ty -= 2 * M_PI;
128
129         /* vary both (x/y) speeds by max. 1% */
130         lissie->dtx *= FLOATRAND(0.99, 1.01);
131         lissie->dty *= FLOATRAND(0.99, 1.01);
132         if (lissie->dtx < MINDT)
133                 lissie->dtx = MINDT;
134         else if (lissie->dtx > MAXDT)
135                 lissie->dtx = MAXDT;
136         if (lissie->dty < MINDT)
137                 lissie->dty = MINDT;
138         else if (lissie->dty > MAXDT)
139                 lissie->dty = MAXDT;
140
141         lissie->loc[p].x = lissie->xi + (int) (sin(lissie->tx) * lissie->rx);
142         lissie->loc[p].y = lissie->yi + (int) (sin(lissie->ty) * lissie->ry);
143
144         /* Mask */
145         XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
146         Lissie(oldp);
147
148         /* Redraw */
149         if (MI_NPIXELS(mi) > 2) {
150                 XSetForeground(display, gc, MI_PIXEL(mi, lissie->color));
151                 if (++lissie->color >= (unsigned) MI_NPIXELS(mi))
152                         lissie->color = 0;
153         } else
154                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
155         Lissie(p);
156         if (lissie->redrawing) {
157                 int         i;
158
159                 lissie->redrawpos++;
160                 /* This compensates for the changed p
161                    since the last callback. */
162
163                 for (i = 0; i < REDRAWSTEP; i++) {
164                         Lissie((p - lissie->redrawpos + MAXLISSIELEN) % MAXLISSIELEN);
165                         if (++(lissie->redrawpos) >= lissie->len) {
166                                 lissie->redrawing = 0;
167                                 break;
168                         }
169                 }
170         }
171 }
172
173 static void
174 initlissie(ModeInfo * mi, lissiestruct * lissie)
175 {
176         lissstruct *lp = &lisses[MI_SCREEN(mi)];
177         int         size = MI_SIZE(mi);
178         int         i;
179
180         if (MI_NPIXELS(mi) > 2)
181                 lissie->color = NRAND(MI_NPIXELS(mi));
182         else
183                 lissie->color = MI_WHITE_PIXEL(mi);
184         /* Initialize parameters */
185         if (size < -MINSIZE)
186                 lissie->ri = NRAND(MIN(-size, MAX(MINSIZE,
187                    MIN(lp->width, lp->height) / 4)) - MINSIZE + 1) + MINSIZE;
188         else if (size < MINSIZE) {
189                 if (!size)
190                         lissie->ri = MAX(MINSIZE, MIN(lp->width, lp->height) / 4);
191                 else
192                         lissie->ri = MINSIZE;
193         } else
194                 lissie->ri = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / 4));
195         lissie->xi = INTRAND(lp->width / 4 + lissie->ri,
196                              lp->width * 3 / 4 - lissie->ri);
197         lissie->yi = INTRAND(lp->height / 4 + lissie->ri,
198                              lp->height * 3 / 4 - lissie->ri);
199         lissie->rx = INTRAND(lp->width / 4,
200                    MIN(lp->width - lissie->xi, lissie->xi)) - 2 * lissie->ri;
201         lissie->ry = INTRAND(lp->height / 4,
202                   MIN(lp->height - lissie->yi, lissie->yi)) - 2 * lissie->ri;
203         lissie->len = INTRAND(MINLISSIELEN, MAXLISSIELEN - 1);
204         lissie->pos = 0;
205
206         lissie->redrawing = 0;
207
208         lissie->tx = FLOATRAND(0, 2 * M_PI);
209         lissie->ty = FLOATRAND(0, 2 * M_PI);
210         lissie->dtx = FLOATRAND(MINDT, MAXDT);
211         lissie->dty = FLOATRAND(MINDT, MAXDT);
212
213         for (i = 0; i < MAXLISSIELEN; i++)
214                 lissie->loc[i].x = lissie->loc[i].y = 0;
215         /* Draw lissie */
216         drawlissie(mi, lissie);
217 }
218
219 void
220 init_lissie(ModeInfo * mi)
221 {
222         lissstruct *lp;
223         unsigned char ball;
224
225         if (lisses == NULL) {
226                 if ((lisses = (lissstruct *) calloc(MI_NUM_SCREENS(mi),
227                                                sizeof (lissstruct))) == NULL)
228                         return;
229         }
230         lp = &lisses[MI_SCREEN(mi)];
231
232         lp->width = MI_WIDTH(mi);
233         lp->height = MI_HEIGHT(mi);
234
235         lp->nlissies = MI_COUNT(mi);
236         if (lp->nlissies < -MINLISSIES) {
237                 if (lp->lissie) {
238                         (void) free((void *) lp->lissie);
239                         lp->lissie = (lissiestruct *) NULL;
240                 }
241                 lp->nlissies = NRAND(-lp->nlissies - MINLISSIES + 1) + MINLISSIES;
242         } else if (lp->nlissies < MINLISSIES)
243                 lp->nlissies = MINLISSIES;
244
245         lp->loopcount = 0;
246
247         if (lp->lissie == NULL)
248                 if ((lp->lissie = (lissiestruct *) calloc(lp->nlissies,
249                                 sizeof (lissiestruct))) == NULL)
250                         return;
251
252         MI_CLEARWINDOW(mi);
253         lp->painted = False;
254
255         for (ball = 0; ball < (unsigned char) lp->nlissies; ball++)
256                 initlissie(mi, &lp->lissie[ball]);
257
258 }
259
260 void
261 draw_lissie(ModeInfo * mi)
262 {
263         register unsigned char ball;
264         lissstruct *lp;
265
266         if (lisses == NULL)
267                 return;
268         lp = &lisses[MI_SCREEN(mi)];
269         if (lp->lissie == NULL)
270                 return;
271
272         MI_IS_DRAWN(mi) = True;
273
274         if (++lp->loopcount > MI_CYCLES(mi)) {
275                 init_lissie(mi);
276         } else {
277                 lp->painted = True;
278                 for (ball = 0; ball < (unsigned char) lp->nlissies; ball++)
279                         drawlissie(mi, &lp->lissie[ball]);
280         }
281 }
282
283 void
284 release_lissie(ModeInfo * mi)
285 {
286         if (lisses != NULL) {
287                 int         screen;
288
289                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
290                         lissstruct *lp = &lisses[screen];
291
292                         if (lp->lissie != NULL) {
293                                 (void) free((void *) lp->lissie);
294                                 /* lp->lissie = NULL; */
295                         }
296                 }
297                 (void) free((void *) lisses);
298                 lisses = (lissstruct *) NULL;
299         }
300 }
301
302 void
303 refresh_lissie(ModeInfo * mi)
304 {
305         int         i;
306         lissstruct *lp;
307
308         if (lisses == NULL)
309                 return;
310         lp = &lisses[MI_SCREEN(mi)];
311         if (lp->lissie == NULL)
312                 return;
313
314         if (lp->painted) {
315                 MI_CLEARWINDOW(mi);
316                 for (i = 0; i < lp->nlissies; i++) {
317                         lp->lissie[i].redrawing = 1;
318                         lp->lissie[i].redrawpos = 0;
319                 }
320         }
321 }
322
323 #endif /* MODE_lissie */