summaryrefslogtreecommitdiffstats
path: root/hacks/vermiculate.c
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/vermiculate.c
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'hacks/vermiculate.c')
-rw-r--r--hacks/vermiculate.c1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/hacks/vermiculate.c b/hacks/vermiculate.c
new file mode 100644
index 0000000..9364791
--- /dev/null
+++ b/hacks/vermiculate.c
@@ -0,0 +1,1221 @@
+/*
+ * @(#) vermiculate.c
+ * @(#) Copyright (C) 2001 Tyler Pierce (tyler@alumni.brown.edu)
+ * The full program, with documentation, is available at:
+ * http://freshmeat.net/projects/fdm
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <ctype.h>
+#include <math.h>
+#include "screenhack.h"
+
+#define degs 360
+#define degs2 (degs/2)
+#define degs4 (degs/4)
+#define degs8 (degs/8)
+#define dtor 0.0174532925 /* pi / degs2; */
+#define thrmax 120
+#define tailmax (thrmax * 2 + 1)
+#define tmodes '7'
+#define ymax (st->hei - 1)
+#define ymin 0
+#define xmax (st->wid - 1)
+#define xmin 0
+#define rlmax 200
+#define SPEEDINC 10
+#define SPEEDMAX 1000
+#define wraparound(VAL,LOWER,UPPER) { \
+ if (VAL >= UPPER) \
+ VAL -= UPPER - LOWER; \
+ else if (VAL < LOWER) \
+ VAL += UPPER - LOWER; }
+#define arrcpy(DEST,SRC) memcpy (DEST, SRC, sizeof(DEST))
+
+typedef double real;
+typedef unsigned char banktype[thrmax];
+
+typedef struct linedata
+{
+ int deg, spiturn, turnco, turnsize;
+ unsigned char col;
+ Bool dead;
+
+ char orichar;
+ real x, y;
+ int tmode, tsc, tslen, tclim, otslen, ctinc, reclen, recpos, circturn, prey,
+ slice;
+ int xrec[rlmax + 1], yrec[rlmax + 1];
+ int turnseq[50];
+ Bool filled, killwalls, vhfollow,
+ selfbounce, tailfollow, realbounce, little;
+}
+linedata;
+
+static const struct stringAndSpeed
+{
+ char *str;
+ int speed;
+}
+sampleStrings[] =
+{
+/* { "]]]]]]]]7ces123400-9-8#c123456#s9998880004#ma3#car9ma6#c-#r1", 600} ,
+ { "bmarrrr#c1234#lc5678#lyet]", 600} , */
+ { "AEBMN222222223#CAR9CAD4CAOV", 150} ,
+ { "mn333#c23#f1#]]]]]]]]]]]3bc9#r9#c78#f9#ma4#", 600} ,
+ { "AEBMN22222#CAD4CAORc1#f2#c1#r6", 100} ,
+/* { "mn6666666#c1i#f1#y2#sy2#vyety1#ry13i#l", 40} , */
+ { "aebmnrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#", 500} ,
+/* { "bg+++++++++++++++++++++++#mnrrrrrrrrrrrrrrrrrrrrrrr#y1#k", 500}, */
+/* { "BMN22222223#CAD4CAOVYAS", 150}, */
+/* { "aebmnrrrrrrrrrrrrrrrr#yaryakg--#", 100} , */
+ { "mn6rrrrrrrrrrrrrrr#by1i#lcalc1#fnyav" , 200 } ,
+ { "mn1rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#by1i#lcalc1#fn", 2000 },
+ { "baeMn333333333333333333333333#CerrYerCal", 800 },
+ { "baeMn1111111111111111111111111111111111111111111111111111111111#Cer9YesYevYerCal", 1200 },
+ { "baMn111111222222333333444444555555#Ct1#lCt2#lCt3#lCt4#lCt5#lCerrYerYet", 1400 },
+ { "baMn111111222222333333444444555555#Ct1#lCt2#lCt3#lCt4#lCt5#lCerrYerYetYt1i#lYt1i#sYt1#v", 1400 }
+};
+
+struct state {
+ Display *dpy;
+ Window window;
+
+ GC mygc;
+ Colormap mycmap;
+ XWindowAttributes xgwa;
+ XColor mycolors[tailmax];
+
+ int hei, wid, speed;
+ Bool erasing, cleared, autopal;
+ char *instring;
+ int max_ticks;
+
+ real sinof[degs], cosof[degs], tanof[degs];
+ unsigned char *point;
+
+ linedata thread[thrmax];
+ banktype bank;
+ int bnkt;
+ int boxw, boxh, curviness, gridden, ogd, bordcorn;
+ unsigned char bordcol, threads;
+ char ch, boolop;
+
+ int reset_p;
+ int cyc;
+};
+
+
+
+static void
+consume_instring(struct state *st);
+
+static Bool
+wasakeypressed (struct state *st)
+{
+ if (*st->instring != 0)
+ return True;
+ else
+ return False;
+}
+
+static char
+readkey (struct state *st)
+{
+ char readkey_result;
+ if (*st->instring == 0)
+ {
+ readkey_result = '#';
+ }
+ else
+ {
+ readkey_result = *st->instring;
+ st->instring++;
+ };
+ return toupper (readkey_result);
+}
+
+static unsigned int
+random1 (unsigned int i)
+{
+ return (ya_random () % i);
+}
+
+static unsigned long
+waitabit (struct state *st)
+{
+ int result = 0;
+ st->cyc += st->threads;
+ while (st->cyc > st->speed)
+ {
+ result += 10000;
+ st->cyc -= st->speed;
+ }
+ return result;
+}
+
+static void
+clearscreen (struct state *st)
+{
+ XClearWindow (st->dpy, st->window);
+ memset (st->point, 0, st->wid * st->hei);
+}
+
+static void
+sp (struct state *st, int x, int y, int c)
+{
+ XSetForeground (st->dpy, st->mygc, st->mycolors[c].pixel);
+ XDrawPoint (st->dpy, st->window, st->mygc, x, y);
+ st->point[(st->wid * y) + x] = c;
+}
+
+static int
+gp (struct state *st, int x, int y)
+{
+ return st->point[(st->wid * y) + x];
+}
+
+static void
+redraw (struct state *st, int x, int y, int width, int height)
+{
+ int xc, yc;
+ for (xc = x; xc <= x + width - 1; xc++)
+ for (yc = y; yc <= y + height - 1; yc++)
+ if (st->point[st->wid * yc + xc] != 0)
+ sp (st, xc, yc, st->point[st->wid * yc + xc]);
+}
+
+static void
+palupdate (struct state *st, Bool forceUpdate)
+{
+ if (forceUpdate || *st->instring == 0)
+ {
+ redraw (st, xmin, ymin, st->wid, st->hei);
+ }
+}
+
+static void
+randpal (struct state *st)
+{
+ int ncolors = tailmax - 1;
+ make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->mycmap,
+ &st->mycolors[1], &ncolors, True, True, 0, True);
+ if (ncolors < tailmax - 1)
+ {
+ int c;
+ for (c = 1; c < tailmax; c++)
+ st->mycolors[c].pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy));
+ }
+}
+
+static void
+gridupdate (struct state *st, Bool interruptible)
+{
+ int x, y;
+ if (st->gridden > 0)
+ for (x = 0; x <= xmax && !(wasakeypressed (st) && interruptible); x += st->boxw)
+ for (y = 0; y <= ymax; y += st->boxh)
+ {
+ if (random1 (15) < st->gridden)
+ {
+#define lesser(A,B) ( ((A)<(B)) ? (A) : (B) )
+ int max = lesser (x + st->boxw, xmax);
+ int xc;
+ for (xc = x; xc <= max; xc++)
+ sp (st, xc, y, 1);
+ }
+ if (random1 (15) < st->gridden)
+ {
+ int max = lesser (y + st->boxh, ymax);
+ int yc;
+ for (yc = y; yc <= max; yc++)
+ sp (st, x, yc, 1);
+ }
+ }
+}
+
+static void
+bordupdate (struct state *st)
+{
+ int xbord, ybord;
+
+ if (st->bordcorn == 0 || st->bordcorn == 1)
+ ybord = ymin;
+ else
+ ybord = ymax;
+ if (st->bordcorn == 0 || st->bordcorn == 3)
+ xbord = xmin;
+ else
+ xbord = xmax;
+ {
+ int x, y;
+ for (x = xmin; x <= xmax; x++)
+ sp (st, x, ybord, st->bordcol);
+ for (y = ymin; y <= ymax; y++)
+ sp (st, xbord, y, st->bordcol);
+ }
+}
+
+static Bool
+inbank (struct state *st, unsigned char thr)
+{
+ int c;
+ if (st->bnkt > 0)
+ for (c = 1; c <= st->bnkt; c++)
+ if (st->bank[c - 1] == thr)
+ return True;
+ return False;
+}
+
+static void
+pickbank (struct state *st)
+{
+ unsigned char thr = 1;
+ st->bnkt = 0;
+ st->ch = '\0';
+ do
+ {
+ while (inbank (st, thr))
+ thr = thr % st->threads + 1;
+
+ palupdate (st, False);
+ st->ch = readkey (st);
+ palupdate (st, False);
+ switch (st->ch)
+ {
+ case '+':
+ case '-':
+ do
+ {
+ if (st->ch == '+')
+ thr++;
+ else
+ thr--;
+ wraparound (thr, 1, st->threads + 1);
+ }
+ while (inbank (st, thr));
+ break;
+ case ' ':
+ st->bank[++st->bnkt - 1] = thr;
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+
+ st->bank[++st->bnkt - 1] = st->ch - '0';
+ if (st->bank[st->bnkt - 1] > st->threads)
+ st->bnkt--;
+ break;
+ case 'I':
+ {
+ banktype tbank;
+ int tbankt = 0;
+ int c;
+ for (c = 1; c <= st->threads; c++)
+ if (!inbank (st, c))
+ tbank[++tbankt - 1] = c;
+ st->bnkt = tbankt;
+ arrcpy (st->bank, tbank);
+ }
+ break;
+ case 'T':
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+
+ {
+ int c;
+ for (c = 1; c <= st->threads; c++)
+ if (st->thread[c - 1].tmode == st->ch - '0')
+ st->bank[++st->bnkt - 1] = c;
+ }
+ break;
+ }
+ break;
+ case 'A':
+ for (st->bnkt = 1; st->bnkt <= st->threads; st->bnkt++)
+ st->bank[st->bnkt - 1] = st->bnkt;
+ st->bnkt = st->threads;
+ break;
+ case 'E':
+ for (st->bnkt = 1; st->bnkt <= thrmax; st->bnkt++)
+ st->bank[st->bnkt - 1] = st->bnkt;
+ st->bnkt = thrmax;
+ break;
+ }
+ }
+ while (!(st->bnkt >= st->threads || st->ch == 'N' || st->ch == '\15' || st->ch == '#'));
+ if (st->bnkt == 0 && st->ch != 'N')
+ {
+ st->bnkt = 1;
+ st->bank[0] = thr;
+ }
+ palupdate (st, False);
+}
+
+static void
+bankmod (char boolop, Bool * Bool_)
+{
+ switch (boolop)
+ {
+ case 'T':
+ *Bool_ = !*Bool_;
+ break;
+ case 'Y':
+ *Bool_ = True;
+ break;
+ case 'N':
+ *Bool_ = False;
+ break;
+ }
+}
+
+static void
+newonscreen (struct state *st, unsigned char thr)
+{
+ linedata *LP = &st->thread[thr - 1];
+ LP->filled = False;
+ LP->dead = False;
+ LP->reclen = (LP->little) ?
+ random1 (10) + 5 : random1 (rlmax - 30) + 30;
+ LP->deg = random1 (degs);
+ LP->y = random1 (st->hei);
+ LP->x = random1 (st->wid);
+ LP->recpos = 0;
+ LP->turnco = 2;
+ LP->turnsize = random1 (4) + 2;
+}
+
+static void
+firstinit (struct state *st, unsigned char thr)
+{
+ linedata *LP = &st->thread[thr - 1];
+ LP->col = thr + 1;
+ LP->prey = 0;
+ LP->tmode = 1;
+ LP->slice = degs / 3;
+ LP->orichar = 'R';
+ LP->spiturn = 5;
+ LP->selfbounce = False;
+ LP->realbounce = False;
+ LP->vhfollow = False;
+ LP->tailfollow = False;
+ LP->killwalls = False;
+ LP->little = False;
+ LP->ctinc = random1 (2) * 2 - 1;
+ LP->circturn = ((thr % 2) * 2 - 1) * ((thr - 1) % 7 + 1);
+ LP->tsc = 1;
+ LP->tslen = 6;
+ LP->turnseq[0] = 6;
+ LP->turnseq[1] = -6;
+ LP->turnseq[2] = 6;
+ LP->turnseq[3] = 6;
+ LP->turnseq[4] = -6;
+ LP->turnseq[5] = 6;
+ LP->tclim = (unsigned char) (((real) degs) / 2 / 12);
+}
+
+static void
+maininit (struct state *st)
+{
+ if (!st->instring)
+ {
+ int n = random1 (sizeof (sampleStrings) / sizeof (sampleStrings[0]));
+ st->instring = sampleStrings[n].str;
+ st->speed = sampleStrings[n].speed;
+ }
+ st->boxh = 10;
+ st->boxw = 10;
+ st->gridden = 0;
+ st->bordcorn = 0;
+ st->threads = 4;
+ st->curviness = 30;
+ st->bordcol = 1;
+ st->ogd = 8;
+ st->ch = '\0';
+ st->erasing = True;
+ {
+ unsigned char thr;
+ for (thr = 1; thr <= thrmax; thr++)
+ {
+ firstinit (st, thr);
+ newonscreen (st, thr);
+ }
+ }
+ {
+ int d;
+ for (d = degs - 1; d >= 0; d--)
+ {
+ st->sinof[d] = sin (d * dtor);
+ st->cosof[d] = cos (d * dtor);
+ if (d % degs4 == 0)
+ st->tanof[d] = st->tanof[d + 1];
+ else
+ st->tanof[d] = tan (d * dtor);
+ }
+ }
+ randpal (st);
+}
+
+static Bool
+move (struct state *st, unsigned char thr)
+{
+ linedata *LP = &st->thread[thr - 1];
+ if (LP->dead)
+ return (False);
+ if (LP->prey == 0)
+ switch (LP->tmode)
+ {
+ case 1:
+ LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize;
+ break;
+ case 2:
+ if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4)
+ {
+ if (LP->orichar == 'D')
+ {
+ if (LP->deg % degs4 != degs8)
+ LP->deg = degs4 * random1 (4) + degs8;
+ }
+ else if (LP->orichar == 'V')
+ if (LP->deg % degs4 != 0)
+ LP->deg = degs4 * random1 (4);
+ }
+ if (random1 (100) == 0)
+ {
+ if (LP->slice == 0)
+ LP->deg = LP->deg - degs4 + random1 (degs2);
+ else
+ LP->deg += (random1 (2) * 2 - 1) * LP->slice;
+ }
+ break;
+ case 3:
+ LP->deg += LP->circturn;
+ break;
+ case 4:
+ if (abs (LP->spiturn) > 11)
+ LP->spiturn = 5;
+ else
+ LP->deg += LP->spiturn;
+ if (random1 (15 - abs (LP->spiturn)) == 0)
+ {
+ LP->spiturn += LP->ctinc;
+ if (abs (LP->spiturn) > 10)
+ LP->ctinc *= -1;
+ }
+ break;
+ case 5:
+ LP->turnco = abs (LP->turnco) - 1;
+ if (LP->turnco == 0)
+ {
+ LP->turnco = st->curviness + random1 (10);
+ LP->circturn *= -1;
+ }
+ LP->deg += LP->circturn;
+ break;
+ case 6:
+ if (abs (LP->turnco) == 1)
+ LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5);
+ else if (LP->turnco == 0)
+ LP->turnco = 2;
+ else if (LP->turnco > 0)
+ {
+ LP->turnco--;
+ LP->deg += LP->circturn;
+ }
+ else
+ LP->turnco++;
+ break;
+ case 7:
+ LP->turnco++;
+ if (LP->turnco > LP->tclim)
+ {
+ LP->turnco = 1;
+ LP->tsc = (LP->tsc % LP->tslen) + 1;
+ }
+ LP->deg += LP->turnseq[LP->tsc - 1];
+ break;
+ }
+ else
+ {
+ int desdeg;
+ real dy, dx;
+ if (LP->tailfollow || LP->prey == thr)
+ {
+ dx = st->thread[LP->prey - 1].xrec[st->thread[LP->prey - 1].recpos] - LP->x;
+ dy = st->thread[LP->prey - 1].yrec[st->thread[LP->prey - 1].recpos] - LP->y;
+ }
+ else
+ {
+ dx = st->thread[LP->prey - 1].x - LP->x;
+ dy = st->thread[LP->prey - 1].y - LP->y;
+ }
+ desdeg =
+ (LP->vhfollow) ?
+ ((fabs (dx) > fabs (dy)) ?
+ ((dx > 0) ?
+ 0 * degs4
+ :
+ 2 * degs4)
+ :
+ ((dy > 0) ?
+ 1 * degs4
+ :
+ 3 * degs4))
+ :
+ ((dx > 0) ?
+ ((dy > 0) ?
+ 1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8));
+ if (desdeg - desdeg % degs4 != LP->deg - LP->deg % degs4
+ || LP->vhfollow)
+ {
+ if (!LP->vhfollow)
+ {
+ /* Using atan2 here doesn't seem to slow things down: */
+ desdeg = atan2 (dy, dx) / dtor;
+ wraparound (desdeg, 0, degs);
+ }
+ if (abs (desdeg - LP->deg) <= abs (LP->circturn))
+ LP->deg = desdeg;
+ else
+ LP->deg +=
+ (desdeg > LP->deg) ?
+ ((desdeg - LP->deg > degs2) ?
+ -abs (LP->circturn) : abs (LP->circturn))
+ : ((LP->deg - desdeg > degs2) ?
+ abs (LP->circturn) : -abs (LP->circturn));
+ }
+ else
+ LP->deg +=
+ (st->tanof[LP->deg] >
+ dy / dx) ? -abs (LP->circturn) : abs (LP->circturn);
+ }
+
+ wraparound (LP->deg, 0, degs);
+ {
+ unsigned char oldcol;
+ real oldy = LP->y, oldx = LP->x;
+ LP->x += st->cosof[LP->deg];
+ wraparound (LP->x, xmin, xmax + 1);
+ LP->y += st->sinof[LP->deg];
+ wraparound (LP->y, ymin, ymax + 1);
+#define xi ((int) LP->x)
+#define yi ((int) LP->y)
+
+ oldcol = gp (st, xi, yi);
+ if (oldcol != 0)
+ {
+ Bool vertwall = False, horiwall = False;
+ if (oldcol == 1 && ((LP->killwalls && st->gridden > 0) || LP->realbounce))
+ {
+ vertwall = (gp (st, xi, (int) oldy) == 1);
+ horiwall = (gp (st, (int) oldx, yi) == 1);
+ }
+ if (oldcol == 1 && LP->realbounce && (vertwall || horiwall))
+ {
+ if (vertwall)
+ LP->deg = -LP->deg + degs2;
+ else
+ LP->deg = -LP->deg;
+ }
+ else
+ {
+ if ((oldcol != LP->col && LP->realbounce)
+ || (oldcol == LP->col && LP->selfbounce))
+ LP->deg += degs4 * (random1 (2) * 2 - 1);
+ else if (oldcol != LP->col)
+ LP->deg += degs2;
+ }
+ if (LP->killwalls && st->gridden > 0 && oldcol == 1)
+ {
+ if (vertwall && xi + 1 <= xmax)
+ {
+ int yy;
+ for (yy = yi - yi % st->boxh;
+ yy <= yi - yi % st->boxh + st->boxh && yy <= ymax; yy++)
+ if (gp (st, xi + 1, yy) != 1 || yy == ymax)
+ sp (st, xi, yy, 0);
+ }
+ if (horiwall && yi + 1 <= ymax)
+ {
+ int xx;
+ for (xx = xi - xi % st->boxw;
+ xx <= xi - xi % st->boxw + st->boxw && xx <= xmax; xx++)
+ if (gp (st, xx, yi + 1) != 1 || xx == xmax)
+ sp (st, xx, yi, 0);
+ }
+ }
+ if (oldcol != LP->col || LP->selfbounce)
+ {
+ LP->x = oldx;
+ LP->y = oldy;
+ }
+ wraparound (LP->deg, 0, degs);
+ }
+ }
+
+ sp (st, xi, yi, LP->col);
+ if (LP->filled)
+ {
+ if (st->erasing)
+ sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0);
+ else
+ sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax);
+ }
+ LP->yrec[LP->recpos] = yi;
+ LP->xrec[LP->recpos] = xi;
+ if (LP->recpos == LP->reclen - 1)
+ LP->filled = True;
+ if (LP->filled && !st->erasing)
+ {
+ int co = LP->recpos;
+ LP->dead = True;
+ do
+ {
+ int nextco = co + 1;
+ wraparound (nextco, 0, LP->reclen);
+ if (LP->yrec[co] != LP->yrec[nextco]
+ || LP->xrec[co] != LP->xrec[nextco])
+ LP->dead = False;
+ co = nextco;
+ }
+ while (!(!LP->dead || co == LP->recpos));
+ }
+ LP->recpos++;
+ wraparound (LP->recpos, 0, LP->reclen);
+ return (!LP->dead);
+}
+
+static unsigned long
+vermiculate_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ int had_instring = (st->instring != 0);
+ int tick = 0;
+ int this_delay = 0;
+ int loop = 0;
+
+
+ AGAIN:
+ if (st->reset_p)
+ {
+ st->reset_p = 0;
+
+ clearscreen (st);
+ {
+ unsigned char thr;
+ for (thr = 1; thr <= st->threads; thr++)
+ newonscreen (st, thr);
+ }
+ if (st->autopal)
+ {
+ randpal (st);
+ palupdate (st, False);
+ }
+ bordupdate (st);
+ gridupdate (st, False);
+ }
+
+ {
+ Bool alltrap = True;
+ unsigned char thr;
+ for (thr = 1; thr <= st->threads; thr++)
+ if (move (st, thr))
+ alltrap = False;
+ if (alltrap) /* all threads are trapped */
+ st->reset_p = True;
+ if (st->speed != SPEEDMAX)
+ this_delay = waitabit (st);
+ }
+
+ if (tick++ > st->max_ticks && !had_instring)
+ {
+ tick = 0;
+ st->instring = 0;
+ maininit(st);
+ st->reset_p = True;
+ st->autopal = False;
+ }
+
+ if (this_delay == 0 && loop++ < 1000)
+ goto AGAIN;
+
+ return this_delay;
+}
+
+static void *
+vermiculate_init (Display *d, Window w)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ st->dpy = d;
+ st->window = w;
+ st->reset_p = 1;
+ st->instring = get_string_resource (st->dpy, "instring", "Instring");
+ if (st->instring && !*st->instring)
+ st->instring = 0;
+
+ st->max_ticks = get_integer_resource (st->dpy, "ticks", "Integer");
+ st->speed = get_integer_resource (st->dpy, "speed", "Speed");
+ if (st->speed <= 0) st->speed = 1;
+ st->mycolors[0].pixel = BlackPixel (st->dpy, DefaultScreen (st->dpy));
+
+ XSetWindowBackground (st->dpy, st->window,
+ BlackPixel (st->dpy, DefaultScreen (st->dpy)));
+ {
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+ st->wid = st->xgwa.width;
+ st->hei = st->xgwa.height;
+ st->mycmap = st->xgwa.colormap;
+ }
+ {
+ XGCValues mygcv;
+ st->mygc = XCreateGC (st->dpy, st->window, 0, &mygcv);
+ }
+
+ st->point = (unsigned char *) calloc (1, st->wid * st->hei);
+ maininit (st);
+ palupdate (st, True);
+ consume_instring(st);
+ return st;
+}
+
+
+static void
+vermiculate_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ st->wid = w;
+ st->hei = h;
+ free (st->point);
+ st->point = (unsigned char *) calloc (1, st->wid * st->hei);
+}
+
+static Bool
+vermiculate_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ struct state *st = (struct state *) closure;
+ if (screenhack_event_helper (dpy, window, event))
+ {
+ st->reset_p = 1;
+ return True;
+ }
+ return False;
+}
+
+static void
+consume_instring(struct state *st)
+{
+ char boolop;
+
+ while (wasakeypressed (st))
+ {
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case 'M':
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case 'A':
+ case 'N':
+ {
+ unsigned char othreads = st->threads;
+ if (st->ch == 'N')
+ st->threads = 0;
+ do
+ {
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ st->thread[++st->threads - 1].tmode = st->ch - '0';
+ break;
+ case 'R':
+ st->thread[++st->threads - 1].tmode =
+ random1 (tmodes - '0') + 1;
+ break;
+ }
+ }
+ while (!(st->ch == '\15' || st->ch == '#'
+ || st->threads == thrmax));
+ if (st->threads == 0)
+ st->threads = othreads;
+ st->reset_p = 1;
+ }
+ break;
+ }
+ break;
+ case 'C':
+ pickbank (st);
+ if (st->bnkt > 0)
+ {
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case 'D':
+ st->ch = readkey (st);
+ switch (st->ch)
+ {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+/* Careful! The following macro needs to be at the beginning of any
+block in which it's invoked, since it declares variables: */
+#define forallinbank(LDP) linedata *LDP; int bankc; \
+ for (bankc = 1; \
+ ((bankc <= st->bnkt) ? ( \
+ (LDP = &st->thread[st->bank[bankc - 1] - 1], 1) \
+ ) : 0) ; bankc++)
+ {
+ forallinbank (L) L->slice = degs / (st->ch - '0');
+ }
+ break;
+ case 'M':
+ {
+ forallinbank (L) L->slice = 0;
+ }
+ break;
+ }
+ break;
+ case 'S':
+ {
+ forallinbank (L)
+ {
+ L->otslen = L->tslen;
+ L->tslen = 0;
+ }
+ }
+ do
+ {
+ char oldch = st->ch;
+ st->ch = readkey (st);
+ {
+ forallinbank (L)
+ {
+ switch (st->ch)
+ {
+ case '0':
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ L->tslen++;
+ L->turnseq[L->tslen - 1] = st->ch - '0';
+ if (oldch == '-')
+ L->turnseq[L->tslen - 1] *= -1;
+ if (bankc % 2 == 0)
+ L->turnseq[L->tslen - 1] *= -1;
+ break;
+ }
+ }
+ }
+ }
+ while (!(st->ch == '\15' || st->ch == '#'
+ || st->thread[st->bank[0] - 1].tslen == 50));
+ {
+ forallinbank (L)
+ {
+ int seqSum = 0, c;
+
+ if (L->tslen == 0)
+ L->tslen = L->otslen;
+ for (c = 1; c <= L->tslen; c++)
+ seqSum += L->turnseq[c - 1];
+ if (seqSum == 0)
+ L->tclim = 1;
+ else
+ L->tclim =
+ (int) (((real) degs2) / abs (seqSum));
+ L->tsc = random1 (L->tslen) + 1;
+ }
+ }
+ break;
+ case 'T':
+ {
+ st->ch = readkey (st);
+ {
+ forallinbank (L)
+ {
+ switch (st->ch)
+ {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ L->tmode = st->ch - '0';
+ break;
+ case 'R':
+ L->tmode = random1 (tmodes - '0') + 1;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case 'O':
+ st->ch = readkey (st);
+ {
+ forallinbank (L) L->orichar = st->ch;
+ }
+ break;
+ case 'F':
+ {
+ banktype fbank;
+ arrcpy (fbank, st->bank);
+ {
+ int fbnkt = st->bnkt;
+ int bankc;
+ pickbank (st);
+ for (bankc = 1; bankc <= fbnkt; bankc++)
+ {
+ linedata *L = &st->thread[fbank[bankc - 1] - 1];
+ if (st->ch == 'N')
+ L->prey = 0;
+ else
+ L->prey = st->bank[0 + (bankc - 1) % st->bnkt];
+ }
+ }
+ }
+ break;
+ case 'L':
+ {
+ forallinbank (L) L->prey = st->bank[bankc % st->bnkt];
+ }
+ break;
+ case 'R':
+ st->ch = readkey (st);
+ {
+ forallinbank (L) switch (st->ch)
+ {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ L->circturn = 10 - (st->ch - '0');
+ break;
+ case 'R':
+ L->circturn = random1 (7) + 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case 'T':
+ case 'Y':
+ case 'N':
+ boolop = st->ch;
+ pickbank (st);
+ if (st->bnkt > 0)
+ {
+ st->ch = readkey (st);
+ {
+ forallinbank (L)
+ {
+ switch (st->ch)
+ {
+ case 'S':
+ bankmod (boolop, &L->selfbounce);
+ break;
+ case 'V':
+ bankmod (boolop, &L->vhfollow);
+ break;
+ case 'R':
+ bankmod (boolop, &L->realbounce);
+ break;
+ case 'L':
+ bankmod (boolop, &L->little);
+ st->cleared = True;
+ break;
+ case 'T':
+ bankmod (boolop, &L->tailfollow);
+ break;
+ case 'K':
+ bankmod (boolop, &L->killwalls);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case 'R':
+ if (st->bordcol == 1)
+ {
+ st->bordcol = 0;
+ bordupdate (st);
+ st->bordcorn = (st->bordcorn + 1) % 4;
+ st->bordcol = 1;
+ bordupdate (st);
+ }
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ {
+ int c;
+ for (c = 1; c <= thrmax; c++)
+ st->thread[c - 1].tmode = st->ch - '0';
+ }
+ break;
+ case '\40':
+ st->cleared = True;
+ break;
+ case 'E':
+ st->erasing = !st->erasing;
+ break;
+ case 'P':
+ randpal (st);
+ palupdate (st, True);
+ break;
+ case 'G':
+ {
+ char dimch = 'B';
+ Bool gridchanged = True;
+ if (st->gridden == 0)
+ st->gridden = st->ogd;
+ do
+ {
+ int msize = 0;
+ if (gridchanged)
+ {
+ clearscreen (st);
+ gridupdate (st, True);
+ }
+ st->ch = readkey (st);
+ gridchanged = True;
+ switch (st->ch)
+ {
+ case '+':
+ msize = 1;
+ break;
+ case '-':
+ msize = -1;
+ break;
+ case ']':
+ if (st->gridden < 15)
+ st->gridden++;
+ break;
+ case '[':
+ if (st->gridden > 0)
+ st->gridden--;
+ break;
+ case 'O':
+ st->ogd = st->gridden;
+ st->gridden = 0;
+ break;
+ case 'S':
+ st->boxw = st->boxh;
+ case 'W':
+ case 'H':
+ case 'B':
+ dimch = st->ch;
+ break;
+ default:
+ gridchanged = False;
+ }
+ if (dimch == 'W' || dimch == 'B')
+ st->boxw += msize;
+ if (dimch == 'H' || dimch == 'B')
+ st->boxh += msize;
+ if (st->boxw == 0)
+ st->boxw = 1;
+ if (st->boxh == 0)
+ st->boxh = 1;
+ }
+ while (!(st->ch == '\15' || st->ch == '#' || st->ch == 'O'));
+ st->cleared = True;
+ }
+ break;
+ case 'A':
+ st->autopal = !st->autopal;
+ break;
+ case 'B':
+ st->bordcol = 1 - st->bordcol;
+ bordupdate (st);
+ break;
+ case '-':
+ st->speed -= SPEEDINC;
+ if (st->speed < 1)
+ st->speed = 1;
+ break;
+ case '+':
+ st->speed += SPEEDINC;
+ if (st->speed > SPEEDMAX)
+ st->speed = SPEEDMAX;
+ break;
+ case '/':
+ if (st->curviness > 5)
+ st->curviness -= 5;
+ break;
+ case '*':
+ if (st->curviness < 50)
+ st->curviness += 5;
+ break;
+ case ']':
+ if (st->threads < thrmax)
+ newonscreen (st, ++st->threads);
+ break;
+ case '[':
+ if (st->threads > 1)
+ {
+ linedata *L = &st->thread[st->threads - 1];
+ int lastpos = (L->filled) ? L->reclen - 1 : L->recpos;
+ int c;
+ for (c = 0; c <= lastpos; c++)
+ sp (st, L->xrec[c], L->yrec[c], 0);
+ st->threads--;
+ }
+ break;
+ }
+ }
+}
+
+static void
+vermiculate_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+
+ if (st->point)
+ {
+ free(st->point);
+ }
+ free (st);
+}
+
+
+static const char *vermiculate_defaults[] = {
+ ".lowrez: true",
+ ".background: Black",
+ "*ticks: 20000",
+ "*fpsSolid: true",
+ "*speed: 1",
+ "*instring: ",
+#ifdef HAVE_MOBILE
+ "*ignoreRotation: True",
+#endif
+ 0
+};
+
+static XrmOptionDescRec vermiculate_options[] = {
+ {"-speed", ".speed", XrmoptionSepArg, 0},
+ {"-instring", ".instring", XrmoptionSepArg, 0},
+ {0, 0, 0, 0}
+};
+
+
+XSCREENSAVER_MODULE ("Vermiculate", vermiculate)