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