ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / hacks / helix.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
2  *  Jamie Zawinski <jwz@netscape.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */
14
15 /* 10-May-97: merged ellipse code by Dan Stromberg <strombrg@nis.acs.uci.edu>
16  *            as found in xlockmore 4.03a10.
17  * 1992:      jwz created.
18  */
19
20 #include <math.h>
21 #include "screenhack.h"
22
23 static double sins [360];
24 static double coss [360];
25
26 static GC draw_gc, erase_gc;
27 static unsigned int default_fg_pixel;
28
29 static void
30 init_helix (Display *dpy, Window window)
31 {
32   int i;
33   XGCValues gcv;
34   XWindowAttributes xgwa;
35   Colormap cmap;
36   XGetWindowAttributes (dpy, window, &xgwa);
37   cmap = xgwa.colormap;
38   gcv.foreground = default_fg_pixel =
39     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
40   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
41   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
42   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
43
44   for (i = 0; i < 360; i++)
45     {
46       sins [i] = sin ((((double) i) / 180.0) * M_PI);
47       coss [i] = cos ((((double) i) / 180.0) * M_PI);
48     }
49 }
50
51 static int
52 gcd (int a, int b)
53 {
54   while (b > 0)
55     {
56       int tmp;
57       tmp = a % b;
58       a = b;
59       b = tmp;
60     }
61   return (a < 0 ? -a : a);
62 }
63
64 static void
65 helix (Display *dpy, Window window,
66        int radius1, int radius2, int d_angle,
67        int factor1, int factor2, int factor3, int factor4)
68 {
69   XWindowAttributes xgwa;
70   int width, height;
71   int xmid, ymid;
72   int x1, y1, x2, y2, angle, limit;
73   int i;
74
75   XClearWindow (dpy, window);
76   XGetWindowAttributes (dpy, window, &xgwa);
77   width = xgwa.width;
78   height = xgwa.height;
79
80   xmid = width / 2;
81   ymid = height / 2;
82   x1 = xmid;
83   y1 = ymid + radius2;
84   x2 = xmid;
85   y2 = ymid + radius1;
86   angle = 0;
87   limit = 1 + (360 / gcd (360, d_angle));
88   
89   for (i = 0; i < limit; i++)
90     {
91       int tmp;
92 #define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y))))
93
94       x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]);
95       y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]);
96       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
97       x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]);
98       y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]);
99
100       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
101       angle += d_angle;
102       XFlush (dpy);
103     }
104 }
105
106 static void
107 trig (Display *dpy, Window window,
108       int d_angle, int factor1, int factor2,
109       int offset, int d_angle_offset, int dir, int density)
110 {
111   XWindowAttributes xgwa;
112   int width, height;
113   int xmid, ymid;
114   int x1, y1, x2, y2;
115   int tmp, angle;
116   Colormap cmap;
117
118   XClearWindow (dpy, window);
119   XGetWindowAttributes (dpy, window, &xgwa);
120   cmap = xgwa.colormap;
121   width = xgwa.width;
122   height = xgwa.height;
123
124   xmid = width / 2;
125   ymid = height / 2;
126
127   while (d_angle >= -360 && d_angle <= 360)
128     {
129       angle = d_angle + d_angle_offset;
130       x1 = (sins [pmod(angle * factor1, 360)] * xmid) + xmid;
131       y1 = (coss [pmod(angle * factor1, 360)] * ymid) + ymid;
132       x2 = (sins [pmod(angle * factor2 + offset, 360)] * xmid) + xmid;
133       y2 = (coss [pmod(angle * factor2 + offset, 360)] * ymid) + ymid;
134       XDrawLine(dpy, window, draw_gc, x1, y1, x2, y2);
135       tmp = (int) 360 / (2 * density * factor1 * factor2);
136       if (tmp == 0)     /* Do not want it getting stuck... */
137         tmp = 1;        /* Would not need if floating point */
138       d_angle += dir * tmp;
139     }
140 }
141
142 #define min(a,b) ((a)<(b)?(a):(b))
143
144 static void
145 random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
146 {
147   Colormap cmap;
148   int width, height;
149   int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
150   double divisor;
151   XWindowAttributes xgwa;
152   XGetWindowAttributes (dpy, window, &xgwa);
153   width = xgwa.width;
154   height = xgwa.height;
155   cmap = xgwa.colormap;
156
157   radius = min (width, height) / 2;
158
159   d_angle = 0;
160   factor1 = 2;
161   factor2 = 2;
162   factor3 = 2;
163   factor4 = 2;
164
165   divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
166
167   if ((random () & 1) == 0)
168     {
169       radius1 = radius;
170       radius2 = radius / divisor;
171     }
172   else
173     {
174       radius2 = radius;
175       radius1 = radius / divisor;
176     }
177
178   while (gcd (360, d_angle) >= 2)
179     d_angle = random () % 360;
180
181 #define random_factor()                         \
182   (((random() % 7) ? ((random() & 1) + 1) : 3)  \
183    * (((random() & 1) * 2) - 1))
184
185   while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
186     {
187       factor1 = random_factor ();
188       factor2 = random_factor ();
189       factor3 = random_factor ();
190       factor4 = random_factor ();
191     }
192
193   if (mono_p)
194     XSetForeground (dpy, draw_gc, default_fg_pixel);
195   else
196     {
197       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
198                   &color->red, &color->green, &color->blue);
199       if ((*got_color = XAllocColor (dpy, cmap, color)))
200         XSetForeground (dpy, draw_gc, color->pixel);
201       else
202         XSetForeground (dpy, draw_gc, default_fg_pixel);
203     }
204   helix (dpy, window, radius1, radius2, d_angle,
205          factor1, factor2, factor3, factor4);
206 }
207
208 static void
209 random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
210 {
211   Colormap cmap;
212   int width, height;
213   int radius, d_angle, factor1, factor2;
214   int offset, d_angle_offset, dir, density;
215
216   XWindowAttributes xgwa;
217   XGetWindowAttributes (dpy, window, &xgwa);
218   width = xgwa.width;
219   height = xgwa.height;
220   cmap = xgwa.colormap;
221
222   radius = min (width, height) / 2;
223
224   d_angle = 0;
225   factor1 = (random() % 8) + 1;
226   do {
227     factor2 = (random() % 8) + 1;
228   } while (factor1 == factor2);
229
230   dir = (random() & 1) ? 1 : -1;
231   d_angle_offset = random() % 360;
232   offset = ((random() % ((360 / 4) - 1)) + 1) / 4;
233   density = 1 << ((random() % 4) + 4);  /* Higher density, higher angles */
234
235   if (mono_p)
236     XSetForeground (dpy, draw_gc, default_fg_pixel);
237   else
238     {
239       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
240                   &color->red, &color->green, &color->blue);
241       if ((*got_color = XAllocColor (dpy, cmap, color)))
242         XSetForeground (dpy, draw_gc, color->pixel);
243       else
244         XSetForeground (dpy, draw_gc, default_fg_pixel);
245     }
246   trig (dpy, window, d_angle, factor1, factor2,
247         offset, d_angle_offset, dir, density);
248 }
249
250 static void
251 random_helix_or_trig (Display *dpy, Window window)
252 {
253   int i;
254   Bool free_color = False;
255   XColor color;
256   int width, height;
257   XWindowAttributes xgwa;
258   Colormap cmap;
259   XGetWindowAttributes (dpy, window, &xgwa);
260   width = xgwa.width;
261   height = xgwa.height;
262   cmap = xgwa.colormap;
263
264   if (random() & 1)
265     random_helix(dpy, window, &color, &free_color);
266   else
267     random_trig(dpy, window, &color, &free_color);
268
269   XSync (dpy, True);
270   sleep (5);
271
272   for (i = 0; i < height; i++)
273     {
274       int y = (random () % height);
275       XDrawLine (dpy, window, erase_gc, 0, y, width, y);
276       XFlush (dpy);
277       if ((i % 50) == 0)
278         usleep (10000);
279     }
280   XClearWindow (dpy, window);
281   if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
282   XSync (dpy, True);
283   sleep (1);
284 }
285
286 \f
287 char *progclass = "Helix";
288
289 char *defaults [] = {
290   "Helix.background: black",            /* to placate SGI */
291   0
292 };
293
294 XrmOptionDescRec options [] = { { 0, } };
295
296 void
297 screenhack (Display *dpy, Window window)
298 {
299   init_helix (dpy, window);
300   while (1)
301     random_helix_or_trig (dpy, window);
302 }