http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[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 PROGCLASS "Laser"
32 #define HACK_INIT init_laser
33 #define HACK_DRAW draw_laser
34 #define laser_opts xlockmore_opts
35 #define DEFAULTS "*delay: 40000 \n" \
36  "*count: 10 \n" \
37  "*cycles: 200 \n" \
38  "*ncolors: 64 \n"
39 #define BRIGHT_COLORS
40 #include "xlockmore.h"          /* in xscreensaver distribution */
41 #else /* STANDALONE */
42 #include "xlock.h"              /* in xlockmore distribution */
43 #endif /* STANDALONE */
44
45 #ifdef MODE_laser
46
47 ModeSpecOpt laser_opts =
48 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
49
50 #ifdef USE_MODULES
51 ModStruct   laser_description =
52 {"laser", "init_laser", "draw_laser", "release_laser",
53  "refresh_laser", "init_laser", (char *) NULL, &laser_opts,
54  20000, -10, 200, 1, 64, 1.0, "",
55  "Shows spinning lasers", 0, NULL};
56
57 #endif
58
59 #define MINREDRAW 3             /* Number of redrawn on each frame */
60 #define MAXREDRAW 8
61
62 #define MINLASER  1             /* Laser number */
63
64 #define MINWIDTH  2             /* Laser ray width range */
65 #define MAXWIDTH 40
66
67 #define MINSPEED  2             /* Speed range */
68 #define MAXSPEED 17
69
70 #define MINDIST  10             /* Minimal distance from edges */
71
72 #define COLORSTEP 2             /* Laser color step */
73
74 #define RANGE_RAND(min,max) (int) ((min) + LRAND() % ((max) - (min)))
75
76 typedef enum {
77         TOP, RIGHT, BOTTOM, LEFT
78 } border;
79
80 typedef struct {
81         int         bx;         /* border x */
82         int         by;         /* border y */
83         border      bn;         /* active border */
84         int         dir;        /* direction */
85         int         speed;      /* laser velocity from MINSPEED to MAXSPEED */
86         int         sx[MAXWIDTH];       /* x stack */
87         int         sy[MAXWIDTH];       /* x stack */
88         XGCValues   gcv;        /* for color */
89 } laserstruct;
90
91 typedef struct {
92         int         width;
93         int         height;
94         int         cx;         /* center x */
95         int         cy;         /* center y */
96         int         lw;         /* laser width */
97         int         ln;         /* laser number */
98         int         lr;         /* laser redraw */
99         int         sw;         /* stack width */
100         int         so;         /* stack offset */
101         int         time;       /* up time */
102         GC          stippledGC;
103         XGCValues   gcv_black;  /* for black color */
104         laserstruct *laser;
105 } lasersstruct;
106
107 static lasersstruct *lasers = (lasersstruct *) NULL;
108
109 static void
110 free_laser(Display *display, lasersstruct *lp)
111 {
112         if (lp->laser != NULL) {
113                 (void) free((void *) lp->laser);
114                 lp->laser = (laserstruct *) NULL;
115         }
116         if (lp->stippledGC != None) {
117                 XFreeGC(display, lp->stippledGC);
118                 lp->stippledGC = None;
119         }
120 }
121
122 void
123 init_laser(ModeInfo * mi)
124 {
125         Display *display = MI_DISPLAY(mi);
126         int         i, c = 0;
127         lasersstruct *lp;
128
129         if (lasers == NULL) {
130                 if ((lasers = (lasersstruct *) calloc(MI_NUM_SCREENS(mi),
131                                              sizeof (lasersstruct))) == NULL)
132                         return;
133         }
134         lp = &lasers[MI_SCREEN(mi)];
135
136         lp->width = MI_WIDTH(mi);
137         lp->height = MI_HEIGHT(mi);
138         lp->time = 0;
139
140         lp->ln = MI_COUNT(mi);
141         if (lp->ln < -MINLASER) {
142                 /* if lp->ln is random ... the size can change */
143                 if (lp->laser != NULL) {
144                         (void) free((void *) lp->laser);
145                         lp->laser = (laserstruct *) NULL;
146                 }
147                 lp->ln = NRAND(-lp->ln - MINLASER + 1) + MINLASER;
148         } else if (lp->ln < MINLASER)
149                 lp->ln = MINLASER;
150
151         if (lp->laser == NULL) {
152                 if ((lp->laser = (laserstruct *) malloc(lp->ln *
153                                 sizeof (laserstruct))) == NULL) {
154                         free_laser(display, lp);
155                         return;
156                 }
157         }
158         if (lp->stippledGC == None) {
159                 XGCValues   gcv;
160
161                 gcv.foreground = MI_WHITE_PIXEL(mi);
162                 gcv.background = MI_BLACK_PIXEL(mi);
163                 lp->gcv_black.foreground = MI_BLACK_PIXEL(mi);
164                 if ((lp->stippledGC = XCreateGC(display, MI_WINDOW(mi),
165                                 GCForeground | GCBackground, &gcv)) == None) {
166                         free_laser(display, lp);
167                         return;
168                 }
169         }
170         MI_CLEARWINDOW(mi);
171
172         if (MINDIST < lp->width - MINDIST)
173                 lp->cx = RANGE_RAND(MINDIST, lp->width - MINDIST);
174         else
175                 lp->cx = RANGE_RAND(0, lp->width);
176         if (MINDIST < lp->height - MINDIST)
177                 lp->cy = RANGE_RAND(MINDIST, lp->height - MINDIST);
178         else
179                 lp->cy = RANGE_RAND(0, lp->height);
180         lp->lw = RANGE_RAND(MINWIDTH, MAXWIDTH);
181         lp->lr = RANGE_RAND(MINREDRAW, MAXREDRAW);
182         lp->sw = 0;
183         lp->so = 0;
184
185         if (MI_NPIXELS(mi) > 2)
186                 c = NRAND(MI_NPIXELS(mi));
187
188         for (i = 0; i < lp->ln; i++) {
189                 laserstruct *l = &lp->laser[i];
190
191                 l->bn = (border) NRAND(4);
192
193                 switch (l->bn) {
194                         case TOP:
195                                 l->bx = NRAND(lp->width);
196                                 l->by = 0;
197                                 break;
198                         case RIGHT:
199                                 l->bx = lp->width;
200                                 l->by = NRAND(lp->height);
201                                 break;
202                         case BOTTOM:
203                                 l->bx = NRAND(lp->width);
204                                 l->by = lp->height;
205                                 break;
206                         case LEFT:
207                                 l->bx = 0;
208                                 l->by = NRAND(lp->height);
209                 }
210
211                 l->dir = (int) (LRAND() & 1);
212                 l->speed = ((RANGE_RAND(MINSPEED, MAXSPEED) * lp->width) / 1000) + 1;
213                 if (MI_NPIXELS(mi) > 2) {
214                         l->gcv.foreground = MI_PIXEL(mi, c);
215                         c = (c + COLORSTEP) % MI_NPIXELS(mi);
216                 } else
217                         l->gcv.foreground = MI_WHITE_PIXEL(mi);
218         }
219 }
220
221 static void
222 draw_laser_once(ModeInfo * mi)
223 {
224         Display    *display = MI_DISPLAY(mi);
225         lasersstruct *lp = &lasers[MI_SCREEN(mi)];
226         int         i;
227
228         for (i = 0; i < lp->ln; i++) {
229                 laserstruct *l = &lp->laser[i];
230
231                 if (lp->sw >= lp->lw) {
232                         XChangeGC(display, lp->stippledGC, GCForeground, &(lp->gcv_black));
233                         XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
234                                   lp->cx, lp->cy,
235                                   l->sx[lp->so], l->sy[lp->so]);
236                 }
237                 if (l->dir) {
238                         switch (l->bn) {
239                                 case TOP:
240                                         l->bx -= l->speed;
241                                         if (l->bx < 0) {
242                                                 l->by = -l->bx;
243                                                 l->bx = 0;
244                                                 l->bn = LEFT;
245                                         }
246                                         break;
247                                 case RIGHT:
248                                         l->by -= l->speed;
249                                         if (l->by < 0) {
250                                                 l->bx = lp->width + l->by;
251                                                 l->by = 0;
252                                                 l->bn = TOP;
253                                         }
254                                         break;
255                                 case BOTTOM:
256                                         l->bx += l->speed;
257                                         if (l->bx >= lp->width) {
258                                                 l->by = lp->height - l->bx % lp->width;
259                                                 l->bx = lp->width;
260                                                 l->bn = RIGHT;
261                                         }
262                                         break;
263                                 case LEFT:
264                                         l->by += l->speed;
265                                         if (l->by >= lp->height) {
266                                                 l->bx = l->by % lp->height;
267                                                 l->by = lp->height;
268                                                 l->bn = BOTTOM;
269                                         }
270                         }
271                 } else {
272                         switch (l->bn) {
273                                 case TOP:
274                                         l->bx += l->speed;
275                                         if (l->bx >= lp->width) {
276                                                 l->by = l->bx % lp->width;
277                                                 l->bx = lp->width;
278                                                 l->bn = RIGHT;
279                                         }
280                                         break;
281                                 case RIGHT:
282                                         l->by += l->speed;
283                                         if (l->by >= lp->height) {
284                                                 l->bx = lp->width - l->by % lp->height;
285                                                 l->by = lp->height;
286                                                 l->bn = BOTTOM;
287                                         }
288                                         break;
289                                 case BOTTOM:
290                                         l->bx -= l->speed;
291                                         if (l->bx < 0) {
292                                                 l->by = lp->height + l->bx;
293                                                 l->bx = 0;
294                                                 l->bn = LEFT;
295                                         }
296                                         break;
297                                 case LEFT:
298                                         l->by -= l->speed;
299                                         if (l->by < 0) {
300                                                 l->bx = -l->bx;
301                                                 l->by = 0;
302                                                 l->bn = TOP;
303                                         }
304                         }
305                 }
306
307                 XChangeGC(display, lp->stippledGC, GCForeground, &l->gcv);
308                 XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
309                           lp->cx, lp->cy, l->bx, l->by);
310
311                 l->sx[lp->so] = l->bx;
312                 l->sy[lp->so] = l->by;
313
314         }
315
316         if (lp->sw < lp->lw)
317                 ++lp->sw;
318
319         lp->so = (lp->so + 1) % lp->lw;
320 }
321
322 void
323 draw_laser(ModeInfo * mi)
324 {
325         int         i;
326         lasersstruct *lp;
327
328         if (lasers == NULL)
329                 return;
330         lp = &lasers[MI_SCREEN(mi)];
331         if (lp->laser == NULL)
332                 return;
333
334         MI_IS_DRAWN(mi) = True;
335         for (i = 0; i < lp->lr; i++)
336                 draw_laser_once(mi);
337
338         if (++lp->time > MI_CYCLES(mi))
339                 init_laser(mi);
340 }
341
342 void
343 release_laser(ModeInfo * mi)
344 {
345         if (lasers != NULL) {
346                 int         screen;
347
348                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
349                         free_laser(MI_DISPLAY(mi), &lasers[screen]);
350                 (void) free((void *) lasers);
351                 lasers = (lasersstruct *) NULL;
352         }
353 }
354
355 void
356 refresh_laser(ModeInfo * mi)
357 {
358         MI_CLEARWINDOW(mi);
359 }
360
361 #endif /* MODE_laser */