1 | /* -*- Mode: C; tab-width: 4 -*- */ |
---|
2 | /* rotor --- a swirly rotor */ |
---|
3 | |
---|
4 | #if 0 |
---|
5 | static const char sccsid[] = "@(#)rotor.c 5.00 2000/11/01 xlockmore"; |
---|
6 | #endif |
---|
7 | |
---|
8 | /*- |
---|
9 | * Copyright (c) 1991 by Patrick J. Naughton. |
---|
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 | * 08-Mar-1995: CAT stuff for ## was tripping up some C compilers. Removed. |
---|
27 | * 01-Dec-1993: added patch for AIXV3 from Tom McConnell |
---|
28 | * <tmcconne@sedona.intel.com> |
---|
29 | * 11-Nov-1990: put into xlock by Steve Zellers <zellers@sun.com> |
---|
30 | * 16-Oct-1990: Received from Tom Lawrence (tcl@cs.brown.edu: 'flight' |
---|
31 | * simulator) |
---|
32 | */ |
---|
33 | |
---|
34 | #ifdef STANDALONE |
---|
35 | #define MODE_rotor |
---|
36 | #define PROGCLASS "Rotor" |
---|
37 | #define HACK_INIT init_rotor |
---|
38 | #define HACK_DRAW draw_rotor |
---|
39 | #define rotor_opts xlockmore_opts |
---|
40 | #define DEFAULTS "*delay: 10000 \n" \ |
---|
41 | "*count: 4 \n" \ |
---|
42 | "*cycles: 20 \n" \ |
---|
43 | "*size: -6 \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_rotor |
---|
52 | |
---|
53 | ModeSpecOpt rotor_opts = |
---|
54 | {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; |
---|
55 | |
---|
56 | #ifdef USE_MODULES |
---|
57 | ModStruct rotor_description = |
---|
58 | {"rotor", "init_rotor", "draw_rotor", "release_rotor", |
---|
59 | "refresh_rotor", "init_rotor", (char *) NULL, &rotor_opts, |
---|
60 | 100, 4, 100, -6, 64, 0.3, "", |
---|
61 | "Shows Tom's Roto-Rooter", 0, NULL}; |
---|
62 | |
---|
63 | #endif |
---|
64 | |
---|
65 | /*- |
---|
66 | * A 'batchcount' of 3 or 4 works best! |
---|
67 | */ |
---|
68 | |
---|
69 | #define MAXANGLE 3000.0 /* irrectangular (was 10000.0) */ |
---|
70 | |
---|
71 | /* How many segments to draw per cycle when redrawing */ |
---|
72 | #define REDRAWSTEP 3 |
---|
73 | |
---|
74 | typedef struct { |
---|
75 | float angle; |
---|
76 | float radius; |
---|
77 | float start_radius; |
---|
78 | float end_radius; |
---|
79 | float radius_drift_max; |
---|
80 | float radius_drift_now; |
---|
81 | |
---|
82 | float ratio; |
---|
83 | float start_ratio; |
---|
84 | float end_ratio; |
---|
85 | float ratio_drift_max; |
---|
86 | float ratio_drift_now; |
---|
87 | } elem; |
---|
88 | |
---|
89 | typedef struct { |
---|
90 | int pix; |
---|
91 | int lastx, lasty; |
---|
92 | int num, rotor, prev; |
---|
93 | int nsave; |
---|
94 | float angle; |
---|
95 | int centerx, centery; |
---|
96 | int prevcenterx, prevcentery; |
---|
97 | unsigned char firsttime; |
---|
98 | unsigned char iconifiedscreen; /* for iconified view */ |
---|
99 | unsigned char forward; |
---|
100 | unsigned char unused; |
---|
101 | elem *elements; |
---|
102 | XPoint *save; |
---|
103 | int redrawing, redrawpos; |
---|
104 | int linewidth; |
---|
105 | } rotorstruct; |
---|
106 | |
---|
107 | static rotorstruct *rotors = (rotorstruct *) NULL; |
---|
108 | |
---|
109 | static void |
---|
110 | free_rotor(rotorstruct *rp) |
---|
111 | { |
---|
112 | if (rp->elements != NULL) { |
---|
113 | (void) free((void *) rp->elements); |
---|
114 | rp->elements = (elem *) NULL; |
---|
115 | } |
---|
116 | if (rp->save != NULL) { |
---|
117 | (void) free((void *) rp->save); |
---|
118 | rp->save = (XPoint *) NULL; |
---|
119 | } |
---|
120 | } |
---|
121 | |
---|
122 | void |
---|
123 | init_rotor(ModeInfo * mi) |
---|
124 | { |
---|
125 | int x; |
---|
126 | elem *pelem; |
---|
127 | unsigned char wasiconified; |
---|
128 | rotorstruct *rp; |
---|
129 | |
---|
130 | if (rotors == NULL) { |
---|
131 | if ((rotors = (rotorstruct *) calloc(MI_NUM_SCREENS(mi), |
---|
132 | sizeof (rotorstruct))) == NULL) |
---|
133 | return; |
---|
134 | } |
---|
135 | rp = &rotors[MI_SCREEN(mi)]; |
---|
136 | |
---|
137 | rp->prevcenterx = rp->centerx; |
---|
138 | rp->prevcentery = rp->centery; |
---|
139 | |
---|
140 | rp->centerx = MI_WIDTH(mi) / 2; |
---|
141 | rp->centery = MI_HEIGHT(mi) / 2; |
---|
142 | |
---|
143 | rp->redrawing = 0; |
---|
144 | /* |
---|
145 | * sometimes, you go into iconified view, only to see a really whizzy pattern |
---|
146 | * that you would like to look more closely at. Normally, clicking in the |
---|
147 | * icon reinitializes everything - but I don't, cuz I'm that kind of guy. |
---|
148 | * HENCE, the wasiconified stuff you see here. |
---|
149 | */ |
---|
150 | |
---|
151 | wasiconified = rp->iconifiedscreen; |
---|
152 | rp->iconifiedscreen = MI_IS_ICONIC(mi); |
---|
153 | |
---|
154 | if (wasiconified && !rp->iconifiedscreen) |
---|
155 | rp->firsttime = True; |
---|
156 | else { |
---|
157 | |
---|
158 | /* This is a fudge is needed since prevcenter may not be set when it comes |
---|
159 | from the the random mode and return is pressed (and its not the first |
---|
160 | mode that was running). This assumes that the size of the lock screen |
---|
161 | window / size of the icon window = 12 */ |
---|
162 | if (!rp->prevcenterx) |
---|
163 | rp->prevcenterx = rp->centerx * 12; |
---|
164 | if (!rp->prevcentery) |
---|
165 | rp->prevcentery = rp->centery * 12; |
---|
166 | |
---|
167 | rp->num = MI_COUNT(mi); |
---|
168 | if (rp->num < 0) { |
---|
169 | rp->num = NRAND(-rp->num) + 1; |
---|
170 | if (rp->elements != NULL) { |
---|
171 | (void) free((void *) rp->elements); |
---|
172 | rp->elements = (elem *) NULL; |
---|
173 | } |
---|
174 | } |
---|
175 | if (rp->elements == NULL) |
---|
176 | if ((rp->elements = (elem *) calloc(rp->num, |
---|
177 | sizeof (elem))) == NULL) { |
---|
178 | free_rotor(rp); |
---|
179 | return; |
---|
180 | } |
---|
181 | rp->nsave = MI_CYCLES(mi); |
---|
182 | if (rp->nsave <= 1) |
---|
183 | rp->nsave = 2; |
---|
184 | if (rp->save == NULL) |
---|
185 | if ((rp->save = (XPoint *) malloc(rp->nsave * |
---|
186 | sizeof (XPoint))) == NULL) { |
---|
187 | free_rotor(rp); |
---|
188 | return; |
---|
189 | } |
---|
190 | for (x = 0; x < rp->nsave; x++) { |
---|
191 | rp->save[x].x = rp->centerx; |
---|
192 | rp->save[x].y = rp->centery; |
---|
193 | } |
---|
194 | |
---|
195 | pelem = rp->elements; |
---|
196 | |
---|
197 | for (x = rp->num; --x >= 0; pelem++) { |
---|
198 | pelem->radius_drift_max = 1.0; |
---|
199 | pelem->radius_drift_now = 1.0; |
---|
200 | |
---|
201 | pelem->end_radius = 100.0; |
---|
202 | |
---|
203 | pelem->ratio_drift_max = 1.0; |
---|
204 | pelem->ratio_drift_now = 1.0; |
---|
205 | pelem->end_ratio = 10.0; |
---|
206 | } |
---|
207 | if (MI_NPIXELS(mi) > 2) |
---|
208 | rp->pix = NRAND(MI_NPIXELS(mi)); |
---|
209 | |
---|
210 | rp->rotor = 0; |
---|
211 | rp->prev = 1; |
---|
212 | rp->lastx = rp->centerx; |
---|
213 | rp->lasty = rp->centery; |
---|
214 | rp->angle = (float) NRAND((long) MAXANGLE) / 3.0; |
---|
215 | rp->forward = rp->firsttime = True; |
---|
216 | } |
---|
217 | rp->linewidth = MI_SIZE(mi); |
---|
218 | |
---|
219 | if (rp->linewidth == 0) |
---|
220 | rp->linewidth = 1; |
---|
221 | if (rp->linewidth < 0) |
---|
222 | rp->linewidth = NRAND(-rp->linewidth) + 1; |
---|
223 | |
---|
224 | MI_CLEARWINDOW(mi); |
---|
225 | } |
---|
226 | |
---|
227 | void |
---|
228 | draw_rotor(ModeInfo * mi) |
---|
229 | { |
---|
230 | Display *display = MI_DISPLAY(mi); |
---|
231 | GC gc = MI_GC(mi); |
---|
232 | register elem *pelem; |
---|
233 | int thisx, thisy; |
---|
234 | int i; |
---|
235 | int x_1, y_1, x_2, y_2; |
---|
236 | rotorstruct *rp; |
---|
237 | |
---|
238 | if (rotors == NULL) |
---|
239 | return; |
---|
240 | rp = &rotors[MI_SCREEN(mi)]; |
---|
241 | if (rp->elements == NULL) |
---|
242 | return; |
---|
243 | |
---|
244 | MI_IS_DRAWN(mi) = True; |
---|
245 | if (!rp->iconifiedscreen) { |
---|
246 | thisx = rp->centerx; |
---|
247 | thisy = rp->centery; |
---|
248 | } else { |
---|
249 | thisx = rp->prevcenterx; |
---|
250 | thisy = rp->prevcentery; |
---|
251 | } |
---|
252 | XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), rp->linewidth, |
---|
253 | LineSolid, CapButt, JoinMiter); |
---|
254 | for (i = rp->num, pelem = rp->elements; --i >= 0; pelem++) { |
---|
255 | if (pelem->radius_drift_max <= pelem->radius_drift_now) { |
---|
256 | pelem->start_radius = pelem->end_radius; |
---|
257 | pelem->end_radius = (float) NRAND(40000) / 100.0 - 200.0; |
---|
258 | pelem->radius_drift_max = (float) NRAND(100000) + 10000.0; |
---|
259 | pelem->radius_drift_now = 0.0; |
---|
260 | } |
---|
261 | if (pelem->ratio_drift_max <= pelem->ratio_drift_now) { |
---|
262 | pelem->start_ratio = pelem->end_ratio; |
---|
263 | pelem->end_ratio = (float) NRAND(2000) / 100.0 - 10.0; |
---|
264 | pelem->ratio_drift_max = (float) NRAND(100000) + 10000.0; |
---|
265 | pelem->ratio_drift_now = 0.0; |
---|
266 | } |
---|
267 | pelem->ratio = pelem->start_ratio + |
---|
268 | (pelem->end_ratio - pelem->start_ratio) / |
---|
269 | pelem->ratio_drift_max * pelem->ratio_drift_now; |
---|
270 | pelem->angle = rp->angle * pelem->ratio; |
---|
271 | pelem->radius = pelem->start_radius + |
---|
272 | (pelem->end_radius - pelem->start_radius) / |
---|
273 | pelem->radius_drift_max * pelem->radius_drift_now; |
---|
274 | |
---|
275 | thisx += (int) (COSF(pelem->angle) * pelem->radius); |
---|
276 | thisy += (int) (SINF(pelem->angle) * pelem->radius); |
---|
277 | |
---|
278 | pelem->ratio_drift_now += 1.0; |
---|
279 | pelem->radius_drift_now += 1.0; |
---|
280 | } |
---|
281 | if (rp->firsttime) |
---|
282 | rp->firsttime = False; |
---|
283 | else { |
---|
284 | XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); |
---|
285 | |
---|
286 | x_1 = (int) rp->save[rp->rotor].x; |
---|
287 | y_1 = (int) rp->save[rp->rotor].y; |
---|
288 | x_2 = (int) rp->save[rp->prev].x; |
---|
289 | y_2 = (int) rp->save[rp->prev].y; |
---|
290 | |
---|
291 | if (rp->iconifiedscreen) { |
---|
292 | x_1 = x_1 * rp->centerx / rp->prevcenterx; |
---|
293 | x_2 = x_2 * rp->centerx / rp->prevcenterx; |
---|
294 | y_1 = y_1 * rp->centery / rp->prevcentery; |
---|
295 | y_2 = y_2 * rp->centery / rp->prevcentery; |
---|
296 | } |
---|
297 | XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); |
---|
298 | |
---|
299 | if (MI_NPIXELS(mi) > 2) { |
---|
300 | XSetForeground(display, gc, MI_PIXEL(mi, rp->pix)); |
---|
301 | if (++rp->pix >= MI_NPIXELS(mi)) |
---|
302 | rp->pix = 0; |
---|
303 | } else |
---|
304 | XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); |
---|
305 | |
---|
306 | x_1 = rp->lastx; |
---|
307 | y_1 = rp->lasty; |
---|
308 | x_2 = thisx; |
---|
309 | y_2 = thisy; |
---|
310 | |
---|
311 | if (rp->iconifiedscreen) { |
---|
312 | x_1 = x_1 * rp->centerx / rp->prevcenterx; |
---|
313 | x_2 = x_2 * rp->centerx / rp->prevcenterx; |
---|
314 | y_1 = y_1 * rp->centery / rp->prevcentery; |
---|
315 | y_2 = y_2 * rp->centery / rp->prevcentery; |
---|
316 | } |
---|
317 | XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); |
---|
318 | } |
---|
319 | rp->save[rp->rotor].x = rp->lastx = thisx; |
---|
320 | rp->save[rp->rotor].y = rp->lasty = thisy; |
---|
321 | |
---|
322 | ++rp->rotor; |
---|
323 | rp->rotor %= rp->nsave; |
---|
324 | ++rp->prev; |
---|
325 | rp->prev %= rp->nsave; |
---|
326 | if (rp->forward) { |
---|
327 | rp->angle += 0.01; |
---|
328 | if (rp->angle >= MAXANGLE) { |
---|
329 | rp->angle = MAXANGLE; |
---|
330 | rp->forward = False; |
---|
331 | } |
---|
332 | } else { |
---|
333 | rp->angle -= 0.1; |
---|
334 | if (rp->angle <= 0) { |
---|
335 | rp->angle = 0.0; |
---|
336 | rp->forward = True; |
---|
337 | } |
---|
338 | } |
---|
339 | if (rp->redrawing) { |
---|
340 | int j; |
---|
341 | |
---|
342 | for (i = 0; i < REDRAWSTEP; i++) { |
---|
343 | j = (rp->rotor - rp->redrawpos + rp->nsave) % rp->nsave; |
---|
344 | |
---|
345 | x_1 = (int) rp->save[j].x; |
---|
346 | y_1 = (int) rp->save[j].y; |
---|
347 | x_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].x; |
---|
348 | y_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].y; |
---|
349 | |
---|
350 | if (rp->iconifiedscreen) { |
---|
351 | x_1 = x_1 * rp->centerx / rp->prevcenterx; |
---|
352 | x_2 = x_2 * rp->centerx / rp->prevcenterx; |
---|
353 | y_1 = y_1 * rp->centery / rp->prevcentery; |
---|
354 | y_2 = y_2 * rp->centery / rp->prevcentery; |
---|
355 | } |
---|
356 | XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2); |
---|
357 | |
---|
358 | if (++(rp->redrawpos) >= rp->nsave) { |
---|
359 | rp->redrawing = 0; |
---|
360 | break; |
---|
361 | } |
---|
362 | } |
---|
363 | } |
---|
364 | XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, |
---|
365 | LineSolid, CapButt, JoinMiter); |
---|
366 | } |
---|
367 | |
---|
368 | void |
---|
369 | release_rotor(ModeInfo * mi) |
---|
370 | { |
---|
371 | if (rotors != NULL) { |
---|
372 | int screen; |
---|
373 | |
---|
374 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) |
---|
375 | free_rotor(&rotors[screen]); |
---|
376 | (void) free((void *) rotors); |
---|
377 | rotors = (rotorstruct *) NULL; |
---|
378 | } |
---|
379 | } |
---|
380 | |
---|
381 | void |
---|
382 | refresh_rotor(ModeInfo * mi) |
---|
383 | { |
---|
384 | rotorstruct *rp; |
---|
385 | |
---|
386 | if (rotors == NULL) |
---|
387 | return; |
---|
388 | rp = &rotors[MI_SCREEN(mi)]; |
---|
389 | |
---|
390 | MI_CLEARWINDOW(mi); |
---|
391 | rp->redrawing = 1; |
---|
392 | rp->redrawpos = 1; |
---|
393 | } |
---|
394 | |
---|
395 | #endif /* MODE_rotor */ |
---|