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