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