http://www.jwz.org/xscreensaver/xscreensaver-5.10.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)  (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 (Display *dpy, Window window)
112 {
113   struct state *st = (struct state *) calloc (1, sizeof(*st));
114     XGCValues gcv;
115     Colormap cmap;
116     XWindowAttributes xgwa;
117     Bool writeable = False;
118     int i;
119
120     st->dpy = dpy;
121     st->window = window;
122
123    st->delay= get_integer_resource(st->dpy, "delay", "Integer");
124
125     XClearWindow(st->dpy, st->window);
126     XGetWindowAttributes(st->dpy, st->window, &xgwa);
127     st->width  = xgwa.width;
128     st->height = xgwa.height;
129
130     cmap = xgwa.colormap;
131     gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground",
132         "Foreground");
133     st->draw_gc = XCreateGC(st->dpy, st->window, GCForeground, &gcv);
134     gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background");
135     st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
136     cmap = xgwa.colormap;
137     if( st->ncolors ) {
138         free_colors(st->dpy, cmap, st->colors, st->ncolors);
139         st->ncolors = 0;
140     }
141     if( mono_p ) {
142       st->ncolors=1;
143       st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground");
144     } else {
145       st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer");
146       if (st->ncolors < 0 || st->ncolors > NCOLORSMAX)
147         st->ncolors = NCOLORSMAX;
148       make_uniform_colormap(st->dpy, xgwa.visual, cmap, st->colors, &st->ncolors, True,
149           &writeable, False);
150       if (st->ncolors <= 0) {
151         st->ncolors = 1;
152         st->colors[0].pixel=get_pixel_resource(st->dpy, cmap, "foreground","Foreground");
153       }
154     }
155     st->count= get_integer_resource(st->dpy, "count", "Integer");
156     st->frac = get_integer_resource(st->dpy, "fill",  "Integer")*0.01;
157     st->cycle= get_boolean_resource(st->dpy, "cycle", "Cycle");
158     st->disorder=get_float_resource(st->dpy, "disorder", "Float");
159     st->handedness=get_float_resource(st->dpy, "handedness", "Float");
160
161     if(st->frac<0.01) st->frac=0.01;
162     if(st->frac>0.99) st->frac=0.99;
163     if(st->count==0) st->count=st->width/32;
164     if(st->count<1) st->count=1;
165     if(st->count>1000) st->count=1000;
166
167     if(st->worms) free(st->worms);
168     if(st->fill)  free(st->fill);
169
170     st->worms=calloc(st->count, sizeof(struct worm));
171     st->fill=calloc(st->width*st->height, sizeof(int));
172
173     st->dirh[0]=0; st->dirh[1]=1; st->dirh[2]=0; st->dirh[3]=st->width-1;
174     st->dirv[0]=st->height-1; st->dirv[1]=0; st->dirv[2]=1; st->dirv[3]=0;
175     for(i=0;i<st->count;i++) {
176         st->worms[i].h=R(st->width);
177         st->worms[i].v=R(st->height);
178         st->worms[i].s=R(4)+4*PROB(st->handedness);
179         st->worms[i].c=R(st->ncolors);
180         if(st->cycle) { st->worms[i].cc=R(3)+st->ncolors; }
181         else st->worms[i].cc=0;
182     }
183
184     return st;
185 }
186
187 static unsigned long
188 squiral_draw (Display *dpy, Window window, void *closure)
189 {
190   struct state *st = (struct state *) closure;
191   int i;
192
193   if(st->inclear<st->height) {
194     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
195     memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
196     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
197               st->height-st->inclear-1);
198     memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
199     st->inclear++;
200     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->inclear, st->width-1, st->inclear);
201     if (st->inclear < st->height)
202       memset(&st->fill[st->inclear*st->width], 0, sizeof(int)*st->width);
203     XDrawLine(st->dpy, st->window, st->erase_gc, 0, st->height-st->inclear-1, st->width-1,
204               st->height-st->inclear-1);
205     if (st->height - st->inclear >= 1)
206       memset(&st->fill[(st->height-st->inclear-1)*st->width], 0, sizeof(int)*st->width);
207     st->inclear++;
208     if(st->inclear>st->height/2) st->inclear=st->height;
209   }
210   else if(st->cov>(st->frac*st->width*st->height)) {
211     st->inclear=0;
212     st->cov=0;
213   }
214   for(i=0;i<st->count;i++) do_worm(st, &st->worms[i]);
215   return st->delay;
216 }
217
218 static void
219 squiral_reshape (Display *dpy, Window window, void *closure, 
220                  unsigned int w, unsigned int h)
221 {
222 }
223
224 static Bool
225 squiral_event (Display *dpy, Window window, void *closure, XEvent *event)
226 {
227   return False;
228 }
229
230 static void
231 squiral_free (Display *dpy, Window window, void *closure)
232 {
233   struct state *st = (struct state *) closure;
234   free (st);
235 }
236
237
238 static const char *squiral_defaults[] = {
239   ".background: black",
240   ".foreground: white",
241   "*fpsSolid:   true",
242   "*fill:       75",
243   "*count:      0",
244   "*ncolors:    100",
245   "*delay:      10000",
246   "*disorder:   0.005",
247   "*cycle:      False",
248   "*handedness: 0.5",
249   0
250 };
251
252 static XrmOptionDescRec squiral_options[] = {
253     {"-fill", ".fill", XrmoptionSepArg, 0},
254     {"-count", ".count", XrmoptionSepArg, 0},
255     {"-delay", ".delay", XrmoptionSepArg, 0},
256     {"-disorder", ".disorder", XrmoptionSepArg, 0},
257     {"-handedness", ".handedness", XrmoptionSepArg, 0},
258     {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
259     {"-cycle", ".cycle", XrmoptionNoArg, "True"},
260     {"-no-cycle", ".cycle", XrmoptionNoArg, "False"},
261     { 0, 0, 0, 0 }
262 };
263
264 XSCREENSAVER_MODULE ("Squiral", squiral)