1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
2 * Jamie Zawinski <jwz@netscape.com>
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
13 /* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */
15 /* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen
17 * 10-May-97: merged ellipse code by Dan Stromberg <strombrg@nis.acs.uci.edu>
18 * as found in xlockmore 4.03a10.
23 #include "screenhack.h"
26 static double sins [360];
27 static double coss [360];
29 static GC draw_gc, erase_gc;
30 static unsigned int default_fg_pixel;
31 static int erase_speed, sleep_time, erase_mode;
33 void erase_window (Display *dpy, Window win, GC gc, int width, int height,
37 init_helix (Display *dpy, Window window)
41 XWindowAttributes xgwa;
43 XGetWindowAttributes (dpy, window, &xgwa);
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);
51 for (i = 0; i < 360; i++)
53 sins [i] = sin ((((double) i) / 180.0) * M_PI);
54 coss [i] = cos ((((double) i) / 180.0) * M_PI);
68 return (a < 0 ? -a : a);
72 helix (Display *dpy, Window window,
73 int radius1, int radius2, int d_angle,
74 int factor1, int factor2, int factor3, int factor4)
76 XWindowAttributes xgwa;
79 int x1, y1, x2, y2, angle, limit;
82 XClearWindow (dpy, window);
83 XGetWindowAttributes (dpy, window, &xgwa);
94 limit = 1 + (360 / gcd (360, d_angle));
96 for (i = 0; i < limit; i++)
99 #define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y))))
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)]);
107 XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
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)
118 XWindowAttributes xgwa;
125 XClearWindow (dpy, window);
126 XGetWindowAttributes (dpy, window, &xgwa);
127 cmap = xgwa.colormap;
129 height = xgwa.height;
134 while (d_angle >= -360 && d_angle <= 360)
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;
149 #define min(a,b) ((a)<(b)?(a):(b))
152 random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
156 int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
158 XWindowAttributes xgwa;
159 XGetWindowAttributes (dpy, window, &xgwa);
161 height = xgwa.height;
162 cmap = xgwa.colormap;
164 radius = min (width, height) / 2;
172 divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
174 if ((random () & 1) == 0)
177 radius2 = radius / divisor;
182 radius1 = radius / divisor;
185 while (gcd (360, d_angle) >= 2)
186 d_angle = random () % 360;
188 #define random_factor() \
189 (((random() % 7) ? ((random() & 1) + 1) : 3) \
190 * (((random() & 1) * 2) - 1))
192 while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
194 factor1 = random_factor ();
195 factor2 = random_factor ();
196 factor3 = random_factor ();
197 factor4 = random_factor ();
201 XSetForeground (dpy, draw_gc, default_fg_pixel);
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);
209 XSetForeground (dpy, draw_gc, default_fg_pixel);
211 helix (dpy, window, radius1, radius2, d_angle,
212 factor1, factor2, factor3, factor4);
216 random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
220 int radius, d_angle, factor1, factor2;
221 int offset, d_angle_offset, dir, density;
223 XWindowAttributes xgwa;
224 XGetWindowAttributes (dpy, window, &xgwa);
226 height = xgwa.height;
227 cmap = xgwa.colormap;
229 radius = min (width, height) / 2;
232 factor1 = (random() % 8) + 1;
234 factor2 = (random() % 8) + 1;
235 } while (factor1 == factor2);
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 */
243 XSetForeground (dpy, draw_gc, default_fg_pixel);
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);
251 XSetForeground (dpy, draw_gc, default_fg_pixel);
253 trig (dpy, window, d_angle, factor1, factor2,
254 offset, d_angle_offset, dir, density);
258 random_helix_or_trig (Display *dpy, Window window)
261 Bool free_color = False;
264 XWindowAttributes xgwa;
266 XGetWindowAttributes (dpy, window, &xgwa);
268 height = xgwa.height;
269 cmap = xgwa.colormap;
272 random_helix(dpy, window, &color, &free_color);
274 random_trig(dpy, window, &color, &free_color);
277 sleep ( sleep_time );
279 erase_window(dpy, window, erase_gc, width, height, erase_mode, erase_speed);
281 if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
287 char *progclass = "Helix";
289 char *defaults [] = {
290 "Helix.background: black", /* to placate SGI */
291 "Helix.eraseSpeed: 400",
293 "Helix.eraseMode: -1",
297 XrmOptionDescRec options [] = {
298 { "-erase-speed", ".eraseSpeed", XrmoptionSepArg, 0 },
299 { "-delay", ".delay", XrmoptionSepArg, 0 },
300 { "-erase-mode", ".eraseMode", XrmoptionSepArg, 0 },
303 int options_size = (sizeof (options) / sizeof (options[0]));
306 screenhack (Display *dpy, Window window)
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);
313 random_helix_or_trig (dpy, window);