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