http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.34.tar.gz
[xscreensaver] / hacks / vermiculate.c
1 /*
2  *  @(#) vermiculate.c
3  *  @(#) Copyright (C) 2001 Tyler Pierce (tyler@alumni.brown.edu)
4  *  The full program, with documentation, is available at:
5  *    http://freshmeat.net/projects/fdm
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation.  No representations are made about the suitability of this
12  * software for any purpose.  It is provided "as is" without express or
13  * implied warranty.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <math.h>
23
24 #ifdef VERMICULATE_STANDALONE
25 #include "yarandom.h"
26 #include "usleep.h"
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <X11/Xresource.h>
31 #else
32 #include "screenhack.h"
33 #include "config.h"
34 #endif /* VERMICULATE_STANDALONE */
35
36 #define degs 360
37 #define degs2 (degs/2)
38 #define degs4 (degs/4)
39 #define degs8 (degs/8)
40 #define dtor 0.0174532925       /*  pi / degs2; */
41 #define thrmax 120
42 #define tailmax (thrmax * 2 + 1)
43 #define tmodes '7'
44 #define ymax (hei - 1)
45 #define ymin 0
46 #define xmax (wid - 1)
47 #define xmin 0
48 #define rlmax 200
49 #define SPEEDINC 10
50 #define SPEEDMAX 1000
51 #define wraparound(VAL,LOWER,UPPER) {   \
52                     if (VAL >= UPPER)   \
53                       VAL -= UPPER - LOWER;     \
54                     else if (VAL < LOWER)       \
55                       VAL += UPPER - LOWER; }
56 #define arrcpy(DEST,SRC) memcpy (DEST, SRC, sizeof(DEST))
57
58 typedef double real;
59 typedef unsigned char banktype[thrmax];
60
61 typedef struct linedata
62 {
63   int deg, spiturn, turnco, turnsize;
64   unsigned char col;
65   Bool dead;
66
67   char orichar;
68   real x, y;
69   int tmode, tsc, tslen, tclim, otslen, ctinc, reclen, recpos, circturn, prey,
70     slice;
71   int xrec[rlmax + 1], yrec[rlmax + 1];
72   int turnseq[50];
73   Bool filled, killwalls, vhfollow,
74     selfbounce, tailfollow, realbounce, little;
75 }
76 linedata;
77
78 #ifdef    VERMICULATE_STANDALONE
79 static XEvent myevent;
80 static Bool use_root = False;
81 static unsigned char rgb[256][3];
82
83 #else
84 char *progclass = "Vermiculate";
85
86 char *defaults[] = {
87   ".ticks: 20000",
88   0
89 };
90
91 XrmOptionDescRec options[] = {
92   {"-speed", ".speed", XrmoptionSepArg, 0},
93   {"-instring", ".instring", XrmoptionSepArg, 0},
94   {0, 0, 0, 0}
95 };
96 #endif /* VERMICULATE_STANDALONE */
97
98 static Display *mydpy;
99 static Window mywindow;
100 static GC mygc;
101 static Colormap mycmap;
102 static XWindowAttributes xgwa;
103 static Bool neednewkey = True;
104 static XColor mycolors[tailmax];
105
106 static int hei = 500, wid = 500, speed = 100;
107 static Bool erasing = True;
108 static char *instring = 0;
109 static int max_ticks;
110
111 static struct stringAndSpeed
112 {
113   char *str;
114   int speed;
115 }
116 sampleStrings[] =
117 {
118   { "]]]]]]]]7ces123400-9-8#c123456#s9998880004#ma3#car9ma6#c-#r1", 600} ,
119   { "bmarrrr#c1234#lc5678#lyet]", 600} ,
120   { "AEBMN222222223#CAR9CAD4CAOV", 150} ,
121   { "mn333#c23#f1#]]]]]]]]]]]3bc9#r9#c78#f9#ma4#", 600} ,
122   { "AEBMN22222#CAD4CAORc1#f2#c1#r6", 100} ,
123 /*  { "mn6666666#c1i#f1#y2#sy2#vyety1#ry13i#l", 40} , */
124   { "aebmnrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#", 500} ,
125   { "bg+++++++++++++++++++++++#mnrrrrrrrrrrrrrrrrrrrrrrr#y1#k", 500} ,
126   { "BMN22222223#CAD4CAOVYAS", 150} ,
127 /*  { "aebmnrrrrrrrrrrrrrrrr#yaryakg--#", 100} , */
128   { "mn6rrrrrrrrrrrrrrr#by1i#lcalc1#fnyav", 200 } ,
129   { "mn1rrrrrrrrrrrrrrr#by1i#lcalc1#fn", 200 }
130 };
131
132 static real sinof[degs], cosof[degs], tanof[degs];
133 static unsigned char *point;
134
135 static linedata thread[thrmax];
136 static banktype bank;
137 static int bankt, boxw, boxh, curviness, gridden, ogd, bordcorn;
138 static unsigned char bordcol, threads;
139 static char ch, boolop;
140
141 static Bool
142 wasakeypressed (void)
143 {
144   if (!neednewkey || *instring != 0)
145     return True;
146   else
147 #ifdef VERMICULATE_STANDALONE
148     return !(neednewkey =
149              !XCheckWindowEvent (mydpy, mywindow, KeyPressMask, &myevent));
150 #else
151     return False;
152 #endif /* VERMICULATE_STANDALONE */
153 }
154
155 static char
156 readkey (void)
157 {
158   char readkey_result;
159   if (*instring == 0)
160     {
161 #ifdef VERMICULATE_STANDALONE
162       char key_buffer[1];
163       KeySym key_sym;
164       if (neednewkey)
165         XWindowEvent (mydpy, mywindow, KeyPressMask, &myevent);
166       XLookupString (&myevent.xkey, key_buffer, 1, &key_sym, NULL);
167       readkey_result = key_sym;
168 #else
169       readkey_result = '#';
170 #endif /* VERMICULATE_STANDALONE */
171       neednewkey = True;
172     }
173   else
174     {
175       readkey_result = *instring;
176       instring++;
177     };
178   return toupper (readkey_result);
179 }
180
181 static unsigned int
182 random1 (unsigned int i)
183 {
184   return (ya_random () % i);
185 }
186
187 static void
188 waitabit (void)
189 {
190   static int cyc = 0;
191   cyc += threads;
192   while (cyc > speed)
193     {
194       usleep (10000);
195       cyc -= speed;
196     }
197 }
198
199 static void
200 clearscreen (void)
201 {
202   XClearWindow (mydpy, mywindow);
203   memset (point, 0, wid * hei);
204 }
205
206 static void
207 sp (int x, int y, int c)
208 {
209   XSetForeground (mydpy, mygc, mycolors[c].pixel);
210   XDrawPoint (mydpy, mywindow, mygc, x, y);
211   point[(wid * y) + x] = c;
212 }
213
214 static int
215 gp (int x, int y)
216 {
217   return point[(wid * y) + x];
218 }
219
220 static void
221 redraw (int x, int y, int width, int height)
222 {
223   int xc, yc;
224   for (xc = x; xc <= x + width - 1; xc++)
225     for (yc = y; yc <= y + height - 1; yc++)
226       if (point[wid * yc + xc] != 0)
227         sp (xc, yc, point[wid * yc + xc]);
228 }
229
230 static void
231 palupdate (Bool forceUpdate)
232 {
233   if (forceUpdate || *instring == 0)
234     {
235 #ifdef VERMICULATE_STANDALONE
236       int colnum;
237       for (colnum = 0; colnum < tailmax; colnum++)
238         {
239           mycolors[colnum].red = rgb[colnum][0] << 10;
240           mycolors[colnum].green = rgb[colnum][1] << 10;
241           mycolors[colnum].blue = rgb[colnum][2] << 10;
242           mycolors[colnum].flags = DoRed | DoBlue | DoGreen;
243           XAllocColor (mydpy, mycmap, &mycolors[colnum]);
244         };
245 #endif /* VERMICULATE_STANDALONE */
246       redraw (xmin, ymin, wid, hei);
247     }
248 }
249
250 static void
251 randpal (void)
252 {
253 #ifdef VERMICULATE_STANDALONE
254   int co, ro;
255   for (co = 1; co <= 255; co++)
256     for (ro = 0; ro <= 2; ro++)
257       if (co > tailmax)
258         rgb[co][ro] = random1 (20);
259       else
260         rgb[co][ro] = random1 (64);
261   for (ro = 0; ro <= 2; ro++)
262     rgb[0][ro] = 0;
263 #else
264   int ncolors = tailmax - 1;
265   make_random_colormap (mydpy,
266                         xgwa.visual,
267                         mycmap, &mycolors[1], &ncolors, True, True, 0, True);
268   if (ncolors < tailmax - 1)
269     {
270       int c;
271       for (c = 1; c < tailmax; c++)
272         mycolors[c].pixel = WhitePixel (mydpy, DefaultScreen (mydpy));
273     }
274 #endif /* VERMICULATE_STANDALONE */
275 }
276
277 static void
278 gridupdate (Bool interruptible)
279 {
280   int x, y;
281   if (gridden > 0)
282     for (x = 0; x <= xmax && !(wasakeypressed () && interruptible); x += boxw)
283       for (y = 0; y <= ymax; y += boxh)
284         {
285           if (random1 (15) < gridden)
286             {
287 #define lesser(A,B) ( ((A)<(B)) ? (A) : (B) )
288               int max = lesser (x + boxw, xmax);
289               int xc;
290               for (xc = x; xc <= max; xc++)
291                 sp (xc, y, 1);
292             }
293           if (random1 (15) < gridden)
294             {
295               int max = lesser (y + boxh, ymax);
296               int yc;
297               for (yc = y; yc <= max; yc++)
298                 sp (x, yc, 1);
299             }
300         }
301 }
302
303 static void
304 bordupdate (void)
305 {
306   int xbord, ybord;
307
308   if (bordcorn == 0 || bordcorn == 1)
309     ybord = ymin;
310   else
311     ybord = ymax;
312   if (bordcorn == 0 || bordcorn == 3)
313     xbord = xmin;
314   else
315     xbord = xmax;
316   {
317     int x, y;
318     for (x = xmin; x <= xmax; x++)
319       sp (x, ybord, bordcol);
320     for (y = ymin; y <= ymax; y++)
321       sp (ybord, y, bordcol);
322   }
323 }
324
325 static Bool
326 inbank (unsigned char thr)
327 {
328   int c;
329   if (bankt > 0)
330     for (c = 1; c <= bankt; c++)
331       if (bank[c - 1] == thr)
332         return True;
333   return False;
334 }
335
336 static void
337 pickbank (void)
338 {
339   unsigned char thr = 1;
340 #ifdef VERMICULATE_STANDALONE
341   int co, ro;
342   unsigned char orgb[256][3];
343
344   arrcpy (orgb, rgb);
345   for (co = 2; co <= tailmax; co++)
346     for (ro = 0; ro <= 2; ro++)
347       rgb[co][ro] = 25;
348 #endif /* VERMICULATE_STANDALONE */
349   bankt = 0;
350   ch = '\0';
351   do
352     {
353       while (inbank (thr))
354         thr = thr % threads + 1;
355 #ifdef VERMICULATE_STANDALONE
356       for (co = 1; co <= threads; co++)
357         {
358           for (ro = 0; ro <= 2; ro++)
359             rgb[co + 1][ro] = 25;
360           if (inbank (co))
361             for (ro = 0; ro <= 1; ro++)
362               rgb[co + 1][ro] = 60;
363         }
364       for (ro = 0; ro <= 2; ro++)
365         rgb[thr + 1][ro] = 60;
366 #endif /* VERMICULATE_STANDALONE */
367       palupdate (False);
368       ch = readkey ();
369       palupdate (False);
370       switch (ch)
371         {
372         case '+':
373         case '-':
374           do
375             {
376               if (ch == '+')
377                 thr++;
378               else
379                 thr--;
380               wraparound (thr, 1, threads + 1);
381             }
382           while (inbank (thr));
383           break;
384         case ' ':
385           bank[++bankt - 1] = thr;
386           break;
387         case '1'...'9':
388           bank[++bankt - 1] = ch - '0';
389           if (bank[bankt - 1] > threads)
390             bankt--;
391           break;
392         case 'I':
393           {
394             banktype tbank;
395             int tbankt = 0;
396             int c;
397             for (c = 1; c <= threads; c++)
398               if (!inbank (c))
399                 tbank[++tbankt - 1] = c;
400             bankt = tbankt;
401             arrcpy (bank, tbank);
402           }
403           break;
404         case 'T':
405           ch = readkey ();
406           switch (ch)
407             {
408             case '1'...tmodes:
409               {
410                 int c;
411                 for (c = 1; c <= threads; c++)
412                   if (thread[c - 1].tmode == ch - '0')
413                     bank[++bankt - 1] = c;
414               }
415               break;
416             }
417           break;
418         case 'A':
419           for (bankt = 1; bankt <= threads; bankt++)
420             bank[bankt - 1] = bankt;
421           bankt = threads;
422           break;
423         case 'E':
424           for (bankt = 1; bankt <= thrmax; bankt++)
425             bank[bankt - 1] = bankt;
426           bankt = thrmax;
427           break;
428         }
429     }
430   while (!(bankt >= threads || ch == 'N' || ch == '\15' || ch == '#'));
431   if (bankt == 0 && ch != 'N')
432     {
433       bankt = 1;
434       bank[0] = thr;
435     }
436 #ifdef VERMICULATE_STANDALONE
437   arrcpy (rgb, orgb);
438 #endif /* VERMICULATE_STANDALONE */
439   palupdate (False);
440 }
441
442 static void
443 bankmod (Bool * Bool_)
444 {
445   switch (boolop)
446     {
447     case 'T':
448       *Bool_ = !*Bool_;
449       break;
450     case 'Y':
451       *Bool_ = True;
452       break;
453     case 'N':
454       *Bool_ = False;
455       break;
456     }
457 }
458
459 static void
460 newonscreen (unsigned char thr)
461 {
462   linedata *LP = &thread[thr - 1];
463   LP->filled = False;
464   LP->dead = False;
465   LP->reclen = (LP->little) ? 
466         random1 (10) + 5 : random1 (rlmax - 30) + 30;
467   LP->deg = random1 (degs);
468   LP->y = random1 (hei);
469   LP->x = random1 (wid);
470   LP->recpos = 0;
471   LP->turnco = 2;
472   LP->turnsize = random1 (4) + 2;
473 }
474
475 static void
476 firstinit (unsigned char thr)
477 {
478   linedata *LP = &thread[thr - 1];
479   LP->col = thr + 1;
480   LP->prey = 0;
481   LP->tmode = 1;
482   LP->slice = degs / 3;
483   LP->orichar = 'R';
484   LP->spiturn = 5;
485   LP->selfbounce = False;
486   LP->realbounce = False;
487   LP->vhfollow = False;
488   LP->tailfollow = False;
489   LP->killwalls = False;
490   LP->little = False;
491   LP->ctinc = random1 (2) * 2 - 1;
492   LP->circturn = ((thr % 2) * 2 - 1) * ((thr - 1) % 7 + 1);
493   LP->tsc = 1;
494   LP->tslen = 6;
495   LP->turnseq[0] = 6;
496   LP->turnseq[1] = -6;
497   LP->turnseq[2] = 6;
498   LP->turnseq[3] = 6;
499   LP->turnseq[4] = -6;
500   LP->turnseq[5] = 6;
501   LP->tclim = (unsigned char) (((real) degs) / 2 / 12);
502 }
503
504 static void
505 maininit (void)
506 {
507   if (!instring)
508     {
509       int n = random1 (sizeof (sampleStrings) / sizeof (sampleStrings[0]));
510       instring = sampleStrings[n].str;
511       speed = sampleStrings[n].speed;
512     }
513   boxh = 10;
514   boxw = 10;
515   gridden = 0;
516   bordcorn = 0;
517   threads = 4;
518   curviness = 30;
519   bordcol = 1;
520   ogd = 8;
521   ch = '\0';
522   erasing = True;
523   {
524     unsigned char thr;
525     for (thr = 1; thr <= thrmax; thr++)
526       {
527         firstinit (thr);
528         newonscreen (thr);
529       }
530   }
531   {
532     int d;
533     for (d = degs - 1; d >= 0; d--)
534       {
535         sinof[d] = sin (d * dtor);
536         cosof[d] = cos (d * dtor);
537         if (d % degs4 == 0)
538           tanof[d] = tanof[d + 1];
539         else
540           tanof[d] = tan (d * dtor);
541       }
542   }
543   randpal ();
544 }
545
546 static Bool
547 move (unsigned char thr)
548 {
549   linedata *LP = &thread[thr - 1];
550   if (LP->dead)
551     return (False);
552   if (LP->prey == 0)
553     switch (LP->tmode)
554       {
555       case 1:
556         LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize;
557         break;
558       case 2:
559         if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4)
560           {
561             if (LP->orichar == 'D')
562               {
563                 if (LP->deg % degs4 != degs8)
564                   LP->deg = degs4 * random1 (4) + degs8;
565               }
566             else if (LP->orichar == 'V')
567               if (LP->deg % degs4 != 0)
568                 LP->deg = degs4 * random1 (4);
569           }
570         if (random1 (100) == 0)
571           {
572             if (LP->slice == 0)
573               LP->deg = LP->deg - degs4 + random1 (degs2);
574             else
575               LP->deg += (random1 (2) * 2 - 1) * LP->slice;
576           }
577         break;
578       case 3:
579         LP->deg += LP->circturn;
580         break;
581       case 4:
582         if (abs (LP->spiturn) > 11)
583           LP->spiturn = 5;
584         else
585           LP->deg += LP->spiturn;
586         if (random1 (15 - abs (LP->spiturn)) == 0)
587           {
588             LP->spiturn += LP->ctinc;
589             if (abs (LP->spiturn) > 10)
590               LP->ctinc *= -1;
591           }
592         break;
593       case 5:
594         LP->turnco = abs (LP->turnco) - 1;
595         if (LP->turnco == 0)
596           {
597             LP->turnco = curviness + random1 (10);
598             LP->circturn *= -1;
599           }
600         LP->deg += LP->circturn;
601         break;
602       case 6:
603         if (abs (LP->turnco) == 1)
604           LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5);
605         else if (LP->turnco == 0)
606           LP->turnco = 2;
607         else if (LP->turnco > 0)
608           {
609             LP->turnco--;
610             LP->deg += LP->circturn;
611           }
612         else
613           LP->turnco++;
614         break;
615       case 7:
616         LP->turnco++;
617         if (LP->turnco > LP->tclim)
618           {
619             LP->turnco = 1;
620             LP->tsc = (LP->tsc % LP->tslen) + 1;
621           }
622         LP->deg += LP->turnseq[LP->tsc - 1];
623         break;
624       }
625   else
626     {
627       int desdeg;
628       real dy, dx;
629       if (LP->tailfollow || LP->prey == thr)
630         {
631           dx = thread[LP->prey - 1].xrec[thread[LP->prey - 1].recpos] - LP->x;
632           dy = thread[LP->prey - 1].yrec[thread[LP->prey - 1].recpos] - LP->y;
633         }
634       else
635         {
636           dx = thread[LP->prey - 1].x - LP->x;
637           dy = thread[LP->prey - 1].y - LP->y;
638         }
639       desdeg =
640         (LP->vhfollow) ?
641         ((fabs (dx) > fabs (dy)) ?
642          ((dx > 0) ?
643           0 * degs4
644           :
645           2 * degs4)
646          :
647          ((dy > 0) ?
648           1 * degs4
649           :
650           3 * degs4))
651         :
652         ((dx > 0) ?
653          ((dy > 0) ?
654           1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8));
655       if (desdeg - desdeg % degs4 != LP->deg - LP->deg % degs4
656           || LP->vhfollow)
657         {
658           if (!LP->vhfollow)
659            { 
660               /* Using atan2 here doesn't seem to slow things down: */
661               desdeg = atan2 (dy, dx) / dtor;
662               wraparound (desdeg, 0, degs);
663            }
664           if (abs (desdeg - LP->deg) <= abs (LP->circturn))
665             LP->deg = desdeg;
666           else
667             LP->deg +=
668               (desdeg > LP->deg) ?
669               ((desdeg - LP->deg > degs2) ?
670                -abs (LP->circturn) : abs (LP->circturn))
671               : ((LP->deg - desdeg > degs2) ?
672                  abs (LP->circturn) : -abs (LP->circturn));
673         }
674       else
675         LP->deg +=
676           (tanof[LP->deg] >
677            dy / dx) ? -abs (LP->circturn) : abs (LP->circturn);
678     }
679
680   wraparound (LP->deg, 0, degs);
681   {
682     unsigned char oldcol;
683     real oldy = LP->y, oldx = LP->x;
684     LP->x += cosof[LP->deg];
685     wraparound (LP->x, xmin, xmax + 1);
686     LP->y += sinof[LP->deg];
687     wraparound (LP->y, ymin, ymax + 1);
688 #define xi ((int) LP->x)
689 #define yi ((int) LP->y)
690
691     oldcol = gp (xi, yi);
692     if (oldcol != 0)
693       {
694         Bool vertwall = False, horiwall = False;
695         if (oldcol == 1 && ((LP->killwalls && gridden > 0) || LP->realbounce))
696           {
697             vertwall = (gp (xi, (int) oldy) == 1);
698             horiwall = (gp ((int) oldx, yi) == 1);
699           }
700         if (oldcol == 1 && LP->realbounce && (vertwall || horiwall))
701           {
702             if (vertwall)
703               LP->deg = -LP->deg + degs2;
704             else
705               LP->deg = -LP->deg;
706           }
707         else
708           {
709             if ((oldcol != LP->col && LP->realbounce)
710                 || (oldcol == LP->col && LP->selfbounce))
711               LP->deg += degs4 * (random1 (2) * 2 - 1);
712             else if (oldcol != LP->col)
713               LP->deg += degs2;
714           }
715         if (LP->killwalls && gridden > 0 && oldcol == 1)
716           {
717             if (vertwall && xi + 1 <= xmax)
718               {
719                 int yy;
720                 for (yy = yi - yi % boxh;
721                      yy <= yi - yi % boxh + boxh && yy <= ymax; yy++)
722                   if (gp (xi + 1, yy) != 1 || yy == ymax)
723                     sp (xi, yy, 0);
724               }
725             if (horiwall && yi + 1 <= ymax)
726               {
727                 int xx;
728                 for (xx = xi - xi % boxw;
729                      xx <= xi - xi % boxw + boxw && xx <= xmax; xx++)
730                   if (gp (xx, yi + 1) != 1 || xx == xmax)
731                     sp (xx, yi, 0);
732               }
733           }
734         if (oldcol != LP->col || LP->selfbounce)
735           {
736             LP->x = oldx;
737             LP->y = oldy;
738           }
739         wraparound (LP->deg, 0, degs);
740       }
741   }
742
743   sp (xi, yi, LP->col);
744   if (LP->filled)
745     {
746       if (erasing)
747         sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0);
748       else
749         sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax);
750     }
751   LP->yrec[LP->recpos] = yi;
752   LP->xrec[LP->recpos] = xi;
753   if (LP->recpos == LP->reclen - 1)
754     LP->filled = True;
755   if (LP->filled && !erasing)
756     {
757       int co = LP->recpos;
758       LP->dead = True;
759       do
760         {
761           int nextco = co + 1;
762           wraparound (nextco, 0, LP->reclen);
763           if (LP->yrec[co] != LP->yrec[nextco]
764               || LP->xrec[co] != LP->xrec[nextco])
765             LP->dead = False;
766           co = nextco;
767         }
768       while (!(!LP->dead || co == LP->recpos));
769     }
770   LP->recpos++;
771   wraparound (LP->recpos, 0, LP->reclen);
772   return (!LP->dead);
773 }
774
775 static void
776 vermiculate_main (void)
777 {
778   int had_instring = (instring != 0);
779   int tick = 0;
780   Bool halted = False, autopal = False, cleared;
781   point = (unsigned char *) malloc (wid * hei);
782   maininit ();
783   palupdate (True);
784
785   do
786     {
787       clearscreen ();
788       {
789         unsigned char thr;
790         for (thr = 1; thr <= threads; thr++)
791           newonscreen (thr);
792       }
793       if (autopal)
794         {
795           randpal ();
796           palupdate (False);
797         }
798       bordupdate ();
799       gridupdate (False);
800       cleared = False;
801       do
802         {
803           while (wasakeypressed ())
804             {
805               ch = readkey ();
806               switch (ch)
807                 {
808                 case 'M':
809                   ch = readkey ();
810                   switch (ch)
811                     {
812                     case 'A':
813                     case 'N':
814                       {
815                         unsigned char othreads = threads;
816                         if (ch == 'N')
817                           threads = 0;
818                         do
819                           {
820                             ch = readkey ();
821                             switch (ch)
822                               {
823                               case '1'...tmodes:
824                                 thread[++threads - 1].tmode = ch - '0';
825                                 break;
826                               case 'R':
827                                 thread[++threads - 1].tmode =
828                                   random1 (tmodes - '0') + 1;
829                                 break;
830                               }
831                           }
832                         while (!(ch == '\15' || ch == '#'
833                                  || threads == thrmax));
834                         if (threads == 0)
835                           threads = othreads;
836                         cleared = True;
837                       }
838                       break;
839                     }
840                   break;
841                 case 'C':
842                   pickbank ();
843                   if (bankt > 0)
844                     {
845                       ch = readkey ();
846                       switch (ch)
847                         {
848                         case 'D':
849                           ch = readkey ();
850                           switch (ch)
851                             {
852                             case '1'...'9':
853 /* Careful!  The following macro needs to be at the beginning of any
854 block in which it's invoked, since it declares variables: */
855 #define forallinbank(LDP) linedata *LDP; int bankc; \
856                 for (bankc = 1; \
857                 (LDP = &thread[bank[bankc - 1] - 1],    \
858                 bankc <= bankt); bankc++)
859                               {
860                                 forallinbank (L) L->slice = degs / (ch - '0');
861                               }
862                               break;
863                             case 'M':
864                               {
865                                 forallinbank (L) L->slice = 0;
866                               }
867                               break;
868                             }
869                           break;
870                         case 'S':
871                           {
872                             forallinbank (L)
873                             {
874                               L->otslen = L->tslen;
875                               L->tslen = 0;
876                             }
877                           }
878                           do
879                             {
880                               char oldch = ch;
881                               ch = readkey ();
882                               {
883                                 forallinbank (L)
884                                 {
885                                   switch (ch)
886                                     {
887                                     case '0'...'9':
888                                       L->tslen++;
889                                       L->turnseq[L->tslen - 1] = ch - '0';
890                                       if (oldch == '-')
891                                         L->turnseq[L->tslen - 1] *= -1;
892                                       if (bankc % 2 == 0)
893                                         L->turnseq[L->tslen - 1] *= -1;
894                                       break;
895                                     }
896                                 }
897                               }
898                             }
899                           while (!(ch == '\15' || ch == '#'
900                                    || thread[bank[0] - 1].tslen == 50));
901                           {
902                             forallinbank (L)
903                             {
904                               int seqSum = 0, c;
905
906                               if (L->tslen == 0)
907                                 L->tslen = L->otslen;
908                               for (c = 1; c <= L->tslen; c++)
909                                 seqSum += L->turnseq[c - 1];
910                               if (seqSum == 0)
911                                 L->tclim = 1;
912                               else
913                                 L->tclim =
914                                   (int) (((real) degs2) / abs (seqSum));
915                               L->tsc = random1 (L->tslen) + 1;
916                             }
917                           }
918                           break;
919                         case 'T':
920                           {
921                             ch = readkey ();
922                             {
923                               forallinbank (L)
924                               {
925                                 switch (ch)
926                                   {
927                                   case '1'...tmodes:
928                                     L->tmode = ch - '0';
929                                     break;
930                                   case 'R':
931                                     L->tmode = random1 (tmodes - '0') + 1;
932                                     break;
933                                   }
934                               }
935                             }
936                           }
937                           break;
938                         case 'O':
939                           ch = readkey ();
940                           {
941                             forallinbank (L) L->orichar = ch;
942                           }
943                           break;
944                         case 'F':
945                           {
946                             banktype fbank;
947                             arrcpy (fbank, bank);
948                             {
949                               int fbankt = bankt;
950                               int bankc;
951                               pickbank ();
952                               for (bankc = 1; bankc <= fbankt; bankc++)
953                                 {
954                                   linedata *L = &thread[fbank[bankc - 1] - 1];
955                                   if (ch == 'N')
956                                     L->prey = 0;
957                                   else
958                                     L->prey = bank[0 + (bankc - 1) % bankt];
959                                 }
960                             }
961                           }
962                           break;
963                         case 'L':
964                           {
965                             forallinbank (L) L->prey = bank[bankc % bankt];
966                           }
967                           break;
968                         case 'R':
969                           ch = readkey ();
970                           {
971                             forallinbank (L) switch (ch)
972                               {
973                               case '1'...'9':
974                                 L->circturn = 10 - (ch - '0');
975                                 break;
976                               case 'R':
977                                 L->circturn = random1 (7) + 1;
978                                 break;
979                               }
980                           }
981                           break;
982                         }
983                     }
984                   break;
985                 case 'T':
986                 case 'Y':
987                 case 'N':
988                   boolop = ch;
989                   pickbank ();
990                   if (bankt > 0)
991                     {
992                       ch = readkey ();
993                       {
994                         forallinbank (L)
995                         {
996                           switch (ch)
997                             {
998                             case 'S':
999                               bankmod (&L->selfbounce);
1000                               break;
1001                             case 'V':
1002                               bankmod (&L->vhfollow);
1003                               break;
1004                             case 'R':
1005                               bankmod (&L->realbounce);
1006                               break;
1007                             case 'L':
1008                               bankmod (&L->little);
1009                               cleared = True;
1010                               break;
1011                             case 'T':
1012                               bankmod (&L->tailfollow);
1013                               break;
1014                             case 'K':
1015                               bankmod (&L->killwalls);
1016                               break;
1017                             }
1018                         }
1019                       }
1020                     }
1021                   break;
1022                 case 'R':
1023                   if (bordcol == 1)
1024                     {
1025                       bordcol = 0;
1026                       bordupdate ();
1027                       bordcorn = (bordcorn + 1) % 4;
1028                       bordcol = 1;
1029                       bordupdate ();
1030                     }
1031                   break;
1032                 case '\33':
1033                   halted = True;
1034                   break;
1035                 case '1'...tmodes:
1036                   {
1037                     int c;
1038                     for (c = 1; c <= thrmax; c++)
1039                       thread[c - 1].tmode = ch - '0';
1040                   }
1041                   break;
1042                 case '\40':
1043                   cleared = True;
1044                   break;
1045                 case 'E':
1046                   erasing = !erasing;
1047                   break;
1048                 case 'P':
1049                   randpal ();
1050                   palupdate (True);
1051                   break;
1052                 case 'G':
1053                   {
1054                     char dimch = 'B';
1055                     Bool gridchanged = True;
1056                     if (gridden == 0)
1057                       gridden = ogd;
1058                     do
1059                       {
1060                         int msize = 0;
1061                         if (gridchanged)
1062                           {
1063                             clearscreen ();
1064                             gridupdate (True);
1065                           }
1066                         ch = readkey ();
1067                         gridchanged = True;
1068                         switch (ch)
1069                           {
1070                           case '+':
1071                             msize = 1;
1072                             break;
1073                           case '-':
1074                             msize = -1;
1075                             break;
1076                           case ']':
1077                             if (gridden < 15)
1078                               gridden++;
1079                             break;
1080                           case '[':
1081                             if (gridden > 0)
1082                               gridden--;
1083                             break;
1084                           case 'O':
1085                             ogd = gridden;
1086                             gridden = 0;
1087                             break;
1088                           case 'S':
1089                             boxw = boxh;
1090                           case 'W':
1091                           case 'H':
1092                           case 'B':
1093                             dimch = ch;
1094                             break;
1095                           default:
1096                             gridchanged = False;
1097                           }
1098                         if (dimch == 'W' || dimch == 'B')
1099                           boxw += msize;
1100                         if (dimch == 'H' || dimch == 'B')
1101                           boxh += msize;
1102                         if (boxw == 0)
1103                           boxw = 1;
1104                         if (boxh == 0)
1105                           boxh = 1;
1106                       }
1107                     while (!(ch == '\15' || ch == '#' || ch == 'O'));
1108                     cleared = True;
1109                   }
1110                   break;
1111                 case 'A':
1112                   autopal = !autopal;
1113                   break;
1114                 case 'B':
1115                   bordcol = 1 - bordcol;
1116                   bordupdate ();
1117                   break;
1118                 case '-':
1119                   speed -= SPEEDINC;
1120                   if (speed < 1)
1121                     speed = 1;
1122                   break;
1123                 case '+':
1124                   speed += SPEEDINC;
1125                   if (speed > SPEEDMAX)
1126                     speed = SPEEDMAX;
1127                   break;
1128                 case '/':
1129                   if (curviness > 5)
1130                     curviness -= 5;
1131                   break;
1132                 case '*':
1133                   if (curviness < 50)
1134                     curviness += 5;
1135                   break;
1136                 case ']':
1137                   if (threads < thrmax)
1138                     newonscreen (++threads);
1139                   break;
1140                 case '[':
1141                   if (threads > 1)
1142                     {
1143                       linedata *L = &thread[threads - 1];
1144                       int lastpos = (L->filled) ? L->reclen - 1 : L->recpos;
1145                       int c;
1146                       for (c = 0; c <= lastpos; c++)
1147                         sp (L->xrec[c], L->yrec[c], 0);
1148                       threads--;
1149                     }
1150                   break;
1151                 }
1152             }
1153
1154 #ifdef VERMICULATE_STANDALONE
1155           {
1156             XEvent xe;
1157             while (XCheckWindowEvent
1158                    (mydpy, mywindow, StructureNotifyMask | ExposureMask, &xe))
1159               switch (xe.type)
1160                 {
1161                 case ConfigureNotify:
1162                   wid = xe.xconfigure.width;
1163                   hei = xe.xconfigure.height;
1164                   free (point);
1165                   point = (unsigned char *) malloc (wid * hei);
1166                   cleared = True;
1167                   break;
1168                 case Expose:
1169                   if (!cleared)
1170                     redraw (xe.xexpose.x,
1171                             xe.xexpose.y, xe.xexpose.width,
1172                             xe.xexpose.height);
1173                   break;
1174                 }
1175           }
1176 #else
1177           screenhack_handle_events (mydpy);
1178 #endif /* VERMICULATE_STANDALONE */
1179
1180           if (!cleared)
1181             {
1182               Bool alltrap = True;
1183               unsigned char thr;
1184               for (thr = 1; thr <= threads; thr++)
1185                 if (move (thr))
1186                   alltrap = False;
1187               if (alltrap)      /* all threads are trapped */
1188                 cleared = True;
1189               if (speed != SPEEDMAX)
1190                 waitabit ();
1191             }
1192
1193           if (tick++ > max_ticks && !had_instring)
1194             {
1195               tick = 0;
1196               instring = 0;
1197               maininit();
1198               cleared = True;
1199               autopal = False;
1200             }
1201         }
1202       while (!(halted || cleared));
1203     }
1204   while (!halted);
1205 }
1206
1207 void
1208 commonXinit (void)
1209 {
1210   XSetWindowBackground (mydpy, mywindow,
1211                         BlackPixel (mydpy, DefaultScreen (mydpy)));
1212   {
1213     XGetWindowAttributes (mydpy, mywindow, &xgwa);
1214     wid = xgwa.width;
1215     hei = xgwa.height;
1216     mycmap = xgwa.colormap;
1217   }
1218   {
1219     XGCValues mygcv;
1220     XGetGCValues (mydpy, XDefaultGC (mydpy, XDefaultScreen (mydpy)),
1221                   GCForeground, &mygcv);
1222     mygc = XCreateGC (mydpy, mywindow, GCForeground, &mygcv);
1223   }
1224 }
1225
1226 #ifdef VERMICULATE_STANDALONE
1227 /* Function Name: GetVRoot (slightly changed from the X Windows FAQ)
1228  * Description: Gets the root window, even if it's a virtual root
1229  * Arguments: the display and the screen
1230  * Returns: the root window for the client
1231  */
1232 static Window
1233 GetVRoot (Display * dpy, int scr)
1234 {
1235   Window rootReturn, parentReturn, *children;
1236   unsigned int numChildren;
1237   Window root = RootWindow (dpy, scr);
1238   Atom __SWM_VROOT = None;
1239   int i;
1240
1241   __SWM_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1242   XQueryTree (dpy, root, &rootReturn, &parentReturn, &children, &numChildren);
1243   for (i = 0; i < numChildren; i++)
1244     {
1245       Atom actual_type;
1246       int actual_format;
1247       unsigned long int nitems, bytesafter;
1248       Window *newRoot = NULL;
1249
1250       if (XGetWindowProperty (dpy, children[i], __SWM_VROOT, 0, 1,
1251                               False, XA_WINDOW, &actual_type, &actual_format,
1252                               &nitems, &bytesafter,
1253                               (unsigned char **) &newRoot) == Success
1254           && newRoot)
1255         {
1256           root = *newRoot;
1257           break;
1258         }
1259     }
1260
1261   XFree ((char *) children);
1262   return root;
1263 }
1264
1265 int
1266 main (int argc, char **argv)
1267 {
1268   int argnum;
1269   if ((mydpy = XOpenDisplay (NULL)) == NULL)
1270     {
1271       fprintf (stderr, "%s: cannot connect to X server %s\n", argv[0],
1272                XDisplayName (NULL));
1273       exit (1);
1274     }
1275
1276   for (argnum = 1; argnum < argc; argnum++)
1277     {
1278       if (!strcmp (argv[argnum], "-geometry"))
1279         {
1280           int x, y;
1281           unsigned int uh, uw;
1282           XParseGeometry (argv[++argnum], &x, &y, &uw, &uh);
1283           hei = (int) uh;
1284           wid = (int) uw;
1285         }
1286       else if (!strcmp (argv[argnum], "-instring"))
1287         instring = argv[++argnum];
1288       else if (!strcmp (argv[argnum], "-root"))
1289         use_root = True;
1290       else if (!strcmp (argv[argnum], "-speed"))
1291         speed = atoi (argv[++argnum]);
1292       else
1293         {
1294           fprintf (stderr,
1295                    "\nvermiculate options are:"
1296                    "\n -speed NUMBER:  set speed, can be from 1 to %d."
1297                    "\n -root:  use root window."
1298                    "\n -instring STRING:  put STRING in kbd buffer."
1299                    "\n -geometry WIDTHxHEIGHT \n", SPEEDMAX);
1300           exit (1);
1301         }
1302     }
1303
1304   if (use_root)
1305     mywindow = GetVRoot (mydpy, DefaultScreen (mydpy));
1306   else
1307     mywindow = XCreateSimpleWindow (mydpy, DefaultRootWindow (mydpy), 0, 0,
1308                                     wid, hei, 0, 0, BlackPixel (mydpy,
1309                                                                 DefaultScreen
1310                                                                 (mydpy)));
1311   XStoreName (mydpy, mywindow, "vermiculate");
1312   XMapWindow (mydpy, mywindow);
1313   commonXinit ();
1314   XSelectInput (mydpy, mywindow,
1315                 KeyPressMask | ExposureMask | StructureNotifyMask);
1316
1317 #undef ya_rand_init
1318   ya_rand_init (0);
1319
1320   vermiculate_main ();
1321   return 0;
1322 }
1323
1324 #else
1325
1326 void
1327 screenhack (Display * d, Window w)
1328 {
1329   mydpy = d;
1330   mywindow = w;
1331   instring = get_string_resource ("instring", "Instring");
1332   max_ticks = get_integer_resource ("ticks", "Integer");
1333   {
1334     int temp = get_integer_resource ("speed", "Speed");
1335     if (temp != 0)
1336       speed = temp;
1337   }
1338   commonXinit ();
1339   mycolors[0].pixel = BlackPixel (mydpy, DefaultScreen (mydpy));
1340   vermiculate_main ();
1341 }
1342 #endif /* VERMICULATE_STANDALONE */