summaryrefslogtreecommitdiffstats
path: root/hacks/demon.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/demon.c')
-rw-r--r--hacks/demon.c952
1 files changed, 952 insertions, 0 deletions
diff --git a/hacks/demon.c b/hacks/demon.c
new file mode 100644
index 0000000..0fff863
--- /dev/null
+++ b/hacks/demon.c
@@ -0,0 +1,952 @@
+/* -*- Mode: C; tab-width: 4 -*- */
+/* demon --- David Griffeath's cellular automata */
+
+#if 0
+static const char sccsid[] = "@(#)demon.c 5.00 2000/11/01 xlockmore";
+#endif
+
+/*-
+ * Copyright (c) 1995 by David Bagley.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Revision History:
+ * 01-Nov-2000: Allocation checks
+ * 10-May-1997: Compatible with xscreensaver
+ * 16-Apr-1997: -neighbors 3, 9 (not sound mathematically), 12, and 8 added
+ * 30-May-1996: Ron Hitchens <ron@idiom.com>
+ * Fixed memory management that caused leaks
+ * 14-Apr-1996: -neighbors 6 runtime-time option added
+ * 21-Aug-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific
+ * American Magazine" Aug 1989 pp 102-105. Also very similar
+ * to hodgepodge machine described in A.K. Dewdney's "Computer
+ * Recreations", Scientific American Magazine" Aug 1988
+ * pp 104-107. Also used life.c as a guide.
+ */
+
+/*-
+ * A cellular universe of 4 phases debris, droplets, defects, and demons.
+ */
+
+/*-
+ Grid Number of Neighbors
+ ---- ------------------
+ Square 4 or 8
+ Hexagon 6
+ Triangle 3, 9, or 12
+*/
+
+#ifndef HAVE_JWXYZ
+# define DO_STIPPLE
+#endif
+
+#ifdef STANDALONE
+# define MODE_demon
+# define DEFAULTS "*delay: 50000 \n" \
+ "*count: 0 \n" \
+ "*cycles: 1000 \n" \
+ "*size: -30 \n" \
+ "*ncolors: 64 \n" \
+ "*fpsSolid: true \n" \
+ "*ignoreRotation: True \n" \
+
+# define UNIFORM_COLORS
+# define release_demon 0
+# define reshape_demon 0
+# define demon_handle_event 0
+# include "xlockmore.h" /* in xscreensaver distribution */
+#else /* STANDALONE */
+# include "xlock.h" /* in xlockmore distribution */
+#endif /* STANDALONE */
+#include "automata.h"
+
+#ifdef MODE_demon
+
+/*-
+ * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
+ */
+#define DEF_NEIGHBORS "0" /* choose random value */
+
+static int neighbors;
+
+static XrmOptionDescRec opts[] =
+{
+ {"-neighbors", ".demon.neighbors", XrmoptionSepArg, 0}
+};
+
+static argtype vars[] =
+{
+ {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
+};
+static OptionStruct desc[] =
+{
+ {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"}
+};
+
+ENTRYPOINT ModeSpecOpt demon_opts =
+{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
+
+#ifdef USE_MODULES
+ModStruct demon_description =
+{"demon", "init_demon", "draw_demon", (char *) NULL,
+ "refresh_demon", "init_demon", "free_demon", &demon_opts,
+ 50000, 0, 1000, -7, 64, 1.0, "",
+ "Shows Griffeath's cellular automata", 0, NULL};
+
+#endif
+
+#define DEMONBITS(n,w,h)\
+ if ((dp->pixmaps[dp->init_bits]=\
+ XCreatePixmapFromBitmapData(MI_DISPLAY(mi),window,(char *)n,w,h,1,0,1))==None){\
+ free_demon(mi); return;} else {dp->init_bits++;}
+
+#define REDRAWSTEP 2000 /* How many cells to draw per cycle */
+#define MINSTATES 2
+#define MINGRIDSIZE 5
+#define MINSIZE 4
+#define NEIGHBORKINDS 6
+
+/* Singly linked list */
+typedef struct _CellList {
+ XPoint pt;
+ struct _CellList *next;
+} CellList;
+
+typedef struct {
+ int generation;
+ int xs, ys;
+ int xb, yb;
+ int nrows, ncols;
+ int width, height;
+ int states;
+ int state;
+ int redrawing, redrawpos;
+ int *ncells;
+ CellList **cellList;
+ unsigned char *oldcell, *newcell;
+ int neighbors;
+ int init_bits;
+ GC stippledGC;
+ Pixmap pixmaps[NUMSTIPPLES - 1];
+ union {
+ XPoint hexagon[6];
+ XPoint triangle[2][3];
+ } shape;
+} demonstruct;
+
+static char plots[2][NEIGHBORKINDS] =
+{
+ {3, 4, 6, 8, 9, 12}, /* Neighborhoods */
+ {12, 16, 18, 20, 22, 24} /* Number of states */
+};
+
+static demonstruct *demons = (demonstruct *) NULL;
+
+static void
+drawcell(ModeInfo * mi, int col, int row, unsigned char state)
+{
+ demonstruct *dp = &demons[MI_SCREEN(mi)];
+ GC gc;
+
+ if (!state) {
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ gc = MI_GC(mi);
+ } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
+ MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) /
+ (dp->states - 1)) % MI_NPIXELS(mi)));
+ gc = MI_GC(mi);
+ } else {
+ XGCValues gcv;
+#ifdef DO_STIPPLE
+ gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
+#endif /* DO_STIPPLE */
+ gcv.foreground = MI_WHITE_PIXEL(mi);
+ gcv.background = MI_BLACK_PIXEL(mi);
+ XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
+ GCStipple | GCForeground | GCBackground, &gcv);
+ gc = dp->stippledGC;
+ }
+ if (dp->neighbors == 6) {
+ int ccol = 2 * col + !(row & 1), crow = 2 * row;
+
+ dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
+ dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
+ if (dp->xs == 1 && dp->ys == 1)
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
+ gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y);
+ else
+ XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ dp->shape.hexagon, 6, Convex, CoordModePrevious);
+ } else if (dp->neighbors == 4 || dp->neighbors == 8) {
+ XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ dp->xb + dp->xs * col, dp->yb + dp->ys * row,
+ dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3));
+ } else { /* TRI */
+ int orient = (col + row) % 2; /* O left 1 right */
+
+ dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
+ dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
+ if (dp->xs <= 3 || dp->ys <= 3)
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
+ dp->shape.triangle[orient][0].y);
+ else {
+ if (orient)
+ dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
+ else
+ dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
+ XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
+
+ }
+ }
+}
+
+static Bool
+addtolist(ModeInfo * mi, int col, int row, unsigned char state)
+{
+ demonstruct *dp = &demons[MI_SCREEN(mi)];
+ CellList *current;
+
+ current = dp->cellList[state];
+ if ((dp->cellList[state] = (CellList *)
+ malloc(sizeof (CellList))) == NULL) {
+ return False;
+ }
+ dp->cellList[state]->pt.x = col;
+ dp->cellList[state]->pt.y = row;
+ dp->cellList[state]->next = current;
+ dp->ncells[state]++;
+ return True;
+}
+
+
+static void
+free_state(demonstruct * dp, int state)
+{
+ CellList *current;
+
+ while (dp->cellList[state]) {
+ current = dp->cellList[state];
+ dp->cellList[state] = dp->cellList[state]->next;
+ (void) free((void *) current);
+ }
+ dp->cellList[state] = (CellList *) NULL;
+ if (dp->ncells != NULL)
+ dp->ncells[state] = 0;
+}
+
+
+static void
+free_list(demonstruct * dp)
+{
+ int state;
+
+ for (state = 0; state < dp->states; state++)
+ free_state(dp, state);
+ (void) free((void *) dp->cellList);
+ dp->cellList = (CellList **) NULL;
+}
+
+static void
+free_struct(demonstruct * dp)
+{
+ if (dp->cellList != NULL) {
+ free_list(dp);
+ }
+ if (dp->ncells != NULL) {
+ (void) free((void *) dp->ncells);
+ dp->ncells = (int *) NULL;
+ }
+ if (dp->oldcell != NULL) {
+ (void) free((void *) dp->oldcell);
+ dp->oldcell = (unsigned char *) NULL;
+ }
+ if (dp->newcell != NULL) {
+ (void) free((void *) dp->newcell);
+ dp->newcell = (unsigned char *) NULL;
+ }
+}
+
+ENTRYPOINT void
+free_demon(ModeInfo * mi)
+{
+ Display *display = MI_DISPLAY(mi);
+ demonstruct *dp = &demons[MI_SCREEN(mi)];
+ int shade;
+
+ if (dp->stippledGC != None) {
+ XFreeGC(display, dp->stippledGC);
+ dp->stippledGC = None;
+ }
+ for (shade = 0; shade < dp->init_bits; shade++) {
+ XFreePixmap(display, dp->pixmaps[shade]);
+ }
+ dp->init_bits = 0;
+ free_struct(dp);
+}
+
+static Bool
+draw_state(ModeInfo * mi, int state)
+{
+ demonstruct *dp = &demons[MI_SCREEN(mi)];
+ GC gc;
+ XRectangle *rects;
+ CellList *current;
+
+ if (!state) {
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
+ gc = MI_GC(mi);
+ } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
+ XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
+ MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) /
+ (dp->states - 1)) % MI_NPIXELS(mi)));
+ gc = MI_GC(mi);
+ } else {
+ XGCValues gcv;
+
+#ifdef DO_STIPPLE
+ gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
+#endif /* DO_STIPPLE */
+ gcv.foreground = MI_WHITE_PIXEL(mi);
+ gcv.background = MI_BLACK_PIXEL(mi);
+ XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
+ GCStipple | GCForeground | GCBackground, &gcv);
+ gc = dp->stippledGC;
+ }
+ if (dp->neighbors == 6) { /* Draw right away, slow */
+ current = dp->cellList[state];
+ while (current) {
+ int col, row, ccol, crow;
+
+ col = current->pt.x;
+ row = current->pt.y;
+ ccol = 2 * col + !(row & 1), crow = 2 * row;
+ dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
+ dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
+ if (dp->xs == 1 && dp->ys == 1)
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
+ gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y);
+ else
+ XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ dp->shape.hexagon, 6, Convex, CoordModePrevious);
+ current = current->next;
+ }
+ } else if (dp->neighbors == 4 || dp->neighbors == 8) {
+ /* Take advantage of XDrawRectangles */
+ int ncells = 0;
+
+ /* Create Rectangle list from part of the cellList */
+ if ((rects = (XRectangle *) malloc(dp->ncells[state] *
+ sizeof (XRectangle))) == NULL) {
+ return False;
+ }
+ current = dp->cellList[state];
+ while (current) {
+ rects[ncells].x = dp->xb + current->pt.x * dp->xs;
+ rects[ncells].y = dp->yb + current->pt.y * dp->ys;
+ rects[ncells].width = dp->xs - (dp->xs > 3);
+ rects[ncells].height = dp->ys - (dp->ys > 3);
+ current = current->next;
+ ncells++;
+ }
+ /* Finally get to draw */
+ XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, ncells);
+ /* Free up rects list and the appropriate part of the cellList */
+ (void) free((void *) rects);
+ } else { /* TRI */
+ current = dp->cellList[state];
+ while (current) {
+ int col, row, orient;
+
+ col = current->pt.x;
+ row = current->pt.y;
+ orient = (col + row) % 2; /* O left 1 right */
+ dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
+ dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
+ if (dp->xs <= 3 || dp->ys <= 3)
+ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
+ dp->shape.triangle[orient][0].y);
+ else {
+ if (orient)
+ dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
+ else
+ dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
+ XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+ dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
+ }
+ current = current->next;
+ }
+ }
+ free_state(dp, state);
+ return True;
+}
+
+static void
+RandomSoup(ModeInfo * mi)
+{
+ demonstruct *dp = &demons[MI_SCREEN(mi)];
+ int row, col, mrow = 0;
+
+ for (row = 0; row < dp->nrows; ++row) {
+ for (col = 0; col < dp->ncols; ++col) {
+ dp->oldcell[col + mrow] =
+ (unsigned char) LRAND() % ((unsigned char) dp->states);
+ if (!addtolist(mi, col, row, dp->oldcell[col + mrow]))
+ return; /* sparse soup */
+ }
+ mrow += dp->ncols;
+ }
+}
+
+ENTRYPOINT void
+init_demon (ModeInfo * mi)
+{
+ int size = MI_SIZE(mi), nk;
+ demonstruct *dp;
+
+ MI_INIT (mi, demons);
+ dp = &demons[MI_SCREEN(mi)];
+
+ if (MI_WIDTH(mi) < 100 || MI_HEIGHT(mi) < 100) /* tiny window */
+ size = MIN(MI_WIDTH(mi), MI_HEIGHT(mi));
+
+ dp->generation = 0;
+ dp->redrawing = 0;
+#ifdef DO_STIPPLE
+ if (MI_NPIXELS(mi) < NUMSTIPPLES) {
+ Window window = MI_WINDOW(mi);
+ if (dp->stippledGC == None) {
+ XGCValues gcv;
+
+ gcv.fill_style = FillOpaqueStippled;
+ if ((dp->stippledGC = XCreateGC(MI_DISPLAY(mi), window,
+ GCFillStyle, &gcv)) == None) {
+ free_demon(mi);
+ return;
+ }
+ }
+ if (dp->init_bits == 0) {
+ int i;
+
+ for (i = 1; i < NUMSTIPPLES; i++) {
+ DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
+ }
+ }
+ }
+#endif /* DO_STIPPLE */
+ free_struct(dp);
+
+#ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False);
+#endif
+
+ for (nk = 0; nk < NEIGHBORKINDS; nk++) {
+ if (neighbors == plots[0][nk]) {
+ dp->neighbors = plots[0][nk];
+ break;
+ }
+ if (nk == NEIGHBORKINDS - 1) {
+ nk = NRAND(NEIGHBORKINDS);
+ dp->neighbors = plots[0][nk];
+ break;
+ }
+ }
+
+ dp->states = MI_COUNT(mi);
+ if (dp->states < -MINSTATES)
+ dp->states = NRAND(-dp->states - MINSTATES + 1) + MINSTATES;
+ else if (dp->states < MINSTATES)
+ dp->states = plots[1][nk];
+ if ((dp->cellList = (CellList **) calloc(dp->states,
+ sizeof (CellList *))) == NULL) {
+ free_demon(mi);
+ return;
+ }
+ if ((dp->ncells = (int *) calloc(dp->states, sizeof (int))) == NULL) {
+ free_demon(mi);
+ return;
+ }
+
+ dp->state = 0;
+
+ dp->width = MI_WIDTH(mi);
+ dp->height = MI_HEIGHT(mi);
+
+ if (dp->neighbors == 6) {
+ int nccols, ncrows, i;
+
+ if (dp->width < 8)
+ dp->width = 8;
+ if (dp->height < 8)
+ dp->height = 8;
+ if (size < -MINSIZE)
+ dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
+ else if (size < MINSIZE) {
+ if (!size)
+ dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
+ else
+ dp->ys = MINSIZE;
+ } else
+ dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE));
+ dp->xs = dp->ys;
+ nccols = MAX(dp->width / dp->xs - 2, 2);
+ ncrows = MAX(dp->height / dp->ys - 1, 4);
+ dp->ncols = nccols / 2;
+ dp->nrows = 2 * (ncrows / 4);
+ dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
+ dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 + dp->ys - 2;
+ for (i = 0; i < 6; i++) {
+ dp->shape.hexagon[i].x = (dp->xs - 1) * hexagonUnit[i].x;
+ dp->shape.hexagon[i].y = ((dp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
+ }
+ } else if (dp->neighbors == 4 || dp->neighbors == 8) {
+ if (size < -MINSIZE)
+ dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
+ else if (size < MINSIZE) {
+ if (!size)
+ dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
+ else
+ dp->ys = MINSIZE;
+ } else
+ dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE));
+ dp->xs = dp->ys;
+ dp->ncols = MAX(dp->width / dp->xs, 2);
+ dp->nrows = MAX(dp->height / dp->ys, 2);
+ dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
+ dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
+ } else { /* TRI */
+ int orient, i;
+
+ if (dp->width < 2)
+ dp->width = 2;
+ if (dp->height < 2)
+ dp->height = 2;
+ if (size < -MINSIZE)
+ dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
+ else if (size < MINSIZE) {
+ if (!size)
+ dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
+ else
+ dp->ys = MINSIZE;
+ } else
+ dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
+ MINGRIDSIZE));
+ dp->xs = (int) (1.52 * dp->ys);
+ dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
+ dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
+ dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
+ dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
+ for (orient = 0; orient < 2; orient++) {
+ for (i = 0; i < 3; i++) {
+ dp->shape.triangle[orient][i].x =
+ (dp->xs - 2) * triangleUnit[orient][i].x;
+ dp->shape.triangle[orient][i].y =
+ (dp->ys - 2) * triangleUnit[orient][i].y;
+ }
+ }
+ }
+
+ MI_CLEARWINDOW(mi);
+
+ if ((dp->oldcell = (unsigned char *)
+ malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
+ free_demon(mi);
+ return;
+ }
+
+ if ((dp->newcell = (unsigned char *)
+ malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
+ free_demon(mi);
+ return;
+ }
+
+ RandomSoup(mi);
+}
+
+ENTRYPOINT void
+draw_demon (ModeInfo * mi)
+{
+ int i, j, k, l, mj = 0, ml;
+ demonstruct *dp;
+
+ if (demons == NULL)
+ return;
+ dp = &demons[MI_SCREEN(mi)];
+ if (dp->cellList == NULL)
+ return;
+
+ MI_IS_DRAWN(mi) = True;
+ if (dp->state >= dp->states) {
+ (void) memcpy((char *) dp->newcell, (char *) dp->oldcell,
+ dp->ncols * dp->nrows * sizeof (unsigned char));
+
+ if (dp->neighbors == 6) {
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ /* NE */
+ if (!(j & 1))
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ else
+ k = i;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* E */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SE */
+ if (!(j & 1))
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ else
+ k = i;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SW */
+ if (j & 1)
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ else
+ k = i;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* W */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* NW */
+ if (j & 1)
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ else
+ k = i;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ mj += dp->ncols;
+ }
+ } else if (dp->neighbors == 4 || dp->neighbors == 8) {
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ /* N */
+ k = i;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* E */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* S */
+ k = i;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* W */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ /*l = j;*/
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ mj += dp->ncols;
+ }
+ if (dp->neighbors == 8) {
+ mj = 0;
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ /* NE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* NW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ mj += dp->ncols;
+ }
+ }
+ } else if (dp->neighbors == 3 || dp->neighbors == 9 ||
+ dp->neighbors == 12) {
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ if ((i + j) % 2) { /* right */
+ /* W */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ } else { /* left */
+ /* E */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ /* N */
+ k = i;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* S */
+ k = i;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ mj += dp->ncols;
+ }
+ if (dp->neighbors == 9 || dp->neighbors == 12) {
+ mj = 0;
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ /* NN */
+ k = i;
+ if (!j)
+ l = dp->nrows - 2;
+ else if (!(j - 1))
+ l = dp->nrows - 1;
+ else
+ l = j - 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SS */
+ k = i;
+ if (j + 1 == dp->nrows)
+ l = 1;
+ else if (j + 2 == dp->nrows)
+ l = 0;
+ else
+ l = j + 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* NW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* NE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ l = (!j) ? dp->nrows - 1 : j - 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ l = (j + 1 == dp->nrows) ? 0 : j + 1;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ mj += dp->ncols;
+ }
+ if (dp->neighbors == 12) {
+ mj = 0;
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++) {
+ if ((i + j) % 2) { /* right */
+ /* NNW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ if (!j)
+ l = dp->nrows - 2;
+ else if (!(j - 1))
+ l = dp->nrows - 1;
+ else
+ l = j - 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SSW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ if (j + 1 == dp->nrows)
+ l = 1;
+ else if (j + 2 == dp->nrows)
+ l = 0;
+ else
+ l = j + 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* EE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ /*l = j;*/
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ } else { /* left */
+ /* NNE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ if (!j)
+ l = dp->nrows - 2;
+ else if (!(j - 1))
+ l = dp->nrows - 1;
+ else
+ l = j - 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* SSE */
+ k = (i + 1 == dp->ncols) ? 0 : i + 1;
+ if (j + 1 == dp->nrows)
+ l = 1;
+ else if (j + 2 == dp->nrows)
+ l = 0;
+ else
+ l = j + 2;
+ ml = l * dp->ncols;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ /* WW */
+ k = (!i) ? dp->ncols - 1 : i - 1;
+ /*l = j;*/
+ ml = mj;
+ if (dp->oldcell[k + ml] ==
+ (int) (dp->oldcell[i + mj] + 1) % dp->states)
+ dp->newcell[i + mj] = dp->oldcell[k + ml];
+ }
+ }
+ mj += dp->ncols;
+ }
+ }
+ }
+ }
+ mj = 0;
+ for (j = 0; j < dp->nrows; j++) {
+ for (i = 0; i < dp->ncols; i++)
+ if (dp->oldcell[i + mj] != dp->newcell[i + mj]) {
+ dp->oldcell[i + mj] = dp->newcell[i + mj];
+ if (!addtolist(mi, i, j, dp->oldcell[i + mj])) {
+ free_demon(mi);
+ return;
+ }
+ }
+ mj += dp->ncols;
+ }
+ if (++dp->generation > MI_CYCLES(mi))
+ init_demon(mi);
+ dp->state = 0;
+ } else {
+ if (dp->ncells[dp->state])
+ if (!draw_state(mi, dp->state)) {
+ free_demon(mi);
+ return;
+ }
+ dp->state++;
+ }
+ if (dp->redrawing) {
+ for (i = 0; i < REDRAWSTEP; i++) {
+ if (dp->oldcell[dp->redrawpos]) {
+ drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
+ dp->oldcell[dp->redrawpos]);
+ }
+ if (++(dp->redrawpos) >= dp->ncols * dp->nrows) {
+ dp->redrawing = 0;
+ break;
+ }
+ }
+ }
+}
+
+#ifndef STANDALONE
+ENTRYPOINT void
+refresh_demon (ModeInfo * mi)
+{
+ demonstruct *dp;
+
+ if (demons == NULL)
+ return;
+ dp = &demons[MI_SCREEN(mi)];
+
+ dp->redrawing = 1;
+ dp->redrawpos = 0;
+}
+#endif
+
+XSCREENSAVER_MODULE ("Demon", demon)
+
+#endif /* MODE_demon */