ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.25.tar.Z
[xscreensaver] / hacks / helix.c
1 /* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@mcom.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 "screenhack.h"
13 #ifdef __STDC__
14 #include <math.h>       /* for M_PI */
15 #endif
16
17 static double sins [360];
18 static double coss [360];
19
20 static GC draw_gc, erase_gc;
21 static unsigned int default_fg_pixel;
22
23 static void
24 init_helix (dpy, window)
25      Display *dpy;
26      Window window;
27 {
28   int i;
29   XGCValues gcv;
30   XWindowAttributes xgwa;
31   Colormap cmap;
32   XGetWindowAttributes (dpy, window, &xgwa);
33   cmap = xgwa.colormap;
34   gcv.foreground = default_fg_pixel =
35     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
36   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
37   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
38   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
39
40   for (i = 0; i < 360; i++)
41     {
42       sins [i] = sin ((((double) i) / 180.0) * M_PI);
43       coss [i] = cos ((((double) i) / 180.0) * M_PI);
44     }
45 }
46
47 static int
48 gcd (a, b)
49      int a, b;
50 {
51   while (b > 0)
52     {
53       int tmp;
54       tmp = a % b;
55       a = b;
56       b = tmp;
57     }
58   return (a < 0 ? -a : a);
59 }
60
61 static void
62 helix (dpy, window,
63        radius1, radius2, d_angle,
64        factor1, factor2, factor3, factor4)
65      Display *dpy;
66      Window window;
67      int radius1, radius2, d_angle;
68      int factor1, factor2, factor3, factor4;
69 {
70   XWindowAttributes xgwa;
71   int width, height;
72   int xmid, ymid;
73   int x1, y1, x2, y2, angle, limit;
74   int i;
75
76   XClearWindow (dpy, window);
77   XGetWindowAttributes (dpy, window, &xgwa);
78   width = xgwa.width;
79   height = xgwa.height;
80
81   xmid = width / 2;
82   ymid = height / 2;
83   x1 = xmid;
84   y1 = ymid + radius2;
85   x2 = xmid;
86   y2 = ymid + radius1;
87   angle = 0;
88   limit = 1 + (360 / gcd (360, d_angle));
89   
90   for (i = 0; i < limit; i++)
91     {
92       int tmp;
93 #define pmod(x,y) (tmp = (x % y), (tmp >= 0 ? tmp : tmp + y))
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       XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
100       angle += d_angle;
101       XFlush (dpy);
102     }
103 }
104
105 #define min(a,b) ((a)<(b)?(a):(b))
106
107 static void
108 random_helix (dpy, window)
109      Display *dpy;
110      Window window;
111 {
112   Colormap cmap;
113   int width, height;
114   int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
115   double divisor;
116   XColor color;
117   int i, got_color = 0;
118   XWindowAttributes xgwa;
119   XGetWindowAttributes (dpy, window, &xgwa);
120   width = xgwa.width;
121   height = xgwa.height;
122   cmap = xgwa.colormap;
123
124   radius = min (width, height) / 2;
125
126   d_angle = 0;
127   factor1 = 2;
128   factor2 = 2;
129   factor3 = 2;
130   factor4 = 2;
131
132   divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
133
134   if ((random () & 1) == 0)
135     {
136       radius1 = radius;
137       radius2 = radius / divisor;
138     }
139   else
140     {
141       radius2 = radius;
142       radius1 = radius / divisor;
143     }
144
145   while (gcd (360, d_angle) >= 2)
146     d_angle = random () % 360;
147
148 #define random_factor()                         \
149   (((random() % 7) ? ((random() & 1) + 1) : 3)  \
150    * (((random() & 1) * 2) - 1))
151
152   while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
153     {
154       factor1 = random_factor ();
155       factor2 = random_factor ();
156       factor3 = random_factor ();
157       factor4 = random_factor ();
158     }
159
160   if (mono_p)
161     XSetForeground (dpy, draw_gc, default_fg_pixel);
162   else
163     {
164       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
165                   &color.red, &color.green, &color.blue);
166       if ((got_color = XAllocColor (dpy, cmap, &color)))
167         XSetForeground (dpy, draw_gc, color.pixel);
168       else
169         XSetForeground (dpy, draw_gc, default_fg_pixel);
170     }
171   helix (dpy, window, radius1, radius2, d_angle,
172          factor1, factor2, factor3, factor4);
173
174   XSync (dpy, True);
175   sleep (5);
176
177   for (i = 0; i < height; i++)
178     {
179       int y = (random () % height);
180       XDrawLine (dpy, window, erase_gc, 0, y, width, y);
181       XFlush (dpy);
182       if ((i % 50) == 0)
183         usleep (10000);
184     }
185   XClearWindow (dpy, window);
186   if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
187   XSync (dpy, True);
188   sleep (1);
189 }
190
191 \f
192 char *progclass = "Helix";
193
194 char *defaults [] = {
195   "Helix.background: black",            /* to placate SGI */
196   0
197 };
198
199 XrmOptionDescRec options [] = { 0 };
200 int options_size = 0;
201
202 void
203 screenhack (dpy, window)
204      Display *dpy;
205      Window window;
206 {
207   init_helix (dpy, window);
208   while (1)
209     random_helix (dpy, window);
210 }