began for maemo
[xscreensaver] / xscreensaver / hacks / laser.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* laser --- spinning lasers */
3
4 #if 0
5 static const char sccsid[] = "@(#)laser.c       5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9  * Copyright (c) 1995 Pascal Pensa <pensa@aurora.unice.fr>
10  *
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * Revision History:
24  * 01-Nov-2000: Allocation checks
25  * 10-May-1997: Compatible with xscreensaver
26  * 1995: Written.
27  */
28
29 #ifdef STANDALONE
30 # define MODE_laser
31 # define DEFAULTS       "*delay: 40000 \n" \
32                                         "*count: 10 \n" \
33                                         "*cycles: 200 \n" \
34                                         "*ncolors: 64 \n"
35 # define BRIGHT_COLORS
36 # define reshape_laser 0
37 # define laser_handle_event 0
38 # include "xlockmore.h"         /* in xscreensaver distribution */
39 #else /* STANDALONE */
40 # include "xlock.h"             /* in xlockmore distribution */
41 #endif /* STANDALONE */
42
43 #ifdef MODE_laser
44
45 ENTRYPOINT ModeSpecOpt laser_opts =
46 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
47
48 #ifdef USE_MODULES
49 ModStruct   laser_description =
50 {"laser", "init_laser", "draw_laser", "release_laser",
51  "refresh_laser", "init_laser", (char *) NULL, &laser_opts,
52  20000, -10, 200, 1, 64, 1.0, "",
53  "Shows spinning lasers", 0, NULL};
54
55 #endif
56
57 #define MINREDRAW 3             /* Number of redrawn on each frame */
58 #define MAXREDRAW 8
59
60 #define MINLASER  1             /* Laser number */
61
62 #define MINWIDTH  2             /* Laser ray width range */
63 #define MAXWIDTH 40
64
65 #define MINSPEED  2             /* Speed range */
66 #define MAXSPEED 17
67
68 #define MINDIST  10             /* Minimal distance from edges */
69
70 #define COLORSTEP 2             /* Laser color step */
71
72 #define RANGE_RAND(min,max) (int) ((min) + LRAND() % ((max) - (min)))
73
74 typedef enum {
75         TOP, RIGHT, BOTTOM, LEFT
76 } border;
77
78 typedef struct {
79         int         bx;         /* border x */
80         int         by;         /* border y */
81         border      bn;         /* active border */
82         int         dir;        /* direction */
83         int         speed;      /* laser velocity from MINSPEED to MAXSPEED */
84         int         sx[MAXWIDTH];       /* x stack */
85         int         sy[MAXWIDTH];       /* x stack */
86         XGCValues   gcv;        /* for color */
87 } laserstruct;
88
89 typedef struct {
90         int         width;
91         int         height;
92         int         cx;         /* center x */
93         int         cy;         /* center y */
94         int         lw;         /* laser width */
95         int         ln;         /* laser number */
96         int         lr;         /* laser redraw */
97         int         sw;         /* stack width */
98         int         so;         /* stack offset */
99         int         time;       /* up time */
100         GC          stippledGC;
101         XGCValues   gcv_black;  /* for black color */
102         laserstruct *laser;
103 } lasersstruct;
104
105 static lasersstruct *lasers = (lasersstruct *) NULL;
106
107 static void
108 free_laser(Display *display, lasersstruct *lp)
109 {
110         if (lp->laser != NULL) {
111                 (void) free((void *) lp->laser);
112                 lp->laser = (laserstruct *) NULL;
113         }
114         if (lp->stippledGC != None) {
115                 XFreeGC(display, lp->stippledGC);
116                 lp->stippledGC = None;
117         }
118 }
119
120 ENTRYPOINT void
121 init_laser(ModeInfo * mi)
122 {
123         Display *display = MI_DISPLAY(mi);
124         int         i, c = 0;
125         lasersstruct *lp;
126
127         if (lasers == NULL) {
128                 if ((lasers = (lasersstruct *) calloc(MI_NUM_SCREENS(mi),
129                                              sizeof (lasersstruct))) == NULL)
130                         return;
131         }
132         lp = &lasers[MI_SCREEN(mi)];
133
134         lp->width = MI_WIDTH(mi);
135         lp->height = MI_HEIGHT(mi);
136         lp->time = 0;
137
138         lp->ln = MI_COUNT(mi);
139         if (lp->ln < -MINLASER) {
140                 /* if lp->ln is random ... the size can change */
141                 if (lp->laser != NULL) {
142                         (void) free((void *) lp->laser);
143                         lp->laser = (laserstruct *) NULL;
144                 }
145                 lp->ln = NRAND(-lp->ln - MINLASER + 1) + MINLASER;
146         } else if (lp->ln < MINLASER)
147                 lp->ln = MINLASER;
148
149         if (lp->laser == NULL) {
150                 if ((lp->laser = (laserstruct *) malloc(lp->ln *
151                                 sizeof (laserstruct))) == NULL) {
152                         free_laser(display, lp);
153                         return;
154                 }
155         }
156         if (lp->stippledGC == None) {
157                 XGCValues   gcv;
158
159                 gcv.foreground = MI_WHITE_PIXEL(mi);
160                 gcv.background = MI_BLACK_PIXEL(mi);
161                 lp->gcv_black.foreground = MI_BLACK_PIXEL(mi);
162                 if ((lp->stippledGC = XCreateGC(display, MI_WINDOW(mi),
163                                 GCForeground | GCBackground, &gcv)) == None) {
164                         free_laser(display, lp);
165                         return;
166                 }
167 # ifdef HAVE_COCOA
168     jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), lp->stippledGC, False);
169 # endif
170         }
171         MI_CLEARWINDOW(mi);
172
173         if (MINDIST < lp->width - MINDIST)
174                 lp->cx = RANGE_RAND(MINDIST, lp->width - MINDIST);
175         else
176                 lp->cx = RANGE_RAND(0, lp->width);
177         if (MINDIST < lp->height - MINDIST)
178                 lp->cy = RANGE_RAND(MINDIST, lp->height - MINDIST);
179         else
180                 lp->cy = RANGE_RAND(0, lp->height);
181         lp->lw = RANGE_RAND(MINWIDTH, MAXWIDTH);
182         lp->lr = RANGE_RAND(MINREDRAW, MAXREDRAW);
183         lp->sw = 0;
184         lp->so = 0;
185
186         if (MI_NPIXELS(mi) > 2)
187                 c = NRAND(MI_NPIXELS(mi));
188
189         for (i = 0; i < lp->ln; i++) {
190                 laserstruct *l = &lp->laser[i];
191
192                 l->bn = (border) NRAND(4);
193
194                 switch (l->bn) {
195                         case TOP:
196                                 l->bx = NRAND(lp->width);
197                                 l->by = 0;
198                                 break;
199                         case RIGHT:
200                                 l->bx = lp->width;
201                                 l->by = NRAND(lp->height);
202                                 break;
203                         case BOTTOM:
204                                 l->bx = NRAND(lp->width);
205                                 l->by = lp->height;
206                                 break;
207                         case LEFT:
208                                 l->bx = 0;
209                                 l->by = NRAND(lp->height);
210                 }
211
212                 l->dir = (int) (LRAND() & 1);
213                 l->speed = ((RANGE_RAND(MINSPEED, MAXSPEED) * lp->width) / 1000) + 1;
214                 if (MI_NPIXELS(mi) > 2) {
215                         l->gcv.foreground = MI_PIXEL(mi, c);
216                         c = (c + COLORSTEP) % MI_NPIXELS(mi);
217                 } else
218                         l->gcv.foreground = MI_WHITE_PIXEL(mi);
219         }
220 }
221
222 static void
223 draw_laser_once(ModeInfo * mi)
224 {
225         Display    *display = MI_DISPLAY(mi);
226         lasersstruct *lp = &lasers[MI_SCREEN(mi)];
227         int         i;
228
229         for (i = 0; i < lp->ln; i++) {
230                 laserstruct *l = &lp->laser[i];
231
232                 if (lp->sw >= lp->lw) {
233                         XChangeGC(display, lp->stippledGC, GCForeground, &(lp->gcv_black));
234                         XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
235                                   lp->cx, lp->cy,
236                                   l->sx[lp->so], l->sy[lp->so]);
237                 }
238                 if (l->dir) {
239                         switch (l->bn) {
240                                 case TOP:
241                                         l->bx -= l->speed;
242                                         if (l->bx < 0) {
243                                                 l->by = -l->bx;
244                                                 l->bx = 0;
245                                                 l->bn = LEFT;
246                                         }
247                                         break;
248                                 case RIGHT:
249                                         l->by -= l->speed;
250                                         if (l->by < 0) {
251                                                 l->bx = lp->width + l->by;
252                                                 l->by = 0;
253                                                 l->bn = TOP;
254                                         }
255                                         break;
256                                 case BOTTOM:
257                                         l->bx += l->speed;
258                                         if (l->bx >= lp->width) {
259                                                 l->by = lp->height - l->bx % lp->width;
260                                                 l->bx = lp->width;
261                                                 l->bn = RIGHT;
262                                         }
263                                         break;
264                                 case LEFT:
265                                         l->by += l->speed;
266                                         if (l->by >= lp->height) {
267                                                 l->bx = l->by % lp->height;
268                                                 l->by = lp->height;
269                                                 l->bn = BOTTOM;
270                                         }
271                         }
272                 } else {
273                         switch (l->bn) {
274                                 case TOP:
275                                         l->bx += l->speed;
276                                         if (l->bx >= lp->width) {
277                                                 l->by = l->bx % lp->width;
278                                                 l->bx = lp->width;
279                                                 l->bn = RIGHT;
280                                         }
281                                         break;
282                                 case RIGHT:
283                                         l->by += l->speed;
284                                         if (l->by >= lp->height) {
285                                                 l->bx = lp->width - l->by % lp->height;
286                                                 l->by = lp->height;
287                                                 l->bn = BOTTOM;
288                                         }
289                                         break;
290                                 case BOTTOM:
291                                         l->bx -= l->speed;
292                                         if (l->bx < 0) {
293                                                 l->by = lp->height + l->bx;
294                                                 l->bx = 0;
295                                                 l->bn = LEFT;
296                                         }
297                                         break;
298                                 case LEFT:
299                                         l->by -= l->speed;
300                                         if (l->by < 0) {
301                                                 l->bx = -l->bx;
302                                                 l->by = 0;
303                                                 l->bn = TOP;
304                                         }
305                         }
306                 }
307
308                 XChangeGC(display, lp->stippledGC, GCForeground, &l->gcv);
309                 XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
310                           lp->cx, lp->cy, l->bx, l->by);
311
312                 l->sx[lp->so] = l->bx;
313                 l->sy[lp->so] = l->by;
314
315         }
316
317         if (lp->sw < lp->lw)
318                 ++lp->sw;
319
320         lp->so = (lp->so + 1) % lp->lw;
321 }
322
323 ENTRYPOINT void
324 draw_laser(ModeInfo * mi)
325 {
326         int         i;
327         lasersstruct *lp;
328
329         if (lasers == NULL)
330                 return;
331         lp = &lasers[MI_SCREEN(mi)];
332         if (lp->laser == NULL)
333                 return;
334
335         MI_IS_DRAWN(mi) = True;
336         for (i = 0; i < lp->lr; i++)
337                 draw_laser_once(mi);
338
339         if (++lp->time > MI_CYCLES(mi))
340                 init_laser(mi);
341 }
342
343 ENTRYPOINT void
344 release_laser(ModeInfo * mi)
345 {
346         if (lasers != NULL) {
347                 int         screen;
348
349                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
350                         free_laser(MI_DISPLAY(mi), &lasers[screen]);
351                 (void) free((void *) lasers);
352                 lasers = (lasersstruct *) NULL;
353         }
354 }
355
356 ENTRYPOINT void
357 refresh_laser(ModeInfo * mi)
358 {
359         MI_CLEARWINDOW(mi);
360 }
361
362 XSCREENSAVER_MODULE ("Laser", laser)
363
364 #endif /* MODE_laser */