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