http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / rotor.c
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 */