http://ftp.x.org/contrib/applications/xscreensaver-3.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) (abs(random())<(x*(double)RAND_MAX))
19
20 #define NCOLORSMAX 255
21 static int width, height, count, cycle;
22 static double frac, disorder, handedness;
23 static int ncolors=0;
24 static GC draw_gc, erase_gc;
25 static XColor colors[NCOLORSMAX];
26 #define STATES 8
27
28 /* 0- 3 left-winding  */
29 /* 4- 7 right-winding */
30
31 #define CLEAR1(x,y) (!fill[((y)%height)*width+(x)%width])
32 #define MOVE1(x,y) (fill[((y)%height)*width+(x)%width]=1, XDrawPoint(dpy, window, draw_gc, (x)%width,(y)%height), cov++)
33
34 static int cov;
35 static int dirh[4];
36 static int dirv[4];
37
38 static int *fill;
39
40 #define CLEARDXY(x,y,dx,dy) CLEAR1(x+dx, y+dy) && CLEAR1(x+dx+dx, y+dy+dy)
41 #define MOVEDXY(x,y,dx,dy)  MOVE1 (x+dx, y+dy), MOVE1 (x+dx+dx, y+dy+dy)
42
43 #define CLEAR(d) CLEARDXY(w->h,w->v, dirh[d],dirv[d])
44 #define MOVE(d) (XSetForeground(dpy, draw_gc, colors[w->c].pixel), \
45                   MOVEDXY(w->h,w->v, dirh[d],dirv[d]), \
46                   w->h=w->h+dirh[d]*2, \
47                   w->v=w->v+dirv[d]*2, dir=d)
48
49 #define RANDOM (void) (w->h = R(width), w->v = R(height), w->c = R(ncolors), \
50                   type=R(2), dir=R(4), (cycle && (w->cc=R(3)+ncolors)))
51
52 struct worm {
53     int h;
54     int v;
55     int s;
56     int c;
57     int cc;
58 } *worms;
59
60 #define SUCC(x) ((x+1)%4)
61 #define PRED(x) ((x+3)%4)
62 #define CCW     PRED(dir)
63 #define CW      SUCC(dir)
64 #define REV     ((dir+2)%4)
65 #define STR     (dir)
66 #define TRY(x)  if (CLEAR(x)) { MOVE(x); break; }
67
68 static void
69 do_worm(Display *dpy, Window window, struct worm *w)
70 {
71     int type = w->s / 4;
72     int dir = w->s % 4;
73
74     w->c = (w->c+w->cc) % ncolors;
75
76     if (PROB(disorder)) type=PROB(handedness);
77     switch(type) {
78     case 0: /* CCW */
79         TRY(CCW)
80         TRY(STR)
81         TRY(CW)
82         RANDOM;
83         break;
84     case 1: /* CW */
85         TRY(CW)
86         TRY(STR)
87         TRY(CCW)
88         RANDOM;
89         break;
90     }
91     w->s = type*4+dir;
92     w->h = w->h % width;
93     w->v = w->v % height;
94 }
95
96 static void
97 init_squiral(Display *dpy, Window window)
98 {
99     XGCValues gcv;
100     Colormap cmap;
101     XWindowAttributes xgwa;
102     Bool writeable = False;
103     int i;
104
105     XClearWindow(dpy, window);
106     XGetWindowAttributes(dpy, window, &xgwa);
107     width  = xgwa.width;
108     height = xgwa.height;
109
110     cmap = xgwa.colormap;
111     gcv.foreground = get_pixel_resource("foreground",
112         "Foreground", dpy, cmap);
113     draw_gc = XCreateGC(dpy, window, GCForeground, &gcv);
114     gcv.foreground = get_pixel_resource ("background", "Background",dpy, cmap);
115     erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
116     cmap = xgwa.colormap;
117     if( ncolors ) {
118         free_colors(dpy, cmap, colors, ncolors);
119         ncolors = 0;
120     }
121     if( mono_p ) {
122       ncolors=1;
123       colors[0].pixel=get_pixel_resource("foreground","Foreground", dpy, cmap);
124     } else {
125       ncolors = get_integer_resource("ncolors", "Integer");
126       if (ncolors < 0 || ncolors > NCOLORSMAX)
127         ncolors = NCOLORSMAX;
128       make_uniform_colormap(dpy, xgwa.visual, cmap, colors, &ncolors, True,
129           &writeable, False);
130       if (ncolors <= 0) {
131         ncolors = 1;
132         colors[0].pixel=get_pixel_resource("foreground","Foreground",dpy, cmap);
133       }
134     }
135     count= get_integer_resource("count", "Integer");
136     frac = get_integer_resource("fill",  "Integer")*0.01;
137     cycle= get_boolean_resource("cycle", "Cycle");
138     disorder=get_float_resource("disorder", "Float");
139     handedness=get_float_resource("handedness", "Float");
140
141     if(frac<0.01) frac=0.01;
142     if(frac>0.99) frac=0.99;
143     if(count==0) count=width/32;
144     if(count<1) count=1;
145     if(count>1000) count=1000;
146
147     if(worms) free(worms);
148     if(fill)  free(fill);
149
150     worms=calloc(count, sizeof(struct worm));
151     fill=calloc(width*height, sizeof(int));
152
153     dirh[0]=0; dirh[1]=1; dirh[2]=0; dirh[3]=width-1;
154     dirv[0]=height-1; dirv[1]=0; dirv[2]=1; dirv[3]=0;
155     for(i=0;i<count;i++) {
156         worms[i].h=R(width);
157         worms[i].v=R(height);
158         worms[i].s=R(4)+4*PROB(handedness);
159         worms[i].c=R(ncolors);
160         if(cycle) { worms[i].cc=R(3)+ncolors; }
161         else worms[i].cc=0;
162     }
163 }
164
165 void
166 screenhack(Display *dpy, Window window)
167 {
168    int inclear, i;
169    int delay= get_integer_resource("delay", "Integer");
170    init_squiral(dpy, window);
171    cov=0; inclear=height;
172    while(1) {
173         if(inclear<height) {
174             XDrawLine(dpy, window, erase_gc, 0, inclear, width-1, inclear);
175             memset(&fill[inclear*width], 0, sizeof(int)*width);
176             XDrawLine(dpy, window, erase_gc, 0, height-inclear-1, width-1,
177                     height-inclear-1);
178             memset(&fill[(height-inclear-1)*width], 0, sizeof(int)*width);
179             inclear++;
180             XDrawLine(dpy, window, erase_gc, 0, inclear, width-1, inclear);
181             memset(&fill[inclear*width], 0, sizeof(int)*width);
182             XDrawLine(dpy, window, erase_gc, 0, height-inclear-1, width-1,
183                     height-inclear-1);
184             memset(&fill[(height-inclear-1)*width], 0, sizeof(int)*width);
185             inclear++;
186             if(inclear>height/2) inclear=height;
187         }
188         else if(cov>(frac*width*height)) {
189             inclear=0;
190             cov=0;
191         }
192         for(i=0;i<count;i++) do_worm(dpy, window, &worms[i]);
193         screenhack_handle_events(dpy);
194         usleep(delay);
195     }   
196 }
197
198 char *progclass="Squiral";
199
200 char *defaults[] = {
201   ".background: black",
202   ".foreground: white",
203   "*fill:       75",
204   "*count:      0",
205   "*ncolors:    100",
206   "*delay:      1000",
207   "*disorder:   0.005",
208   "*cycle:      False",
209   "*handedness: .5",
210   0
211 };
212
213 XrmOptionDescRec options[] = {
214     {"-fill", ".fill", XrmoptionSepArg, 0},
215     {"-count", ".count", XrmoptionSepArg, 0},
216     {"-delay", ".delay", XrmoptionSepArg, 0},
217     {"-disorder", ".disorder", XrmoptionSepArg, 0},
218     {"-handedness", ".handedness", XrmoptionSepArg, 0},
219     {"-ncolors", ".ncolors", XrmoptionSepArg, 0},
220     {"-cycle", ".cycle", XrmoptionNoArg, "True"},
221     {"-no-cycle", ".cycle", XrmoptionNoArg, "False"},
222     { 0, 0, 0, 0 }
223 };