source: trunk/third/xscreensaver/hacks/vermiculate.c @ 20148

Revision 20148, 29.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
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
58typedef double real;
59typedef unsigned char banktype[thrmax];
60
61typedef 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}
76linedata;
77
78#ifdef    VERMICULATE_STANDALONE
79static XEvent myevent;
80static Bool use_root = False;
81static unsigned char rgb[256][3];
82
83#else
84char *progclass = "Vermiculate";
85
86char *defaults[] = {
87  ".ticks: 20000",
88  0
89};
90
91XrmOptionDescRec options[] = {
92  {"-speed", ".speed", XrmoptionSepArg, 0},
93  {"-instring", ".instring", XrmoptionSepArg, 0},
94  {0, 0, 0, 0}
95};
96#endif /* VERMICULATE_STANDALONE */
97
98static Display *mydpy;
99static Window mywindow;
100static GC mygc;
101static Colormap mycmap;
102static XWindowAttributes xgwa;
103static Bool neednewkey = True;
104static XColor mycolors[tailmax];
105
106static int hei = 500, wid = 500, speed = 100;
107static Bool erasing = True;
108static char *instring = 0;
109static int max_ticks;
110
111static struct stringAndSpeed
112{
113  char *str;
114  int speed;
115}
116sampleStrings[] =
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
132static real sinof[degs], cosof[degs], tanof[degs];
133static unsigned char *point;
134
135static linedata thread[thrmax];
136static banktype bank;
137static int bankt, boxw, boxh, curviness, gridden, ogd, bordcorn;
138static unsigned char bordcol, threads;
139static char ch, boolop;
140
141static Bool
142wasakeypressed (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
155static char
156readkey (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
181static unsigned int
182random1 (unsigned int i)
183{
184  return (ya_random () % i);
185}
186
187static void
188waitabit (void)
189{
190  static int cyc = 0;
191  cyc += threads;
192  while (cyc > speed)
193    {
194      usleep (10000);
195      cyc -= speed;
196    }
197}
198
199static void
200clearscreen (void)
201{
202  XClearWindow (mydpy, mywindow);
203  memset (point, 0, wid * hei);
204}
205
206static void
207sp (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
214static int
215gp (int x, int y)
216{
217  return point[(wid * y) + x];
218}
219
220static void
221redraw (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
230static void
231palupdate (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
250static void
251randpal (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
277static void
278gridupdate (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
303static void
304bordupdate (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
325static Bool
326inbank (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
336static void
337pickbank (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': case '2': case '3':
388        case '4': case '5': case '6':
389        case '7': case '8': case '9':
390
391          bank[++bankt - 1] = ch - '0';
392          if (bank[bankt - 1] > threads)
393            bankt--;
394          break;
395        case 'I':
396          {
397            banktype tbank;
398            int tbankt = 0;
399            int c;
400            for (c = 1; c <= threads; c++)
401              if (!inbank (c))
402                tbank[++tbankt - 1] = c;
403            bankt = tbankt;
404            arrcpy (bank, tbank);
405          }
406          break;
407        case 'T':
408          ch = readkey ();
409          switch (ch)
410            {
411            case '1': case '2': case '3':
412            case '4': case '5': case '6':
413            case '7': case '8': case '9':
414
415              {
416                int c;
417                for (c = 1; c <= threads; c++)
418                  if (thread[c - 1].tmode == ch - '0')
419                    bank[++bankt - 1] = c;
420              }
421              break;
422            }
423          break;
424        case 'A':
425          for (bankt = 1; bankt <= threads; bankt++)
426            bank[bankt - 1] = bankt;
427          bankt = threads;
428          break;
429        case 'E':
430          for (bankt = 1; bankt <= thrmax; bankt++)
431            bank[bankt - 1] = bankt;
432          bankt = thrmax;
433          break;
434        }
435    }
436  while (!(bankt >= threads || ch == 'N' || ch == '\15' || ch == '#'));
437  if (bankt == 0 && ch != 'N')
438    {
439      bankt = 1;
440      bank[0] = thr;
441    }
442#ifdef VERMICULATE_STANDALONE
443  arrcpy (rgb, orgb);
444#endif /* VERMICULATE_STANDALONE */
445  palupdate (False);
446}
447
448static void
449bankmod (Bool * Bool_)
450{
451  switch (boolop)
452    {
453    case 'T':
454      *Bool_ = !*Bool_;
455      break;
456    case 'Y':
457      *Bool_ = True;
458      break;
459    case 'N':
460      *Bool_ = False;
461      break;
462    }
463}
464
465static void
466newonscreen (unsigned char thr)
467{
468  linedata *LP = &thread[thr - 1];
469  LP->filled = False;
470  LP->dead = False;
471  LP->reclen = (LP->little) ?
472        random1 (10) + 5 : random1 (rlmax - 30) + 30;
473  LP->deg = random1 (degs);
474  LP->y = random1 (hei);
475  LP->x = random1 (wid);
476  LP->recpos = 0;
477  LP->turnco = 2;
478  LP->turnsize = random1 (4) + 2;
479}
480
481static void
482firstinit (unsigned char thr)
483{
484  linedata *LP = &thread[thr - 1];
485  LP->col = thr + 1;
486  LP->prey = 0;
487  LP->tmode = 1;
488  LP->slice = degs / 3;
489  LP->orichar = 'R';
490  LP->spiturn = 5;
491  LP->selfbounce = False;
492  LP->realbounce = False;
493  LP->vhfollow = False;
494  LP->tailfollow = False;
495  LP->killwalls = False;
496  LP->little = False;
497  LP->ctinc = random1 (2) * 2 - 1;
498  LP->circturn = ((thr % 2) * 2 - 1) * ((thr - 1) % 7 + 1);
499  LP->tsc = 1;
500  LP->tslen = 6;
501  LP->turnseq[0] = 6;
502  LP->turnseq[1] = -6;
503  LP->turnseq[2] = 6;
504  LP->turnseq[3] = 6;
505  LP->turnseq[4] = -6;
506  LP->turnseq[5] = 6;
507  LP->tclim = (unsigned char) (((real) degs) / 2 / 12);
508}
509
510static void
511maininit (void)
512{
513  if (!instring)
514    {
515      int n = random1 (sizeof (sampleStrings) / sizeof (sampleStrings[0]));
516      instring = sampleStrings[n].str;
517      speed = sampleStrings[n].speed;
518    }
519  boxh = 10;
520  boxw = 10;
521  gridden = 0;
522  bordcorn = 0;
523  threads = 4;
524  curviness = 30;
525  bordcol = 1;
526  ogd = 8;
527  ch = '\0';
528  erasing = True;
529  {
530    unsigned char thr;
531    for (thr = 1; thr <= thrmax; thr++)
532      {
533        firstinit (thr);
534        newonscreen (thr);
535      }
536  }
537  {
538    int d;
539    for (d = degs - 1; d >= 0; d--)
540      {
541        sinof[d] = sin (d * dtor);
542        cosof[d] = cos (d * dtor);
543        if (d % degs4 == 0)
544          tanof[d] = tanof[d + 1];
545        else
546          tanof[d] = tan (d * dtor);
547      }
548  }
549  randpal ();
550}
551
552static Bool
553move (unsigned char thr)
554{
555  linedata *LP = &thread[thr - 1];
556  if (LP->dead)
557    return (False);
558  if (LP->prey == 0)
559    switch (LP->tmode)
560      {
561      case 1:
562        LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize;
563        break;
564      case 2:
565        if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4)
566          {
567            if (LP->orichar == 'D')
568              {
569                if (LP->deg % degs4 != degs8)
570                  LP->deg = degs4 * random1 (4) + degs8;
571              }
572            else if (LP->orichar == 'V')
573              if (LP->deg % degs4 != 0)
574                LP->deg = degs4 * random1 (4);
575          }
576        if (random1 (100) == 0)
577          {
578            if (LP->slice == 0)
579              LP->deg = LP->deg - degs4 + random1 (degs2);
580            else
581              LP->deg += (random1 (2) * 2 - 1) * LP->slice;
582          }
583        break;
584      case 3:
585        LP->deg += LP->circturn;
586        break;
587      case 4:
588        if (abs (LP->spiturn) > 11)
589          LP->spiturn = 5;
590        else
591          LP->deg += LP->spiturn;
592        if (random1 (15 - abs (LP->spiturn)) == 0)
593          {
594            LP->spiturn += LP->ctinc;
595            if (abs (LP->spiturn) > 10)
596              LP->ctinc *= -1;
597          }
598        break;
599      case 5:
600        LP->turnco = abs (LP->turnco) - 1;
601        if (LP->turnco == 0)
602          {
603            LP->turnco = curviness + random1 (10);
604            LP->circturn *= -1;
605          }
606        LP->deg += LP->circturn;
607        break;
608      case 6:
609        if (abs (LP->turnco) == 1)
610          LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5);
611        else if (LP->turnco == 0)
612          LP->turnco = 2;
613        else if (LP->turnco > 0)
614          {
615            LP->turnco--;
616            LP->deg += LP->circturn;
617          }
618        else
619          LP->turnco++;
620        break;
621      case 7:
622        LP->turnco++;
623        if (LP->turnco > LP->tclim)
624          {
625            LP->turnco = 1;
626            LP->tsc = (LP->tsc % LP->tslen) + 1;
627          }
628        LP->deg += LP->turnseq[LP->tsc - 1];
629        break;
630      }
631  else
632    {
633      int desdeg;
634      real dy, dx;
635      if (LP->tailfollow || LP->prey == thr)
636        {
637          dx = thread[LP->prey - 1].xrec[thread[LP->prey - 1].recpos] - LP->x;
638          dy = thread[LP->prey - 1].yrec[thread[LP->prey - 1].recpos] - LP->y;
639        }
640      else
641        {
642          dx = thread[LP->prey - 1].x - LP->x;
643          dy = thread[LP->prey - 1].y - LP->y;
644        }
645      desdeg =
646        (LP->vhfollow) ?
647        ((fabs (dx) > fabs (dy)) ?
648         ((dx > 0) ?
649          0 * degs4
650          :
651          2 * degs4)
652         :
653         ((dy > 0) ?
654          1 * degs4
655          :
656          3 * degs4))
657        :
658        ((dx > 0) ?
659         ((dy > 0) ?
660          1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8));
661      if (desdeg - desdeg % degs4 != LP->deg - LP->deg % degs4
662          || LP->vhfollow)
663        {
664          if (!LP->vhfollow)
665           {
666              /* Using atan2 here doesn't seem to slow things down: */
667              desdeg = atan2 (dy, dx) / dtor;
668              wraparound (desdeg, 0, degs);
669           }
670          if (abs (desdeg - LP->deg) <= abs (LP->circturn))
671            LP->deg = desdeg;
672          else
673            LP->deg +=
674              (desdeg > LP->deg) ?
675              ((desdeg - LP->deg > degs2) ?
676               -abs (LP->circturn) : abs (LP->circturn))
677              : ((LP->deg - desdeg > degs2) ?
678                 abs (LP->circturn) : -abs (LP->circturn));
679        }
680      else
681        LP->deg +=
682          (tanof[LP->deg] >
683           dy / dx) ? -abs (LP->circturn) : abs (LP->circturn);
684    }
685
686  wraparound (LP->deg, 0, degs);
687  {
688    unsigned char oldcol;
689    real oldy = LP->y, oldx = LP->x;
690    LP->x += cosof[LP->deg];
691    wraparound (LP->x, xmin, xmax + 1);
692    LP->y += sinof[LP->deg];
693    wraparound (LP->y, ymin, ymax + 1);
694#define xi ((int) LP->x)
695#define yi ((int) LP->y)
696
697    oldcol = gp (xi, yi);
698    if (oldcol != 0)
699      {
700        Bool vertwall = False, horiwall = False;
701        if (oldcol == 1 && ((LP->killwalls && gridden > 0) || LP->realbounce))
702          {
703            vertwall = (gp (xi, (int) oldy) == 1);
704            horiwall = (gp ((int) oldx, yi) == 1);
705          }
706        if (oldcol == 1 && LP->realbounce && (vertwall || horiwall))
707          {
708            if (vertwall)
709              LP->deg = -LP->deg + degs2;
710            else
711              LP->deg = -LP->deg;
712          }
713        else
714          {
715            if ((oldcol != LP->col && LP->realbounce)
716                || (oldcol == LP->col && LP->selfbounce))
717              LP->deg += degs4 * (random1 (2) * 2 - 1);
718            else if (oldcol != LP->col)
719              LP->deg += degs2;
720          }
721        if (LP->killwalls && gridden > 0 && oldcol == 1)
722          {
723            if (vertwall && xi + 1 <= xmax)
724              {
725                int yy;
726                for (yy = yi - yi % boxh;
727                     yy <= yi - yi % boxh + boxh && yy <= ymax; yy++)
728                  if (gp (xi + 1, yy) != 1 || yy == ymax)
729                    sp (xi, yy, 0);
730              }
731            if (horiwall && yi + 1 <= ymax)
732              {
733                int xx;
734                for (xx = xi - xi % boxw;
735                     xx <= xi - xi % boxw + boxw && xx <= xmax; xx++)
736                  if (gp (xx, yi + 1) != 1 || xx == xmax)
737                    sp (xx, yi, 0);
738              }
739          }
740        if (oldcol != LP->col || LP->selfbounce)
741          {
742            LP->x = oldx;
743            LP->y = oldy;
744          }
745        wraparound (LP->deg, 0, degs);
746      }
747  }
748
749  sp (xi, yi, LP->col);
750  if (LP->filled)
751    {
752      if (erasing)
753        sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0);
754      else
755        sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax);
756    }
757  LP->yrec[LP->recpos] = yi;
758  LP->xrec[LP->recpos] = xi;
759  if (LP->recpos == LP->reclen - 1)
760    LP->filled = True;
761  if (LP->filled && !erasing)
762    {
763      int co = LP->recpos;
764      LP->dead = True;
765      do
766        {
767          int nextco = co + 1;
768          wraparound (nextco, 0, LP->reclen);
769          if (LP->yrec[co] != LP->yrec[nextco]
770              || LP->xrec[co] != LP->xrec[nextco])
771            LP->dead = False;
772          co = nextco;
773        }
774      while (!(!LP->dead || co == LP->recpos));
775    }
776  LP->recpos++;
777  wraparound (LP->recpos, 0, LP->reclen);
778  return (!LP->dead);
779}
780
781static void
782vermiculate_main (void)
783{
784  int had_instring = (instring != 0);
785  int tick = 0;
786  Bool halted = False, autopal = False, cleared;
787  point = (unsigned char *) malloc (wid * hei);
788  maininit ();
789  palupdate (True);
790
791  do
792    {
793      clearscreen ();
794      {
795        unsigned char thr;
796        for (thr = 1; thr <= threads; thr++)
797          newonscreen (thr);
798      }
799      if (autopal)
800        {
801          randpal ();
802          palupdate (False);
803        }
804      bordupdate ();
805      gridupdate (False);
806      cleared = False;
807      do
808        {
809          while (wasakeypressed ())
810            {
811              ch = readkey ();
812              switch (ch)
813                {
814                case 'M':
815                  ch = readkey ();
816                  switch (ch)
817                    {
818                    case 'A':
819                    case 'N':
820                      {
821                        unsigned char othreads = threads;
822                        if (ch == 'N')
823                          threads = 0;
824                        do
825                          {
826                            ch = readkey ();
827                            switch (ch)
828                              {
829                              case '1': case '2': case '3':
830                              case '4': case '5': case '6':
831                              case '7': case '8': case '9':
832                                thread[++threads - 1].tmode = ch - '0';
833                                break;
834                              case 'R':
835                                thread[++threads - 1].tmode =
836                                  random1 (tmodes - '0') + 1;
837                                break;
838                              }
839                          }
840                        while (!(ch == '\15' || ch == '#'
841                                 || threads == thrmax));
842                        if (threads == 0)
843                          threads = othreads;
844                        cleared = True;
845                      }
846                      break;
847                    }
848                  break;
849                case 'C':
850                  pickbank ();
851                  if (bankt > 0)
852                    {
853                      ch = readkey ();
854                      switch (ch)
855                        {
856                        case 'D':
857                          ch = readkey ();
858                          switch (ch)
859                            {
860                            case '1': case '2': case '3':
861                            case '4': case '5': case '6':
862                            case '7': case '8': case '9':
863/* Careful!  The following macro needs to be at the beginning of any
864block in which it's invoked, since it declares variables: */
865#define forallinbank(LDP) linedata *LDP; int bankc; \
866                for (bankc = 1; \
867                (LDP = &thread[bank[bankc - 1] - 1],    \
868                bankc <= bankt); bankc++)
869                              {
870                                forallinbank (L) L->slice = degs / (ch - '0');
871                              }
872                              break;
873                            case 'M':
874                              {
875                                forallinbank (L) L->slice = 0;
876                              }
877                              break;
878                            }
879                          break;
880                        case 'S':
881                          {
882                            forallinbank (L)
883                            {
884                              L->otslen = L->tslen;
885                              L->tslen = 0;
886                            }
887                          }
888                          do
889                            {
890                              char oldch = ch;
891                              ch = readkey ();
892                              {
893                                forallinbank (L)
894                                {
895                                  switch (ch)
896                                    {
897                                    case '0':
898                                    case '1': case '2': case '3':
899                                    case '4': case '5': case '6':
900                                    case '7': case '8': case '9':
901                                      L->tslen++;
902                                      L->turnseq[L->tslen - 1] = ch - '0';
903                                      if (oldch == '-')
904                                        L->turnseq[L->tslen - 1] *= -1;
905                                      if (bankc % 2 == 0)
906                                        L->turnseq[L->tslen - 1] *= -1;
907                                      break;
908                                    }
909                                }
910                              }
911                            }
912                          while (!(ch == '\15' || ch == '#'
913                                   || thread[bank[0] - 1].tslen == 50));
914                          {
915                            forallinbank (L)
916                            {
917                              int seqSum = 0, c;
918
919                              if (L->tslen == 0)
920                                L->tslen = L->otslen;
921                              for (c = 1; c <= L->tslen; c++)
922                                seqSum += L->turnseq[c - 1];
923                              if (seqSum == 0)
924                                L->tclim = 1;
925                              else
926                                L->tclim =
927                                  (int) (((real) degs2) / abs (seqSum));
928                              L->tsc = random1 (L->tslen) + 1;
929                            }
930                          }
931                          break;
932                        case 'T':
933                          {
934                            ch = readkey ();
935                            {
936                              forallinbank (L)
937                              {
938                                switch (ch)
939                                  {
940                                  case '1': case '2': case '3':
941                                  case '4': case '5': case '6':
942                                  case '7': case '8': case '9':
943                                    L->tmode = ch - '0';
944                                    break;
945                                  case 'R':
946                                    L->tmode = random1 (tmodes - '0') + 1;
947                                    break;
948                                  }
949                              }
950                            }
951                          }
952                          break;
953                        case 'O':
954                          ch = readkey ();
955                          {
956                            forallinbank (L) L->orichar = ch;
957                          }
958                          break;
959                        case 'F':
960                          {
961                            banktype fbank;
962                            arrcpy (fbank, bank);
963                            {
964                              int fbankt = bankt;
965                              int bankc;
966                              pickbank ();
967                              for (bankc = 1; bankc <= fbankt; bankc++)
968                                {
969                                  linedata *L = &thread[fbank[bankc - 1] - 1];
970                                  if (ch == 'N')
971                                    L->prey = 0;
972                                  else
973                                    L->prey = bank[0 + (bankc - 1) % bankt];
974                                }
975                            }
976                          }
977                          break;
978                        case 'L':
979                          {
980                            forallinbank (L) L->prey = bank[bankc % bankt];
981                          }
982                          break;
983                        case 'R':
984                          ch = readkey ();
985                          {
986                            forallinbank (L) switch (ch)
987                              {
988                              case '1': case '2': case '3':
989                              case '4': case '5': case '6':
990                              case '7': case '8': case '9':
991                                L->circturn = 10 - (ch - '0');
992                                break;
993                              case 'R':
994                                L->circturn = random1 (7) + 1;
995                                break;
996                              }
997                          }
998                          break;
999                        }
1000                    }
1001                  break;
1002                case 'T':
1003                case 'Y':
1004                case 'N':
1005                  boolop = ch;
1006                  pickbank ();
1007                  if (bankt > 0)
1008                    {
1009                      ch = readkey ();
1010                      {
1011                        forallinbank (L)
1012                        {
1013                          switch (ch)
1014                            {
1015                            case 'S':
1016                              bankmod (&L->selfbounce);
1017                              break;
1018                            case 'V':
1019                              bankmod (&L->vhfollow);
1020                              break;
1021                            case 'R':
1022                              bankmod (&L->realbounce);
1023                              break;
1024                            case 'L':
1025                              bankmod (&L->little);
1026                              cleared = True;
1027                              break;
1028                            case 'T':
1029                              bankmod (&L->tailfollow);
1030                              break;
1031                            case 'K':
1032                              bankmod (&L->killwalls);
1033                              break;
1034                            }
1035                        }
1036                      }
1037                    }
1038                  break;
1039                case 'R':
1040                  if (bordcol == 1)
1041                    {
1042                      bordcol = 0;
1043                      bordupdate ();
1044                      bordcorn = (bordcorn + 1) % 4;
1045                      bordcol = 1;
1046                      bordupdate ();
1047                    }
1048                  break;
1049                case '\33':
1050                  halted = True;
1051                  break;
1052                case '1': case '2': case '3':
1053                case '4': case '5': case '6':
1054                case '7': case '8': case '9':
1055                  {
1056                    int c;
1057                    for (c = 1; c <= thrmax; c++)
1058                      thread[c - 1].tmode = ch - '0';
1059                  }
1060                  break;
1061                case '\40':
1062                  cleared = True;
1063                  break;
1064                case 'E':
1065                  erasing = !erasing;
1066                  break;
1067                case 'P':
1068                  randpal ();
1069                  palupdate (True);
1070                  break;
1071                case 'G':
1072                  {
1073                    char dimch = 'B';
1074                    Bool gridchanged = True;
1075                    if (gridden == 0)
1076                      gridden = ogd;
1077                    do
1078                      {
1079                        int msize = 0;
1080                        if (gridchanged)
1081                          {
1082                            clearscreen ();
1083                            gridupdate (True);
1084                          }
1085                        ch = readkey ();
1086                        gridchanged = True;
1087                        switch (ch)
1088                          {
1089                          case '+':
1090                            msize = 1;
1091                            break;
1092                          case '-':
1093                            msize = -1;
1094                            break;
1095                          case ']':
1096                            if (gridden < 15)
1097                              gridden++;
1098                            break;
1099                          case '[':
1100                            if (gridden > 0)
1101                              gridden--;
1102                            break;
1103                          case 'O':
1104                            ogd = gridden;
1105                            gridden = 0;
1106                            break;
1107                          case 'S':
1108                            boxw = boxh;
1109                          case 'W':
1110                          case 'H':
1111                          case 'B':
1112                            dimch = ch;
1113                            break;
1114                          default:
1115                            gridchanged = False;
1116                          }
1117                        if (dimch == 'W' || dimch == 'B')
1118                          boxw += msize;
1119                        if (dimch == 'H' || dimch == 'B')
1120                          boxh += msize;
1121                        if (boxw == 0)
1122                          boxw = 1;
1123                        if (boxh == 0)
1124                          boxh = 1;
1125                      }
1126                    while (!(ch == '\15' || ch == '#' || ch == 'O'));
1127                    cleared = True;
1128                  }
1129                  break;
1130                case 'A':
1131                  autopal = !autopal;
1132                  break;
1133                case 'B':
1134                  bordcol = 1 - bordcol;
1135                  bordupdate ();
1136                  break;
1137                case '-':
1138                  speed -= SPEEDINC;
1139                  if (speed < 1)
1140                    speed = 1;
1141                  break;
1142                case '+':
1143                  speed += SPEEDINC;
1144                  if (speed > SPEEDMAX)
1145                    speed = SPEEDMAX;
1146                  break;
1147                case '/':
1148                  if (curviness > 5)
1149                    curviness -= 5;
1150                  break;
1151                case '*':
1152                  if (curviness < 50)
1153                    curviness += 5;
1154                  break;
1155                case ']':
1156                  if (threads < thrmax)
1157                    newonscreen (++threads);
1158                  break;
1159                case '[':
1160                  if (threads > 1)
1161                    {
1162                      linedata *L = &thread[threads - 1];
1163                      int lastpos = (L->filled) ? L->reclen - 1 : L->recpos;
1164                      int c;
1165                      for (c = 0; c <= lastpos; c++)
1166                        sp (L->xrec[c], L->yrec[c], 0);
1167                      threads--;
1168                    }
1169                  break;
1170                }
1171            }
1172
1173#ifdef VERMICULATE_STANDALONE
1174          {
1175            XEvent xe;
1176            while (XCheckWindowEvent
1177                   (mydpy, mywindow, StructureNotifyMask | ExposureMask, &xe))
1178              switch (xe.type)
1179                {
1180                case ConfigureNotify:
1181                  wid = xe.xconfigure.width;
1182                  hei = xe.xconfigure.height;
1183                  free (point);
1184                  point = (unsigned char *) malloc (wid * hei);
1185                  cleared = True;
1186                  break;
1187                case Expose:
1188                  if (!cleared)
1189                    redraw (xe.xexpose.x,
1190                            xe.xexpose.y, xe.xexpose.width,
1191                            xe.xexpose.height);
1192                  break;
1193                }
1194          }
1195#else
1196          screenhack_handle_events (mydpy);
1197#endif /* VERMICULATE_STANDALONE */
1198
1199          if (!cleared)
1200            {
1201              Bool alltrap = True;
1202              unsigned char thr;
1203              for (thr = 1; thr <= threads; thr++)
1204                if (move (thr))
1205                  alltrap = False;
1206              if (alltrap)      /* all threads are trapped */
1207                cleared = True;
1208              if (speed != SPEEDMAX)
1209                waitabit ();
1210            }
1211
1212          if (tick++ > max_ticks && !had_instring)
1213            {
1214              tick = 0;
1215              instring = 0;
1216              maininit();
1217              cleared = True;
1218              autopal = False;
1219            }
1220        }
1221      while (!(halted || cleared));
1222    }
1223  while (!halted);
1224}
1225
1226void
1227commonXinit (void)
1228{
1229  XSetWindowBackground (mydpy, mywindow,
1230                        BlackPixel (mydpy, DefaultScreen (mydpy)));
1231  {
1232    XGetWindowAttributes (mydpy, mywindow, &xgwa);
1233    wid = xgwa.width;
1234    hei = xgwa.height;
1235    mycmap = xgwa.colormap;
1236  }
1237  {
1238    XGCValues mygcv;
1239    XGetGCValues (mydpy, XDefaultGC (mydpy, XDefaultScreen (mydpy)),
1240                  GCForeground, &mygcv);
1241    mygc = XCreateGC (mydpy, mywindow, GCForeground, &mygcv);
1242  }
1243}
1244
1245#ifdef VERMICULATE_STANDALONE
1246/* Function Name: GetVRoot (slightly changed from the X Windows FAQ)
1247 * Description: Gets the root window, even if it's a virtual root
1248 * Arguments: the display and the screen
1249 * Returns: the root window for the client
1250 */
1251static Window
1252GetVRoot (Display * dpy, int scr)
1253{
1254  Window rootReturn, parentReturn, *children;
1255  unsigned int numChildren;
1256  Window root = RootWindow (dpy, scr);
1257  Atom __SWM_VROOT = None;
1258  int i;
1259
1260  __SWM_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1261  XQueryTree (dpy, root, &rootReturn, &parentReturn, &children, &numChildren);
1262  for (i = 0; i < numChildren; i++)
1263    {
1264      Atom actual_type;
1265      int actual_format;
1266      unsigned long int nitems, bytesafter;
1267      Window *newRoot = NULL;
1268
1269      if (XGetWindowProperty (dpy, children[i], __SWM_VROOT, 0, 1,
1270                              False, XA_WINDOW, &actual_type, &actual_format,
1271                              &nitems, &bytesafter,
1272                              (unsigned char **) &newRoot) == Success
1273          && newRoot)
1274        {
1275          root = *newRoot;
1276          break;
1277        }
1278    }
1279
1280  XFree ((char *) children);
1281  return root;
1282}
1283
1284int
1285main (int argc, char **argv)
1286{
1287  int argnum;
1288  if ((mydpy = XOpenDisplay (NULL)) == NULL)
1289    {
1290      fprintf (stderr, "%s: cannot connect to X server %s\n", argv[0],
1291               XDisplayName (NULL));
1292      exit (1);
1293    }
1294
1295  for (argnum = 1; argnum < argc; argnum++)
1296    {
1297      if (!strcmp (argv[argnum], "-geometry"))
1298        {
1299          int x, y;
1300          unsigned int uh, uw;
1301          XParseGeometry (argv[++argnum], &x, &y, &uw, &uh);
1302          hei = (int) uh;
1303          wid = (int) uw;
1304        }
1305      else if (!strcmp (argv[argnum], "-instring"))
1306        instring = argv[++argnum];
1307      else if (!strcmp (argv[argnum], "-root"))
1308        use_root = True;
1309      else if (!strcmp (argv[argnum], "-speed"))
1310        speed = atoi (argv[++argnum]);
1311      else
1312        {
1313          fprintf (stderr,
1314                   "\nvermiculate options are:"
1315                   "\n -speed NUMBER:  set speed, can be from 1 to %d."
1316                   "\n -root:  use root window."
1317                   "\n -instring STRING:  put STRING in kbd buffer."
1318                   "\n -geometry WIDTHxHEIGHT \n", SPEEDMAX);
1319          exit (1);
1320        }
1321    }
1322
1323  if (use_root)
1324    mywindow = GetVRoot (mydpy, DefaultScreen (mydpy));
1325  else
1326    mywindow = XCreateSimpleWindow (mydpy, DefaultRootWindow (mydpy), 0, 0,
1327                                    wid, hei, 0, 0, BlackPixel (mydpy,
1328                                                                DefaultScreen
1329                                                                (mydpy)));
1330  XStoreName (mydpy, mywindow, "vermiculate");
1331  XMapWindow (mydpy, mywindow);
1332  commonXinit ();
1333  XSelectInput (mydpy, mywindow,
1334                KeyPressMask | ExposureMask | StructureNotifyMask);
1335
1336#undef ya_rand_init
1337  ya_rand_init (0);
1338
1339  vermiculate_main ();
1340  return 0;
1341}
1342
1343#else
1344
1345void
1346screenhack (Display * d, Window w)
1347{
1348  mydpy = d;
1349  mywindow = w;
1350  instring = get_string_resource ("instring", "Instring");
1351  max_ticks = get_integer_resource ("ticks", "Integer");
1352  {
1353    int temp = get_integer_resource ("speed", "Speed");
1354    if (temp != 0)
1355      speed = temp;
1356  }
1357  commonXinit ();
1358  mycolors[0].pixel = BlackPixel (mydpy, DefaultScreen (mydpy));
1359  vermiculate_main ();
1360}
1361#endif /* VERMICULATE_STANDALONE */
Note: See TracBrowser for help on using the repository browser.