1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* rotor --- a swirly rotor */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)rotor.c 4.04 97/07/28 xlockmore";
10 * Copyright (c) 1991 by Patrick J. Naughton.
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.
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.
25 * 10-May-97: Compatible with xscreensaver
26 * 08-Mar-95: CAT stuff for ## was tripping up some C compilers. Removed.
27 * 01-Dec-93: added patch for AIXV3 from Tom McConnell
28 * <tmcconne@sedona.intel.com>
29 * 11-Nov-90: put into xlock by Steve Zellers <zellers@sun.com>
30 * 16-Oct-90: Received from Tom Lawrence (tcl@cs.brown.edu: 'flight' simulator)
34 # define PROGCLASS "Rotor"
35 # define HACK_INIT init_rotor
36 # define HACK_DRAW draw_rotor
37 # define rotor_opts xlockmore_opts
38 # define DEFAULTS "*delay: 10000 \n" \
43 # define SMOOTH_COLORS
44 # include "xlockmore.h" /* in xscreensaver distribution */
45 #else /* STANDALONE */
46 # include "xlock.h" /* in xlockmore distribution */
47 #endif /* STANDALONE */
49 ModeSpecOpt rotor_opts =
50 {0, NULL, 0, NULL, NULL};
53 * A 'batchcount' of 3 or 4 works best!
56 #define MAXANGLE 3000.0 /* irrectangular (jwz: was 10000.0) */
58 /* How many segments to draw per cycle when redrawing */
66 float radius_drift_max;
67 float radius_drift_now;
72 float ratio_drift_max;
73 float ratio_drift_now;
83 int prevcenterx, prevcentery;
84 unsigned char firsttime;
85 unsigned char iconifiedscreen; /* for iconified view */
86 unsigned char forward;
90 int redrawing, redrawpos;
93 static rotorstruct *rotors = NULL;
96 init_rotor(ModeInfo * mi)
101 unsigned char wasiconified;
103 if (rotors == NULL) {
104 if ((rotors = (rotorstruct *) calloc(MI_NUM_SCREENS(mi),
105 sizeof (rotorstruct))) == NULL)
108 rp = &rotors[MI_SCREEN(mi)];
110 rp->prevcenterx = rp->centerx;
111 rp->prevcentery = rp->centery;
113 rp->centerx = MI_WIN_WIDTH(mi) / 2;
114 rp->centery = MI_WIN_HEIGHT(mi) / 2;
118 * sometimes, you go into iconified view, only to see a really whizzy pattern
119 * that you would like to look more closely at. Normally, clicking in the
120 * icon reinitializes everything - but I don't, cuz I'm that kind of guy.
121 * HENCE, the wasiconified stuff you see here.
124 wasiconified = rp->iconifiedscreen;
125 rp->iconifiedscreen = MI_WIN_IS_ICONIC(mi);
127 if (wasiconified && !rp->iconifiedscreen)
128 rp->firsttime = True;
131 /* This is a fudge is needed since prevcenter may not be set when it comes
132 from the the random mode and return is pressed (and its not the first
133 mode that was running). This assumes that the size of the lock screen
134 window / size of the icon window = 12 */
135 if (!rp->prevcenterx)
136 rp->prevcenterx = rp->centerx * 12;
137 if (!rp->prevcentery)
138 rp->prevcentery = rp->centery * 12;
140 rp->num = MI_BATCHCOUNT(mi);
142 rp->num = NRAND(-rp->num) + 1;
143 if (rp->elements != NULL) {
144 (void) free((void *) rp->elements);
148 if (rp->elements == NULL)
149 rp->elements = (elem *) calloc(rp->num, sizeof (elem));
150 rp->nsave = MI_CYCLES(mi);
153 if (rp->save == NULL)
154 rp->save = (XPoint *) calloc(rp->nsave, sizeof (XPoint));
156 pelem = rp->elements;
158 for (x = rp->num; --x >= 0; pelem++) {
159 pelem->radius_drift_max = 1.0;
160 pelem->radius_drift_now = 1.0;
162 pelem->end_radius = 100.0;
164 pelem->ratio_drift_max = 1.0;
165 pelem->ratio_drift_now = 1.0;
166 pelem->end_ratio = 10.0;
168 if (MI_NPIXELS(mi) > 2)
169 rp->pix = NRAND(MI_NPIXELS(mi));
173 rp->lastx = rp->centerx;
174 rp->lasty = rp->centery;
175 rp->angle = (float) NRAND((long) MAXANGLE) / 3.0;
176 rp->forward = rp->firsttime = True;
180 int line_width = MI_SIZE(mi);
184 line_width = NRAND(-line_width)+1;
185 XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), line_width,
186 LineSolid, CapButt, JoinMiter);
189 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
193 draw_rotor(ModeInfo * mi)
195 Display *display = MI_DISPLAY(mi);
197 register rotorstruct *rp = &rotors[MI_SCREEN(mi)];
198 register elem *pelem;
201 int x_1, y_1, x_2, y_2;
203 if (!rp->iconifiedscreen) {
207 thisx = rp->prevcenterx;
208 thisy = rp->prevcentery;
210 for (i = rp->num, pelem = rp->elements; --i >= 0; pelem++) {
211 if (pelem->radius_drift_max <= pelem->radius_drift_now) {
212 pelem->start_radius = pelem->end_radius;
213 pelem->end_radius = (float) NRAND(40000) / 100.0 - 200.0;
214 pelem->radius_drift_max = (float) NRAND(100000) + 10000.0;
215 pelem->radius_drift_now = 0.0;
217 if (pelem->ratio_drift_max <= pelem->ratio_drift_now) {
218 pelem->start_ratio = pelem->end_ratio;
219 pelem->end_ratio = (float) NRAND(2000) / 100.0 - 10.0;
220 pelem->ratio_drift_max = (float) NRAND(100000) + 10000.0;
221 pelem->ratio_drift_now = 0.0;
223 pelem->ratio = pelem->start_ratio +
224 (pelem->end_ratio - pelem->start_ratio) /
225 pelem->ratio_drift_max * pelem->ratio_drift_now;
226 pelem->angle = rp->angle * pelem->ratio;
227 pelem->radius = pelem->start_radius +
228 (pelem->end_radius - pelem->start_radius) /
229 pelem->radius_drift_max * pelem->radius_drift_now;
231 thisx += (int) (COSF(pelem->angle) * pelem->radius);
232 thisy += (int) (SINF(pelem->angle) * pelem->radius);
234 pelem->ratio_drift_now += 1.0;
235 pelem->radius_drift_now += 1.0;
238 rp->firsttime = False;
240 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
242 x_1 = (int) rp->save[rp->rotor].x;
243 y_1 = (int) rp->save[rp->rotor].y;
244 x_2 = (int) rp->save[rp->prev].x;
245 y_2 = (int) rp->save[rp->prev].y;
247 if (rp->iconifiedscreen) {
248 x_1 = x_1 * rp->centerx / rp->prevcenterx;
249 x_2 = x_2 * rp->centerx / rp->prevcenterx;
250 y_1 = y_1 * rp->centery / rp->prevcentery;
251 y_2 = y_2 * rp->centery / rp->prevcentery;
253 XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2);
255 if (MI_NPIXELS(mi) > 2) {
256 XSetForeground(display, gc, MI_PIXEL(mi, rp->pix));
257 if (++rp->pix >= MI_NPIXELS(mi))
260 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
267 if (rp->iconifiedscreen) {
268 x_1 = x_1 * rp->centerx / rp->prevcenterx;
269 x_2 = x_2 * rp->centerx / rp->prevcenterx;
270 y_1 = y_1 * rp->centery / rp->prevcentery;
271 y_2 = y_2 * rp->centery / rp->prevcentery;
273 XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2);
275 rp->save[rp->rotor].x = rp->lastx = thisx;
276 rp->save[rp->rotor].y = rp->lasty = thisy;
279 rp->rotor %= rp->nsave;
281 rp->prev %= rp->nsave;
284 if (rp->angle >= MAXANGLE) {
285 rp->angle = MAXANGLE;
290 if (rp->angle <= 0) {
298 for (i = 0; i < REDRAWSTEP; i++) {
299 j = (rp->rotor - rp->redrawpos + rp->nsave) % rp->nsave;
301 x_1 = (int) rp->save[j].x;
302 y_1 = (int) rp->save[j].y;
303 x_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].x;
304 y_2 = (int) rp->save[(j - 1 + rp->nsave) % rp->nsave].y;
306 if (rp->iconifiedscreen) {
307 x_1 = x_1 * rp->centerx / rp->prevcenterx;
308 x_2 = x_2 * rp->centerx / rp->prevcenterx;
309 y_1 = y_1 * rp->centery / rp->prevcentery;
310 y_2 = y_2 * rp->centery / rp->prevcentery;
312 XDrawLine(display, MI_WINDOW(mi), gc, x_1, y_1, x_2, y_2);
314 if (++(rp->redrawpos) >= rp->nsave) {
323 release_rotor(ModeInfo * mi)
325 if (rotors != NULL) {
328 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
329 rotorstruct *rp = &rotors[screen];
331 if (rp->elements != NULL)
332 (void) free((void *) rp->elements);
333 if (rp->save != NULL)
334 (void) free((void *) rp->save);
336 (void) free((void *) rotors);
342 refresh_rotor(ModeInfo * mi)
344 rotorstruct *rp = &rotors[MI_SCREEN(mi)];