From http://www.jwz.org/xscreensaver/xscreensaver-5.37.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         MI_INIT (mi, spirals, 0);
131         sp = &spirals[MI_SCREEN(mi)];
132
133 #ifdef HAVE_JWXYZ
134     jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi),  False);
135 #endif
136
137         sp->width = MI_WIDTH(mi);
138         sp->height = MI_HEIGHT(mi);
139
140         MI_CLEARWINDOW(mi);
141
142         /* Init */
143         sp->nlength = MI_CYCLES(mi);
144
145         if (!sp->traildots)
146                 if ((sp->traildots = (Traildots *) malloc(sp->nlength *
147                                 sizeof (Traildots))) == NULL) {
148                         return;
149                 }
150
151         /* initialize the allocated array */
152         for (i = 0; i < sp->nlength; i++) {
153                 sp->traildots[i].hx = 0.0;
154                 sp->traildots[i].hy = 0.0;
155                 sp->traildots[i].ha = 0.0;
156                 sp->traildots[i].hr = 0.0;
157         }
158         sp->redrawing = 0;
159
160         /* keep the window parameters proportional */
161         sp->top = 10000.0;
162         sp->bottom = 0;
163         sp->right = (float) (sp->width) / (float) (sp->height) * (10000.0);
164         sp->left = 0;
165
166         /* assign the initial values */
167         sp->cx = (float) (5000.0 - NRAND(2000)) / 10000.0 * sp->right;
168         sp->cy = (float) (5000.0 - NRAND(2000));
169         sp->radius = (float) (NRAND(200) + 200);
170         sp->angle = 0.0;
171         sp->dx = (float) (10 - NRAND(20)) * SPEED;
172         sp->dy = (float) (10 - NRAND(20)) * SPEED;
173         sp->dr = (float) ((NRAND(10) + 4) * (1 - (LRAND() & 1) * 2));
174         sp->da = (float) NRAND(360) / 7200.0 + 0.01;
175         if (MI_NPIXELS(mi) > 2)
176                 sp->colors = (float) NRAND(MI_NPIXELS(mi));
177         sp->erase = 0;
178         sp->inc = 0;
179         sp->traildots[sp->inc].hx = sp->cx;
180         sp->traildots[sp->inc].hy = sp->cy;
181         sp->traildots[sp->inc].ha = sp->angle;
182         sp->traildots[sp->inc].hr = sp->radius;
183         sp->inc++;
184
185         sp->dots = MI_COUNT(mi);
186         if (sp->dots < -MINDOTS)
187                 sp->dots = NRAND(sp->dots - MINDOTS + 1) + MINDOTS;
188         /* Absolute minimum */
189         if (sp->dots < MINDOTS)
190                 sp->dots = MINDOTS;
191 }
192
193 ENTRYPOINT void
194 draw_spiral(ModeInfo * mi)
195 {
196         Display    *display = MI_DISPLAY(mi);
197         GC          gc = MI_GC(mi);
198         int         i, j;
199         spiralstruct *sp;
200
201         if (spirals == NULL)
202                 return;
203         sp = &spirals[MI_SCREEN(mi)];
204         if (sp->traildots == NULL)
205                 return;
206
207         MI_IS_DRAWN(mi) = True;
208         if (sp->erase == 1) {
209                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
210                 draw_dots(mi, sp->inc);
211         }
212         sp->cx += sp->dx;
213         sp->traildots[sp->inc].hx = sp->cx;
214
215         if ((sp->cx > 9000.0) || (sp->cx < 1000.0))
216                 sp->dx *= -1.0;
217
218         sp->cy += sp->dy;
219         sp->traildots[sp->inc].hy = sp->cy;
220
221         if ((sp->cy > 9000.0) || (sp->cy < 1000.0))
222                 sp->dy *= -1.0;
223
224         sp->radius += sp->dr;
225         sp->traildots[sp->inc].hr = sp->radius;
226
227         if ((sp->radius > 2500.0) && (sp->dr > 0.0))
228                 sp->dr *= -1.0;
229         else if ((sp->radius < 50.0) && (sp->radius < 0.0))
230                 sp->dr *= -1.0;
231
232         /* Randomly give some variations to:  */
233
234         /* spiral direction (if it is within the boundaries) */
235         if ((NRAND(3000) < 1 * JAGGINESS) &&
236             (((sp->cx > 2000.0) && (sp->cx < 8000.0)) &&
237              ((sp->cy > 2000.0) && (sp->cy < 8000.0)))) {
238                 sp->dx = (float) (10 - NRAND(20)) * SPEED;
239                 sp->dy = (float) (10 - NRAND(20)) * SPEED;
240         }
241         /* The speed of the change in size of the spiral */
242         if (NRAND(3000) < 1 * JAGGINESS) {
243                 if (LRAND() & 1)
244                         sp->dr += (float) (NRAND(3) + 1);
245                 else
246                         sp->dr -= (float) (NRAND(3) + 1);
247
248                 /* don't let it get too wild */
249                 if (sp->dr > 18.0)
250                         sp->dr = 18.0;
251                 else if (sp->dr < 4.0)
252                         sp->dr = 4.0;
253         }
254         /* The speed of rotation */
255         if (NRAND(3000) < 1 * JAGGINESS)
256                 sp->da = (float) NRAND(360) / 7200.0 + 0.01;
257
258         /* Reverse rotation */
259         if (NRAND(3000) < 1 * JAGGINESS)
260                 sp->da *= -1.0;
261
262         sp->angle += sp->da;
263         sp->traildots[sp->inc].ha = sp->angle;
264
265         if (sp->angle > TWOPI)
266                 sp->angle -= TWOPI;
267         else if (sp->angle < 0.0)
268                 sp->angle += TWOPI;
269
270         sp->colors += (float) MI_NPIXELS(mi) / ((float) (2 * sp->nlength));
271         if (sp->colors >= (float) MI_NPIXELS(mi))
272                 sp->colors = 0.0;
273
274         if (MI_NPIXELS(mi) > 2)
275                 XSetForeground(display, gc, MI_PIXEL(mi, (int) sp->colors));
276         else
277                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
278         draw_dots(mi, sp->inc);
279         sp->inc++;
280
281         if (sp->inc > sp->nlength - 1) {
282                 sp->inc -= sp->nlength;
283                 sp->erase = 1;
284         }
285         if (sp->redrawing) {
286                 for (i = 0; i < REDRAWSTEP; i++) {
287                         j = (sp->inc - sp->redrawpos + sp->nlength) % sp->nlength;
288                         draw_dots(mi, j);
289
290                         if (++(sp->redrawpos) >= sp->nlength) {
291                                 sp->redrawing = 0;
292                                 break;
293                         }
294                 }
295         }
296 }
297
298 ENTRYPOINT void
299 release_spiral(ModeInfo * mi)
300 {
301         if (spirals != NULL) {
302                 int         screen;
303
304                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
305                         spiralstruct *sp = &spirals[screen];
306
307                         if (sp->traildots)
308                                 (void) free((void *) sp->traildots);
309                 }
310                 (void) free((void *) spirals);
311                 spirals = (spiralstruct *) NULL;
312         }
313 }
314
315 ENTRYPOINT void
316 refresh_spiral(ModeInfo * mi)
317 {
318         spiralstruct *sp;
319
320         if (spirals == NULL)
321                 return;
322         sp = &spirals[MI_SCREEN(mi)];
323
324         MI_CLEARWINDOW(mi);
325         sp->redrawing = 1;
326         sp->redrawpos = 0;
327 }
328
329 XSCREENSAVER_MODULE ("Spiral", spiral)
330
331 #endif /* MODE_spiral */