1 /* The Spiral Generator, Copyright (c) 2000
2 * by Rohit Singh <rohit_singh@hotmail.com>
4 * Contains code from / To be used with:
5 * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
6 * Jamie Zawinski <jwz@jwz.org>
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notices appear in all copies and that both that
11 * copyright notices and this permission notice appear in supporting
12 * documentation. No representations are made about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
16 * Modified (Dec 2001) by Matthew Strait <straitm@mathcs.carleton.edu>
17 * Added -subdelay and -alwaysfinish
18 * Prevented redrawing over existing lines
22 #include "screenhack.h"
28 XWindowAttributes xgwa;
34 unsigned int default_fg_pixel;
48 enum curstate { NEW_LAYER, DRAW, ERASE1, ERASE2 } drawstate;
54 init_tsg (struct state *st)
59 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
60 cmap = st->xgwa.colormap;
61 gcv.foreground = st->default_fg_pixel =
62 get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
63 st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
64 gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background");
69 go (struct state *st, int radius1, int radius2, int d)
76 width = st->xgwa.width;
77 height = st->xgwa.height;
83 st->x1 = xmid + radius1 - radius2 + d;
87 /* for (theta = 1; / * theta < ( 360 * 100 ) * /; theta++) */
88 /* see below about alwaysfinish */
90 tmpx = xmid + (( radius1 /* * * * * */
91 - radius2 ) /* This algo simulates */
92 * cos(( st->theta /* the rotation of a */
93 * M_PI ) /* circular disk inside */
94 / 180 )) /* a hollow circular */
95 + ( d /* rim. A point on the */
96 * cos(((( radius1 /* disk dist d from the */
97 * st->theta ) /* centre, traces the */
98 - delta ) /* path given by this */
99 / radius2 ) /* equation. */
100 * M_PI /* A deviation (error) */
101 / 180 ) /* of delta needs to be */
102 ); /* given, which greatly */
103 /* adds to the beauty */
104 tmpy = ymid + ( /* of the figure. */
105 ( radius1 - radius2 /* */
106 ) * sin /* Imperfection adds to */
107 ( /* beauty, symbolically */
108 ( st->theta * M_PI /* ... */
109 ) / 180 /* Algo deduced by */
110 ) /* Rohit Singh, Jan'00 */
111 ) + /* based on a toy he */
112 ( d * sin /* used to play with */
113 ( /* when he was a kid. */
116 ( radius1 * st->theta
123 /*makes integers from the calculated values to do the drawing*/
127 /*stores the first values for later reference*/
135 XDrawLine (st->dpy, st->window, st->draw_gc,
136 st->x1, st->y1, st->x2, st->y2);
141 /* compares the exact values calculated to the first
142 exact values calculated */
143 /* this will break when nothing new is being drawn */
144 if(tmpx == st->firstx && tmpy == st->firsty && st->theta != 1) {
145 st->firstx = st->firsty = 0;
150 /* this will break after 36000 iterations if
151 the -alwaysfinish option is not specified */
152 if(!st->always_finish_p && st->theta > ( 360 * 100 ) ) {
153 st->firstx = st->firsty = 0;
165 #define min(a,b) ((a)<(b)?(a):(b))
169 pick_new (struct state *st)
171 int radius = min (st->xgwa.width, st->xgwa.height) / 2;
172 st->divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
173 st->radius1 = radius;
174 st->radius2 = radius / st->divisor + 5;
175 st->distance = 100 + (random() % 200);
181 xspirograph_init (Display *dpy, Window window)
183 struct state *st = (struct state *) calloc (1, sizeof(*st));
186 st->long_delay = get_integer_resource(st->dpy, "delay", "Integer");
187 st->sub_sleep_time = get_integer_resource(st->dpy, "subdelay", "Integer");
188 st->num_layers = get_integer_resource(st->dpy, "layers", "Integer");
189 st->always_finish_p = get_boolean_resource (st->dpy, "alwaysfinish", "Boolean");
191 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
195 st->drawstate = NEW_LAYER;
202 new_colors (struct state *st)
205 XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
208 hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
209 &st->color.red, &st->color.green, &st->color.blue);
210 if ((st->got_color = XAllocColor (st->dpy, st->xgwa.colormap,
212 XSetForeground (st->dpy, st->draw_gc, st->color.pixel);
214 XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
221 xspirograph_draw (Display *dpy, Window window, void *closure)
223 struct state *st = (struct state *) closure;
224 Bool free_color = False;
225 Bool flip_p = (st->counter & 1);
228 switch (st->drawstate) {
230 /* 5 sec delay before starting the erase */
231 st->drawstate = ERASE2;
232 /* shouldn't this use the configured long_delay value??? */
233 return (st->long_delay == 0 ? 0 : 5000000);
236 /* erase, delaying 1/50th sec between frames */
237 st->eraser = erase_window(st->dpy, st->window, st->eraser);
239 /* shouldn't this be a configured pause??? */
241 st->drawstate = NEW_LAYER;
242 /* just finished erasing -- leave screen black for 1 sec */
243 return (st->long_delay == 0 ? 0 : 1000000);
246 /* most common case put in front */
247 for (i = 0; i < 1000; i++) {
248 if (go(st, st->radius1, (flip_p ? st->radius2 : -st->radius2),
250 st->drawstate = NEW_LAYER;
254 /* Next draw is delayed sleep_time (initialized value)*/
255 return st->sub_sleep_time;
258 /* Increment counter */
260 if (st->counter > (2 * st->num_layers)) {
261 /* reset to zero, free, and erase next time through */
264 XFreeColors (st->dpy, st->xgwa.colormap, &st->color.pixel, 1, 0);
265 st->drawstate = ERASE1;
267 /* first, third, fifth, ... time through */
272 st->drawstate = DRAW;
274 /* No delay to the next draw */
279 fprintf(stderr, "%s: invalid state\n", progname);
283 return st->sub_sleep_time;
289 xspirograph_reshape (Display *dpy, Window window, void *closure,
290 unsigned int w, unsigned int h)
292 struct state *st = (struct state *) closure;
293 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
297 xspirograph_event (Display *dpy, Window window, void *closure, XEvent *event)
303 xspirograph_free (Display *dpy, Window window, void *closure)
305 struct state *st = (struct state *) closure;
310 static const char *xspirograph_defaults [] = {
311 ".background: black",
312 ".foreground: white",
317 "*alwaysfinish: false",
321 static XrmOptionDescRec xspirograph_options [] = {
322 { "-delay", ".delay", XrmoptionSepArg, 0 },
323 { "-subdelay", ".subdelay", XrmoptionSepArg, 0 },
324 { "-layers", ".layers", XrmoptionSepArg, 0 },
325 { "-alwaysfinish", ".alwaysfinish", XrmoptionNoArg, "true"},
326 { "-noalwaysfinish", ".alwaysfinish", XrmoptionNoArg, "false"},
330 XSCREENSAVER_MODULE ("XSpirograph", xspirograph)