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