http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / spiral.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* spiral --- spiraling dots */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)spiral.c      5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1994 by Darrick Brown.
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: jwz@jwz.org: turned into a standalone program.
27  * 24-Jul-1995: Fix to allow cycles not to have an arbitrary value by
28  *              Peter Schmitzberger (schmitz@coma.sbg.ac.at).
29  * 06-Mar-1995: Finished cleaning up and final testing.
30  * 03-Mar-1995: Cleaned up code.
31  * 12-Jul-1994: Written.
32  *
33  * Low CPU usage mode.
34  * Idea based on a graphics demo I saw a *LONG* time ago.
35  */
36
37 #ifdef STANDALONE
38 #define MODE_spiral
39 #define PROGCLASS "Spiral"
40 #define HACK_INIT init_spiral
41 #define HACK_DRAW draw_spiral
42 #define spiral_opts xlockmore_opts
43 #define DEFAULTS "*delay: 50000 \n" \
44  "*count: 40 \n" \
45  "*cycles: 350 \n" \
46  "*ncolors: 64 \n"
47 #define SMOOTH_COLORS
48 #include "xlockmore.h"          /* from the xscreensaver distribution */
49 #else /* !STANDALONE */
50 #include "xlock.h"              /* from the xlockmore distribution */
51 #endif /* !STANDALONE */
52
53 #ifdef MODE_spiral
54
55 ModeSpecOpt spiral_opts =
56 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
57
58 #ifdef USE_MODULES
59 ModStruct   spiral_description =
60 {"spiral", "init_spiral", "draw_spiral", "release_spiral",
61  "refresh_spiral", "init_spiral", (char *) NULL, &spiral_opts,
62  5000, -40, 350, 1, 64, 1.0, "",
63  "Shows a helical locus of points", 0, NULL};
64
65 #endif
66
67 #define MAXTRAIL 512            /* The length of the trail */
68 #define MAXDOTS 40
69 #define MINDOTS 1
70 #define TWOPI (2.0*M_PI)        /* for convienence */
71 #define JAGGINESS 4             /* This sets the "Craziness" of the spiral (I like 4) */
72 #define SPEED 2.0
73
74 /* How many segments to draw per cycle when redrawing */
75 #define REDRAWSTEP 3
76
77
78 typedef struct {
79         float       hx, hy, ha, hr;
80 } Traildots;
81
82 typedef struct {
83         Traildots  *traildots;
84         float       cx, cy;
85         float       angle;
86         float       radius;
87         float       dr, da;
88         float       dx, dy;
89         int         erase;
90         int         inc;
91         float       colors;
92         int         width, height;
93         float       top, bottom, left, right;
94         int         dots, nlength;
95         int         redrawing, redrawpos;
96 } spiralstruct;
97
98 static spiralstruct *spirals = (spiralstruct *) NULL;
99
100 static void draw_dots(ModeInfo * mi, int in);
101
102 #define TFX(sp,x) ((int)((x/sp->right)*(float)sp->width))
103 #define TFY(sp,y) ((int)((y/sp->top)*(float)sp->height))
104
105 static void
106 draw_dots(ModeInfo * mi, int in)
107 {
108
109         float       i, inc;
110         float       x, y;
111
112         spiralstruct *sp = &spirals[MI_SCREEN(mi)];
113
114         inc = TWOPI / (float) sp->dots;
115         for (i = 0.0; i < TWOPI; i += inc) {
116                 x = sp->traildots[in].hx + COSF(i + sp->traildots[in].ha) *
117                         sp->traildots[in].hr;
118                 y = sp->traildots[in].hy + SINF(i + sp->traildots[in].ha) *
119                         sp->traildots[in].hr;
120                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
121                            TFX(sp, x), TFY(sp, y));
122         }
123 }
124
125 void
126 init_spiral(ModeInfo * mi)
127 {
128         spiralstruct *sp;
129         int         i;
130
131         if (spirals == NULL) {
132                 if ((spirals = (spiralstruct *) calloc(MI_NUM_SCREENS(mi),
133                                              sizeof (spiralstruct))) == NULL)
134                         return;
135         }
136         sp = &spirals[MI_SCREEN(mi)];
137
138         sp->width = MI_WIDTH(mi);
139         sp->height = MI_HEIGHT(mi);
140
141         MI_CLEARWINDOW(mi);
142
143         /* Init */
144         sp->nlength = MI_CYCLES(mi);
145
146         if (!sp->traildots)
147                 if ((sp->traildots = (Traildots *) malloc(sp->nlength *
148                                 sizeof (Traildots))) == NULL) {
149                         return;
150                 }
151
152         /* initialize the allocated array */
153         for (i = 0; i < sp->nlength; i++) {
154                 sp->traildots[i].hx = 0.0;
155                 sp->traildots[i].hy = 0.0;
156                 sp->traildots[i].ha = 0.0;
157                 sp->traildots[i].hr = 0.0;
158         }
159         sp->redrawing = 0;
160
161         /* keep the window parameters proportional */
162         sp->top = 10000.0;
163         sp->bottom = 0;
164         sp->right = (float) (sp->width) / (float) (sp->height) * (10000.0);
165         sp->left = 0;
166
167         /* assign the initial values */
168         sp->cx = (float) (5000.0 - NRAND(2000)) / 10000.0 * sp->right;
169         sp->cy = (float) (5000.0 - NRAND(2000));
170         sp->radius = (float) (NRAND(200) + 200);
171         sp->angle = 0.0;
172         sp->dx = (float) (10 - NRAND(20)) * SPEED;
173         sp->dy = (float) (10 - NRAND(20)) * SPEED;
174         sp->dr = (float) ((NRAND(10) + 4) * (1 - (LRAND() & 1) * 2));
175         sp->da = (float) NRAND(360) / 7200.0 + 0.01;
176         if (MI_NPIXELS(mi) > 2)
177                 sp->colors = (float) NRAND(MI_NPIXELS(mi));
178         sp->erase = 0;
179         sp->inc = 0;
180         sp->traildots[sp->inc].hx = sp->cx;
181         sp->traildots[sp->inc].hy = sp->cy;
182         sp->traildots[sp->inc].ha = sp->angle;
183         sp->traildots[sp->inc].hr = sp->radius;
184         sp->inc++;
185
186         sp->dots = MI_COUNT(mi);
187         if (sp->dots < -MINDOTS)
188                 sp->dots = NRAND(sp->dots - MINDOTS + 1) + MINDOTS;
189         /* Absolute minimum */
190         if (sp->dots < MINDOTS)
191                 sp->dots = MINDOTS;
192 }
193
194 void
195 draw_spiral(ModeInfo * mi)
196 {
197         Display    *display = MI_DISPLAY(mi);
198         GC          gc = MI_GC(mi);
199         int         i, j;
200         spiralstruct *sp;
201
202         if (spirals == NULL)
203                 return;
204         sp = &spirals[MI_SCREEN(mi)];
205         if (sp->traildots == NULL)
206                 return;
207
208         MI_IS_DRAWN(mi) = True;
209         if (sp->erase == 1) {
210                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
211                 draw_dots(mi, sp->inc);
212         }
213         sp->cx += sp->dx;
214         sp->traildots[sp->inc].hx = sp->cx;
215
216         if ((sp->cx > 9000.0) || (sp->cx < 1000.0))
217                 sp->dx *= -1.0;
218
219         sp->cy += sp->dy;
220         sp->traildots[sp->inc].hy = sp->cy;
221
222         if ((sp->cy > 9000.0) || (sp->cy < 1000.0))
223                 sp->dy *= -1.0;
224
225         sp->radius += sp->dr;
226         sp->traildots[sp->inc].hr = sp->radius;
227
228         if ((sp->radius > 2500.0) && (sp->dr > 0.0))
229                 sp->dr *= -1.0;
230         else if ((sp->radius < 50.0) && (sp->radius < 0.0))
231                 sp->dr *= -1.0;
232
233         /* Randomly give some variations to:  */
234
235         /* spiral direction (if it is within the boundaries) */
236         if ((NRAND(3000) < 1 * JAGGINESS) &&
237             (((sp->cx > 2000.0) && (sp->cx < 8000.0)) &&
238              ((sp->cy > 2000.0) && (sp->cy < 8000.0)))) {
239                 sp->dx = (float) (10 - NRAND(20)) * SPEED;
240                 sp->dy = (float) (10 - NRAND(20)) * SPEED;
241         }
242         /* The speed of the change in size of the spiral */
243         if (NRAND(3000) < 1 * JAGGINESS) {
244                 if (LRAND() & 1)
245                         sp->dr += (float) (NRAND(3) + 1);
246                 else
247                         sp->dr -= (float) (NRAND(3) + 1);
248
249                 /* don't let it get too wild */
250                 if (sp->dr > 18.0)
251                         sp->dr = 18.0;
252                 else if (sp->dr < 4.0)
253                         sp->dr = 4.0;
254         }
255         /* The speed of rotation */
256         if (NRAND(3000) < 1 * JAGGINESS)
257                 sp->da = (float) NRAND(360) / 7200.0 + 0.01;
258
259         /* Reverse rotation */
260         if (NRAND(3000) < 1 * JAGGINESS)
261                 sp->da *= -1.0;
262
263         sp->angle += sp->da;
264         sp->traildots[sp->inc].ha = sp->angle;
265
266         if (sp->angle > TWOPI)
267                 sp->angle -= TWOPI;
268         else if (sp->angle < 0.0)
269                 sp->angle += TWOPI;
270
271         sp->colors += (float) MI_NPIXELS(mi) / ((float) (2 * sp->nlength));
272         if (sp->colors >= (float) MI_NPIXELS(mi))
273                 sp->colors = 0.0;
274
275         if (MI_NPIXELS(mi) > 2)
276                 XSetForeground(display, gc, MI_PIXEL(mi, (int) sp->colors));
277         else
278                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
279         draw_dots(mi, sp->inc);
280         sp->inc++;
281
282         if (sp->inc > sp->nlength - 1) {
283                 sp->inc -= sp->nlength;
284                 sp->erase = 1;
285         }
286         if (sp->redrawing) {
287                 for (i = 0; i < REDRAWSTEP; i++) {
288                         j = (sp->inc - sp->redrawpos + sp->nlength) % sp->nlength;
289                         draw_dots(mi, j);
290
291                         if (++(sp->redrawpos) >= sp->nlength) {
292                                 sp->redrawing = 0;
293                                 break;
294                         }
295                 }
296         }
297 }
298
299 void
300 release_spiral(ModeInfo * mi)
301 {
302         if (spirals != NULL) {
303                 int         screen;
304
305                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
306                         spiralstruct *sp = &spirals[screen];
307
308                         if (sp->traildots)
309                                 (void) free((void *) sp->traildots);
310                 }
311                 (void) free((void *) spirals);
312                 spirals = (spiralstruct *) NULL;
313         }
314 }
315
316 void
317 refresh_spiral(ModeInfo * mi)
318 {
319         spiralstruct *sp;
320
321         if (spirals == NULL)
322                 return;
323         sp = &spirals[MI_SCREEN(mi)];
324
325         MI_CLEARWINDOW(mi);
326         sp->redrawing = 1;
327         sp->redrawpos = 0;
328 }
329
330 #endif /* MODE_spiral */