2a0b0fd29bb61016afe8abe1ed8dddb8925c8f38
[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)  (abs(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(st->dpy, 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(st->dpy, xgwa.visual, cmap, st->colors, &st->ncolors, True,
170           &writeable, False);
171       if (st->ncolors <= 0) {
172         st->ncolors = 1;
173         st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground");
174       }
175     }
176     st->count= get_integer_resource(st->dpy, "count", "Integer");
177     st->frac = get_integer_resource(st->dpy, "fill",  "Integer")*0.01;
178     st->cycle= get_boolean_resource(st->dpy, "cycle", "Cycle");
179     st->disorder=get_float_resource(st->dpy, "disorder", "Float");
180     st->handedness=get_float_resource(st->dpy, "handedness", "Float");
181
182     if(st->frac<0.01) st->frac=0.01;
183     if(st->frac>0.99) st->frac=0.99;
184     if(st->count==0) st->count=st->width/32;
185     if(st->count<1) st->count=1;
186     if(st->count>1000) st->count=1000;
187
188     if(st->worms) free(st->worms);
189     if(st->fill)  free(st->fill);
190
191     squiral_init_1 (st);
192
193     return st;
194 }
195
196 static unsigned long
197 squiral_draw (Display *dpy, Window window, void *closure)
198 {
199   struct state *st = (struct state *) closure;
200   int i;
201
202   if(st->inclear<st->height) {
203     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
204     memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
205     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
206               st->height-st->inclear-1);
207     memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
208     st->inclear++;
209     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
210     if (st->inclear < st->height)
211       memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
212     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
213               st->height-st->inclear-1);
214     if (st->height - st->inclear >= 1)
215       memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
216     st->inclear++;
217     if(st->inclear>st->height/2) st->inclear=st->height;
218   }
219   else if(st->cov>(st->frac*st->width*st->height)) {
220     st->inclear=0;
221     st->cov=0;
222   }
223   for(i=0;i<st->count;i++) do_worm(st, &st->worms[i]);
224   return st->delay;
225 }
226
227 static void
228 squiral_reshape (Display *dpy, Window window, void *closure, 
229                  unsigned int w, unsigned int h)
230 {
231   struct state *st = (struct state *) closure;
232   st->width  = w;
233   st->height = h;
234   squiral_init_1 (st);
235   XClearWindow (dpy, window);
236 }
237
238 static Bool
239 squiral_event (Display *dpy, Window window, void *closure, XEvent *event)
240 {
241   return False;
242 }
243
244 static void
245 squiral_free (Display *dpy, Window window, void *closure)
246 {
247   struct state *st = (struct state *) closure;
248   free (st);
249 }
250
251
252 static const char *squiral_defaults[] = {
253   ".background: black",
254   ".foreground: white",
255   "*fpsSolid:   true",
256   "*fill:       75",
257   "*count:      0",
258   "*ncolors:    100",
259   "*delay:      10000",
260   "*disorder:   0.005",
261   "*cycle:      False",
262   "*handedness: 0.5",
263   0
264 };
265
266 static XrmOptionDescRec squiral_options[] = {
267     {"-fill", ".fill", XrmoptionSepArg, 0},
268     {"-count", ".count", XrmoptionSepArg, 0},
269     {"-delay", ".delay", XrmoptionSepArg, 0},
270     {"-disorder", ".disorder", XrmoptionSepArg, 0},
271     {"-handedness", ".handedness", XrmoptionSepArg, 0},
272     {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
273     {"-cycle", ".cycle", XrmoptionNoArg, "True"},
274     {"-no-cycle", ".cycle", XrmoptionNoArg, "False"},
275     { 0, 0, 0, 0 }
276 };
277
278 XSCREENSAVER_MODULE ("Squiral", squiral)