http://ftp.x.org/contrib/applications/xscreensaver-3.07.tar.gz
[xscreensaver] / hacks / demon.c
diff --git a/hacks/demon.c b/hacks/demon.c
new file mode 100644 (file)
index 0000000..84581c1
--- /dev/null
@@ -0,0 +1,902 @@
+/* -*- Mode: C; tab-width: 4 -*- */
+/* demon --- David Griffeath's cellular automata */
+
+#if !defined( lint ) && !defined( SABER )
+static const char sccsid[] = "@(#)demon.c      4.07 97/11/24 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:
+ * 10-May-97: Compatible with xscreensaver
+ * 16-Apr-97: -neighbors 3, 9 (not sound mathematically), 12, and 8 added
+ * 30-May-96: Ron Hitchens <ron@idiom.com>
+ *            Fixed memory management that caused leaks
+ * 14-Apr-96: -neighbors 6 runtime-time option added
+ * 21-Aug-95: 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 Neigbors
+  ----     ------------------
+  Square   4 or 8
+  Hexagon  6
+  Triangle 3, 9, or 12
+*/
+
+#ifdef STANDALONE
+#define PROGCLASS "Demon"
+#define HACK_INIT init_demon
+#define HACK_DRAW draw_demon
+#define demon_opts xlockmore_opts
+#define DEFAULTS       "*delay:        50000 \n"       \
+                                       "*count:            0 \n"       \
+                                       "*cycles:        1000 \n"       \
+                                       "*size:            -7 \n"       \
+                                       "*ncolors:         64 \n"       \
+                                       "*neighbors:    0 \n"
+# define UNIFORM_COLORS
+# include "xlockmore.h"                /* in xscreensaver distribution */
+#else /* STANDALONE */
+# include "xlock.h"                    /* in xlockmore distribution */
+#endif /* STANDALONE */
+#include "automata.h"
+
+/*-
+ * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
+ */
+#ifdef STANDALONE
+static int neighbors;
+#else
+extern int  neighbors;
+#endif /* !STANDALONE */
+
+ModeSpecOpt demon_opts =
+{0, NULL, 0, NULL, NULL};
+
+#ifdef USE_MODULES
+ModStruct   demon_description =
+{"demon", "init_demon", "draw_demon", "release_demon",
+ "refresh_demon", "init_demon", NULL, &demon_opts,
+ 50000, 0, 1000, -7, 64, 1.0, "",
+ "Shows Griffeath's cellular automata", 0, NULL};
+
+#endif
+
+#define DEMONBITS(n,w,h)\
+  dp->pixmaps[dp->init_bits++]=\
+  XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
+
+#define REDRAWSTEP 2000                /* How many cells to draw per cycle */
+#define MINSTATES 2
+#define MINGRIDSIZE 24
+#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 = 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;
+
+               gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
+               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)
+                       XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi),
+                                      gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y, 1, 1);
+               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)
+                       XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+                       ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
+                                      dp->shape.triangle[orient][0].y, 1, 1);
+               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 void
+addtolist(ModeInfo * mi, int col, int row, unsigned char state)
+{
+       demonstruct *dp = &demons[MI_SCREEN(mi)];
+       CellList   *current;
+
+       current = dp->cellList[state];
+       dp->cellList[state] = (CellList *) malloc(sizeof (CellList));
+       dp->cellList[state]->pt.x = col;
+       dp->cellList[state]->pt.y = row;
+       dp->cellList[state]->next = current;
+       dp->ncells[state]++;
+}
+
+#ifdef DEBUG
+static void
+print_state(ModeInfo * mi, int state)
+{
+       demonstruct *dp = &demons[MI_SCREEN(mi)];
+       CellList   *locallist;
+       int         i = 0;
+
+       locallist = dp->cellList[state];
+       (void) printf("state %d\n", state);
+       while (locallist) {
+               (void) printf("%d       x %d, y %d\n", i,
+                             locallist->pt.x, locallist->pt.y);
+               locallist = locallist->next;
+               i++;
+       }
+}
+
+#endif
+
+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] = NULL;
+       if (dp->ncells)
+               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 = 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 = NULL;
+       }
+       if (dp->oldcell != NULL) {
+               (void) free((void *) dp->oldcell);
+               dp->oldcell = NULL;
+       }
+       if (dp->newcell != NULL) {
+               (void) free((void *) dp->newcell);
+               dp->newcell = NULL;
+       }
+}
+
+static void
+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;
+
+               gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
+               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)
+                               XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi),
+                                              gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y, 1, 1);
+                       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 */
+               rects = (XRectangle *) malloc(dp->ncells[state] * sizeof (XRectangle));
+               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)
+                               XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
+                                              ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
+                                     dp->shape.triangle[orient][0].y, 1, 1);
+                       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);
+       XFlush(MI_DISPLAY(mi));
+}
+
+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);
+                       addtolist(mi, col, row, dp->oldcell[col + mrow]);
+               }
+               mrow += dp->ncols;
+       }
+}
+
+void
+init_demon(ModeInfo * mi)
+{
+       Display    *display = MI_DISPLAY(mi);
+       Window      window = MI_WINDOW(mi);
+       int         size = MI_SIZE(mi), nk;
+       demonstruct *dp;
+
+       if (demons == NULL) {
+               if ((demons = (demonstruct *) calloc(MI_NUM_SCREENS(mi),
+                                             sizeof (demonstruct))) == NULL)
+                       return;
+       }
+       dp = &demons[MI_SCREEN(mi)];
+       dp->generation = 0;
+       dp->redrawing = 0;
+       if (MI_NPIXELS(mi) < NUMSTIPPLES) {
+               if (dp->stippledGC == None) {
+                       XGCValues   gcv;
+
+                       gcv.fill_style = FillOpaqueStippled;
+                       dp->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
+               }
+               if (dp->init_bits == 0) {
+                       int         i;
+
+                       for (i = 1; i < NUMSTIPPLES; i++)
+                               DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
+               }
+       }
+       free_struct(dp);
+
+       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];
+       dp->cellList = (CellList **) calloc(dp->states, sizeof (CellList *));
+       dp->ncells = (int *) calloc(dp->states, sizeof (int));
+
+       dp->state = 0;
+
+       dp->width = MI_WIDTH(mi);
+       dp->height = MI_HEIGHT(mi);
+
+       if (dp->neighbors == 6) {
+               int         nccols, ncrows, i;
+
+               if (dp->width < 2)
+                       dp->width = 2;
+               if (dp->height < 4)
+                       dp->height = 4;
+               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, 2);
+               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;
+               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);
+
+       dp->oldcell = (unsigned char *)
+               malloc(dp->ncols * dp->nrows * sizeof (unsigned char));
+
+       dp->newcell = (unsigned char *)
+               malloc(dp->ncols * dp->nrows * sizeof (unsigned char));
+
+       RandomSoup(mi);
+}
+
+void
+draw_demon(ModeInfo * mi)
+{
+       demonstruct *dp = &demons[MI_SCREEN(mi)];
+       int         i, j, k, l, mj = 0, ml;
+
+       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;
+                                       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];
+                                       /* 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;
+                                       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];
+                                       /* 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;
+                                       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];
+                                       /* 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;
+                                               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 */
+                                               /* E */
+                                               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];
+                                       }
+                                       /* 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];
+                                       addtolist(mi, i, j, dp->oldcell[i + mj]);
+                               }
+                       mj += dp->ncols;
+               }
+               if (++dp->generation > MI_CYCLES(mi))
+                       init_demon(mi);
+               dp->state = 0;
+       } else {
+               if (dp->ncells[dp->state])
+                       draw_state(mi, dp->state);
+               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;
+                       }
+               }
+       }
+}
+void
+release_demon(ModeInfo * mi)
+{
+       if (demons != NULL) {
+               int         screen;
+
+               for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
+                       demonstruct *dp = &demons[screen];
+                       int         shade;
+
+                       if (dp->stippledGC != None) {
+                               XFreeGC(MI_DISPLAY(mi), dp->stippledGC);
+                       }
+                       for (shade = 0; shade < dp->init_bits; shade++)
+                               XFreePixmap(MI_DISPLAY(mi), dp->pixmaps[shade]);
+                       free_struct(dp);
+               }
+               (void) free((void *) demons);
+               demons = NULL;
+       }
+} void
+
+refresh_demon(ModeInfo * mi)
+{
+       demonstruct *dp = &demons[MI_SCREEN(mi)];
+
+       dp->redrawing = 1;
+       dp->redrawpos = 0;
+}