db0255aefbbee22bdaf4dcaf5d7caf568b9a3cdc
[xscreensaver] / hacks / demon.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* demon --- David Griffeath's cellular automata */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)demon.c       4.07 97/11/24 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1995 by David Bagley.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 10-May-97: Compatible with xscreensaver
26  * 16-Apr-97: -neighbors 3, 9 (not sound mathematically), 12, and 8 added
27  * 30-May-96: Ron Hitchens <ron@idiom.com>
28  *            Fixed memory management that caused leaks
29  * 14-Apr-96: -neighbors 6 runtime-time option added
30  * 21-Aug-95: Coded from A.K. Dewdney's "Computer Recreations", Scientific
31  *            American Magazine" Aug 1989 pp 102-105.  Also very similar to
32  *            hodgepodge machine described in A.K. Dewdney's "Computer
33  *            Recreations", Scientific American Magazine" Aug 1988 pp 104-107.
34  *            also used life.c as a guide.
35  */
36
37 /*-
38  * A cellular universe of 4 phases debris, droplets, defects, and demons.
39  */
40
41 /*-
42   Grid     Number of Neigbors
43   ----     ------------------
44   Square   4 or 8
45   Hexagon  6
46   Triangle 3, 9, or 12
47 */
48
49 #ifdef STANDALONE
50 #define PROGCLASS "Demon"
51 #define HACK_INIT init_demon
52 #define HACK_DRAW draw_demon
53 #define demon_opts xlockmore_opts
54 #define DEFAULTS        "*delay:        50000 \n"       \
55                                         "*count:            0 \n"       \
56                                         "*cycles:        1000 \n"       \
57                                         "*size:            -7 \n"       \
58                                         "*ncolors:         64 \n"       \
59                                         "*neighbors:    0 \n"
60 # define SMOOTH_COLORS
61 # include "xlockmore.h"         /* in xscreensaver distribution */
62 #else /* STANDALONE */
63 # include "xlock.h"                     /* in xlockmore distribution */
64 #endif /* STANDALONE */
65 #include "automata.h"
66
67 /*-
68  * neighbors of 0 randomizes it between 3, 4, 6, 8, 9, and 12.
69  */
70 #ifdef STANDALONE
71 static int neighbors;
72 #else
73 extern int  neighbors;
74 #endif /* !STANDALONE */
75
76 ModeSpecOpt demon_opts =
77 {0, NULL, 0, NULL, NULL};
78
79 #ifdef USE_MODULES
80 ModStruct   demon_description =
81 {"demon", "init_demon", "draw_demon", "release_demon",
82  "refresh_demon", "init_demon", NULL, &demon_opts,
83  50000, 0, 1000, -7, 64, 1.0, "",
84  "Shows Griffeath's cellular automata", 0, NULL};
85
86 #endif
87
88 #define DEMONBITS(n,w,h)\
89   dp->pixmaps[dp->init_bits++]=\
90   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
91
92 #define REDRAWSTEP 2000         /* How many cells to draw per cycle */
93 #define MINSTATES 2
94 #define MINGRIDSIZE 24
95 #define MINSIZE 4
96 #define NEIGHBORKINDS 6
97
98 /* Singly linked list */
99 typedef struct _CellList {
100         XPoint      pt;
101         struct _CellList *next;
102 } CellList;
103
104 typedef struct {
105         int         generation;
106         int         xs, ys;
107         int         xb, yb;
108         int         nrows, ncols;
109         int         width, height;
110         int         states;
111         int         state;
112         int         redrawing, redrawpos;
113         int        *ncells;
114         CellList  **cellList;
115         unsigned char *oldcell, *newcell;
116         int         neighbors;
117         int         init_bits;
118         GC          stippledGC;
119         Pixmap      pixmaps[NUMSTIPPLES - 1];
120         union {
121                 XPoint      hexagon[6];
122                 XPoint      triangle[2][3];
123         } shape;
124 } demonstruct;
125
126 static char plots[2][NEIGHBORKINDS] =
127 {
128         {3, 4, 6, 8, 9, 12},    /* Neighborhoods */
129         {12, 16, 18, 20, 22, 24}        /* Number of states */
130 };
131
132 static demonstruct *demons = NULL;
133
134 static void
135 drawcell(ModeInfo * mi, int col, int row, unsigned char state)
136 {
137         demonstruct *dp = &demons[MI_SCREEN(mi)];
138         GC          gc;
139
140         if (!state) {
141                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
142                 gc = MI_GC(mi);
143         } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
144                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
145                            MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) /
146                                          (dp->states - 1)) % MI_NPIXELS(mi)));
147                 gc = MI_GC(mi);
148         } else {
149                 XGCValues   gcv;
150
151                 gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
152                 gcv.foreground = MI_WHITE_PIXEL(mi);
153                 gcv.background = MI_BLACK_PIXEL(mi);
154                 XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
155                           GCStipple | GCForeground | GCBackground, &gcv);
156                 gc = dp->stippledGC;
157         }
158         if (dp->neighbors == 6) {
159                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
160
161                 dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
162                 dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
163                 if (dp->xs == 1 && dp->ys == 1)
164                         XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi),
165                                        gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y, 1, 1);
166                 else
167                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
168                             dp->shape.hexagon, 6, Convex, CoordModePrevious);
169         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
170                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
171                 dp->xb + dp->xs * col, dp->yb + dp->ys * row,
172                 dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3));
173         } else {                /* TRI */
174                 int         orient = (col + row) % 2;   /* O left 1 right */
175
176                 dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
177                 dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
178                 if (dp->xs <= 3 || dp->ys <= 3)
179                         XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
180                         ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
181                                        dp->shape.triangle[orient][0].y, 1, 1);
182                 else {
183                         if (orient)
184                                 dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
185                         else
186                                 dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
187                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
188                                      dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
189
190                 }
191         }
192 }
193
194 static void
195 addtolist(ModeInfo * mi, int col, int row, unsigned char state)
196 {
197         demonstruct *dp = &demons[MI_SCREEN(mi)];
198         CellList   *current;
199
200         current = dp->cellList[state];
201         dp->cellList[state] = (CellList *) malloc(sizeof (CellList));
202         dp->cellList[state]->pt.x = col;
203         dp->cellList[state]->pt.y = row;
204         dp->cellList[state]->next = current;
205         dp->ncells[state]++;
206 }
207
208 #ifdef DEBUG
209 static void
210 print_state(ModeInfo * mi, int state)
211 {
212         demonstruct *dp = &demons[MI_SCREEN(mi)];
213         CellList   *locallist;
214         int         i = 0;
215
216         locallist = dp->cellList[state];
217         (void) printf("state %d\n", state);
218         while (locallist) {
219                 (void) printf("%d       x %d, y %d\n", i,
220                               locallist->pt.x, locallist->pt.y);
221                 locallist = locallist->next;
222                 i++;
223         }
224 }
225
226 #endif
227
228 static void
229 free_state(demonstruct * dp, int state)
230 {
231         CellList   *current;
232
233         while (dp->cellList[state]) {
234                 current = dp->cellList[state];
235                 dp->cellList[state] = dp->cellList[state]->next;
236                 (void) free((void *) current);
237         }
238         dp->cellList[state] = NULL;
239         if (dp->ncells)
240                 dp->ncells[state] = 0;
241 }
242
243
244 static void
245 free_list(demonstruct * dp)
246 {
247         int         state;
248
249         for (state = 0; state < dp->states; state++)
250                 free_state(dp, state);
251         (void) free((void *) dp->cellList);
252         dp->cellList = NULL;
253 }
254
255 static void
256 free_struct(demonstruct * dp)
257 {
258         if (dp->cellList != NULL) {
259                 free_list(dp);
260         }
261         if (dp->ncells != NULL) {
262                 (void) free((void *) dp->ncells);
263                 dp->ncells = NULL;
264         }
265         if (dp->oldcell != NULL) {
266                 (void) free((void *) dp->oldcell);
267                 dp->oldcell = NULL;
268         }
269         if (dp->newcell != NULL) {
270                 (void) free((void *) dp->newcell);
271                 dp->newcell = NULL;
272         }
273 }
274
275 static void
276 draw_state(ModeInfo * mi, int state)
277 {
278         demonstruct *dp = &demons[MI_SCREEN(mi)];
279         GC          gc;
280         XRectangle *rects;
281         CellList   *current;
282
283         if (!state) {
284                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
285                 gc = MI_GC(mi);
286         } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
287                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
288                            MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) /
289                                          (dp->states - 1)) % MI_NPIXELS(mi)));
290                 gc = MI_GC(mi);
291         } else {
292                 XGCValues   gcv;
293
294                 gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
295                 gcv.foreground = MI_WHITE_PIXEL(mi);
296                 gcv.background = MI_BLACK_PIXEL(mi);
297                 XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
298                           GCStipple | GCForeground | GCBackground, &gcv);
299                 gc = dp->stippledGC;
300         }
301         if (dp->neighbors == 6) {       /* Draw right away, slow */
302                 current = dp->cellList[state];
303                 while (current) {
304                         int         col, row, ccol, crow;
305
306                         col = current->pt.x;
307                         row = current->pt.y;
308                         ccol = 2 * col + !(row & 1), crow = 2 * row;
309                         dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
310                         dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
311                         if (dp->xs == 1 && dp->ys == 1)
312                                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi),
313                                                gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y, 1, 1);
314                         else
315                                 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
316                                              dp->shape.hexagon, 6, Convex, CoordModePrevious);
317                         current = current->next;
318                 }
319         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
320                 /* Take advantage of XDrawRectangles */
321                 int         ncells = 0;
322
323                 /* Create Rectangle list from part of the cellList */
324                 rects = (XRectangle *) malloc(dp->ncells[state] * sizeof (XRectangle));
325                 current = dp->cellList[state];
326                 while (current) {
327                         rects[ncells].x = dp->xb + current->pt.x * dp->xs;
328                         rects[ncells].y = dp->yb + current->pt.y * dp->ys;
329                         rects[ncells].width = dp->xs - (dp->xs > 3);
330                         rects[ncells].height = dp->ys - (dp->ys > 3);
331                         current = current->next;
332                         ncells++;
333                 }
334                 /* Finally get to draw */
335                 XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, ncells);
336                 /* Free up rects list and the appropriate part of the cellList */
337                 (void) free((void *) rects);
338         } else {                /* TRI */
339                 current = dp->cellList[state];
340                 while (current) {
341                         int         col, row, orient;
342
343                         col = current->pt.x;
344                         row = current->pt.y;
345                         orient = (col + row) % 2;       /* O left 1 right */
346                         dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
347                         dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
348                         if (dp->xs <= 3 || dp->ys <= 3)
349                                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
350                                                ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
351                                       dp->shape.triangle[orient][0].y, 1, 1);
352                         else {
353                                 if (orient)
354                                         dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
355                                 else
356                                         dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
357                                 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
358                                              dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
359                         }
360                         current = current->next;
361                 }
362         }
363         free_state(dp, state);
364         XFlush(MI_DISPLAY(mi));
365 }
366
367 static void
368 RandomSoup(ModeInfo * mi)
369 {
370         demonstruct *dp = &demons[MI_SCREEN(mi)];
371         int         row, col, mrow = 0;
372
373         for (row = 0; row < dp->nrows; ++row) {
374                 for (col = 0; col < dp->ncols; ++col) {
375                         dp->oldcell[col + mrow] =
376                                 (unsigned char) LRAND() % ((unsigned char) dp->states);
377                         addtolist(mi, col, row, dp->oldcell[col + mrow]);
378                 }
379                 mrow += dp->ncols;
380         }
381 }
382
383 void
384 init_demon(ModeInfo * mi)
385 {
386         Display    *display = MI_DISPLAY(mi);
387         Window      window = MI_WINDOW(mi);
388         int         size = MI_SIZE(mi), nk;
389         demonstruct *dp;
390
391         if (demons == NULL) {
392                 if ((demons = (demonstruct *) calloc(MI_NUM_SCREENS(mi),
393                                               sizeof (demonstruct))) == NULL)
394                         return;
395         }
396         dp = &demons[MI_SCREEN(mi)];
397         dp->generation = 0;
398         dp->redrawing = 0;
399         if (MI_NPIXELS(mi) < NUMSTIPPLES) {
400                 if (dp->stippledGC == None) {
401                         XGCValues   gcv;
402
403                         gcv.fill_style = FillOpaqueStippled;
404                         dp->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
405                 }
406                 if (dp->init_bits == 0) {
407                         int         i;
408
409                         for (i = 1; i < NUMSTIPPLES; i++)
410                                 DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
411                 }
412         }
413         free_struct(dp);
414
415         for (nk = 0; nk < NEIGHBORKINDS; nk++) {
416                 if (neighbors == plots[0][nk]) {
417                         dp->neighbors = plots[0][nk];
418                         break;
419                 }
420                 if (nk == NEIGHBORKINDS - 1) {
421                         nk = NRAND(NEIGHBORKINDS);
422                         dp->neighbors = plots[0][nk];
423                         break;
424                 }
425         }
426
427         dp->states = MI_COUNT(mi);
428         if (dp->states < -MINSTATES)
429                 dp->states = NRAND(-dp->states - MINSTATES + 1) + MINSTATES;
430         else if (dp->states < MINSTATES)
431                 dp->states = plots[1][nk];
432         dp->cellList = (CellList **) calloc(dp->states, sizeof (CellList *));
433         dp->ncells = (int *) calloc(dp->states, sizeof (int));
434
435         dp->state = 0;
436
437         dp->width = MI_WIDTH(mi);
438         dp->height = MI_HEIGHT(mi);
439
440         if (dp->neighbors == 6) {
441                 int         nccols, ncrows, i;
442
443                 if (dp->width < 2)
444                         dp->width = 2;
445                 if (dp->height < 4)
446                         dp->height = 4;
447                 if (size < -MINSIZE)
448                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
449                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
450                 else if (size < MINSIZE) {
451                         if (!size)
452                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
453                         else
454                                 dp->ys = MINSIZE;
455                 } else
456                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
457                                                MINGRIDSIZE));
458                 dp->xs = dp->ys;
459                 nccols = MAX(dp->width / dp->xs - 2, 2);
460                 ncrows = MAX(dp->height / dp->ys - 1, 2);
461                 dp->ncols = nccols / 2;
462                 dp->nrows = 2 * (ncrows / 4);
463                 dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
464                 dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 + dp->ys;
465                 for (i = 0; i < 6; i++) {
466                         dp->shape.hexagon[i].x = (dp->xs - 1) * hexagonUnit[i].x;
467                         dp->shape.hexagon[i].y = ((dp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
468                 }
469         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
470                 if (size < -MINSIZE)
471                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
472                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
473                 else if (size < MINSIZE) {
474                         if (!size)
475                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
476                         else
477                                 dp->ys = MINSIZE;
478                 } else
479                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
480                                                MINGRIDSIZE));
481                 dp->xs = dp->ys;
482                 dp->ncols = MAX(dp->width / dp->xs, 2);
483                 dp->nrows = MAX(dp->height / dp->ys, 2);
484                 dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
485                 dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
486         } else {                /* TRI */
487                 int         orient, i;
488
489                 if (dp->width < 2)
490                         dp->width = 2;
491                 if (dp->height < 2)
492                         dp->height = 2;
493                 if (size < -MINSIZE)
494                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
495                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
496                 else if (size < MINSIZE) {
497                         if (!size)
498                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
499                         else
500                                 dp->ys = MINSIZE;
501                 } else
502                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
503                                                MINGRIDSIZE));
504                 dp->xs = (int) (1.52 * dp->ys);
505                 dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
506                 dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
507                 dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
508                 dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
509                 for (orient = 0; orient < 2; orient++) {
510                         for (i = 0; i < 3; i++) {
511                                 dp->shape.triangle[orient][i].x =
512                                         (dp->xs - 2) * triangleUnit[orient][i].x;
513                                 dp->shape.triangle[orient][i].y =
514                                         (dp->ys - 2) * triangleUnit[orient][i].y;
515                         }
516                 }
517         }
518
519         MI_CLEARWINDOW(mi);
520
521         dp->oldcell = (unsigned char *)
522                 malloc(dp->ncols * dp->nrows * sizeof (unsigned char));
523
524         dp->newcell = (unsigned char *)
525                 malloc(dp->ncols * dp->nrows * sizeof (unsigned char));
526
527         RandomSoup(mi);
528 }
529
530 void
531 draw_demon(ModeInfo * mi)
532 {
533         demonstruct *dp = &demons[MI_SCREEN(mi)];
534         int         i, j, k, l, mj = 0, ml;
535
536         MI_IS_DRAWN(mi) = True;
537
538         if (dp->state >= dp->states) {
539                 (void) memcpy((char *) dp->newcell, (char *) dp->oldcell,
540                               dp->ncols * dp->nrows * sizeof (unsigned char));
541
542                 if (dp->neighbors == 6) {
543                         for (j = 0; j < dp->nrows; j++) {
544                                 for (i = 0; i < dp->ncols; i++) {
545                                         /* NE */
546                                         if (!(j & 1))
547                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
548                                         else
549                                                 k = i;
550                                         l = (!j) ? dp->nrows - 1 : j - 1;
551                                         ml = l * dp->ncols;
552                                         if (dp->oldcell[k + ml] ==
553                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
554                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
555                                         /* E */
556                                         k = (i + 1 == dp->ncols) ? 0 : i + 1;
557                                         l = j;
558                                         ml = mj;
559                                         if (dp->oldcell[k + ml] ==
560                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
561                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
562                                         /* SE */
563                                         if (!(j & 1))
564                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
565                                         else
566                                                 k = i;
567                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
568                                         ml = l * dp->ncols;
569                                         if (dp->oldcell[k + ml] ==
570                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
571                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
572                                         /* SW */
573                                         if (j & 1)
574                                                 k = (!i) ? dp->ncols - 1 : i - 1;
575                                         else
576                                                 k = i;
577                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
578                                         ml = l * dp->ncols;
579                                         if (dp->oldcell[k + ml] ==
580                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
581                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
582                                         /* W */
583                                         k = (!i) ? dp->ncols - 1 : i - 1;
584                                         l = j;
585                                         ml = mj;
586                                         if (dp->oldcell[k + ml] ==
587                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
588                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
589                                         /* NW */
590                                         if (j & 1)
591                                                 k = (!i) ? dp->ncols - 1 : i - 1;
592                                         else
593                                                 k = i;
594                                         l = (!j) ? dp->nrows - 1 : j - 1;
595                                         ml = l * dp->ncols;
596                                         if (dp->oldcell[k + ml] ==
597                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
598                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
599                                 }
600                                 mj += dp->ncols;
601                         }
602                 } else if (dp->neighbors == 4 || dp->neighbors == 8) {
603                         for (j = 0; j < dp->nrows; j++) {
604                                 for (i = 0; i < dp->ncols; i++) {
605                                         /* N */
606                                         k = i;
607                                         l = (!j) ? dp->nrows - 1 : j - 1;
608                                         ml = l * dp->ncols;
609                                         if (dp->oldcell[k + ml] ==
610                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
611                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
612                                         /* E */
613                                         k = (i + 1 == dp->ncols) ? 0 : i + 1;
614                                         l = j;
615                                         ml = mj;
616                                         if (dp->oldcell[k + ml] ==
617                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
618                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
619                                         /* S */
620                                         k = i;
621                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
622                                         ml = l * dp->ncols;
623                                         if (dp->oldcell[k + ml] ==
624                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
625                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
626                                         /* W */
627                                         k = (!i) ? dp->ncols - 1 : i - 1;
628                                         l = j;
629                                         ml = mj;
630                                         if (dp->oldcell[k + ml] ==
631                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
632                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
633                                 }
634                                 mj += dp->ncols;
635                         }
636                         if (dp->neighbors == 8) {
637                                 mj = 0;
638                                 for (j = 0; j < dp->nrows; j++) {
639                                         for (i = 0; i < dp->ncols; i++) {
640                                                 /* NE */
641                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
642                                                 l = (!j) ? dp->nrows - 1 : j - 1;
643                                                 ml = l * dp->ncols;
644                                                 if (dp->oldcell[k + ml] ==
645                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
646                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
647                                                 /* SE */
648                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
649                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
650                                                 ml = l * dp->ncols;
651                                                 if (dp->oldcell[k + ml] ==
652                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
653                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
654                                                 /* SW */
655                                                 k = (!i) ? dp->ncols - 1 : i - 1;
656                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
657                                                 ml = l * dp->ncols;
658                                                 if (dp->oldcell[k + ml] ==
659                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
660                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
661                                                 /* NW */
662                                                 k = (!i) ? dp->ncols - 1 : i - 1;
663                                                 l = (!j) ? dp->nrows - 1 : j - 1;
664                                                 ml = l * dp->ncols;
665                                                 if (dp->oldcell[k + ml] ==
666                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
667                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
668                                         }
669                                         mj += dp->ncols;
670                                 }
671                         }
672                 } else if (dp->neighbors == 3 || dp->neighbors == 9 ||
673                            dp->neighbors == 12) {
674                         for (j = 0; j < dp->nrows; j++) {
675                                 for (i = 0; i < dp->ncols; i++) {
676                                         if ((i + j) % 2) {      /* right */
677                                                 /* W */
678                                                 k = (!i) ? dp->ncols - 1 : i - 1;
679                                                 l = j;
680                                                 ml = mj;
681                                                 if (dp->oldcell[k + ml] ==
682                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
683                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
684                                         } else {        /* left */
685                                                 /* E */
686                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
687                                                 l = j;
688                                                 ml = mj;
689                                                 if (dp->oldcell[k + ml] ==
690                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
691                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
692                                         }
693                                         /* N */
694                                         k = i;
695                                         l = (!j) ? dp->nrows - 1 : j - 1;
696                                         ml = l * dp->ncols;
697                                         if (dp->oldcell[k + ml] ==
698                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
699                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
700                                         /* S */
701                                         k = i;
702                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
703                                         ml = l * dp->ncols;
704                                         if (dp->oldcell[k + ml] ==
705                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
706                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
707                                 }
708                                 mj += dp->ncols;
709                         }
710                         if (dp->neighbors == 9 || dp->neighbors == 12) {
711                                 mj = 0;
712                                 for (j = 0; j < dp->nrows; j++) {
713                                         for (i = 0; i < dp->ncols; i++) {
714                                                 /* NN */
715                                                 k = i;
716                                                 if (!j)
717                                                         l = dp->nrows - 2;
718                                                 else if (!(j - 1))
719                                                         l = dp->nrows - 1;
720                                                 else
721                                                         l = j - 2;
722                                                 ml = l * dp->ncols;
723                                                 if (dp->oldcell[k + ml] ==
724                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
725                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
726                                                 /* SS */
727                                                 k = i;
728                                                 if (j + 1 == dp->nrows)
729                                                         l = 1;
730                                                 else if (j + 2 == dp->nrows)
731                                                         l = 0;
732                                                 else
733                                                         l = j + 2;
734                                                 ml = l * dp->ncols;
735                                                 if (dp->oldcell[k + ml] ==
736                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
737                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
738                                                 /* NW */
739                                                 k = (!i) ? dp->ncols - 1 : i - 1;
740                                                 l = (!j) ? dp->nrows - 1 : j - 1;
741                                                 ml = l * dp->ncols;
742                                                 if (dp->oldcell[k + ml] ==
743                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
744                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
745                                                 /* NE */
746                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
747                                                 l = (!j) ? dp->nrows - 1 : j - 1;
748                                                 ml = l * dp->ncols;
749                                                 if (dp->oldcell[k + ml] ==
750                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
751                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
752                                                 /* SW */
753                                                 k = (!i) ? dp->ncols - 1 : i - 1;
754                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
755                                                 ml = l * dp->ncols;
756                                                 if (dp->oldcell[k + ml] ==
757                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
758                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
759                                                 /* SE */
760                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
761                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
762                                                 ml = l * dp->ncols;
763                                                 if (dp->oldcell[k + ml] ==
764                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
765                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
766                                         }
767                                         mj += dp->ncols;
768                                 }
769                                 if (dp->neighbors == 12) {
770                                         mj = 0;
771                                         for (j = 0; j < dp->nrows; j++) {
772                                                 for (i = 0; i < dp->ncols; i++) {
773                                                         if ((i + j) % 2) {      /* right */
774                                                                 /* NNW */
775                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
776                                                                 if (!j)
777                                                                         l = dp->nrows - 2;
778                                                                 else if (!(j - 1))
779                                                                         l = dp->nrows - 1;
780                                                                 else
781                                                                         l = j - 2;
782                                                                 ml = l * dp->ncols;
783                                                                 if (dp->oldcell[k + ml] ==
784                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
785                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
786                                                                 /* SSW */
787                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
788                                                                 if (j + 1 == dp->nrows)
789                                                                         l = 1;
790                                                                 else if (j + 2 == dp->nrows)
791                                                                         l = 0;
792                                                                 else
793                                                                         l = j + 2;
794                                                                 ml = l * dp->ncols;
795                                                                 if (dp->oldcell[k + ml] ==
796                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
797                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
798                                                                 /* EE */
799                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
800                                                                 l = j;
801                                                                 ml = mj;
802                                                                 if (dp->oldcell[k + ml] ==
803                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
804                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
805                                                         } else {        /* left */
806                                                                 /* NNE */
807                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
808                                                                 if (!j)
809                                                                         l = dp->nrows - 2;
810                                                                 else if (!(j - 1))
811                                                                         l = dp->nrows - 1;
812                                                                 else
813                                                                         l = j - 2;
814                                                                 ml = l * dp->ncols;
815                                                                 if (dp->oldcell[k + ml] ==
816                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
817                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
818                                                                 /* SSE */
819                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
820                                                                 if (j + 1 == dp->nrows)
821                                                                         l = 1;
822                                                                 else if (j + 2 == dp->nrows)
823                                                                         l = 0;
824                                                                 else
825                                                                         l = j + 2;
826                                                                 ml = l * dp->ncols;
827                                                                 if (dp->oldcell[k + ml] ==
828                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
829                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
830                                                                 /* WW */
831                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
832                                                                 l = j;
833                                                                 ml = mj;
834                                                                 if (dp->oldcell[k + ml] ==
835                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
836                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
837                                                         }
838                                                 }
839                                                 mj += dp->ncols;
840                                         }
841                                 }
842                         }
843                 }
844                 mj = 0;
845                 for (j = 0; j < dp->nrows; j++) {
846                         for (i = 0; i < dp->ncols; i++)
847                                 if (dp->oldcell[i + mj] != dp->newcell[i + mj]) {
848                                         dp->oldcell[i + mj] = dp->newcell[i + mj];
849                                         addtolist(mi, i, j, dp->oldcell[i + mj]);
850                                 }
851                         mj += dp->ncols;
852                 }
853                 if (++dp->generation > MI_CYCLES(mi))
854                         init_demon(mi);
855                 dp->state = 0;
856         } else {
857                 if (dp->ncells[dp->state])
858                         draw_state(mi, dp->state);
859                 dp->state++;
860         }
861         if (dp->redrawing) {
862                 for (i = 0; i < REDRAWSTEP; i++) {
863                         if (dp->oldcell[dp->redrawpos]) {
864                                 drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
865                                          dp->oldcell[dp->redrawpos]);
866                         }
867                         if (++(dp->redrawpos) >= dp->ncols * dp->nrows) {
868                                 dp->redrawing = 0;
869                                 break;
870                         }
871                 }
872         }
873 }
874 void
875 release_demon(ModeInfo * mi)
876 {
877         if (demons != NULL) {
878                 int         screen;
879
880                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
881                         demonstruct *dp = &demons[screen];
882                         int         shade;
883
884                         if (dp->stippledGC != None) {
885                                 XFreeGC(MI_DISPLAY(mi), dp->stippledGC);
886                         }
887                         for (shade = 0; shade < dp->init_bits; shade++)
888                                 XFreePixmap(MI_DISPLAY(mi), dp->pixmaps[shade]);
889                         free_struct(dp);
890                 }
891                 (void) free((void *) demons);
892                 demons = NULL;
893         }
894 } void
895
896 refresh_demon(ModeInfo * mi)
897 {
898         demonstruct *dp = &demons[MI_SCREEN(mi)];
899
900         dp->redrawing = 1;
901         dp->redrawpos = 0;
902 }