http://www.ibiblio.org/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996...
[xscreensaver] / hacks / helix.c
1 /* xscreensaver, Copyright (c) 1992, 1995 Jamie Zawinski <jwz@netscape.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include <math.h>
13 #include "screenhack.h"
14
15 static double sins [360];
16 static double coss [360];
17
18 static GC draw_gc, erase_gc;
19 static unsigned int default_fg_pixel;
20
21 static void
22 init_helix (dpy, window)
23      Display *dpy;
24      Window window;
25 {
26   int i;
27   XGCValues gcv;
28   XWindowAttributes xgwa;
29   Colormap cmap;
30   XGetWindowAttributes (dpy, window, &xgwa);
31   cmap = xgwa.colormap;
32   gcv.foreground = default_fg_pixel =
33     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
34   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
35   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
36   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
37
38   for (i = 0; i < 360; i++)
39     {
40       sins [i] = sin ((((double) i) / 180.0) * M_PI);
41       coss [i] = cos ((((double) i) / 180.0) * M_PI);
42     }
43 }
44
45 static int
46 gcd (a, b)
47      int a, b;
48 {
49   while (b > 0)
50     {
51       int tmp;
52       tmp = a % b;
53       a = b;
54       b = tmp;
55     }
56   return (a < 0 ? -a : a);
57 }
58
59 static void
60 helix (dpy, window,
61        radius1, radius2, d_angle,
62        factor1, factor2, factor3, factor4)
63      Display *dpy;
64      Window window;
65      int radius1, radius2, d_angle;
66      int factor1, factor2, factor3, factor4;
67 {
68   XWindowAttributes xgwa;
69   int width, height;
70   int xmid, ymid;
71   int x1, y1, x2, y2, angle, limit;
72   int i;
73
74   XClearWindow (dpy, window);
75   XGetWindowAttributes (dpy, window, &xgwa);
76   width = xgwa.width;
77   height = xgwa.height;
78
79   xmid = width / 2;
80   ymid = height / 2;
81   x1 = xmid;
82   y1 = ymid + radius2;
83   x2 = xmid;
84   y2 = ymid + radius1;
85   angle = 0;
86   limit = 1 + (360 / gcd (360, d_angle));
87   
88   for (i = 0; i < limit; i++)
89     {
90       int tmp;
91 #define pmod(x,y) (tmp = (x % y), (tmp >= 0 ? tmp : tmp + y))
92       x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]);
93       y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]);
94       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
95       x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]);
96       y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]);
97       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
98       angle += d_angle;
99       XFlush (dpy);
100     }
101 }
102
103 #define min(a,b) ((a)<(b)?(a):(b))
104
105 static void
106 random_helix (dpy, window)
107      Display *dpy;
108      Window window;
109 {
110   Colormap cmap;
111   int width, height;
112   int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
113   double divisor;
114   XColor color;
115   int i, got_color = 0;
116   XWindowAttributes xgwa;
117   XGetWindowAttributes (dpy, window, &xgwa);
118   width = xgwa.width;
119   height = xgwa.height;
120   cmap = xgwa.colormap;
121
122   radius = min (width, height) / 2;
123
124   d_angle = 0;
125   factor1 = 2;
126   factor2 = 2;
127   factor3 = 2;
128   factor4 = 2;
129
130   divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
131
132   if ((random () & 1) == 0)
133     {
134       radius1 = radius;
135       radius2 = radius / divisor;
136     }
137   else
138     {
139       radius2 = radius;
140       radius1 = radius / divisor;
141     }
142
143   while (gcd (360, d_angle) >= 2)
144     d_angle = random () % 360;
145
146 #define random_factor()                         \
147   (((random() % 7) ? ((random() & 1) + 1) : 3)  \
148    * (((random() & 1) * 2) - 1))
149
150   while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
151     {
152       factor1 = random_factor ();
153       factor2 = random_factor ();
154       factor3 = random_factor ();
155       factor4 = random_factor ();
156     }
157
158   if (mono_p)
159     XSetForeground (dpy, draw_gc, default_fg_pixel);
160   else
161     {
162       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
163                   &color.red, &color.green, &color.blue);
164       if ((got_color = XAllocColor (dpy, cmap, &color)))
165         XSetForeground (dpy, draw_gc, color.pixel);
166       else
167         XSetForeground (dpy, draw_gc, default_fg_pixel);
168     }
169   helix (dpy, window, radius1, radius2, d_angle,
170          factor1, factor2, factor3, factor4);
171
172   XSync (dpy, True);
173   sleep (5);
174
175   for (i = 0; i < height; i++)
176     {
177       int y = (random () % height);
178       XDrawLine (dpy, window, erase_gc, 0, y, width, y);
179       XFlush (dpy);
180       if ((i % 50) == 0)
181         usleep (10000);
182     }
183   XClearWindow (dpy, window);
184   if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
185   XSync (dpy, True);
186   sleep (1);
187 }
188
189 \f
190 char *progclass = "Helix";
191
192 char *defaults [] = {
193   "Helix.background: black",            /* to placate SGI */
194   0
195 };
196
197 XrmOptionDescRec options [] = { { 0, } };
198 int options_size = 0;
199
200 void
201 screenhack (dpy, window)
202      Display *dpy;
203      Window window;
204 {
205   init_helix (dpy, window);
206   while (1)
207     random_helix (dpy, window);
208 }