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