From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / squiral.c
1 /* squiral, by "Jeff Epler" <jepler@inetnebr.com>, 18-mar-1999.
2  *
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 
9  * implied warranty.
10  */
11
12 #include "screenhack.h"
13 #include "colors.h"
14 #include "erase.h"
15 #include "yarandom.h"
16
17 #define R(x)  (random()%x)
18 #define PROB(x) (frand(1.0) < (x))
19
20 #define NCOLORSMAX 255
21 #define STATES 8
22
23 /* 0- 3 left-winding  */
24 /* 4- 7 right-winding */
25
26 struct worm {
27     int h;
28     int v;
29     int s;
30     int c;
31     int cc;
32 };
33
34
35 struct state {
36   Display *dpy;
37   Window window;
38
39    int width, height, count, cycle;
40    double frac, disorder, handedness;
41    int ncolors;
42    GC draw_gc, erase_gc;
43    XColor colors[NCOLORSMAX];
44
45    int delay;
46
47    int cov;
48    int dirh[4];
49    int dirv[4];
50
51    int *fill;
52
53    struct worm *worms;
54    int inclear;
55 };
56
57 #define CLEAR1(x,y) (!st->fill[((y)%st->height)*st->width+(x)%st->width])
58 #define MOVE1(x,y) (st->fill[((y)%st->height)*st->width+(x)%st->width]=1, XDrawPoint(st->dpy, st->window, st->draw_gc, (x)%st->width,(y)%st->height), st->cov++)
59
60 #define CLEARDXY(x,y,dx,dy) CLEAR1(x+dx, y+dy) && CLEAR1(x+dx+dx, y+dy+dy)
61 #define MOVEDXY(x,y,dx,dy)  MOVE1 (x+dx, y+dy), MOVE1 (x+dx+dx, y+dy+dy)
62
63 #define CLEAR(d) CLEARDXY(w->h,w->v, st->dirh[d],st->dirv[d])
64 #define MOVE(d) (XSetForeground(st->dpy, st->draw_gc, st->colors[w->c].pixel), \
65                   MOVEDXY(w->h,w->v, st->dirh[d],st->dirv[d]), \
66                   w->h=w->h+st->dirh[d]*2, \
67                   w->v=w->v+st->dirv[d]*2, dir=d)
68
69 #define RANDOM (void) (w->h = R(st->width), w->v = R(st->height), w->c = R(st->ncolors), \
70                   type=R(2), dir=R(4), (st->cycle && (w->cc=R(3)+st->ncolors)))
71
72
73
74 #define SUCC(x) ((x+1)%4)
75 #define PRED(x) ((x+3)%4)
76 #define CCW     PRED(dir)
77 #define CW      SUCC(dir)
78 #define REV     ((dir+2)%4)
79 #define STR     (dir)
80 #define TRY(x)  if (CLEAR(x)) { MOVE(x); break; }
81
82 static void
83 do_worm(struct state *st, struct worm *w)
84 {
85     int type = w->s / 4;
86     int dir = w->s % 4;
87
88     w->c = (w->c+w->cc) % st->ncolors;
89
90     if (PROB(st->disorder)) type=PROB(st->handedness);
91     switch(type) {
92     case 0: /* CCW */
93         TRY(CCW)
94         TRY(STR)
95         TRY(CW)
96         RANDOM;
97         break;
98     case 1: /* CW */
99         TRY(CW)
100         TRY(STR)
101         TRY(CCW)
102         RANDOM;
103         break;
104     }
105     w->s = type*4+dir;
106     w->h = w->h % st->width;
107     w->v = w->v % st->height;
108 }
109
110 static void
111 squiral_init_1 (struct state *st)
112 {
113     int i;
114     if (st->worms) free (st->worms);
115     if (st->fill) free (st->fill);
116
117     st->worms=calloc(st->count, sizeof(struct worm));
118     st->fill=calloc(st->width*st->height, sizeof(int));
119
120     st->dirh[0]=0; st->dirh[1]=1; st->dirh[2]=0; st->dirh[3]=st->width-1;
121     st->dirv[0]=st->height-1; st->dirv[1]=0; st->dirv[2]=1; st->dirv[3]=0;
122     for(i=0;i<st->count;i++) {
123         st->worms[i].h=R(st->width);
124         st->worms[i].v=R(st->height);
125         st->worms[i].s=R(4)+4*PROB(st->handedness);
126         st->worms[i].c=R(st->ncolors);
127         if(st->cycle) { st->worms[i].cc=R(3)+st->ncolors; }
128         else st->worms[i].cc=0;
129     }
130 }
131
132 static void *
133 squiral_init (Display *dpy, Window window)
134 {
135   struct state *st = (struct state *) calloc (1, sizeof(*st));
136     XGCValues gcv;
137     Colormap cmap;
138     XWindowAttributes xgwa;
139     Bool writeable = False;
140
141     st->dpy = dpy;
142     st->window = window;
143
144    st->delay= get_integer_resource(st->dpy, "delay", "Integer");
145
146     XClearWindow(st->dpy, st->window);
147     XGetWindowAttributes(st->dpy, st->window, &xgwa);
148     st->width  = xgwa.width;
149     st->height = xgwa.height;
150
151     cmap = xgwa.colormap;
152     gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground",
153         "Foreground");
154     st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
155     gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background");
156     st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
157     cmap = xgwa.colormap;
158     if( st->ncolors ) {
159         free_colors(xgwa.screen, cmap, st->colors, st->ncolors);
160         st->ncolors = 0;
161     }
162     if( mono_p ) {
163       st->ncolors=1;
164       st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground");
165     } else {
166       st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer");
167       if (st->ncolors < 0 || st->ncolors > NCOLORSMAX)
168         st->ncolors = NCOLORSMAX;
169       make_uniform_colormap(xgwa.screen, xgwa.visual, cmap,
170                             st->colors, &st->ncolors, True,
171           &writeable, False);
172       if (st->ncolors <= 0) {
173         st->ncolors = 1;
174         st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground");
175       }
176     }
177     st->count= get_integer_resource(st->dpy, "count", "Integer");
178     st->frac = get_integer_resource(st->dpy, "fill",  "Integer")*0.01;
179     st->cycle= get_boolean_resource(st->dpy, "cycle", "Cycle");
180     st->disorder=get_float_resource(st->dpy, "disorder", "Float");
181     st->handedness=get_float_resource(st->dpy, "handedness", "Float");
182
183     if(st->frac<0.01) st->frac=0.01;
184     if(st->frac>0.99) st->frac=0.99;
185     if(st->count==0) st->count=st->width/32;
186     if(st->count<1) st->count=1;
187     if(st->count>1000) st->count=1000;
188
189     if(st->worms) free(st->worms);
190     if(st->fill)  free(st->fill);
191
192     squiral_init_1 (st);
193
194     return st;
195 }
196
197 static unsigned long
198 squiral_draw (Display *dpy, Window window, void *closure)
199 {
200   struct state *st = (struct state *) closure;
201   int i;
202
203   if(st->inclear<st->height) {
204     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
205     memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
206     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
207               st->height-st->inclear-1);
208     memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
209     st->inclear++;
210     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
211     if (st->inclear < st->height)
212       memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
213     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
214               st->height-st->inclear-1);
215     if (st->height - st->inclear >= 1)
216       memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
217     st->inclear++;
218     if(st->inclear>st->height/2) st->inclear=st->height;
219   }
220   else if(st->cov>(st->frac*st->width*st->height)) {
221     st->inclear=0;
222     st->cov=0;
223   }
224   for(i=0;i<st->count;i++) do_worm(st, &st->worms[i]);
225   return st->delay;
226 }
227
228 static void
229 squiral_reshape (Display *dpy, Window window, void *closure, 
230                  unsigned int w, unsigned int h)
231 {
232   struct state *st = (struct state *) closure;
233   st->width  = w;
234   st->height = h;
235   squiral_init_1 (st);
236   XClearWindow (dpy, window);
237 }
238
239 static Bool
240 squiral_event (Display *dpy, Window window, void *closure, XEvent *event)
241 {
242   struct state *st = (struct state *) closure;
243   if (screenhack_event_helper (dpy, window, event))
244     {
245       squiral_init_1 (st);
246       XClearWindow (dpy, window);
247       return True;
248     }
249   return False;
250 }
251
252 static void
253 squiral_free (Display *dpy, Window window, void *closure)
254 {
255   struct state *st = (struct state *) closure;
256   free (st);
257 }
258
259
260 static const char *squiral_defaults[] = {
261   ".background: black",
262   ".foreground: white",
263   "*fpsSolid:   true",
264   "*fill:       75",
265   "*count:      0",
266   "*ncolors:    100",
267   "*delay:      10000",
268   "*disorder:   0.005",
269   "*cycle:      False",
270   "*handedness: 0.5",
271 #ifdef HAVE_MOBILE
272   "*ignoreRotation: True",
273 #endif
274   0
275 };
276
277 static XrmOptionDescRec squiral_options[] = {
278     {"-fill", ".fill", XrmoptionSepArg, 0},
279     {"-count", ".count", XrmoptionSepArg, 0},
280     {"-delay", ".delay", XrmoptionSepArg, 0},
281     {"-disorder", ".disorder", XrmoptionSepArg, 0},
282     {"-handedness", ".handedness", XrmoptionSepArg, 0},
283     {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
284     {"-cycle", ".cycle", XrmoptionNoArg, "True"},
285     {"-no-cycle", ".cycle", XrmoptionNoArg, "False"},
286     { 0, 0, 0, 0 }
287 };
288
289 XSCREENSAVER_MODULE ("Squiral", squiral)