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