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