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