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 */ |
---|