From http://www.jwz.org/xscreensaver/xscreensaver-5.35.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 # include "xlockmore.h"         /* in xscreensaver distribution */
65 #else /* STANDALONE */
66 # include "xlock.h"             /* in xlockmore distribution */
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         {"-neighbors", ".demon.neighbors", XrmoptionSepArg, 0}
82 };
83
84 static argtype vars[] =
85 {
86         {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
87 };
88 static OptionStruct desc[] =
89 {
90         {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3, 9 or 12"}
91 };
92
93 ENTRYPOINT 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 #ifdef DO_STIPPLE
169                 gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
170 #endif /* DO_STIPPLE */
171                 gcv.foreground = MI_WHITE_PIXEL(mi);
172                 gcv.background = MI_BLACK_PIXEL(mi);
173                 XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
174                           GCStipple | GCForeground | GCBackground, &gcv);
175                 gc = dp->stippledGC;
176         }
177         if (dp->neighbors == 6) {
178                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
179
180                 dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
181                 dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
182                 if (dp->xs == 1 && dp->ys == 1)
183                         XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
184                                        gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y);
185                 else
186                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
187                             dp->shape.hexagon, 6, Convex, CoordModePrevious);
188         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
189                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
190                 dp->xb + dp->xs * col, dp->yb + dp->ys * row,
191                 dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3));
192         } else {                /* TRI */
193                 int         orient = (col + row) % 2;   /* O left 1 right */
194
195                 dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
196                 dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
197                 if (dp->xs <= 3 || dp->ys <= 3)
198                         XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
199                         ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
200                                        dp->shape.triangle[orient][0].y);
201                 else {
202                         if (orient)
203                                 dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
204                         else
205                                 dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
206                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
207                                      dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
208
209                 }
210         }
211 }
212
213 static Bool
214 addtolist(ModeInfo * mi, int col, int row, unsigned char state)
215 {
216         demonstruct *dp = &demons[MI_SCREEN(mi)];
217         CellList   *current;
218
219         current = dp->cellList[state];
220         if ((dp->cellList[state] = (CellList *)
221                 malloc(sizeof (CellList))) == NULL) {
222                 return False;
223         }
224         dp->cellList[state]->pt.x = col;
225         dp->cellList[state]->pt.y = row;
226         dp->cellList[state]->next = current;
227         dp->ncells[state]++;
228         return True;
229 }
230
231
232 static void
233 free_state(demonstruct * dp, int state)
234 {
235         CellList   *current;
236
237         while (dp->cellList[state]) {
238                 current = dp->cellList[state];
239                 dp->cellList[state] = dp->cellList[state]->next;
240                 (void) free((void *) current);
241         }
242         dp->cellList[state] = (CellList *) NULL;
243         if (dp->ncells != NULL)
244                 dp->ncells[state] = 0;
245 }
246
247
248 static void
249 free_list(demonstruct * dp)
250 {
251         int         state;
252
253         for (state = 0; state < dp->states; state++)
254                 free_state(dp, state);
255         (void) free((void *) dp->cellList);
256         dp->cellList = (CellList **) NULL;
257 }
258
259 static void
260 free_struct(demonstruct * dp)
261 {
262         if (dp->cellList != NULL) {
263                 free_list(dp);
264         }
265         if (dp->ncells != NULL) {
266                 (void) free((void *) dp->ncells);
267                 dp->ncells = (int *) NULL;
268         }
269         if (dp->oldcell != NULL) {
270                 (void) free((void *) dp->oldcell);
271                 dp->oldcell = (unsigned char *) NULL;
272         }
273         if (dp->newcell != NULL) {
274                 (void) free((void *) dp->newcell);
275                 dp->newcell = (unsigned char *) NULL;
276         }
277 }
278
279 static void
280 free_demon(Display *display, demonstruct *dp)
281 {
282         int         shade;
283
284         if (dp->stippledGC != None) {
285                 XFreeGC(display, dp->stippledGC);
286                 dp->stippledGC = None;
287         }
288         for (shade = 0; shade < dp->init_bits; shade++) {
289                 XFreePixmap(display, dp->pixmaps[shade]);
290         }
291         dp->init_bits = 0;
292         free_struct(dp);
293 }
294
295 static Bool
296 draw_state(ModeInfo * mi, int state)
297 {
298         demonstruct *dp = &demons[MI_SCREEN(mi)];
299         GC          gc;
300         XRectangle *rects;
301         CellList   *current;
302
303         if (!state) {
304                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
305                 gc = MI_GC(mi);
306         } else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
307                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
308                            MI_PIXEL(mi, (((int) state - 1) * MI_NPIXELS(mi) /
309                                          (dp->states - 1)) % MI_NPIXELS(mi)));
310                 gc = MI_GC(mi);
311         } else {
312                 XGCValues   gcv;
313
314 #ifdef DO_STIPPLE
315                 gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
316 #endif /* DO_STIPPLE */
317                 gcv.foreground = MI_WHITE_PIXEL(mi);
318                 gcv.background = MI_BLACK_PIXEL(mi);
319                 XChangeGC(MI_DISPLAY(mi), dp->stippledGC,
320                           GCStipple | GCForeground | GCBackground, &gcv);
321                 gc = dp->stippledGC;
322         }
323         if (dp->neighbors == 6) {       /* Draw right away, slow */
324                 current = dp->cellList[state];
325                 while (current) {
326                         int         col, row, ccol, crow;
327
328                         col = current->pt.x;
329                         row = current->pt.y;
330                         ccol = 2 * col + !(row & 1), crow = 2 * row;
331                         dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
332                         dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
333                         if (dp->xs == 1 && dp->ys == 1)
334                                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi),
335                                                gc, dp->shape.hexagon[0].x, dp->shape.hexagon[0].y);
336                         else
337                                 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
338                                              dp->shape.hexagon, 6, Convex, CoordModePrevious);
339                         current = current->next;
340                 }
341         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
342                 /* Take advantage of XDrawRectangles */
343                 int         ncells = 0;
344
345                 /* Create Rectangle list from part of the cellList */
346                 if ((rects = (XRectangle *) malloc(dp->ncells[state] *
347                          sizeof (XRectangle))) == NULL) {
348                         return False;
349                 }
350                 current = dp->cellList[state];
351                 while (current) {
352                         rects[ncells].x = dp->xb + current->pt.x * dp->xs;
353                         rects[ncells].y = dp->yb + current->pt.y * dp->ys;
354                         rects[ncells].width = dp->xs - (dp->xs > 3);
355                         rects[ncells].height = dp->ys - (dp->ys > 3);
356                         current = current->next;
357                         ncells++;
358                 }
359                 /* Finally get to draw */
360                 XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, ncells);
361                 /* Free up rects list and the appropriate part of the cellList */
362                 (void) free((void *) rects);
363         } else {                /* TRI */
364                 current = dp->cellList[state];
365                 while (current) {
366                         int         col, row, orient;
367
368                         col = current->pt.x;
369                         row = current->pt.y;
370                         orient = (col + row) % 2;       /* O left 1 right */
371                         dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
372                         dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
373                         if (dp->xs <= 3 || dp->ys <= 3)
374                                 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
375                                                ((orient) ? -1 : 1) + dp->shape.triangle[orient][0].x,
376                                       dp->shape.triangle[orient][0].y);
377                         else {
378                                 if (orient)
379                                         dp->shape.triangle[orient][0].x += (dp->xs / 2 - 1);
380                                 else
381                                         dp->shape.triangle[orient][0].x -= (dp->xs / 2 - 1);
382                                 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
383                                              dp->shape.triangle[orient], 3, Convex, CoordModePrevious);
384                         }
385                         current = current->next;
386                 }
387         }
388         free_state(dp, state);
389         return True;
390 }
391
392 static void
393 RandomSoup(ModeInfo * mi)
394 {
395         demonstruct *dp = &demons[MI_SCREEN(mi)];
396         int         row, col, mrow = 0;
397
398         for (row = 0; row < dp->nrows; ++row) {
399                 for (col = 0; col < dp->ncols; ++col) {
400                         dp->oldcell[col + mrow] =
401                                 (unsigned char) LRAND() % ((unsigned char) dp->states);
402                         if (!addtolist(mi, col, row, dp->oldcell[col + mrow]))
403                                 return; /* sparse soup */
404                 }
405                 mrow += dp->ncols;
406         }
407 }
408
409 ENTRYPOINT void
410 init_demon (ModeInfo * mi)
411 {
412         Display    *display = MI_DISPLAY(mi);
413         int         size = MI_SIZE(mi), nk;
414         demonstruct *dp;
415
416         if (demons == NULL) {
417                 if ((demons = (demonstruct *) calloc(MI_NUM_SCREENS(mi),
418                                               sizeof (demonstruct))) == NULL)
419                         return;
420         }
421         dp = &demons[MI_SCREEN(mi)];
422
423         dp->generation = 0;
424         dp->redrawing = 0;
425 #ifdef DO_STIPPLE
426         if (MI_NPIXELS(mi) < NUMSTIPPLES) {
427           Window window = MI_WINDOW(mi);
428           if (dp->stippledGC == None) {
429                         XGCValues   gcv;
430
431                         gcv.fill_style = FillOpaqueStippled;
432                         if ((dp->stippledGC = XCreateGC(display, window,
433                                  GCFillStyle, &gcv)) == None) {
434                                 free_demon(display, dp);
435                                 return;
436                         }
437                 }
438                 if (dp->init_bits == 0) {
439                         int         i;
440
441                         for (i = 1; i < NUMSTIPPLES; i++) {
442                                 DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
443                         }
444                 }
445         }
446 #endif /* DO_STIPPLE */
447         free_struct(dp);
448
449 #ifdef HAVE_JWXYZ
450     jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False);
451 #endif
452
453         for (nk = 0; nk < NEIGHBORKINDS; nk++) {
454                 if (neighbors == plots[0][nk]) {
455                         dp->neighbors = plots[0][nk];
456                         break;
457                 }
458                 if (nk == NEIGHBORKINDS - 1) {
459                         nk = NRAND(NEIGHBORKINDS);
460                         dp->neighbors = plots[0][nk];
461                         break;
462                 }
463         }
464
465         dp->states = MI_COUNT(mi);
466         if (dp->states < -MINSTATES)
467                 dp->states = NRAND(-dp->states - MINSTATES + 1) + MINSTATES;
468         else if (dp->states < MINSTATES)
469                 dp->states = plots[1][nk];
470         if ((dp->cellList = (CellList **) calloc(dp->states,
471                 sizeof (CellList *))) == NULL) {
472                 free_demon(display, dp);
473                 return;
474         }
475         if ((dp->ncells = (int *) calloc(dp->states, sizeof (int))) == NULL) {
476                 free_demon(display, dp);
477                 return;
478         }
479
480         dp->state = 0;
481
482         dp->width = MI_WIDTH(mi);
483         dp->height = MI_HEIGHT(mi);
484
485         if (dp->neighbors == 6) {
486                 int         nccols, ncrows, i;
487
488                 if (dp->width < 8)
489                         dp->width = 8;
490                 if (dp->height < 8)
491                         dp->height = 8;
492                 if (size < -MINSIZE)
493                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
494                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
495                 else if (size < MINSIZE) {
496                         if (!size)
497                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
498                         else
499                                 dp->ys = MINSIZE;
500                 } else
501                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
502                                                MINGRIDSIZE));
503                 dp->xs = dp->ys;
504                 nccols = MAX(dp->width / dp->xs - 2, 2);
505                 ncrows = MAX(dp->height / dp->ys - 1, 4);
506                 dp->ncols = nccols / 2;
507                 dp->nrows = 2 * (ncrows / 4);
508                 dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
509                 dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 + dp->ys - 2;
510                 for (i = 0; i < 6; i++) {
511                         dp->shape.hexagon[i].x = (dp->xs - 1) * hexagonUnit[i].x;
512                         dp->shape.hexagon[i].y = ((dp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
513                 }
514         } else if (dp->neighbors == 4 || dp->neighbors == 8) {
515                 if (size < -MINSIZE)
516                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
517                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
518                 else if (size < MINSIZE) {
519                         if (!size)
520                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
521                         else
522                                 dp->ys = MINSIZE;
523                 } else
524                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
525                                                MINGRIDSIZE));
526                 dp->xs = dp->ys;
527                 dp->ncols = MAX(dp->width / dp->xs, 2);
528                 dp->nrows = MAX(dp->height / dp->ys, 2);
529                 dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
530                 dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
531         } else {                /* TRI */
532                 int         orient, i;
533
534                 if (dp->width < 2)
535                         dp->width = 2;
536                 if (dp->height < 2)
537                         dp->height = 2;
538                 if (size < -MINSIZE)
539                         dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
540                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
541                 else if (size < MINSIZE) {
542                         if (!size)
543                                 dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
544                         else
545                                 dp->ys = MINSIZE;
546                 } else
547                         dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
548                                                MINGRIDSIZE));
549                 dp->xs = (int) (1.52 * dp->ys);
550                 dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
551                 dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
552                 dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
553                 dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
554                 for (orient = 0; orient < 2; orient++) {
555                         for (i = 0; i < 3; i++) {
556                                 dp->shape.triangle[orient][i].x =
557                                         (dp->xs - 2) * triangleUnit[orient][i].x;
558                                 dp->shape.triangle[orient][i].y =
559                                         (dp->ys - 2) * triangleUnit[orient][i].y;
560                         }
561                 }
562         }
563
564         MI_CLEARWINDOW(mi);
565
566         if ((dp->oldcell = (unsigned char *)
567                 malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
568                 free_demon(display, dp);
569                 return;
570         }
571
572         if ((dp->newcell = (unsigned char *)
573                 malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
574                 free_demon(display, dp);
575                 return;
576         }
577
578         RandomSoup(mi);
579 }
580
581 ENTRYPOINT void
582 draw_demon (ModeInfo * mi)
583 {
584         int         i, j, k, l, mj = 0, ml;
585         demonstruct *dp;
586
587         if (demons == NULL)
588                 return;
589         dp = &demons[MI_SCREEN(mi)];
590         if (dp->cellList == NULL)
591                 return;
592
593         MI_IS_DRAWN(mi) = True;
594         if (dp->state >= dp->states) {
595                 (void) memcpy((char *) dp->newcell, (char *) dp->oldcell,
596                               dp->ncols * dp->nrows * sizeof (unsigned char));
597
598                 if (dp->neighbors == 6) {
599                         for (j = 0; j < dp->nrows; j++) {
600                                 for (i = 0; i < dp->ncols; i++) {
601                                         /* NE */
602                                         if (!(j & 1))
603                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
604                                         else
605                                                 k = i;
606                                         l = (!j) ? dp->nrows - 1 : j - 1;
607                                         ml = l * dp->ncols;
608                                         if (dp->oldcell[k + ml] ==
609                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
610                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
611                                         /* E */
612                                         k = (i + 1 == dp->ncols) ? 0 : i + 1;
613                                         ml = mj;
614                                         if (dp->oldcell[k + ml] ==
615                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
616                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
617                                         /* SE */
618                                         if (!(j & 1))
619                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
620                                         else
621                                                 k = i;
622                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
623                                         ml = l * dp->ncols;
624                                         if (dp->oldcell[k + ml] ==
625                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
626                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
627                                         /* SW */
628                                         if (j & 1)
629                                                 k = (!i) ? dp->ncols - 1 : i - 1;
630                                         else
631                                                 k = i;
632                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
633                                         ml = l * dp->ncols;
634                                         if (dp->oldcell[k + ml] ==
635                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
636                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
637                                         /* W */
638                                         k = (!i) ? dp->ncols - 1 : i - 1;
639                                         ml = mj;
640                                         if (dp->oldcell[k + ml] ==
641                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
642                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
643                                         /* NW */
644                                         if (j & 1)
645                                                 k = (!i) ? dp->ncols - 1 : i - 1;
646                                         else
647                                                 k = i;
648                                         l = (!j) ? dp->nrows - 1 : j - 1;
649                                         ml = l * dp->ncols;
650                                         if (dp->oldcell[k + ml] ==
651                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
652                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
653                                 }
654                                 mj += dp->ncols;
655                         }
656                 } else if (dp->neighbors == 4 || dp->neighbors == 8) {
657                         for (j = 0; j < dp->nrows; j++) {
658                                 for (i = 0; i < dp->ncols; i++) {
659                                         /* N */
660                                         k = i;
661                                         l = (!j) ? dp->nrows - 1 : j - 1;
662                                         ml = l * dp->ncols;
663                                         if (dp->oldcell[k + ml] ==
664                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
665                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
666                                         /* E */
667                                         k = (i + 1 == dp->ncols) ? 0 : i + 1;
668                                         ml = mj;
669                                         if (dp->oldcell[k + ml] ==
670                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
671                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
672                                         /* S */
673                                         k = i;
674                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
675                                         ml = l * dp->ncols;
676                                         if (dp->oldcell[k + ml] ==
677                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
678                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
679                                         /* W */
680                                         k = (!i) ? dp->ncols - 1 : i - 1;
681                                         /*l = j;*/
682                                         ml = mj;
683                                         if (dp->oldcell[k + ml] ==
684                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
685                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
686                                 }
687                                 mj += dp->ncols;
688                         }
689                         if (dp->neighbors == 8) {
690                                 mj = 0;
691                                 for (j = 0; j < dp->nrows; j++) {
692                                         for (i = 0; i < dp->ncols; i++) {
693                                                 /* NE */
694                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
695                                                 l = (!j) ? dp->nrows - 1 : j - 1;
696                                                 ml = l * dp->ncols;
697                                                 if (dp->oldcell[k + ml] ==
698                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
699                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
700                                                 /* SE */
701                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
702                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
703                                                 ml = l * dp->ncols;
704                                                 if (dp->oldcell[k + ml] ==
705                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
706                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
707                                                 /* SW */
708                                                 k = (!i) ? dp->ncols - 1 : i - 1;
709                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
710                                                 ml = l * dp->ncols;
711                                                 if (dp->oldcell[k + ml] ==
712                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
713                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
714                                                 /* NW */
715                                                 k = (!i) ? dp->ncols - 1 : i - 1;
716                                                 l = (!j) ? dp->nrows - 1 : j - 1;
717                                                 ml = l * dp->ncols;
718                                                 if (dp->oldcell[k + ml] ==
719                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
720                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
721                                         }
722                                         mj += dp->ncols;
723                                 }
724                         }
725                 } else if (dp->neighbors == 3 || dp->neighbors == 9 ||
726                            dp->neighbors == 12) {
727                         for (j = 0; j < dp->nrows; j++) {
728                                 for (i = 0; i < dp->ncols; i++) {
729                                         if ((i + j) % 2) {      /* right */
730                                                 /* W */
731                                                 k = (!i) ? dp->ncols - 1 : i - 1;
732                                                 ml = mj;
733                                                 if (dp->oldcell[k + ml] ==
734                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
735                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
736                                         } else {        /* left */
737                                                 /* E */
738                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
739                                                 ml = mj;
740                                                 if (dp->oldcell[k + ml] ==
741                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
742                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
743                                         }
744                                         /* N */
745                                         k = i;
746                                         l = (!j) ? dp->nrows - 1 : j - 1;
747                                         ml = l * dp->ncols;
748                                         if (dp->oldcell[k + ml] ==
749                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
750                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
751                                         /* S */
752                                         k = i;
753                                         l = (j + 1 == dp->nrows) ? 0 : j + 1;
754                                         ml = l * dp->ncols;
755                                         if (dp->oldcell[k + ml] ==
756                                             (int) (dp->oldcell[i + mj] + 1) % dp->states)
757                                                 dp->newcell[i + mj] = dp->oldcell[k + ml];
758                                 }
759                                 mj += dp->ncols;
760                         }
761                         if (dp->neighbors == 9 || dp->neighbors == 12) {
762                                 mj = 0;
763                                 for (j = 0; j < dp->nrows; j++) {
764                                         for (i = 0; i < dp->ncols; i++) {
765                                                 /* NN */
766                                                 k = i;
767                                                 if (!j)
768                                                         l = dp->nrows - 2;
769                                                 else if (!(j - 1))
770                                                         l = dp->nrows - 1;
771                                                 else
772                                                         l = j - 2;
773                                                 ml = l * dp->ncols;
774                                                 if (dp->oldcell[k + ml] ==
775                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
776                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
777                                                 /* SS */
778                                                 k = i;
779                                                 if (j + 1 == dp->nrows)
780                                                         l = 1;
781                                                 else if (j + 2 == dp->nrows)
782                                                         l = 0;
783                                                 else
784                                                         l = j + 2;
785                                                 ml = l * dp->ncols;
786                                                 if (dp->oldcell[k + ml] ==
787                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
788                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
789                                                 /* NW */
790                                                 k = (!i) ? dp->ncols - 1 : i - 1;
791                                                 l = (!j) ? dp->nrows - 1 : j - 1;
792                                                 ml = l * dp->ncols;
793                                                 if (dp->oldcell[k + ml] ==
794                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
795                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
796                                                 /* NE */
797                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
798                                                 l = (!j) ? dp->nrows - 1 : j - 1;
799                                                 ml = l * dp->ncols;
800                                                 if (dp->oldcell[k + ml] ==
801                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
802                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
803                                                 /* SW */
804                                                 k = (!i) ? dp->ncols - 1 : i - 1;
805                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
806                                                 ml = l * dp->ncols;
807                                                 if (dp->oldcell[k + ml] ==
808                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
809                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
810                                                 /* SE */
811                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
812                                                 l = (j + 1 == dp->nrows) ? 0 : j + 1;
813                                                 ml = l * dp->ncols;
814                                                 if (dp->oldcell[k + ml] ==
815                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
816                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
817                                         }
818                                         mj += dp->ncols;
819                                 }
820                                 if (dp->neighbors == 12) {
821                                         mj = 0;
822                                         for (j = 0; j < dp->nrows; j++) {
823                                                 for (i = 0; i < dp->ncols; i++) {
824                                                         if ((i + j) % 2) {      /* right */
825                                                                 /* NNW */
826                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
827                                                                 if (!j)
828                                                                         l = dp->nrows - 2;
829                                                                 else if (!(j - 1))
830                                                                         l = dp->nrows - 1;
831                                                                 else
832                                                                         l = j - 2;
833                                                                 ml = l * dp->ncols;
834                                                                 if (dp->oldcell[k + ml] ==
835                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
836                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
837                                                                 /* SSW */
838                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
839                                                                 if (j + 1 == dp->nrows)
840                                                                         l = 1;
841                                                                 else if (j + 2 == dp->nrows)
842                                                                         l = 0;
843                                                                 else
844                                                                         l = j + 2;
845                                                                 ml = l * dp->ncols;
846                                                                 if (dp->oldcell[k + ml] ==
847                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
848                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
849                                                                 /* EE */
850                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
851                                                                 /*l = j;*/
852                                                                 ml = mj;
853                                                                 if (dp->oldcell[k + ml] ==
854                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
855                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
856                                                         } else {        /* left */
857                                                                 /* NNE */
858                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
859                                                                 if (!j)
860                                                                         l = dp->nrows - 2;
861                                                                 else if (!(j - 1))
862                                                                         l = dp->nrows - 1;
863                                                                 else
864                                                                         l = j - 2;
865                                                                 ml = l * dp->ncols;
866                                                                 if (dp->oldcell[k + ml] ==
867                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
868                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
869                                                                 /* SSE */
870                                                                 k = (i + 1 == dp->ncols) ? 0 : i + 1;
871                                                                 if (j + 1 == dp->nrows)
872                                                                         l = 1;
873                                                                 else if (j + 2 == dp->nrows)
874                                                                         l = 0;
875                                                                 else
876                                                                         l = j + 2;
877                                                                 ml = l * dp->ncols;
878                                                                 if (dp->oldcell[k + ml] ==
879                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
880                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
881                                                                 /* WW */
882                                                                 k = (!i) ? dp->ncols - 1 : i - 1;
883                                                                 /*l = j;*/
884                                                                 ml = mj;
885                                                                 if (dp->oldcell[k + ml] ==
886                                                                     (int) (dp->oldcell[i + mj] + 1) % dp->states)
887                                                                         dp->newcell[i + mj] = dp->oldcell[k + ml];
888                                                         }
889                                                 }
890                                                 mj += dp->ncols;
891                                         }
892                                 }
893                         }
894                 }
895                 mj = 0;
896                 for (j = 0; j < dp->nrows; j++) {
897                         for (i = 0; i < dp->ncols; i++)
898                                 if (dp->oldcell[i + mj] != dp->newcell[i + mj]) {
899                                         dp->oldcell[i + mj] = dp->newcell[i + mj];
900                                         if (!addtolist(mi, i, j, dp->oldcell[i + mj])) {
901                                                 free_demon(MI_DISPLAY(mi), dp);
902                                                 return;
903                                         }
904                                 }
905                         mj += dp->ncols;
906                 }
907                 if (++dp->generation > MI_CYCLES(mi))
908                         init_demon(mi);
909                 dp->state = 0;
910         } else {
911                 if (dp->ncells[dp->state])
912                         if (!draw_state(mi, dp->state)) {
913                                 free_demon(MI_DISPLAY(mi), dp);
914                                 return;
915                         }
916                 dp->state++;
917         }
918         if (dp->redrawing) {
919                 for (i = 0; i < REDRAWSTEP; i++) {
920                         if (dp->oldcell[dp->redrawpos]) {
921                                 drawcell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
922                                          dp->oldcell[dp->redrawpos]);
923                         }
924                         if (++(dp->redrawpos) >= dp->ncols * dp->nrows) {
925                                 dp->redrawing = 0;
926                                 break;
927                         }
928                 }
929         }
930 }
931
932
933 ENTRYPOINT void
934 reshape_demon(ModeInfo * mi, int width, int height)
935 {
936   XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi));
937   init_demon (mi);
938 }
939
940
941 ENTRYPOINT void
942 release_demon (ModeInfo * mi)
943 {
944         if (demons != NULL) {
945                 int         screen;
946
947                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
948                         free_demon(MI_DISPLAY(mi), &demons[screen]);
949                 (void) free((void *) demons);
950                 demons = (demonstruct *) NULL;
951         }
952 }
953
954 ENTRYPOINT void
955 refresh_demon (ModeInfo * mi)
956 {
957         demonstruct *dp;
958
959         if (demons == NULL)
960                 return;
961         dp = &demons[MI_SCREEN(mi)];
962
963         dp->redrawing = 1;
964         dp->redrawpos = 0;
965 }
966
967 ENTRYPOINT Bool
968 demon_handle_event (ModeInfo *mi, XEvent *event)
969 {
970   if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
971     {
972       reshape_demon (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
973       return True;
974     }
975   return False;
976 }
977
978
979
980 XSCREENSAVER_MODULE ("Demon", demon)
981
982 #endif /* MODE_demon */