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