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