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.24 2007/01/18 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1995 by David Bagley.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 18-Jan-2007: Added vertical option.
26  * 01-Nov-2000: Allocation checks
27  * 10-May-1997: Compatible with xscreensaver
28  * 16-Apr-1997: -neighbors 3, 9 (not sound mathematically), 12, and 8 added
29  * 30-May-1996: Ron Hitchens <ron@idiom.com>
30  *            Fixed memory management that caused leaks
31  * 14-Apr-1996: -neighbors 6 runtime-time option added
32  * 21-Aug-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific
33  *              American Magazine" Aug 1989 pp 102-105.  Also very similar
34  *              to hodgepodge machine described in A.K. Dewdney's "Computer
35  *              Recreations", Scientific American Magazine" Aug 1988
36  *              pp 104-107.  Also used life.c as a guide.
37  */
38 
39 /*-
40  * A cellular universe of 4 phases debris, droplets, defects, and demons.
41  */
42 
43 /*-
44   Grid     Number of Neighbors
45   ----     ------------------
46   Square   4 or 8
47   Hexagon  6
48   Triangle 3, 9, or 12
49   Pentagon 5 or 7
50 */
51 
52 #ifdef STANDALONE
53 #define MODE_demon
54 #define DEFAULTS "*delay: 50000 \n" \
55 	"*count: 0 \n" \
56 	"*cycles: 1000 \n" \
57 	"*size: -7 \n" \
58 	"*ncolors: 64 \n" \
59 
60 # define free_demon 0
61 # define reshape_demon 0
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 #define DO_STIPPLE
68 #endif /* STANDALONE */
69 #include "automata.h"
70 
71 #ifdef MODE_demon
72 
73 /*-
74  * neighbors of 0 randomizes it between 3, 4, 5, 6, 7, 8, 9, and 12.
75  */
76 #define DEF_NEIGHBORS  "0"      /* choose random value */
77 #define DEF_VERTICAL "False"
78 #define DEF_COLORS_ONLY "False"
79 
80 static int  neighbors;
81 static Bool vertical;
82 static Bool colorsOnly;
83 
84 static XrmOptionDescRec opts[] =
85 {
86 	{(char *) "-neighbors", (char *) ".demon.neighbors", XrmoptionSepArg, (caddr_t) NULL},
87 	{(char *) "-vertical", (char *) ".demon.vertical", XrmoptionNoArg, (caddr_t) "on"},
88 	{(char *) "+vertical", (char *) ".demon.vertical", XrmoptionNoArg, (caddr_t) "off"},
89 	{(char *) "-colorsonly", (char *) ".demon.colorsonly", XrmoptionNoArg, (caddr_t) "on"},
90 	{(char *) "+colorsonly", (char *) ".demon.colorsonly", XrmoptionNoArg, (caddr_t) "off"}
91 
92 };
93 static argtype vars[] =
94 {
95 	{(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
96 	{(void *) & vertical, (char *) "vertical", (char *) "Vertical", (char *) DEF_VERTICAL, t_Bool},
97 	{(void *) & colorsOnly, (char *) "colorsonly", (char *) "ColorsOnly", (char *) DEF_COLORS_ONLY, t_Bool}
98 };
99 static OptionStruct desc[] =
100 {
101 	{(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3, 9 or 12, pentagons 5 or 7"},
102 	{(char *) "-/+vertical", (char *) "change orientation for hexagons and triangles"},
103 	{(char *) "-/+colorsonly", (char *) "no black cells"}
104 };
105 
106 ENTRYPOINT ModeSpecOpt demon_opts =
107 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
108 
109 #ifdef USE_MODULES
110 ModStruct   demon_description =
111 {"demon", "init_demon", "draw_demon", "release_demon",
112  "refresh_demon", "init_demon", (char *) NULL, &demon_opts,
113  50000, 0, 1000, -7, 64, 1.0, "",
114  "Shows Griffeath's cellular automata", 0, NULL};
115 
116 #endif
117 
118 #define DEMONBITS(n,w,h)\
119   if ((dp->pixmaps[dp->init_bits]=\
120   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
121   free_demon_screen(display,dp); return;} else {dp->init_bits++;}
122 
123 #define REDRAWSTEP 2000		/* How many cells to draw per cycle */
124 #define MINSTATES 2
125 #define MINGRIDSIZE 24
126 #define MINSIZE 4
127 #define NEIGHBORKINDS 8
128 
129 /* Singly linked list */
130 typedef struct _CellList {
131 	XPoint      pt;
132 	struct _CellList *next;
133 } CellList;
134 
135 typedef struct {
136 	Bool        vertical;
137 	Bool        colorsOnly;
138 	int         generation;
139 	int         xs, ys;
140 	int         xb, yb;
141 	int         nrows, ncols;
142 	int         width, height;
143 	int         states;
144 	int         state;
145 	int         redrawing, redrawpos;
146 	int        *ncells;
147 	CellList  **cellList;
148 	unsigned char *oldcell, *newcell;
149 	int         neighbors, polygon;
150 	int         init_bits;
151 	GC          stippledGC;
152 	Pixmap      pixmaps[NUMSTIPPLES - 1];
153 	union {
154 		XPoint      hexagon[7];
155 		XPoint      triangle[2][4];
156 		XPoint      pentagon[4][6];
157 	} shape;
158 } demonstruct;
159 
160 static char plots[2][NEIGHBORKINDS] =
161 {
162 	{3, 4, 5, 6, 7, 8, 9, 12},	/* Neighborhoods */
163 	{12, 16, 17, 18, 19, 20, 22, 24}	/* Number of states */
164 };
165 
166 static demonstruct *demons = (demonstruct *) NULL;
167 
168 static void
drawCell(ModeInfo * mi,int col,int row,unsigned char state)169 drawCell(ModeInfo * mi, int col, int row, unsigned char state)
170 {
171 	demonstruct *dp = &demons[MI_SCREEN(mi)];
172 	Display *display = MI_DISPLAY(mi);
173 	Window window = MI_WINDOW(mi);
174 	GC          gc;
175 
176 	if (!state && !dp->colorsOnly) {
177 		XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
178 		gc = MI_GC(mi);
179 	} else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
180 		int offset = (dp->colorsOnly) ? 0 : 1;
181 
182 		XSetForeground(display, MI_GC(mi),
183 			MI_PIXEL(mi, (((int) state - offset) * MI_NPIXELS(mi) /
184 			(dp->states - offset)) % MI_NPIXELS(mi)));
185 		gc = MI_GC(mi);
186 	} else if (!state) {
187 		XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
188 		gc = MI_GC(mi);
189 	} else {
190 		XGCValues   gcv;
191 
192 		gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
193 		gcv.foreground = MI_WHITE_PIXEL(mi);
194 		gcv.background = MI_BLACK_PIXEL(mi);
195 		XChangeGC(display, dp->stippledGC,
196 			  GCStipple | GCForeground | GCBackground, &gcv);
197 		gc = dp->stippledGC;
198 	}
199 	if (dp->neighbors == 6) {
200 		int ccol = 2 * col + !(row & 1), crow = 2 * row;
201 
202 		if (dp->vertical) {
203 			dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
204 			dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
205 		} else {
206 			dp->shape.hexagon[0].y = dp->xb + ccol * dp->xs;
207 			dp->shape.hexagon[0].x = dp->yb + crow * dp->ys;
208 		}
209 		if (dp->xs == 1 && dp->ys == 1)
210 			XDrawPoint(display, window, gc,
211 				dp->shape.hexagon[0].x,
212 				dp->shape.hexagon[0].y);
213 		else
214 			XFillPolygon(display, window, gc,
215 				dp->shape.hexagon, 6,
216 				Convex, CoordModePrevious);
217 	} else if (dp->neighbors == 4 || dp->neighbors == 8) {
218 		XFillRectangle(display, window, gc,
219 			dp->xb + dp->xs * col, dp->yb + dp->ys * row,
220 			dp->xs - (dp->xs > 3), dp->ys - (dp->ys > 3));
221 	} else if (dp->neighbors == 5 || dp->neighbors == 7) {
222 		int map[4] = {2, 0, 1, 3};
223 		int orient = ((row & 1) * 2 + col) % 4;
224 		int offsetX = 0, offsetY = 0;
225 		switch (orient) {
226 		case 0: /* up */
227 			offsetX = dp->xs;
228 			break;
229 		case 1: /* down */
230 			offsetY = 3 * dp->ys / 2 - 1;
231 			break;
232 		case 2: /* left */
233 			offsetX = -dp->xs / 2;
234 			offsetY = 3 * dp->ys / 4;
235 			break;
236 		case 3: /* right */
237 			offsetX = 3 * dp->xs / 2 - 1;
238 			offsetY = 3 * dp->ys / 4;
239 			break;
240 		default:
241 			(void) printf("wrong orient %d\n", orient);
242 		}
243 		orient = map[orient];
244 		dp->shape.pentagon[orient][0].x =  dp->xb +
245 			col * dp->xs + offsetX;
246 		dp->shape.pentagon[orient][0].y = dp->yb +
247 			row * dp->ys + offsetY;
248 		if (dp->xs <= 2 || dp->ys <= 2)
249 			XDrawPoint(display, window, gc,
250 				dp->shape.pentagon[orient][0].x,
251 				dp->shape.pentagon[orient][0].y);
252 		else
253 			XFillPolygon(display, window, gc,
254 				dp->shape.pentagon[orient], 5, Convex, CoordModePrevious);
255 	} else {		/* TRI */
256 		int orient = (col + row) % 2;	/* O left 1 right */
257 		Bool small = (dp->xs <= 3 || dp->ys <= 3);
258 
259 		if (dp->vertical) {
260 			dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
261 			dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
262 			if (small)
263 				dp->shape.triangle[orient][0].x +=
264 					((orient) ? -1 : 1);
265 			else
266 				dp->shape.triangle[orient][0].x +=
267 					(dp->xs / 2  - 1) * ((orient) ? 1 : -1);
268 		} else {
269 			dp->shape.triangle[orient][0].y = dp->xb + col * dp->xs;
270 			dp->shape.triangle[orient][0].x = dp->yb + row * dp->ys;
271 			if (small)
272 				dp->shape.triangle[orient][0].y +=
273 					((orient) ? -1 : 1);
274 			else
275 				dp->shape.triangle[orient][0].y +=
276 					(dp->xs / 2  - 1) * ((orient) ? 1 : -1);
277 		}
278 		if (small)
279 			XDrawPoint(display, window, gc,
280 				dp->shape.triangle[orient][0].x,
281 				dp->shape.triangle[orient][0].y);
282 		else {
283 			XFillPolygon(display, window, gc,
284 				dp->shape.triangle[orient], 3,
285 				Convex, CoordModePrevious);
286 			XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
287 			XDrawLines(display, window, gc,
288 				dp->shape.triangle[orient], 4,
289 				CoordModePrevious);
290 		}
291 	}
292 }
293 
294 static Bool
addtolist(ModeInfo * mi,int col,int row,unsigned char state)295 addtolist(ModeInfo * mi, int col, int row, unsigned char state)
296 {
297 	demonstruct *dp = &demons[MI_SCREEN(mi)];
298 	CellList   *current;
299 
300 	current = dp->cellList[state];
301 	if ((dp->cellList[state] = (CellList *)
302 		malloc(sizeof (CellList))) == NULL) {
303 		return False;
304 	}
305 	dp->cellList[state]->pt.x = col;
306 	dp->cellList[state]->pt.y = row;
307 	dp->cellList[state]->next = current;
308 	dp->ncells[state]++;
309 	return True;
310 }
311 
312 #ifdef DEBUG
313 static void
print_state(ModeInfo * mi,int state)314 print_state(ModeInfo * mi, int state)
315 {
316 	demonstruct *dp = &demons[MI_SCREEN(mi)];
317 	CellList   *locallist;
318 	int         i = 0;
319 
320 	locallist = dp->cellList[state];
321 	(void) printf("state %d\n", state);
322 	while (locallist) {
323 		(void) printf("%d	x %d, y %d\n", i,
324 			      locallist->pt.x, locallist->pt.y);
325 		locallist = locallist->next;
326 		i++;
327 	}
328 }
329 
330 #endif
331 
332 static void
free_state(demonstruct * dp,int state)333 free_state(demonstruct * dp, int state)
334 {
335 	CellList   *current;
336 
337 	while (dp->cellList[state]) {
338 		current = dp->cellList[state];
339 		dp->cellList[state] = dp->cellList[state]->next;
340 		free(current);
341 	}
342 	dp->cellList[state] = (CellList *) NULL;
343 	if (dp->ncells != NULL)
344 		dp->ncells[state] = 0;
345 }
346 
347 
348 static void
free_list(demonstruct * dp)349 free_list(demonstruct * dp)
350 {
351 	int         state;
352 
353 	for (state = 0; state < dp->states; state++)
354 		free_state(dp, state);
355 	free(dp->cellList);
356 	dp->cellList = (CellList **) NULL;
357 }
358 
359 static void
free_struct(demonstruct * dp)360 free_struct(demonstruct * dp)
361 {
362 	if (dp->cellList != NULL) {
363 		free_list(dp);
364 	}
365 	if (dp->ncells != NULL) {
366 		free(dp->ncells);
367 		dp->ncells = (int *) NULL;
368 	}
369 	if (dp->oldcell != NULL) {
370 		free(dp->oldcell);
371 		dp->oldcell = (unsigned char *) NULL;
372 	}
373 	if (dp->newcell != NULL) {
374 		free(dp->newcell);
375 		dp->newcell = (unsigned char *) NULL;
376 	}
377 }
378 
379 static void
free_demon_screen(Display * display,demonstruct * dp)380 free_demon_screen(Display *display, demonstruct *dp)
381 {
382 	int         shade;
383 
384 	if (dp == NULL) {
385 		return;
386 	}
387 	if (dp->stippledGC != None) {
388 		XFreeGC(display, dp->stippledGC);
389 		dp->stippledGC = None;
390 	}
391 	for (shade = 0; shade < dp->init_bits; shade++) {
392 		XFreePixmap(display, dp->pixmaps[shade]);
393 	}
394 	dp->init_bits = 0;
395 	free_struct(dp);
396 	dp = NULL;
397 }
398 
399 static Bool
draw_state(ModeInfo * mi,int state)400 draw_state(ModeInfo * mi, int state)
401 {
402 	demonstruct *dp = &demons[MI_SCREEN(mi)];
403 	Display *display = MI_DISPLAY(mi);
404 	Window window = MI_WINDOW(mi);
405 	GC          gc;
406 	XRectangle *rects;
407 	CellList   *current;
408 
409 	if (!state && !dp->colorsOnly) {
410 		XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
411 		gc = MI_GC(mi);
412 	} else if (MI_NPIXELS(mi) >= NUMSTIPPLES) {
413 		int offset = (dp->colorsOnly) ? 0 : 1;
414 
415 		XSetForeground(display, MI_GC(mi),
416 			   MI_PIXEL(mi, (((int) state - offset) * MI_NPIXELS(mi) /
417 					 (dp->states - offset)) % MI_NPIXELS(mi)));
418 		gc = MI_GC(mi);
419 	} else if (!state) {
420 		XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
421 		gc = MI_GC(mi);
422 	} else {
423 		XGCValues   gcv;
424 
425 		gcv.stipple = dp->pixmaps[(state - 1) % (NUMSTIPPLES - 1)];
426 		gcv.foreground = MI_WHITE_PIXEL(mi);
427 		gcv.background = MI_BLACK_PIXEL(mi);
428 		XChangeGC(display, dp->stippledGC,
429 			  GCStipple | GCForeground | GCBackground, &gcv);
430 		gc = dp->stippledGC;
431 	}
432 	if (dp->neighbors == 6) {	/* Draw right away, slow */
433 		current = dp->cellList[state];
434 		while (current) {
435 			int col = current->pt.x;
436 			int row = current->pt.y;
437 			int ccol = 2 * col + !(row & 1);
438 			int crow = 2 * row;
439 
440 			if (dp->vertical) {
441 				dp->shape.hexagon[0].x = dp->xb + ccol * dp->xs;
442 				dp->shape.hexagon[0].y = dp->yb + crow * dp->ys;
443 			} else {
444 				dp->shape.hexagon[0].y = dp->xb + ccol * dp->xs;
445 				dp->shape.hexagon[0].x = dp->yb + crow * dp->ys;
446 			}
447 			if (dp->xs == 1 && dp->ys == 1)
448 				XDrawPoint(display, window, gc,
449 					dp->shape.hexagon[0].x,
450 					dp->shape.hexagon[0].y);
451 			else
452 				XFillPolygon(display, window, gc,
453 					dp->shape.hexagon, 6,
454 					Convex, CoordModePrevious);
455 			current = current->next;
456 		}
457 	} else if (dp->neighbors == 4 || dp->neighbors == 8) {
458 		/* Take advantage of XDrawRectangles */
459 		int         ncells = 0;
460 
461 		/* Create Rectangle list from part of the cellList */
462 		if ((rects = (XRectangle *) malloc(dp->ncells[state] *
463 			 sizeof (XRectangle))) == NULL) {
464 			return False;
465 		}
466 		current = dp->cellList[state];
467 		while (current) {
468 			rects[ncells].x = dp->xb + current->pt.x * dp->xs;
469 			rects[ncells].y = dp->yb + current->pt.y * dp->ys;
470 			rects[ncells].width = dp->xs - (dp->xs > 3);
471 			rects[ncells].height = dp->ys - (dp->ys > 3);
472 			current = current->next;
473 			ncells++;
474 		}
475 		/* Finally get to draw */
476 		XFillRectangles(display, window, gc, rects, ncells);
477 		/* Free up rects list and the appropriate part of the cellList */
478 		free(rects);
479 	} else if (dp->neighbors == 5 || dp->neighbors == 7) {
480 		int map[4] = {2, 0, 1, 3};
481 		current = dp->cellList[state];
482 		while (current) {
483 			int col = current->pt.x;
484 			int row = current->pt.y;
485 			int orient = ((row & 1) * 2 + col) % 4;
486 			int offsetX = 0, offsetY = 0;
487 
488 			switch (orient) {
489 			case 0: /* up */
490 				offsetX = dp->xs;
491 				break;
492 			case 1: /* down */
493 				offsetY = 3 * dp->ys / 2 - 1;
494 				break;
495 			case 2: /* left */
496 				offsetX = -dp->xs / 2;
497 				offsetY = 3 * dp->ys / 4;
498 				break;
499 			case 3: /* right */
500 				offsetX = 3 * dp->xs / 2 - 1;
501 				offsetY = 3 * dp->ys / 4;
502 				break;
503 			default:
504 				(void) printf("wrong orient %d\n", orient);
505 			}
506 			orient = map[orient];
507 			dp->shape.pentagon[orient][0].x =  dp->xb +
508 				col * dp->xs + offsetX;
509 			dp->shape.pentagon[orient][0].y = dp->yb +
510 				row * dp->ys + offsetY;
511 			if (dp->xs <= 2 || dp->ys <= 2)
512 				XDrawPoint(display, window, gc,
513 					dp->shape.pentagon[orient][0].x,
514 					dp->shape.pentagon[orient][0].y);
515 			else
516 				XFillPolygon(display, window, gc,
517 					dp->shape.pentagon[orient], 5,
518 					Convex, CoordModePrevious);
519 			current = current->next;
520 		}
521 	} else {		/* TRI */
522 		XGCValues values;
523 		GC borderGC = XCreateGC(display, window, 0, &values);
524 		Bool small = (dp->xs <= 3 || dp->ys <= 3);
525 
526 		current = dp->cellList[state];
527 		while (current) {
528 			int         col, row, orient;
529 
530 			col = current->pt.x;
531 			row = current->pt.y;
532 			orient = (col + row) % 2;	/* O left 1 right */
533 			if (dp->vertical) {
534 				dp->shape.triangle[orient][0].x = dp->xb + col * dp->xs;
535 				dp->shape.triangle[orient][0].y = dp->yb + row * dp->ys;
536 				if (small)
537 					dp->shape.triangle[orient][0].x +=
538 						((orient) ? -1 : 1);
539 				else
540 					dp->shape.triangle[orient][0].x +=
541 						(dp->xs / 2  - 1) * ((orient) ? 1 : -1);
542 			} else {
543 				dp->shape.triangle[orient][0].y = dp->xb + col * dp->xs;
544 				dp->shape.triangle[orient][0].x = dp->yb + row * dp->ys;
545 				if (small)
546 					dp->shape.triangle[orient][0].y +=
547 						((orient) ? -1 : 1);
548 				else
549 					dp->shape.triangle[orient][0].y +=
550 						(dp->xs / 2  - 1) * ((orient) ? 1 : -1);
551 			}
552 			if (small)
553 				XDrawPoint(display, window, gc,
554 					dp->shape.triangle[orient][0].x,
555 					dp->shape.triangle[orient][0].y);
556 			else {
557 				XFillPolygon(display, window, gc,
558 					dp->shape.triangle[orient], 3,
559 					Convex, CoordModePrevious);
560 				if (borderGC != None) {
561 					XSetForeground(display, borderGC, MI_BLACK_PIXEL(mi));
562 					XDrawLines(display, window, borderGC,
563 						dp->shape.triangle[orient], 4,
564 						CoordModePrevious);
565 				}
566 			}
567 			current = current->next;
568 		}
569 		if (borderGC != None)
570 			XFreeGC(display, borderGC);
571 	}
572 	free_state(dp, state);
573 	XFlush(display);
574 	return True;
575 }
576 
577 static void
RandomSoup(ModeInfo * mi)578 RandomSoup(ModeInfo * mi)
579 {
580 	demonstruct *dp = &demons[MI_SCREEN(mi)];
581 	int         row, col, mrow = 0;
582 
583 	for (row = 0; row < dp->nrows; ++row) {
584 		for (col = 0; col < dp->ncols; ++col) {
585 			dp->oldcell[col + mrow] =
586 				(unsigned char) LRAND() % ((unsigned char) dp->states);
587 			if (!addtolist(mi, col, row, dp->oldcell[col + mrow]))
588 				return; /* sparse soup */
589 		}
590 		mrow += dp->ncols;
591 	}
592 }
593 
594 static int
positionOfNeighbor(demonstruct * dp,int n,int col,int row)595 positionOfNeighbor(demonstruct * dp, int n, int col, int row)
596 {
597 	int dir = n * (360 / dp->neighbors);
598 
599 	if (dp->polygon == 4 || dp->polygon == 6) {
600 		switch (dir) {
601 		case 0:
602 			col = (col + 1 == dp->ncols) ? 0 : col + 1;
603 			break;
604 		case 45:
605 			col = (col + 1 == dp->ncols) ? 0 : col + 1;
606 			row = (!row) ? dp->nrows - 1 : row - 1;
607 			break;
608 		case 60:
609 			if (!(row & 1))
610 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
611 			row = (!row) ? dp->nrows - 1 : row - 1;
612 			break;
613 		case 90:
614 			row = (!row) ? dp->nrows - 1 : row - 1;
615 			break;
616 		case 120:
617 			if (row & 1)
618 				col = (!col) ? dp->ncols - 1 : col - 1;
619 			row = (!row) ? dp->nrows - 1 : row - 1;
620 			break;
621 		case 135:
622 			col = (!col) ? dp->ncols - 1 : col - 1;
623 			row = (!row) ? dp->nrows - 1 : row - 1;
624 			break;
625 		case 180:
626 			col = (!col) ? dp->ncols - 1 : col - 1;
627 			break;
628 		case 225:
629 			col = (!col) ? dp->ncols - 1 : col - 1;
630 			row = (row + 1 == dp->nrows) ? 0 : row + 1;
631 			break;
632 		case 240:
633 			if (row & 1)
634 				col = (!col) ? dp->ncols - 1 : col - 1;
635 			row = (row + 1 == dp->nrows) ? 0 : row + 1;
636 			break;
637 		case 270:
638 			row = (row + 1 == dp->nrows) ? 0 : row + 1;
639 			break;
640 		case 300:
641 			if (!(row & 1))
642 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
643 			row = (row + 1 == dp->nrows) ? 0 : row + 1;
644 			break;
645 		case 315:
646 			col = (col + 1 == dp->ncols) ? 0 : col + 1;
647 			row = (row + 1 == dp->nrows) ? 0 : row + 1;
648 			break;
649 		default:
650 			(void) fprintf(stderr, "wrong direction %d\n", dir);
651 		}
652 	} else if (dp->polygon == 3) {
653 		if ((col + row) & 1) {	/* right */
654 			switch (dir) {
655 			case 0:
656 				col = (!col) ? dp->ncols - 1 : col - 1;
657 				break;
658 			case 30:
659 			case 40:
660 				col = (!col) ? dp->ncols - 1 : col - 1;
661 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
662 				break;
663 			case 60:
664 				col = (!col) ? dp->ncols - 1 : col - 1;
665 				if (row + 1 == dp->nrows)
666 					row = 1;
667 				else if (row + 2 == dp->nrows)
668 					row = 0;
669 				else
670 					row = row + 2;
671 				break;
672 			case 80:
673 			case 90:
674 				if (row + 1 == dp->nrows)
675 					row = 1;
676 				else if (row + 2 == dp->nrows)
677 					row = 0;
678 				else
679 					row = row + 2;
680 				break;
681 			case 120:
682 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
683 				break;
684 			case 150:
685 			case 160:
686 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
687 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
688 				break;
689 			case 180:
690 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
691 				break;
692 			case 200:
693 			case 210:
694 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
695 				row = (!row) ? dp->nrows - 1 : row - 1;
696 				break;
697 			case 240:
698 				row = (!row) ? dp->nrows - 1 : row - 1;
699 				break;
700 			case 270:
701 			case 280:
702 				if (!row)
703 					row = dp->nrows - 2;
704 				else if (!(row - 1))
705 					row = dp->nrows - 1;
706 				else
707 					row = row - 2;
708 				break;
709 			case 300:
710 				col = (!col) ? dp->ncols - 1 : col - 1;
711 				if (!row)
712 					row = dp->nrows - 2;
713 				else if (!(row - 1))
714 					row = dp->nrows - 1;
715 				else
716 					row = row - 2;
717 				break;
718 			case 320:
719 			case 330:
720 				col = (!col) ? dp->ncols - 1 : col - 1;
721 				row = (!row) ? dp->nrows - 1 : row - 1;
722 				break;
723 			default:
724 				(void) fprintf(stderr, "wrong direction %d\n",
725 					dir);
726 			}
727 		} else {	/* left */
728 			switch (dir) {
729 			case 0:
730 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
731 				break;
732 			case 30:
733 			case 40:
734 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
735 				row = (!row) ? dp->nrows - 1 : row - 1;
736 				break;
737 			case 60:
738 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
739 				if (!row)
740 					row = dp->nrows - 2;
741 				else if (row == 1)
742 					row = dp->nrows - 1;
743 				else
744 					row = row - 2;
745 				break;
746 			case 80:
747 			case 90:
748 				if (!row)
749 					row = dp->nrows - 2;
750 				else if (row == 1)
751 					row = dp->nrows - 1;
752 				else
753 					row = row - 2;
754 				break;
755 			case 120:
756 				row = (!row) ? dp->nrows - 1 : row - 1;
757 				break;
758 			case 150:
759 			case 160:
760 				col = (!col) ? dp->ncols - 1 : col - 1;
761 				row = (!row) ? dp->nrows - 1 : row - 1;
762 				break;
763 			case 180:
764 				col = (!col) ? dp->ncols - 1 : col - 1;
765 				break;
766 			case 200:
767 			case 210:
768 				col = (!col) ? dp->ncols - 1 : col - 1;
769 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
770 				break;
771 			case 240:
772 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
773 				break;
774 			case 270:
775 			case 280:
776 				if (row + 1 == dp->nrows)
777 					row = 1;
778 				else if (row + 2 == dp->nrows)
779 					row = 0;
780 				else
781 					row = row + 2;
782 				break;
783 			case 300:
784 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
785 				if (row + 1 == dp->nrows)
786 					row = 1;
787 				else if (row + 2 == dp->nrows)
788 					row = 0;
789 				else
790 					row = row + 2;
791 				break;
792 			case 320:
793 			case 330:
794 				col = (col + 1 == dp->ncols) ? 0 : col + 1;
795 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
796 				break;
797 			default:
798 				(void) fprintf(stderr, "wrong direction %d\n",
799 					dir);
800 			}
801 		}
802 	} else {
803 		int orient = ((row & 1) * 2 + col) % 4;
804 		switch (orient) { /* up, down, left, right */
805 		case 0:
806 			switch (dir) {
807 			case 0:
808 				col++;
809 				break;
810 			case 51: /* 7 */
811 			case 72: /* 5 */
812 				col = (col + 2 >= dp->ncols) ? 0 : col + 2;
813 				break;
814 			case 102: /* 7 corner */
815 				col = (col + 3 >= dp->ncols) ? 1 : col + 3;
816 				row = (row == 0) ? dp->nrows - 1 : row - 1;
817 				break;
818 			case 144: /* 5 */
819 			case 153: /* 7 */
820 				col++;
821 				row = (row == 0) ? dp->nrows - 1 : row - 1;
822 				break;
823 			case 204: /* 7 */
824 			case 216: /* 5 */
825 				row = (row == 0) ? dp->nrows - 1 : row - 1;
826 				break;
827 			case 255: /* 7 */
828 				col = (col == 0) ? dp->ncols - 1 : col - 1;
829 				row = (row == 0) ? dp->nrows - 1 : row - 1;
830 				break;
831 			case 288: /* 5 */
832 			case 306: /* 7 */
833 				col = (col == 0) ? dp->ncols - 1 : col - 1;
834 				break;
835 			default:
836 				(void) fprintf(stderr, "wrong direction %d\n",
837 					dir);
838 			}
839 			break;
840 		case 1:
841 			switch (dir) {
842 			case 0:
843 				col--;
844 				break;
845 			case 51: /* 7 */
846 			case 72: /* 5 */
847 				col = (col == 1) ? dp->ncols - 1 : col - 2;
848 				break;
849 			case 102: /* 7 */
850 				col = (col == 1) ? dp->ncols - 2 : col - 3;
851 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
852 				break;
853 			case 144: /* 5 */
854 			case 153: /* 7 */
855 				col--;
856 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
857 				break;
858 			case 204: /* 7 */
859 			case 216: /* 5 */
860 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
861 				break;
862 			case 255: /* 7 */
863 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
864 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
865 				break;
866 			case 288: /* 5 */
867 			case 306: /* 7 */
868 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
869 				break;
870 			default:
871 				(void) fprintf(stderr, "wrong direction %d\n",
872 					dir);
873 			}
874 			break;
875 		case 2:
876 			switch (dir) {
877 			case 0:
878 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
879 				break;
880 			case 51: /* 7 */
881 			case 72: /* 5 */
882 				row = (row == 0) ? dp->nrows - 1 : row - 1;
883 				col++;
884 				break;
885 			case 102: /* 7 */
886 				col = (col == 0) ? dp->ncols - 1 : col - 1;
887 				row = (row == 0) ? dp->nrows - 1 : row - 1;
888 				break;
889 			case 144: /* 5 */
890 			case 153: /* 7 */
891 				col = (col == 0) ? dp->ncols - 2 : col - 2;
892 				break;
893 			case 204: /* 7 */
894 			case 216: /* 5 */
895 				col = (col == 0) ? dp->ncols - 1 : col - 1;
896 				break;
897 			case 255: /* 7 */
898 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
899 				col = (col == 0) ? dp->ncols - 1 : col - 1;
900 				break;
901 			case 288: /* 5 */
902 			case 306: /* 7 */
903 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
904 				break;
905 			default:
906 				(void) fprintf(stderr, "wrong direction %d\n",
907 					dir);
908 			}
909 			break;
910 		case 3:
911 			switch (dir) {
912 			case 0:
913 				col--;
914 				break;
915 			case 51: /* 7 */
916 			case 72: /* 5 */
917 				col = (col == 0) ? dp->ncols - 1 : col - 1;
918 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
919 				break;
920 			case 102: /* 7 */
921 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
922 				row = (row + 1 == dp->nrows) ? 0 : row + 1;
923 				break;
924 			case 144: /* 5 */
925 			case 153: /* 7 */
926 				col = (col + 2 >= dp->ncols) ? 1 : col + 2;
927 				break;
928 			case 204: /* 7 */
929 			case 216: /* 5 */
930 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
931 				break;
932 			case 255: /* 7 */
933 				col = (col + 1 >= dp->ncols) ? 0 : col + 1;
934 				row = (row == 0) ? dp->nrows - 1 : row - 1;
935 				break;
936 			case 288: /* 5 */
937 			case 306: /* 7 */
938 				row = (row == 0) ? dp->nrows - 1 : row - 1;
939 				break;
940 			default:
941 				(void) fprintf(stderr, "wrong direction %d\n",
942 					dir);
943 			}
944 			break;
945 		default:
946 			(void) fprintf(stderr, "wrong orient %d\n",
947 				orient);
948 		}
949 	}
950 	return (row * dp->ncols + col);
951 }
952 
953 ENTRYPOINT void
init_demon(ModeInfo * mi)954 init_demon(ModeInfo * mi)
955 {
956 	Display    *display = MI_DISPLAY(mi);
957 	Window      window = MI_WINDOW(mi);
958 	int         size = MI_SIZE(mi), nk;
959 	demonstruct *dp;
960 
961 	MI_INIT(mi, demons);
962 	dp = &demons[MI_SCREEN(mi)];
963 
964 	dp->generation = 0;
965 	dp->redrawing = 0;
966 	if (MI_NPIXELS(mi) < NUMSTIPPLES) {
967 		if (dp->stippledGC == None) {
968 			XGCValues   gcv;
969 
970 			gcv.fill_style = FillOpaqueStippled;
971 			if ((dp->stippledGC = XCreateGC(display, window,
972 				 GCFillStyle, &gcv)) == None) {
973 				free_demon_screen(display, dp);
974 				return;
975 			}
976 		}
977 		if (dp->init_bits == 0) {
978 			int         i;
979 
980 			for (i = 1; i < NUMSTIPPLES; i++) {
981 				DEMONBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
982 			}
983 		}
984 	}
985 	free_struct(dp);
986 
987 	for (nk = 0; nk < NEIGHBORKINDS; nk++) {
988 		if (neighbors == plots[0][nk]) {
989 			dp->neighbors = plots[0][nk];
990 			break;
991 		}
992 		if (nk == NEIGHBORKINDS - 1) {
993 			nk = NRAND(NEIGHBORKINDS);
994 			dp->neighbors = plots[0][nk];
995 			break;
996 		}
997 	}
998 
999 	dp->states = MI_COUNT(mi);
1000 	if (dp->states < -MINSTATES)
1001 		dp->states = NRAND(-dp->states - MINSTATES + 1) + MINSTATES;
1002 	else if (dp->states < MINSTATES)
1003 		dp->states = plots[1][nk];
1004 	if ((dp->cellList = (CellList **) calloc(dp->states,
1005 		sizeof (CellList *))) == NULL) {
1006 		free_demon_screen(display, dp);
1007 		return;
1008 	}
1009 	if ((dp->ncells = (int *) calloc(dp->states, sizeof (int))) == NULL) {
1010 		free_demon_screen(display, dp);
1011 		return;
1012 	}
1013 
1014 	dp->state = 0;
1015 	if (MI_IS_FULLRANDOM(mi)) {
1016 		dp->vertical = (Bool) (LRAND() & 1);
1017 		dp->colorsOnly = (Bool) (LRAND() & 1);
1018 	} else {
1019 		dp->vertical = vertical;
1020 		dp->colorsOnly = colorsOnly;
1021 	}
1022 	dp->width = MI_WIDTH(mi);
1023 	dp->height = MI_HEIGHT(mi);
1024 	if (dp->neighbors == 6) {
1025 		int nccols, ncrows, side;
1026 
1027 		dp->polygon = 6;
1028 		if (!dp->vertical) {
1029 			dp->height = MI_WIDTH(mi);
1030 			dp->width = MI_HEIGHT(mi);
1031 		}
1032 		if (dp->width < 8)
1033 			dp->width = 8;
1034 		if (dp->height < 8)
1035 			dp->height = 8;
1036 		if (size < -MINSIZE)
1037 			dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1038 				      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1039 		else if (size < MINSIZE) {
1040 			if (!size)
1041 				dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
1042 			else
1043 				dp->ys = MINSIZE;
1044 		} else
1045 			dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1046 					       MINGRIDSIZE));
1047 		dp->xs = dp->ys;
1048 		nccols = MAX(dp->width / dp->xs - 2, 2);
1049 		ncrows = MAX(dp->height / dp->ys - 1, 4);
1050 		dp->ncols = nccols / 2;
1051 		dp->nrows = 2 * (ncrows / 4);
1052 		dp->xb = (dp->width - dp->xs * nccols) / 2 + dp->xs / 2;
1053 		dp->yb = (dp->height - dp->ys * (ncrows / 2) * 2) / 2 +
1054 			dp->ys / 3;
1055 		for (side = 0; side < 6; side++) {
1056 			if (dp->vertical) {
1057 				dp->shape.hexagon[side].x =
1058 					(dp->xs - 1) * hexagonUnit[side].x;
1059 				dp->shape.hexagon[side].y =
1060 					((dp->ys - 1) * hexagonUnit[side].y /
1061 					2) * 4 / 3;
1062 			} else {
1063 				dp->shape.hexagon[side].y =
1064 					(dp->xs - 1) * hexagonUnit[side].x;
1065 				dp->shape.hexagon[side].x =
1066 					((dp->ys - 1) * hexagonUnit[side].y /
1067 					2) * 4 / 3;
1068 			}
1069 		}
1070 	} else if (dp->neighbors == 4 || dp->neighbors == 8) {
1071 		dp->polygon = 4;
1072 		if (size < -MINSIZE)
1073 			dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1074 				      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1075 		else if (size < MINSIZE) {
1076 			if (!size)
1077 				dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
1078 			else
1079 				dp->ys = MINSIZE;
1080 		} else
1081 			dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1082 					       MINGRIDSIZE));
1083 		dp->xs = dp->ys;
1084 		dp->ncols = MAX(dp->width / dp->xs, 2);
1085 		dp->nrows = MAX(dp->height / dp->ys, 2);
1086 		dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
1087 		dp->yb = (dp->height - dp->ys * dp->nrows) / 2;
1088 	} else if (dp->neighbors == 5 || dp->neighbors == 7) {
1089 				int orient, side;
1090 		dp->polygon = 5;
1091 		if (dp->width < 2)
1092 			dp->width = 2;
1093 		if (dp->height < 2)
1094 			dp->height = 2;
1095 		if (size < -MINSIZE)
1096 			dp->xs = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1097 				MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1098 		else if (size < MINSIZE) {
1099 			if (!size) {
1100 				int min = MIN(dp->width, dp->height) / (4 * MINGRIDSIZE);
1101 				int max = MIN(dp->width, dp->height) / (MINGRIDSIZE);
1102 
1103 				dp->xs = MAX(MINSIZE, min + NRAND(max - min + 1));
1104 			} else
1105 				dp->xs = MINSIZE;
1106 		} else
1107 			dp->xs = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1108 				MINGRIDSIZE));
1109 		dp->ys = dp->xs * 2;
1110 		dp->ncols = (MAX((dp->width - 4) / dp->xs, 8) / 4) * 4;
1111 		dp->nrows = (MAX((dp->height - dp->ys / 2) / dp->ys, 8)) / 2 * 2;
1112 		dp->xb = (dp->width - dp->xs * dp->ncols) / 2;
1113 		dp->yb = (dp->height - dp->ys * dp->nrows) / 2 - 2;
1114 		for (orient = 0; orient < 4; orient++) {
1115 			for (side = 0; side < 5; side++) {
1116 				dp->shape.pentagon[orient][side].x =
1117 					2 * (dp->xs - 1) * pentagonUnit[orient][side].x / 4;
1118 				dp->shape.pentagon[orient][side].y =
1119 					(dp->ys - 1) * pentagonUnit[orient][side].y / 4;
1120 			}
1121 		}
1122 	} else {		/* TRI */
1123 		int orient, side;
1124 
1125 		dp->polygon = 3;
1126 		if (!dp->vertical) {
1127 			dp->height = MI_WIDTH(mi);
1128 			dp->width = MI_HEIGHT(mi);
1129 		}
1130 		if (dp->width < 2)
1131 			dp->width = 2;
1132 		if (dp->height < 2)
1133 			dp->height = 2;
1134 		if (size < -MINSIZE)
1135 			dp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1136 				      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1137 		else if (size < MINSIZE) {
1138 			if (!size)
1139 				dp->ys = MAX(MINSIZE, MIN(dp->width, dp->height) / MINGRIDSIZE);
1140 			else
1141 				dp->ys = MINSIZE;
1142 		} else
1143 			dp->ys = MIN(size, MAX(MINSIZE, MIN(dp->width, dp->height) /
1144 					       MINGRIDSIZE));
1145 		dp->xs = (int) (1.52 * dp->ys);
1146 		dp->ncols = (MAX(dp->width / dp->xs - 1, 2) / 2) * 2;
1147 		dp->nrows = (MAX(dp->height / dp->ys - 1, 2) / 2) * 2;
1148 		dp->xb = (dp->width - dp->xs * dp->ncols) / 2 + dp->xs / 2;
1149 		dp->yb = (dp->height - dp->ys * dp->nrows) / 2 + dp->ys / 2;
1150 		for (orient = 0; orient < 2; orient++) {
1151 			for (side = 0; side < 3; side++) {
1152 				if (dp->vertical) {
1153 					dp->shape.triangle[orient][side].x =
1154 						(dp->xs - 2) * triangleUnit[orient][side].x;
1155 					dp->shape.triangle[orient][side].y =
1156 						(dp->ys - 2) * triangleUnit[orient][side].y;
1157 				} else {
1158 					dp->shape.triangle[orient][side].y =
1159 						(dp->xs - 2) * triangleUnit[orient][side].x;
1160 					dp->shape.triangle[orient][side].x =
1161 						(dp->ys - 2) * triangleUnit[orient][side].y;
1162 				}
1163 			}
1164 		}
1165 	}
1166 
1167 	MI_CLEARWINDOW(mi);
1168 
1169 	if ((dp->oldcell = (unsigned char *)
1170 		malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
1171 		free_demon_screen(display, dp);
1172 		return;
1173 	}
1174 
1175 	if ((dp->newcell = (unsigned char *)
1176 		malloc(dp->ncols * dp->nrows * sizeof (unsigned char))) == NULL) {
1177 		free_demon_screen(display, dp);
1178 		return;
1179 	}
1180 
1181 	RandomSoup(mi);
1182 }
1183 
1184 ENTRYPOINT void
draw_demon(ModeInfo * mi)1185 draw_demon(ModeInfo * mi)
1186 {
1187 	int         i, j, k, l, n, mj = 0;
1188 	Bool        change = False;
1189 	demonstruct *dp;
1190 
1191 	if (demons == NULL)
1192 		return;
1193 	dp = &demons[MI_SCREEN(mi)];
1194 	if (dp->cellList == NULL)
1195 		return;
1196 
1197 	MI_IS_DRAWN(mi) = True;
1198 	if (dp->state >= dp->states) {
1199 		(void) memcpy((char *) dp->newcell, (char *) dp->oldcell,
1200 			      dp->ncols * dp->nrows * sizeof (unsigned char));
1201 
1202 		for (j = 0; j < dp->nrows; j++) {
1203 			mj =  dp->ncols * j;
1204 			for (i = 0; i < dp->ncols; i++) {
1205 				for (n = 0; n < dp->neighbors; n++) {
1206 					l = positionOfNeighbor(dp, n, i, j);
1207 					k = i + mj;
1208 					if (dp->oldcell[l] ==
1209 						    (int) (dp->oldcell[k] + 1) % dp->states)
1210 						dp->newcell[k] = dp->oldcell[l];
1211 				}
1212 			}
1213 		}
1214 		mj = 0;
1215 		for (j = 0; j < dp->nrows; j++) {
1216 			for (i = 0; i < dp->ncols; i++)
1217 				if (dp->oldcell[i + mj] != dp->newcell[i + mj]) {
1218 					dp->oldcell[i + mj] = dp->newcell[i + mj];
1219 					if (!addtolist(mi, i, j, dp->oldcell[i + mj])) {
1220 						free_demon_screen(MI_DISPLAY(mi), dp);
1221 						return;
1222 					}
1223 					change = True;
1224 				}
1225 			mj += dp->ncols;
1226 		}
1227 		if (++dp->generation > MI_CYCLES(mi) || !change)
1228 			init_demon(mi);
1229 		dp->state = 0;
1230 	} else {
1231 		if (dp->ncells[dp->state])
1232 			if (!draw_state(mi, dp->state)) {
1233 				free_demon_screen(MI_DISPLAY(mi), dp);
1234 				return;
1235 			}
1236 		dp->state++;
1237 	}
1238 	if (dp->redrawing) {
1239 		for (i = 0; i < REDRAWSTEP; i++) {
1240 			if (dp->oldcell[dp->redrawpos]) {
1241 				drawCell(mi, dp->redrawpos % dp->ncols, dp->redrawpos / dp->ncols,
1242 					 dp->oldcell[dp->redrawpos]);
1243 			}
1244 			if (++(dp->redrawpos) >= dp->ncols * dp->nrows) {
1245 				dp->redrawing = 0;
1246 				break;
1247 			}
1248 		}
1249 	}
1250 }
1251 
1252 ENTRYPOINT void
release_demon(ModeInfo * mi)1253 release_demon(ModeInfo * mi)
1254 {
1255 	if (demons != NULL) {
1256 		int         screen;
1257 
1258 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1259 			free_demon_screen(MI_DISPLAY(mi), &demons[screen]);
1260 		free(demons);
1261 		demons = (demonstruct *) NULL;
1262 	}
1263 }
1264 
1265 #ifndef STANDALONE
1266 ENTRYPOINT void
refresh_demon(ModeInfo * mi)1267 refresh_demon(ModeInfo * mi)
1268 {
1269 	demonstruct *dp;
1270 
1271 	if (demons == NULL)
1272 		return;
1273 	dp = &demons[MI_SCREEN(mi)];
1274 
1275 	dp->redrawing = 1;
1276 	dp->redrawpos = 0;
1277 }
1278 #endif
1279 
1280 XSCREENSAVER_MODULE ("Demon", demon)
1281 
1282 #endif /* MODE_demon */
1283