http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / helix.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
2  *  Jamie Zawinski <jwz@jwz.org>
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 /* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen
16  *            eraser.
17  * 10-May-97: merged ellipse code by Dan Stromberg <strombrg@nis.acs.uci.edu>
18  *            as found in xlockmore 4.03a10.
19  * 1992:      jwz created.
20  */
21
22 /* 25 April 2002: Matthew Strait <straitm@mathcs.carleton.edu> added
23 -subdelay option so the drawing process can be watched */
24
25 #include <math.h>
26 #include "screenhack.h"
27 #include "erase.h"
28
29 static double sins [360];
30 static double coss [360];
31
32 static GC draw_gc;
33 static unsigned int default_fg_pixel;
34 static int sleep_time;
35 static int subdelay;
36
37 static void
38 init_helix (Display *dpy, Window window)
39 {
40   int i;
41   XGCValues gcv;
42   XWindowAttributes xgwa;
43   Colormap cmap;
44   XGetWindowAttributes (dpy, window, &xgwa);
45   cmap = xgwa.colormap;
46   gcv.foreground = default_fg_pixel =
47     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
48   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
49   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
50
51   for (i = 0; i < 360; i++)
52     {
53       sins [i] = sin ((((double) i) / 180.0) * M_PI);
54       coss [i] = cos ((((double) i) / 180.0) * M_PI);
55     }
56 }
57
58 static int
59 gcd (int a, int b)
60 {
61   while (b > 0)
62     {
63       int tmp;
64       tmp = a % b;
65       a = b;
66       b = tmp;
67     }
68   return (a < 0 ? -a : a);
69 }
70
71 static void
72 helix (Display *dpy, Window window,
73        int radius1, int radius2, int d_angle,
74        int factor1, int factor2, int factor3, int factor4)
75 {
76   XWindowAttributes xgwa;
77   int width, height;
78   int xmid, ymid;
79   int x1, y1, x2, y2, angle, limit;
80   int i;
81
82   XClearWindow (dpy, window);
83   XGetWindowAttributes (dpy, window, &xgwa);
84   width = xgwa.width;
85   height = xgwa.height;
86
87   xmid = width / 2;
88   ymid = height / 2;
89   x1 = xmid;
90   y1 = ymid + radius2;
91   x2 = xmid;
92   y2 = ymid + radius1;
93   angle = 0;
94   limit = 1 + (360 / gcd (360, d_angle));
95   
96   for (i = 0; i < limit; i++)
97     {
98       int tmp;
99 #define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y))))
100
101       x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]);
102       y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]);
103       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
104       x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]);
105       y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]);
106       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
107       angle += d_angle;
108
109       /* if we sleep every time, it's too slow */
110       if(subdelay && i%16 == 0) usleep(subdelay);
111
112       XFlush (dpy);
113     }
114 }
115
116 static void
117 trig (Display *dpy, Window window,
118       int d_angle, int factor1, int factor2,
119       int offset, int d_angle_offset, int dir, int density)
120 {
121   XWindowAttributes xgwa;
122   int width, height;
123   int xmid, ymid;
124   int x1, y1, x2, y2;
125   int tmp, angle;
126   Colormap cmap;
127
128   XClearWindow (dpy, window);
129   XGetWindowAttributes (dpy, window, &xgwa);
130   cmap = xgwa.colormap;
131   width = xgwa.width;
132   height = xgwa.height;
133
134   xmid = width / 2;
135   ymid = height / 2;
136
137   while (d_angle >= -360 && d_angle <= 360)
138     {
139       angle = d_angle + d_angle_offset;
140       x1 = (sins [pmod(angle * factor1, 360)] * xmid) + xmid;
141       y1 = (coss [pmod(angle * factor1, 360)] * ymid) + ymid;
142       x2 = (sins [pmod(angle * factor2 + offset, 360)] * xmid) + xmid;
143       y2 = (coss [pmod(angle * factor2 + offset, 360)] * ymid) + ymid;
144       XDrawLine(dpy, window, draw_gc, x1, y1, x2, y2);
145       tmp = (int) 360 / (2 * density * factor1 * factor2);
146       if (tmp == 0)     /* Do not want it getting stuck... */
147         tmp = 1;        /* Would not need if floating point */
148       d_angle += dir * tmp;
149
150       /* this draws faster, so we sleep somewhat more often */
151       if(subdelay && d_angle%4 == 0) usleep(subdelay);
152       
153       /* without this, the subdelay effect is lost */
154       XFlush (dpy);
155     }
156 }
157
158 #define min(a,b) ((a)<(b)?(a):(b))
159
160 static void
161 random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
162 {
163   Colormap cmap;
164   int width, height;
165   int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
166   double divisor;
167   XWindowAttributes xgwa;
168   XGetWindowAttributes (dpy, window, &xgwa);
169   width = xgwa.width;
170   height = xgwa.height;
171   cmap = xgwa.colormap;
172
173   radius = min (width, height) / 2;
174
175   d_angle = 0;
176   factor1 = 2;
177   factor2 = 2;
178   factor3 = 2;
179   factor4 = 2;
180
181   divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
182
183   if ((random () & 1) == 0)
184     {
185       radius1 = radius;
186       radius2 = radius / divisor;
187     }
188   else
189     {
190       radius2 = radius;
191       radius1 = radius / divisor;
192     }
193
194   while (gcd (360, d_angle) >= 2)
195     d_angle = random () % 360;
196
197 #define random_factor()                         \
198   (((random() % 7) ? ((random() & 1) + 1) : 3)  \
199    * (((random() & 1) * 2) - 1))
200
201   while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
202     {
203       factor1 = random_factor ();
204       factor2 = random_factor ();
205       factor3 = random_factor ();
206       factor4 = random_factor ();
207     }
208
209   if (mono_p)
210     XSetForeground (dpy, draw_gc, default_fg_pixel);
211   else
212     {
213       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
214                   &color->red, &color->green, &color->blue);
215       if ((*got_color = XAllocColor (dpy, cmap, color)))
216         XSetForeground (dpy, draw_gc, color->pixel);
217       else
218         XSetForeground (dpy, draw_gc, default_fg_pixel);
219     }
220   helix (dpy, window, radius1, radius2, d_angle,
221          factor1, factor2, factor3, factor4);
222 }
223
224 static void
225 random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
226 {
227   Colormap cmap;
228   int width, height;
229   int radius, d_angle, factor1, factor2;
230   int offset, d_angle_offset, dir, density;
231
232   XWindowAttributes xgwa;
233   XGetWindowAttributes (dpy, window, &xgwa);
234   width = xgwa.width;
235   height = xgwa.height;
236   cmap = xgwa.colormap;
237
238   radius = min (width, height) / 2;
239
240   d_angle = 0;
241   factor1 = (random() % 8) + 1;
242   do {
243     factor2 = (random() % 8) + 1;
244   } while (factor1 == factor2);
245
246   dir = (random() & 1) ? 1 : -1;
247   d_angle_offset = random() % 360;
248   offset = ((random() % ((360 / 4) - 1)) + 1) / 4;
249   density = 1 << ((random() % 4) + 4);  /* Higher density, higher angles */
250
251   if (mono_p)
252     XSetForeground (dpy, draw_gc, default_fg_pixel);
253   else
254     {
255       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
256                   &color->red, &color->green, &color->blue);
257       if ((*got_color = XAllocColor (dpy, cmap, color)))
258         XSetForeground (dpy, draw_gc, color->pixel);
259       else
260         XSetForeground (dpy, draw_gc, default_fg_pixel);
261     }
262   trig (dpy, window, d_angle, factor1, factor2,
263         offset, d_angle_offset, dir, density);
264 }
265
266 static void
267 random_helix_or_trig (Display *dpy, Window window)
268 {
269   Bool free_color = False;
270   XColor color;
271   int width, height;
272   XWindowAttributes xgwa;
273   Colormap cmap;
274   XGetWindowAttributes (dpy, window, &xgwa);
275   width = xgwa.width;
276   height = xgwa.height;
277   cmap = xgwa.colormap;
278
279   if (random() & 1)
280     random_helix(dpy, window, &color, &free_color);
281   else
282     random_trig(dpy, window, &color, &free_color);
283
284   XSync (dpy, False);
285   screenhack_handle_events (dpy);
286   sleep ( sleep_time );
287
288   screenhack_handle_events (dpy);
289   erase_full_window(dpy, window);
290
291   if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
292   XSync (dpy, False);
293   screenhack_handle_events (dpy);
294   sleep (1);
295 }
296
297 \f
298 char *progclass = "Helix";
299
300 char *defaults [] = {
301   ".background: black",
302   "*delay:      5",
303   "*subdelay:   0",
304   0
305 };
306
307 XrmOptionDescRec options [] = {   
308   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
309   { "-subdelay",        ".subdelay",            XrmoptionSepArg, 0 },
310   { 0,                  0,                      0,               0 },
311 };
312 int options_size = (sizeof (options) / sizeof (options[0]));
313
314 void
315 screenhack (Display *dpy, Window window)
316 {
317   sleep_time = get_integer_resource("delay", "Integer");
318   subdelay = get_integer_resource("subdelay", "Integer");
319   init_helix (dpy, window);
320   while (1)
321     random_helix_or_trig (dpy, window);
322 }