1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
2 * Jamie Zawinski <jwz@jwz.org>
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.
22 /* 25 April 2002: Matthew Strait <straitm@mathcs.carleton.edu> added
23 -subdelay option so the drawing process can be watched */
26 #include "screenhack.h"
29 static double sins [360];
30 static double coss [360];
33 static unsigned int default_fg_pixel;
34 static int sleep_time;
38 init_helix (Display *dpy, Window window)
42 XWindowAttributes xgwa;
44 XGetWindowAttributes (dpy, window, &xgwa);
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);
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)]);
106 XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
109 /* if we sleep every time, it's too slow */
110 if(subdelay && i%16 == 0) usleep(subdelay);
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)
121 XWindowAttributes xgwa;
128 XClearWindow (dpy, window);
129 XGetWindowAttributes (dpy, window, &xgwa);
130 cmap = xgwa.colormap;
132 height = xgwa.height;
137 while (d_angle >= -360 && d_angle <= 360)
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;
150 /* this draws faster, so we sleep somewhat more often */
151 if(subdelay && d_angle%4 == 0) usleep(subdelay);
153 /* without this, the subdelay effect is lost */
158 #define min(a,b) ((a)<(b)?(a):(b))
161 random_helix (Display *dpy, Window window, XColor *color, Bool *got_color)
165 int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
167 XWindowAttributes xgwa;
168 XGetWindowAttributes (dpy, window, &xgwa);
170 height = xgwa.height;
171 cmap = xgwa.colormap;
173 radius = min (width, height) / 2;
181 divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
183 if ((random () & 1) == 0)
186 radius2 = radius / divisor;
191 radius1 = radius / divisor;
194 while (gcd (360, d_angle) >= 2)
195 d_angle = random () % 360;
197 #define random_factor() \
198 (((random() % 7) ? ((random() & 1) + 1) : 3) \
199 * (((random() & 1) * 2) - 1))
201 while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
203 factor1 = random_factor ();
204 factor2 = random_factor ();
205 factor3 = random_factor ();
206 factor4 = random_factor ();
210 XSetForeground (dpy, draw_gc, default_fg_pixel);
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);
218 XSetForeground (dpy, draw_gc, default_fg_pixel);
220 helix (dpy, window, radius1, radius2, d_angle,
221 factor1, factor2, factor3, factor4);
225 random_trig (Display *dpy, Window window, XColor *color, Bool *got_color)
229 int radius, d_angle, factor1, factor2;
230 int offset, d_angle_offset, dir, density;
232 XWindowAttributes xgwa;
233 XGetWindowAttributes (dpy, window, &xgwa);
235 height = xgwa.height;
236 cmap = xgwa.colormap;
238 radius = min (width, height) / 2;
241 factor1 = (random() % 8) + 1;
243 factor2 = (random() % 8) + 1;
244 } while (factor1 == factor2);
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 */
252 XSetForeground (dpy, draw_gc, default_fg_pixel);
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);
260 XSetForeground (dpy, draw_gc, default_fg_pixel);
262 trig (dpy, window, d_angle, factor1, factor2,
263 offset, d_angle_offset, dir, density);
267 random_helix_or_trig (Display *dpy, Window window)
269 Bool free_color = False;
272 XWindowAttributes xgwa;
274 XGetWindowAttributes (dpy, window, &xgwa);
276 height = xgwa.height;
277 cmap = xgwa.colormap;
280 random_helix(dpy, window, &color, &free_color);
282 random_trig(dpy, window, &color, &free_color);
285 screenhack_handle_events (dpy);
286 sleep ( sleep_time );
288 screenhack_handle_events (dpy);
289 erase_full_window(dpy, window);
291 if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
293 screenhack_handle_events (dpy);
298 char *progclass = "Helix";
300 char *defaults [] = {
301 ".background: black",
307 XrmOptionDescRec options [] = {
308 { "-delay", ".delay", XrmoptionSepArg, 0 },
309 { "-subdelay", ".subdelay", XrmoptionSepArg, 0 },
312 int options_size = (sizeof (options) / sizeof (options[0]));
315 screenhack (Display *dpy, Window window)
317 sleep_time = get_integer_resource("delay", "Integer");
318 subdelay = get_integer_resource("subdelay", "Integer");
319 init_helix (dpy, window);
321 random_helix_or_trig (dpy, window);