http://ftp.x.org/contrib/applications/xscreensaver-3.07.tar.gz
[xscreensaver] / hacks / truchet.c
1 /* truchet --- curved and straight tilings
2  * Copyright (c) 1998 Adrian Likins <adrian@gimp.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* This screensaver draws two varieties of truchet patterns, a curved one and
14    a straight one. There are lots and lots of command line options to play
15    with.
16
17    If your running remotely or on a slow machine or slow xserver, some of the
18    settings will be way too much. The default settings should be okay though. 
19
20    This screensaver doesnt use anything bizarre or special at all, just a few
21    standard xlib calls.
22
23    A few suggested commandline combos..All these were tested on a k6-200
24    running XFree86 3.3 on a ark2000, so your mileage may vary...
25
26       truchet -delay 200 -no-curves
27       truchet -delay 500 -no-curves -square -no-erase
28       truchet -delay 500 -no-erase -square -erase-count 5
29       truchet -scroll
30       truchet -scroll -no-erase -anim-step-size 9
31       truchet -delay 200 -no-angles -min-width 36 -max-width 36
32       truchet -delay 200 -no-curves -min-width 12 -max-width 12
33       truchet -delay 200 -no-curves -min-width 36 -max-width 36 -no-erase
34       truchet -delay 100 -min-width 256 -max-width 512 -no-erase \
35               -min-linewidth 96 -root
36       truchet -min-width 64 -max-width 128 -no-erase -max-linewidth 4 \
37               -root -no-angles
38       truchet -min-width 64 -max-width 128 -no-erase -max-linewidth 4 \
39               -root -no-curves -delay 25
40  */
41
42 #include "screenhack.h"
43
44 #define MAXRATIO 2
45
46
47 char *progclass="Truchet";
48
49 char *defaults [] = {
50   "*minWidth:                 40",
51   "*minHeight:                40",
52   "*max-Width:                150",
53   "*max-Height:               150",
54   "*maxLineWidth:             25",
55   "*minLineWidth:             2",
56   "*erase:                    True",
57   "*eraseCount:               25",        
58   "*square:                   True",
59   "*delay:                    1000",
60   "*curves:                   True",
61   "*angles:                   True",
62   "*angles-and-curves:        True",
63   "*scroll:                   False",
64   "*scroll-overlap:           400",
65   "*anim-delay:               100",
66   "*anim-step-size:           3",
67   "*randomize:                false",
68    0
69 };
70
71 /* options passed to this program */
72 XrmOptionDescRec options [] = {
73   { "-min-width",      ".minWidth",       XrmoptionSepArg, 0 },
74   { "-max-height",     ".max-Height",      XrmoptionSepArg, 0 },
75   { "-max-width",      ".max-Width",       XrmoptionSepArg, 0 },
76   { "-min-height",     ".minHeight",      XrmoptionSepArg, 0 },
77   { "-max-linewidth",  ".maxLineWidth",   XrmoptionSepArg, 0 },
78   { "-min-linewidth",  ".minLineWidth",   XrmoptionSepArg, 0 },
79   { "-erase",          ".erase",          XrmoptionNoArg, "True" },
80   { "-no-erase",       ".erase",          XrmoptionNoArg, "False" },
81   { "-erase-count",    ".eraseCount",     XrmoptionSepArg, 0 },
82   { "-square",         ".square",         XrmoptionNoArg, "True" },
83   { "-not-square",     ".square",         XrmoptionNoArg, "False" },
84   { "-curves",         ".curves",         XrmoptionNoArg, "True" },
85   { "-angles",         ".angles",         XrmoptionNoArg,  "True" },
86   { "-no-angles",      ".angles",         XrmoptionNoArg,  "False" },
87   { "-no-curves",      ".curves",         XrmoptionNoArg, "False" },
88   { "-delay",          ".delay",          XrmoptionSepArg, 0 },
89   { "-scroll",         ".scroll",         XrmoptionNoArg, "True" },
90   { "-scroll-overlap", ".scroll-overlap", XrmoptionSepArg, 0 },
91   { "-anim-delay",     ".anim-delay",     XrmoptionSepArg, 0 },
92   { "-anim-step-size",  ".anim-step-size", XrmoptionSepArg, 0 },
93   { "-randomize",       ".randomize",     XrmoptionNoArg, "True" },
94   { 0, 0, 0, 0 }
95 };
96
97 static GC agc, bgc;
98 static int linewidth;
99 static int width, height;
100 static XWindowAttributes xgwa;
101 static Pixmap frame;
102 static int overlap;
103
104 static void draw_truchet(Display *disp, Window win);
105 static void draw_angles(Display *disp, Window win);
106 static void scroll_area(Display *disp, Window win, int delay, int step_size);
107
108 static void draw_angles(Display *disp, Window win)
109 {
110   int countX;
111   int countY;
112
113   countX=0;
114   countY=0;
115   
116   while((xgwa.height+overlap) > countY*height)
117         {
118           while((xgwa.width+overlap) > countX*width)
119             {
120               if(random()%2)
121               {
122                 /* block1 */
123                 XDrawLine(disp,frame,agc,
124                           (countX*width)+(width/2),
125                           (countY*height), 
126                           (countX*width)+(width),
127                           (countY*height)+(height/2));
128                 XDrawLine(disp,frame,agc,
129                           (countX*width), 
130                           (countY*height)+(height/2),
131                           (countX*width)+(width/2),
132                           (countY*height)+(height));
133               }
134             else
135               {
136                 /* block 2 */
137                 XDrawLine(disp,frame,agc, 
138                           (countX*width)+(width/2),
139                           (countY*height),
140                           (countX*width),
141                           (countY*height)+(height/2));
142                 XDrawLine(disp,frame,agc,
143                           (countX*width)+(width),
144                           (countY*height)+(height/2),
145                           (countX*width)+(width/2),
146                           (countY*height)+(height)); 
147               }
148               countX++;
149             }
150           countY++;
151           countX=0;
152         }
153
154   countX=0;
155   countY=0;
156 }
157   
158
159 static void draw_truchet(Display *disp, Window win)
160 {
161   int countX;
162   int countY;
163
164
165   countX=0;
166   countY=0;
167
168
169   while(xgwa.height+overlap > countY*height)
170         {
171           while(xgwa.width+overlap > countX*width)
172             {
173               if(random()%2)
174               {
175                 /* block1 */
176                 XDrawArc(disp, frame, agc,
177                          ((countX*width)-(width/2)),
178                          ((countY*height)-(height/2)),
179                          width,
180                          height,
181                          0, -5760);
182                 XDrawArc(disp,frame, agc,
183                          ((countX*width)+(width/2)),
184                          ((countY*height)+(height/2)),
185                          width,
186                          height,
187                          11520,
188                          -5760);
189               }
190             else
191               {
192                 /* block 2 */
193                 XDrawArc(disp,frame,agc,
194                          ((countX*width)+(width/2)),
195                          ((countY*height)-(height/2)),
196                          width,
197                          height,
198                          17280,
199                          -5760);
200                 XDrawArc(disp,frame,agc,
201                          ((countX*width)-(width/2)),
202                          ((countY*height)+(height/2)),
203                          width,
204                          height,
205                          0,
206                          5760);
207               }
208               countX++;
209             }
210           countY++;
211           countX=0;
212         }
213    countX=0;
214    countY=0;
215 }
216 /* this is the function called for your screensaver */
217 void screenhack(Display *disp, Window win)
218 {
219   XGCValues gcv;
220   int countX;
221   int countY;
222   int maxlinewidth;
223   int minlinewidth;
224   int minwidth;
225   int minheight;
226   int max_height; 
227   int max_width; 
228   int delay;
229   int count;
230   int anim_delay;
231   int anim_step_size;
232
233
234   Colormap cmap;
235   XColor fgc;
236   Bool curves;
237   Bool square;
238   Bool angles;
239   Bool erase;
240   Bool eraseCount;
241   Bool scroll;
242   
243
244   maxlinewidth = get_integer_resource ("maxLineWidth", "Integer");
245   minlinewidth = get_integer_resource ("minLineWidth", "Integer");
246   minwidth = get_integer_resource ("minWidth", "Integer");
247   minheight = get_integer_resource ("minHeight", "Integer");
248   max_width = get_integer_resource ("max-Width", "Integer"); 
249   max_height = get_integer_resource ("max-Height", "Integer" ); 
250   delay = get_integer_resource ("delay", "Integer");
251   eraseCount = get_integer_resource ("eraseCount", "Integer");
252   square = get_boolean_resource ("square", "Boolean");
253   curves = get_boolean_resource ("curves", "Boolean");
254   angles = get_boolean_resource ("angles", "Boolean");
255   erase = get_boolean_resource ("erase", "Boolean");
256   scroll = get_boolean_resource ("scroll", "Boolean");
257   overlap = get_integer_resource ("scroll-overlap", "Integer");
258   anim_delay = get_integer_resource ("anim-delay", "Integer");
259   anim_step_size = get_integer_resource ("anim-step-size", "Integer");
260
261   if (get_boolean_resource("randomize", "Randomize"))
262     {
263       int i = (random() % 12);
264       switch(i) {
265       case 0:
266         break;
267       case 1:
268         curves = False;
269         break;
270       case 2:
271         curves = False;
272         square = True;
273         erase = False;
274         break;
275       case 3:
276         square = True;
277         erase = False;
278         eraseCount = 5;
279         break;
280       case 4:
281         scroll = True;
282         break;
283       case 5:
284         scroll = True;
285         erase = False;
286         anim_step_size = 9;
287         break;
288       case 6:
289         angles = False;
290         minwidth = max_width = 36;
291         break;
292       case 7:
293         curves = False;
294         minwidth = max_width = 12;
295         break;
296       case 8:
297         curves = False;
298         erase = False;
299         minwidth = max_width = 36;
300         break;
301       case 9:
302         erase = False;
303         minwidth = 256;
304         max_width = 512;
305         minlinewidth = 96;
306         break;
307       case 10:
308         angles = False;
309         minwidth = 64;
310         max_width = 128;
311         maxlinewidth = 4;
312         break;
313       case 11:
314         curves = False;
315         minwidth = 64;
316         max_width = 128;
317         maxlinewidth = 4;
318         break;
319       default:
320         abort();
321         break;
322       }
323     }
324
325   XGetWindowAttributes (disp, win, &xgwa);
326   gcv.foreground = BlackPixel(disp,0);
327   gcv.background = WhitePixel(disp,0);
328   gcv.line_width = 25;
329   cmap = xgwa.colormap;
330
331   gcv.foreground = get_pixel_resource("background", "Background",
332                                       disp, xgwa.colormap);
333
334   bgc = XCreateGC (disp, win, GCForeground, &gcv);
335   agc = XCreateGC(disp, win, GCForeground, &gcv);
336
337   XFillRectangle(disp, win, bgc, 0, 0, xgwa.width, xgwa.height);
338
339  
340   width=60;
341   height=60;
342   linewidth=1;
343   countX=0;
344   countY=0;
345   count=0;
346   XSetForeground(disp, agc, gcv.background);
347   
348   
349   frame = XCreatePixmap(disp,win, xgwa.width+overlap, xgwa.height+overlap, xgwa.depth); 
350   
351
352   while(1)
353     {
354       if (!mono_p)
355         {
356         /* XXX there are probably bugs with this. */
357         /* could be...I just borrowed this code from munch */
358
359         fgc.red = random() % 65535;
360         fgc.green = random() % 65535;
361         fgc.blue = random() % 65535;
362         
363         if (XAllocColor(disp, cmap, &fgc)) 
364           {
365             XSetForeground(disp, agc, fgc.pixel);
366           }
367         else
368           {
369             /* use white if all else fails  */
370             XSetForeground(disp,agc, gcv.background);
371           }
372       }
373
374       
375       
376
377       /* generate a random line width */
378       linewidth=(random()% maxlinewidth);
379
380       /* check for lower bound */
381       if(linewidth < minlinewidth)
382         linewidth = minlinewidth;
383
384       /* try to get an odd linewidth as it seem to work a little better */
385       if(linewidth%2)
386         linewidth++;
387
388       /* grab a random height and width */ 
389       width=(random()%max_width);
390       height=(random()%max_height);
391
392       /* make sure we dont get a 0 height or width */
393       if(width == 0 || height == 0)
394         {
395           height=max_height;
396           width=max_width;
397         }
398
399
400       /* check for min height and width */
401       if(height < minheight)
402         {
403           height=minheight;
404         }
405       if(width < minwidth)
406         {
407           width=minwidth;
408         }
409
410       /* if tiles need to be square, fix it... */
411       if(square)
412         height=width;
413
414       /* check for sane aspect ratios */
415       if((width/height) > MAXRATIO) 
416         height=width;
417       if((height/width) > MAXRATIO)
418         width=height;
419       
420       /* to avoid linewidths of zero */
421       if(linewidth == 0 || linewidth < minlinewidth)
422         linewidth = minlinewidth;
423
424       /* try to keep from getting line widths that would be too big */
425       if(linewidth > 0 && linewidth >= (height/5))
426         linewidth = height/5;
427   
428       XSetLineAttributes(disp, agc, linewidth, LineSolid, CapRound, JoinRound);
429
430       if(erase || (count >= eraseCount))
431         {
432           /*  XClearWindow(disp,win); */
433           XFillRectangle(disp, frame, bgc, 0, 0, xgwa.width+overlap, xgwa.height+overlap);
434           count=0;
435         }
436             
437       if(!scroll)
438         overlap=0;
439             
440       /* do the fun stuff...*/
441       if(curves && angles)
442         {
443           if(random()%2)
444             draw_truchet(disp,win);
445           else
446             draw_angles(disp,win);
447         }
448       else if(curves && !angles)
449         draw_truchet(disp,win);
450       else if(!curves && angles)
451         draw_angles(disp,win);
452
453    
454       XCopyArea(disp,frame,win,agc,0,0,xgwa.width,xgwa.height,0,0);
455       if(scroll)
456         {
457           scroll_area(disp,win,anim_delay,anim_step_size);
458           delay = 0;
459         }
460       else
461         XSync(disp, False);
462       
463       screenhack_handle_events (disp);
464
465       /* the delay to try to minimize seizures */
466       usleep((delay*1000)); 
467       count++;
468       
469     }
470
471 }
472
473 static void scroll_area(Display *disp, Window win, int delay, int step_size)
474 {
475
476   int scrollcount_x;
477   int scrollcount_y;
478   int offset;
479   int scroll;
480   /* note local delay overirdes static delay cause... */
481
482
483   scrollcount_x=0;
484   scrollcount_y=0;
485
486   offset=overlap/2;
487   scroll=overlap/4;
488   
489       /* if anyone knows a good way to generate a more random scrolling motion... */
490   while(scrollcount_x <= scroll)
491     {
492       XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
493       XSync(disp, False);
494       scrollcount_x=scrollcount_x+step_size;
495       scrollcount_y=scrollcount_y+step_size;
496       usleep(1000*delay); 
497     }
498   while(scrollcount_x >= 0)
499     {
500       XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
501       XSync(disp, False);
502       scrollcount_y=scrollcount_y+step_size;
503       scrollcount_x=scrollcount_x-step_size;
504       usleep(1000*delay); 
505     }
506   while(scrollcount_y >= scroll)
507     {
508       XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
509       XSync(disp, False);
510       scrollcount_x=scrollcount_x-step_size;
511       scrollcount_y=scrollcount_y-step_size;
512       usleep(1000*delay); 
513     }
514   while(scrollcount_y > 0)
515     {
516       XCopyArea(disp, frame, win, agc,scrollcount_x+offset,scrollcount_y+offset, xgwa.width, xgwa.height, 0,0);
517       XSync(disp, False);
518       scrollcount_y=scrollcount_y-step_size;
519       scrollcount_x=scrollcount_x+step_size;
520       usleep(1000*delay); 
521     }
522   
523   XSync(disp, False);
524   scrollcount_x=0;
525   scrollcount_y=0;
526   
527 }