ftp://ftp.sunet.se/pub/os/Linux/distributions/ultrapenguin/ultrapenguin-1.1/SRPMS...
[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 /* 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 #include <math.h>
23 #include "screenhack.h"
24 #include "erase.h"
25
26 static double sins [360];
27 static double coss [360];
28
29 static GC draw_gc, erase_gc;
30 static unsigned int default_fg_pixel;
31 static int erase_speed, sleep_time, erase_mode;
32
33 void erase_window (Display *dpy, Window win, GC gc, int width, int height,
34                    int mode, int delay);
35
36 static void
37 init_helix (Display *dpy, Window window)
38 {
39   int i;
40   XGCValues gcv;
41   XWindowAttributes xgwa;
42   Colormap cmap;
43   XGetWindowAttributes (dpy, window, &xgwa);
44   cmap = xgwa.colormap;
45   gcv.foreground = default_fg_pixel =
46     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
47   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
48   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
49   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
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
107       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
108       angle += d_angle;
109       XFlush (dpy);
110     }
111 }
112
113 static void
114 trig (Display *dpy, Window window,
115       int d_angle, int factor1, int factor2,
116       int offset, int d_angle_offset, int dir, int density)
117 {
118   XWindowAttributes xgwa;
119   int width, height;
120   int xmid, ymid;
121   int x1, y1, x2, y2;
122   int tmp, angle;
123   Colormap cmap;
124
125   XClearWindow (dpy, window);
126   XGetWindowAttributes (dpy, window, &xgwa);
127   cmap = xgwa.colormap;
128   width = xgwa.width;
129   height = xgwa.height;
130
131   xmid = width / 2;
132   ymid = height / 2;
133
134   while (d_angle >= -360 && d_angle <= 360)
135     {
136       angle = d_angle + d_angle_offset;
137       x1 = (sins [pmod(angle * factor1, 360)] * xmid) + xmid;
138       y1 = (coss [pmod(angle * factor1, 360)] * ymid) + ymid;
139       x2 = (sins [pmod(angle * factor2 + offset, 360)] * xmid) + xmid;
140       y2 = (coss [pmod(angle * factor2 + offset, 360)] * ymid) + ymid;
141       XDrawLine(dpy, window, draw_gc, x1, y1, x2, y2);
142       tmp = (int) 360 / (2 * density * factor1 * factor2);
143       if (tmp == 0)     /* Do not want it getting stuck... */
144         tmp = 1;        /* Would not need if floating point */
145       d_angle += dir * tmp;
146     }
147 }
148
149 #define min(a,b) ((a)<(b)?(a):(b))
150
151 static void
152 random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
153 {
154   Colormap cmap;
155   int width, height;
156   int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
157   double divisor;
158   XWindowAttributes xgwa;
159   XGetWindowAttributes (dpy, window, &xgwa);
160   width = xgwa.width;
161   height = xgwa.height;
162   cmap = xgwa.colormap;
163
164   radius = min (width, height) / 2;
165
166   d_angle = 0;
167   factor1 = 2;
168   factor2 = 2;
169   factor3 = 2;
170   factor4 = 2;
171
172   divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
173
174   if ((random () & 1) == 0)
175     {
176       radius1 = radius;
177       radius2 = radius / divisor;
178     }
179   else
180     {
181       radius2 = radius;
182       radius1 = radius / divisor;
183     }
184
185   while (gcd (360, d_angle) >= 2)
186     d_angle = random () % 360;
187
188 #define random_factor()                         \
189   (((random() % 7) ? ((random() & 1) + 1) : 3)  \
190    * (((random() & 1) * 2) - 1))
191
192   while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
193     {
194       factor1 = random_factor ();
195       factor2 = random_factor ();
196       factor3 = random_factor ();
197       factor4 = random_factor ();
198     }
199
200   if (mono_p)
201     XSetForeground (dpy, draw_gc, default_fg_pixel);
202   else
203     {
204       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
205                   &color->red, &color->green, &color->blue);
206       if ((*got_color = XAllocColor (dpy, cmap, color)))
207         XSetForeground (dpy, draw_gc, color->pixel);
208       else
209         XSetForeground (dpy, draw_gc, default_fg_pixel);
210     }
211   helix (dpy, window, radius1, radius2, d_angle,
212          factor1, factor2, factor3, factor4);
213 }
214
215 static void
216 random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
217 {
218   Colormap cmap;
219   int width, height;
220   int radius, d_angle, factor1, factor2;
221   int offset, d_angle_offset, dir, density;
222
223   XWindowAttributes xgwa;
224   XGetWindowAttributes (dpy, window, &xgwa);
225   width = xgwa.width;
226   height = xgwa.height;
227   cmap = xgwa.colormap;
228
229   radius = min (width, height) / 2;
230
231   d_angle = 0;
232   factor1 = (random() % 8) + 1;
233   do {
234     factor2 = (random() % 8) + 1;
235   } while (factor1 == factor2);
236
237   dir = (random() & 1) ? 1 : -1;
238   d_angle_offset = random() % 360;
239   offset = ((random() % ((360 / 4) - 1)) + 1) / 4;
240   density = 1 << ((random() % 4) + 4);  /* Higher density, higher angles */
241
242   if (mono_p)
243     XSetForeground (dpy, draw_gc, default_fg_pixel);
244   else
245     {
246       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
247                   &color->red, &color->green, &color->blue);
248       if ((*got_color = XAllocColor (dpy, cmap, color)))
249         XSetForeground (dpy, draw_gc, color->pixel);
250       else
251         XSetForeground (dpy, draw_gc, default_fg_pixel);
252     }
253   trig (dpy, window, d_angle, factor1, factor2,
254         offset, d_angle_offset, dir, density);
255 }
256
257 static void
258 random_helix_or_trig (Display *dpy, Window window)
259 {
260   int i;
261   Bool free_color = False;
262   XColor color;
263   int width, height;
264   XWindowAttributes xgwa;
265   Colormap cmap;
266   XGetWindowAttributes (dpy, window, &xgwa);
267   width = xgwa.width;
268   height = xgwa.height;
269   cmap = xgwa.colormap;
270
271   if (random() & 1)
272     random_helix(dpy, window, &color, &free_color);
273   else
274     random_trig(dpy, window, &color, &free_color);
275
276   XSync (dpy, True);
277   sleep ( sleep_time );
278
279   erase_window(dpy, window, erase_gc, width, height, erase_mode, erase_speed);
280
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   "Helix.eraseSpeed: 400",
292   "Helix.delay: 5",
293   "Helix.eraseMode: -1",
294   0
295 };
296
297 XrmOptionDescRec options [] = {   
298   { "-erase-speed",     ".eraseSpeed",          XrmoptionSepArg, 0 },
299   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
300   { "-erase-mode",      ".eraseMode",           XrmoptionSepArg, 0 },
301   { 0 },
302 };
303 int options_size = (sizeof (options) / sizeof (options[0]));
304
305 void
306 screenhack (Display *dpy, Window window)
307 {
308   erase_speed = get_integer_resource("eraseSpeed", "Integer");
309   sleep_time = get_integer_resource("delay", "Integer");
310   erase_mode = get_integer_resource("eraseMode", "Integer");
311   init_helix (dpy, window);
312   while (1)
313     random_helix_or_trig (dpy, window);
314 }