1 /* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
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
12 /* Algorithm from a Mac program by Chris Tate, written in 1988 or so. */
14 /* 18-Sep-97: Johannes Keukelaar (johannes@nada.kth.se): Improved screen
16 * 10-May-97: merged ellipse code by Dan Stromberg <strombrg@nis.acs.uci.edu>
17 * as found in xlockmore 4.03a10.
21 /* 25 April 2002: Matthew Strait <straitm@mathcs.carleton.edu> added
22 -subdelay option so the drawing process can be watched */
25 #include "screenhack.h"
28 enum draw_state { HELIX, DRAW_HELIX, TRIG, DRAW_TRIG, LINGER, ERASE };
31 enum draw_state dstate;
36 unsigned int default_fg_pixel;
44 int x1, y1, x2, y2, angle, i;
46 int radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
48 int offset, dir, density;
52 helix_init (Display *dpy, Window window)
54 struct state *st = (struct state *) calloc (1, sizeof(*st));
57 XWindowAttributes xgwa;
59 st->sleep_time = get_integer_resource(dpy, "delay", "Integer");
60 st->subdelay = get_integer_resource(dpy, "subdelay", "Integer");
62 XGetWindowAttributes (dpy, window, &xgwa);
63 st->width = xgwa.width;
64 st->height = xgwa.height;
65 st->cmap = xgwa.colormap;
66 gcv.foreground = st->default_fg_pixel =
67 get_pixel_resource (dpy, st->cmap, "foreground", "Foreground");
68 st->draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
69 gcv.foreground = get_pixel_resource (dpy, st->cmap, "background", "Background");
71 for (i = 0; i < 360; i++)
73 st->sins [i] = sin ((((double) i) / 180.0) * M_PI);
74 st->coss [i] = cos ((((double) i) / 180.0) * M_PI);
77 st->dstate = (random() & 1) ? HELIX : TRIG;
92 return (a < 0 ? -a : a);
96 helix (Display *dpy, Window window, struct state *st)
98 int xmid = st->width / 2;
99 int ymid = st->height / 2;
100 int limit = 1 + (360 / gcd (360, st->d_angle));
105 st->y1 = ymid + st->radius2;
107 st->y2 = ymid + st->radius1;
111 /* for (st->i = 0; st->i < limit; st->i++)*/
114 #define pmod(x,y) (tmp=((x) % (y)), (tmp >= 0 ? tmp : (tmp + (y))))
116 st->x1 = xmid + (((double) st->radius1) * st->sins [pmod ((st->angle * st->factor1), 360)]);
117 st->y1 = ymid + (((double) st->radius2) * st->coss [pmod ((st->angle * st->factor2), 360)]);
118 XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2);
119 st->x2 = xmid + (((double) st->radius2) * st->sins [pmod ((st->angle * st->factor3), 360)]);
120 st->y2 = ymid + (((double) st->radius1) * st->coss [pmod ((st->angle * st->factor4), 360)]);
121 XDrawLine (dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2);
122 st->angle += st->d_angle;
131 trig (Display *dpy, Window window, struct state *st)
133 int xmid = st->width / 2;
134 int ymid = st->height / 2;
136 /* while (st->d_angle >= -360 && st->d_angle <= 360)*/
139 int angle = st->d_angle + st->d_angle_offset;
140 st->x1 = (st->sins [pmod(angle * st->factor1, 360)] * xmid) + xmid;
141 st->y1 = (st->coss [pmod(angle * st->factor1, 360)] * ymid) + ymid;
142 st->x2 = (st->sins [pmod(angle * st->factor2 + st->offset, 360)] * xmid) + xmid;
143 st->y2 = (st->coss [pmod(angle * st->factor2 + st->offset, 360)] * ymid) + ymid;
144 XDrawLine(dpy, window, st->draw_gc, st->x1, st->y1, st->x2, st->y2);
145 tmp = (int) 360 / (2 * st->density * st->factor1 * st->factor2);
146 if (tmp == 0) /* Do not want it getting stuck... */
147 tmp = 1; /* Would not need if floating point */
148 st->d_angle += st->dir * tmp;
151 if (st->d_angle < -360 || st->d_angle > 360)
156 #define min(a,b) ((a)<(b)?(a):(b))
159 random_helix (Display *dpy, Window window, struct state *st,
160 XColor *color, Bool *got_color)
165 radius = min (st->width, st->height) / 2;
174 divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
176 if ((random () & 1) == 0)
178 st->radius1 = radius;
179 st->radius2 = radius / divisor;
183 st->radius2 = radius;
184 st->radius1 = radius / divisor;
187 while (gcd (360, st->d_angle) >= 2)
188 st->d_angle = random () % 360;
190 #define random_factor() \
191 (((random() % 7) ? ((random() & 1) + 1) : 3) \
192 * (((random() & 1) * 2) - 1))
194 while (gcd (gcd (gcd (st->factor1, st->factor2), st->factor3), st->factor4) != 1)
196 st->factor1 = random_factor ();
197 st->factor2 = random_factor ();
198 st->factor3 = random_factor ();
199 st->factor4 = random_factor ();
203 XSetForeground (dpy, st->draw_gc, st->default_fg_pixel);
206 hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
207 &color->red, &color->green, &color->blue);
208 if ((*got_color = XAllocColor (dpy, st->cmap, color)))
209 XSetForeground (dpy, st->draw_gc, color->pixel);
211 XSetForeground (dpy, st->draw_gc, st->default_fg_pixel);
214 XClearWindow (dpy, window);
218 random_trig (Display *dpy, Window window, struct state *st,
219 XColor *color, Bool *got_color)
222 st->factor1 = (random() % 8) + 1;
224 st->factor2 = (random() % 8) + 1;
225 } while (st->factor1 == st->factor2);
227 st->dir = (random() & 1) ? 1 : -1;
228 st->d_angle_offset = random() % 360;
229 st->offset = ((random() % ((360 / 4) - 1)) + 1) / 4;
230 st->density = 1 << ((random() % 4) + 4); /* Higher density, higher angles */
233 XSetForeground (dpy, st->draw_gc, st->default_fg_pixel);
236 hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
237 &color->red, &color->green, &color->blue);
238 if ((*got_color = XAllocColor (dpy, st->cmap, color)))
239 XSetForeground (dpy, st->draw_gc, color->pixel);
241 XSetForeground (dpy, st->draw_gc, st->default_fg_pixel);
244 XClearWindow (dpy, window);
248 /* random_helix_or_trig */
250 helix_draw (Display *dpy, Window window, void *closure)
252 struct state *st = (struct state *) closure;
253 Bool free_color = False;
255 int delay = st->subdelay;
256 int erase_delay = 10000;
260 st->eraser = erase_window (dpy, window, st->eraser);
269 delay = st->sleep_time * 1000000;
274 st->eraser = erase_window (dpy, window, st->eraser);
276 if (free_color) XFreeColors (dpy, st->cmap, &color.pixel, 1, 0);
277 st->dstate = (random() & 1) ? HELIX : TRIG;
281 for (ii = 0; ii < 10; ii++) {
282 helix (dpy, window, st);
283 if (st->dstate != DRAW_HELIX)
289 for (ii = 0; ii < 5; ii++) {
290 trig (dpy, window, st);
291 if (st->dstate != DRAW_TRIG)
297 random_helix (dpy, window, st, &color, &free_color);
298 st->dstate = DRAW_HELIX;
302 random_trig(dpy, window, st, &color, &free_color);
303 st->dstate = DRAW_TRIG;
315 helix_reshape (Display *dpy, Window window, void *closure,
316 unsigned int w, unsigned int h)
318 struct state *st = (struct state *) closure;
324 helix_event (Display *dpy, Window window, void *closure, XEvent *event)
330 helix_free (Display *dpy, Window window, void *closure)
332 struct state *st = (struct state *) closure;
338 static const char *helix_defaults [] = {
339 ".background: black",
340 ".foreground: white",
347 static XrmOptionDescRec helix_options [] = {
348 { "-delay", ".delay", XrmoptionSepArg, 0 },
349 { "-subdelay", ".subdelay", XrmoptionSepArg, 0 },
353 XSCREENSAVER_MODULE ("Helix", helix)