0853faa580812cfd98583b281ba99e577e67bae9
[xscreensaver] / hacks / xspirograph.c
1 /* The Spiral Generator, Copyright (c) 2000 
2  * by Rohit Singh <rohit_singh@hotmail.com>
3  * 
4  * Contains code from / To be used with:
5  * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
6  * Jamie Zawinski <jwz@jwz.org>
7  *
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 
14  * implied warranty.
15  */
16
17 #include <math.h>
18 #include "screenhack.h"
19 #include "erase.h"
20
21 static GC       draw_gc;
22 static int      sleep_time;
23 static int      num_layers;
24 static unsigned int default_fg_pixel;
25
26 static void
27 init_tsg (Display *dpy, Window window)
28 {
29   XGCValues     gcv;
30   Colormap      cmap;
31   XWindowAttributes xgwa;
32
33   XGetWindowAttributes (dpy, window, &xgwa);
34   cmap = xgwa.colormap;
35   gcv.foreground = default_fg_pixel =
36     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
37   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
38   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
39 }
40
41
42 static void
43 go (Display *dpy, Window window,
44        int radius1, int radius2,
45        int d)
46 {
47   XWindowAttributes xgwa;
48   int width, height;
49   int xmid, ymid;
50   int x1, y1, x2, y2;
51   int theta;
52   int delta;
53
54   XGetWindowAttributes (dpy, window, &xgwa);
55   width  = xgwa.width;
56   height = xgwa.height;
57   delta = 1;
58   xmid = width / 2;
59   ymid = height / 2;
60
61   x1 = xmid + radius1 - radius2 + d;
62   y1 = ymid;
63
64
65   for (theta = 1; theta < ( 360 * 100 ); theta++)
66     {
67         x2 = xmid + ((       radius1              /* * * * *            */
68                   - radius2        )             /* This algo simulates */
69                   * cos((      theta            /* the rotation of a    */
70                   * M_PI           )            /* circular disk inside */
71                   / 180           ))            /* a hollow circular    */
72                   + (              d            /* rim. A point on the  */
73                   * cos((((  radius1            /* disk dist d from the */
74                   * theta          )            /* centre, traces the   */
75                   - delta          )            /* path given by this   */
76                   / radius2        )            /* equation.            */
77                   *             M_PI            /* A deviation (error)  */
78                   / 180            )            /* of delta needs to be */
79                                    );           /* given, which greatly */
80                                                 /* adds to the beauty   */
81         y2 = ymid + (                           /* of the figure.       */
82                      ( radius1 - radius2        /*                      */
83                       ) * sin                   /* Imperfection adds to */
84                        (                        /* beauty, symbolically */
85                         ( theta * M_PI          /* ...                  */
86                          ) / 180                /* Algo deduced by      */
87                           )                     /* Rohit Singh, Jan'00  */
88                            ) +                  /* based on a toy he    */
89                             ( d * sin           /* used to play with    */
90                              (                  /* when he was a kid.  */
91                               (                 /*            * * * * */
92                                (                
93                                 ( radius1 * theta
94                                  ) - delta
95                                   ) / radius2
96                                    ) * M_PI / 180
97                                     )
98                                      );
99                                 
100
101         XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
102
103         x1 = x2;
104         y1 = y2;
105         XFlush (dpy);
106     }
107 }
108
109
110 #define min(a,b) ((a)<(b)?(a):(b))
111
112 static void
113 getset (Display *dpy, Window window, XColor *color, Bool *got_color)
114 {
115   Colormap cmap;
116   int width, height;
117   int radius, radius1, radius2;
118   double divisor;
119   XWindowAttributes xgwa;
120   int distance;
121   int counter = 0;
122
123   XGetWindowAttributes (dpy, window, &xgwa);
124   width = xgwa.width;
125   height = xgwa.height;
126   cmap = xgwa.colormap;
127
128   radius = min (width, height) / 2;
129
130   XClearWindow (dpy, window);
131
132
133   for(counter = 0; counter < num_layers; counter ++)
134   {
135     divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
136
137     radius1 = radius;
138     radius2 = radius / divisor + 5;
139     distance = 100 + (random() % 200);
140
141     if (mono_p)
142       XSetForeground (dpy, draw_gc, default_fg_pixel);
143     else
144     {
145       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
146                   &color->red, &color->green, &color->blue);
147       if ((*got_color = XAllocColor (dpy, cmap, color)))
148         XSetForeground (dpy, draw_gc, color->pixel);
149       else
150         XSetForeground (dpy, draw_gc, default_fg_pixel);
151     }
152     go (dpy, window, radius1, -radius2, distance);
153
154     /* once again, with a parameter negated, just for kicks */
155     if (mono_p)
156       XSetForeground (dpy, draw_gc, default_fg_pixel);
157     else
158     {
159       hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
160                   &color->red, &color->green, &color->blue);
161       if ((*got_color = XAllocColor (dpy, cmap, color)))
162         XSetForeground (dpy, draw_gc, color->pixel);
163       else
164         XSetForeground (dpy, draw_gc, default_fg_pixel);
165     }
166     go (dpy, window, radius1, radius2, distance);
167   }
168 }
169
170 static void
171 getset_go (Display *dpy, Window window)
172 {
173   Bool          free_color = False;
174   XColor        color;
175   int           width;
176   int           height;
177   XWindowAttributes xgwa;
178   Colormap      cmap;
179
180   XGetWindowAttributes (dpy, window, &xgwa);
181
182   width  = xgwa.width;
183   height = xgwa.height;
184   cmap   = xgwa.colormap;
185
186   getset(dpy, window, &color, &free_color);
187
188   XSync (dpy, False);
189   screenhack_handle_events (dpy);
190   sleep ( sleep_time );
191
192   screenhack_handle_events (dpy);
193   erase_full_window(dpy, window);
194
195   if (free_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
196   XSync (dpy, False);
197   screenhack_handle_events (dpy);
198   sleep (1);
199 }
200
201 char *progclass = "XSpiroGraph";
202
203 char *defaults [] = {
204   ".background: black",
205   "*delay:      5",
206   "*layers:     1",
207   0
208 };
209
210 XrmOptionDescRec options [] = {   
211   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
212   { "-layers",          ".layers",              XrmoptionSepArg, 0 },
213   { 0, 0, 0, 0 }
214 };
215 int options_size = (sizeof (options) / sizeof (options[0]));
216
217 void
218 screenhack (Display *dpy, Window window)
219 {
220   sleep_time = get_integer_resource("delay", "Integer");
221   num_layers = get_integer_resource("layers", "Integer");
222   init_tsg (dpy, window);
223   while (1)
224    getset_go (dpy, window);
225 }