1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* life3d --- Extension to Conway's game of Life, Carter Bays' B5/S45 3d life */
3
4 #if 0
5 static const char sccsid[] = "@(#)life3d.c 5.27 2008/07/28 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1994 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 * 09-Nov-2010: cubic close packing (-neighbors 14)
26 * 31-Jul-2008: 4544 3D life from paper by Carter Bays.
27 * 18-Apr-2004: Added shooting gliders for B6/S567
28 * 13-Mar-2004: Added references
29 * 28-Apr-2003: Randomized "rotation" of life form
30 * 25-Jan-2003: Spawned a life3d.h
31 * 19-Jan-2003: added more gliders from http://www.cse.sc.edu/~bays
32 * 08-Jan-2003: Double buffering
33 * 01-Nov-2000: Allocation checks
34 * 10-May-1997: Compatible with xscreensaver
35 * 18-Apr-1997: Memory leak fixed by Tom Schmidt <tschmidt AT micron.com>
36 * 12-Mar-1995: added LIFE_B6S567 compile-time option
37 * 12-Feb-1995: shooting gliders added
38 * 07-Dec-1994: used life.c and a DOS version of 3dlife
39 * Copyright 1993 Anthony Wesley awesley@canb.auug.org.au found at
40 * life.anu.edu.au /pub/complex_systems/alife/3DLIFE.ZIP
41 *
42 *
43 * References:
44 * Bays, Carter, "A Note About the Discovery of Many New Rules for the
45 * Game of 3D Life", Complex Systems 16 (2006) 381-386
46 * Bays, Carter, "Candidates for the Game of Life in Three Dimensions",
47 * 1987, Complex Systems 1 373-400
48 * Bays, Carter, "Patterns for Simple Cellular Automata in a Universe of
49 * Dense-Packed Spheres", 1987, Complex Systems 1 853-875
50 * Bays, Carter, "A Note on the Discovery of a New Game of Three-
51 * Dimensional Life", 1988, Complex Systems 2 255-258
52 * Bays, Carter, "A New Candidate Rule for the Game of Three-Dimensional
53 * Life", 1992, Complex Systems 6 433-441
54 * Bays, Carter, "Further Notes on the Game of Three-Dimensional Life",
55 * 1994, Complex Systems 8 67-73
56 * Bays, Carter, "A Note About the Discovery of Many New Rules for the
57 Game of Three-Dimensional Life", 2006, Complex Systems 16 381-386
58 * Dewdney, A.K., "The Armchair Universe, Computer Recreations from the
59 * Pages of Scientific American Magazine", W.H. Freedman and Company,
60 * New York, 1988 (February 1987 p 16)
61 * Bays, Carter, "The Game of Three Dimensional Life", 86/11/20
62 * with (latest?) update from 87/2/1 http://www.cse.sc.edu/~bays/
63 * Meeker, Lee Earl, "Four Dimensional Cellular Automata and the Game
64 * of Life" 1998 http://home.sc.rr.com/lmeeker/Lee/Home.html
65 */
66
67 #ifdef STANDALONE
68 #define MODE_life3d
69 #define DEFAULTS "*delay: 1000000 \n" \
70 "*count: 35 \n" \
71 "*cycles: 85 \n" \
72 "*ncolors: 200 \n" \
73 "*wireframe: False \n" \
74 "*fullrandom: False \n" \
75 "*verbose: False \n" \
76
77 # define reshape_life3d 0
78 # define life3d_handle_event 0
79 #include "xlockmore.h" /* in xscreensaver distribution */
80 #else /* STANDALONE */
81 #include "xlock.h" /* in xlockmore distribution */
82 #include "iostuff.h"
83 #endif /* STANDALONE */
84 #define DO_STIPPLE
85 #include "automata.h"
86
87 #ifdef MODE_life3d
88 #define LIFE_NAMES 1
89 #include "life3d.h"
90
91 #ifdef LIFE_NAMES
92 #define DEF_LABEL "True"
93 #define FONT_HEIGHT 19
94 #define FONT_WIDTH 15
95 #endif
96 #define DEF_NEIGHBORS "0" /* choose best value (26) */
97 #define DEF_SERIAL "False"
98 #define DEF_REPEAT "0" /* Frequently 2 */
99
100 #if 1
101 #define DEF_RULE "G" /* All rules with gliders */
102 #else
103 #define DEF_RULE "P" /* All rules with known patterns */
104 #define DEF_RULE "B5/S45"
105 #define DEF_RULE "B5/S56"
106 #define DEF_RULE "B5/S678"
107 #define DEF_RULE "B6/S567"
108 #define DEF_RULE "B67/S67"
109 /* There is a glider for B67/S67 but its kind of big */
110 #endif
111
112 #define DEF_GLIDERSEARCH "False"
113 #define DEF_PATTERNSEARCH "False"
114 #define DEF_DRAW "True"
115
116 #ifdef LIFE_NAMES
117 static Bool label;
118 #endif
119 static Bool draw;
120 static int neighbors;
121 static int repeat;
122 static char *rule;
123 static char *lifefile;
124 static Bool serial;
125 static Bool glidersearch;
126 static Bool patternsearch;
127
128 static XrmOptionDescRec opts[] =
129 {
130 #ifdef LIFE_NAMES
131 {(char *) "-label", (char *) ".life3d.label", XrmoptionNoArg, (caddr_t) "on"},
132 {(char *) "+label", (char *) ".life3d.label", XrmoptionNoArg, (caddr_t) "off"},
133 #endif
134 {(char *) "-draw", (char *) ".life3d.draw", XrmoptionNoArg, (caddr_t) "on"},
135 {(char *) "+draw", (char *) ".life3d.draw", XrmoptionNoArg, (caddr_t) "off"},
136 {(char *) "-neighbors", (char *) ".life3d.neighbors", XrmoptionSepArg, (caddr_t) NULL},
137 {(char *) "-repeat", (char *) ".life3d.repeat", XrmoptionSepArg, (caddr_t) NULL},
138 {(char *) "-rule", (char *) ".life3d.rule", XrmoptionSepArg, (caddr_t) NULL},
139 {(char *) "-lifefile", (char *) ".life3d.lifefile", XrmoptionSepArg, (caddr_t) NULL},
140 {(char *) "-serial", (char *) ".life3d.serial", XrmoptionNoArg, (caddr_t) "on"},
141 {(char *) "+serial", (char *) ".life3d.serial", XrmoptionNoArg, (caddr_t) "off"},
142 {(char *) "-glidersearch", (char *) ".life3d.glidersearch", XrmoptionNoArg, (caddr_t) "on"},
143 {(char *) "+glidersearch", (char *) ".life3d.glidersearch", XrmoptionNoArg, (caddr_t) "off"},
144 {(char *) "-patternsearch", (char *) ".life3d.patternsearch", XrmoptionNoArg, (caddr_t) "on"},
145 {(char *) "+patternsearch", (char *) ".life3d.patternsearch", XrmoptionNoArg, (caddr_t) "off"},
146 };
147 static argtype vars[] =
148 {
149 #ifdef LIFE_NAMES
150 {(void *) & label, (char *) "label", (char *) "Label", (char *) DEF_LABEL, t_Bool},
151 #endif
152 {(void *) & draw, (char *) "draw", (char *) "Draw", (char *) DEF_DRAW, t_Bool},
153 {(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
154 {(void *) & repeat, (char *) "repeat", (char *) "Repeat", (char *) DEF_REPEAT, t_Int},
155 {(void *) & rule, (char *) "rule", (char *) "Rule", (char *) DEF_RULE, t_String},
156 #ifdef STANDALONE
157 {(void *) & lifefile, (char *) "lifefile", (char *) "LifeFile", (char *) "/dev/null", t_String},
158 #else
159 {(void *) & lifefile, (char *) "lifefile", (char *) "LifeFile", (char *) "", t_String},
160 #endif
161 {(void *) & serial, (char *) "serial", (char *) "Serial", (char *) DEF_SERIAL, t_Bool},
162 {(void *) & glidersearch, (char *) "glidersearch", (char *) "GliderSearch", (char *) DEF_GLIDERSEARCH, t_Bool},
163 {(void *) & patternsearch, (char *) "patternsearch", (char *) "PatternSearch", (char *) DEF_PATTERNSEARCH, t_Bool},
164 };
165 static OptionStruct desc[] =
166 {
167 #ifdef LIFE_NAMES
168 {(char *) "-/+label", (char *) "turn on/off name labeling"},
169 #endif
170 {(char *) "-/+draw", (char *) "turn on/off drawing to speed search"},
171 {(char *) "-neighbors num", (char *) "cubes 6, 8, 18, 20, 26, rhombic dodecahedron 12, (-)18, truncated octahedron 14, or tetrahedron 22"},
172 {(char *) "-repeat num", (char *) "repeat for period to exclude in search"}, /* this is not as good as Bays' signature idea */
173 {(char *) "-rule string", (char *) "B<birth_neighborhood>/S<survival_neighborhood> parameters"},
174 {(char *) "-lifefile file", (char *) "life file"},
175 {(char *) "-/+serial", (char *) "turn on/off picking of sequential patterns"},
176 {(char *) "-/+glidersearch", (char *) "search for gliders"},
177 {(char *) "-/+patternsearch", (char *) "search for patterns"},
178 };
179
180 ENTRYPOINT ModeSpecOpt life3d_opts =
181 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
182
183 #ifdef USE_MODULES
184 ModStruct life3d_description =
185 {"life3d", "init_life3d", "draw_life3d", "release_life3d",
186 "refresh_life3d", "change_life3d", "free_life3d", &life3d_opts,
187 1000000, 35, 85, 1, 64, 1.0, "",
188 "Shows Bays' game of 3D Life", 0, NULL};
189
190 #endif
191
192 #define LIFE3DBITS(n,w,h)\
193 if ((lp->pixmaps[lp->init_bits]=\
194 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
195 free_life3d_screen(display,lp); return;} else {lp->init_bits++;}
196
197 #define ON 0x40
198 #define OFF 0
199
200 /* Don't change these numbers without changing the offset() macro below! */
201 #define MAXSTACKS 64
202 #define MAXROWS 128
203 #define MAXCOLUMNS 128
204 #define BASESIZE ((MAXCOLUMNS*MAXROWS*MAXSTACKS)>>6)
205 #define SOUPPERCENT 30
206 /* #define SOUPSIZE(s) MAX(s/4,10) */
207 /* 20B4S45 frequently has unlimited growth, which is not pretty */
208 #define SOUPSIZE(s) (lp->neighbors == 20 && lp->patterned_rule == LIFE_20B4S45) ? 4 : ((lp->neighbors == 18 && lp->patterned_rule == LIFE_18B4S45) ? 6 : 10)
209
210 #define RT_ANGLE 90
211 #define HALFRT_ANGLE 45
212
213 /* Store state of cell in top bit. Reserve low bits for count of living nbrs */
214 #define Set3D(x,y,z) SetMem(lp,(unsigned int)x,(unsigned int)y,(unsigned int)z,ON)
215 #define Reset3D(x,y,z) SetMem(lp,(unsigned int)x,(unsigned int)y,(unsigned int)z,OFF)
216
217 #define SetList(x,y,z) if (!SetMem(lp,(unsigned int)x,(unsigned int)y,(unsigned int)z,ON)) return False; \
218 if (!addToList(lp,(unsigned int)x,(unsigned int)y,(unsigned int)z)) return False
219
220 #define CellState3D(c) ((c)&ON)
221 #define CellNbrs3D(c) ((c)&0x1f) /* 26 <= 31 */
222
223 #define EyeToScreen 72.0 /* distance from eye to screen */
224 #define HalfScreenD 14.0 /* 1/2 the diameter of screen */
225 #define BUCKETSIZE 10
226 #define NBUCKETS ((MAXCOLUMNS+MAXROWS+MAXSTACKS)*BUCKETSIZE)
227 #define Distance(x1,y1,z1,x2,y2,z2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
228
229 #define IP (M_PI / 180.0)
230
231 #define COLORBASE 3
232 #define COLORS (COLORBASE + 2)
233
234 #define BLACK 0
235 #define RED 1
236 #define GREEN 2
237 #define BLUE 3
238 #define UV 3 /* Place holder... make BLUE for now */
239 #define WHITE 4
240
241 typedef struct _CellList {
242 unsigned char x, y, z; /* Location in world coordinates */
243 char visible; /* 1 if the cube is to be displayed */
244 short dist; /* dist from cell to eye */
245 struct _CellList *next; /* pointer to next entry on linked list */
246 struct _CellList *prev;
247 struct _CellList *priority;
248 } CellList;
249
250 typedef struct {
251 Bool painted;
252 int neighbors;
253 paramstruct param;
254 int pattern, patterned_rule;
255 int ox, oy, oz; /* origin */
256 double vx, vy, vz; /* viewpoint */
257 int generation;
258 int ncols, nrows, nstacks;
259 int memstart;
260 char visible;
261 int noChangeCount;
262 int ncells;
263 unsigned char *base[BASESIZE];
264 double A, B, C, F;
265 int width, height;
266 int init_bits;
267 unsigned long colors[COLORS];
268 Pixmap pixmaps[NUMSTIPPLES - 1];
269 GC stippledGC;
270 double azm;
271 double metaAlt, metaAzm, metaDist;
272 CellList *ptrhead, *ptrend, eraserhead, eraserend;
273 CellList *buckethead[NBUCKETS], *bucketend[NBUCKETS];
274 Bool wireframe;
275 Pixmap dbuf;
276 int allPatterns, allGliders;
277 paramstruct input_param;
278 int labelOffsetX, labelOffsetY;
279 char ruleString[80], nameString[80];
280 } life3dstruct;
281
282 static life3dstruct *life3ds = (life3dstruct *) NULL;
283
284 static char *filePattern = (char *) NULL;
285
286 #if 0
287 static int
288 invplot(int local_neighbors)
289 {
290 switch (local_neighbors) {
291 case 6: /* faces only */
292 return 0;
293 case 8: /* corners only */
294 return 1;
295 case 12: /* edges only, i.e. only odd #'d cells, hexagonal close packing */
296 return 2;
297 case 14: /* cubic close packing */
298 return 3;
299 case -14: /* faces and corners */
300 return 4;
301 case 16: /* tetrahedral */
302 return 5;
303 case 18: /* faces and edges */
304 return 6;
305 case -18: /* hexagonal close and corners */
306 return 7;
307 case 20: /* corners and edges */
308 return 8;
309 case 22: /* tetrahedral */
310 return 9;
311 case 26: /* all */
312 return 10;
313 default:
314 (void) fprintf(stderr, "no neighborhood like %d known\n",
315 local_neighbors);
316 return 9;
317 }
318 }
319 #endif
320
321 #define tetra(x, y, z) (((x % 2) == 1) && ((y % 2) == 1) && ((z % 2) == 1))
322 #define rTetra(x, y, z) (tetra(x, y, z) && (((x + y + z) % 4) == 1))
323 #define lTetra(x, y, z) (tetra(x, y, z) && (((x + y + z) % 4) == 3))
324
325 static int
codeToPatternedRule(int local_neighbors,paramstruct param)326 codeToPatternedRule(int local_neighbors, paramstruct param)
327 {
328 unsigned int i;
329
330 switch (local_neighbors) {
331 case 12:
332 for (i = 0; i < LIFE_12RULES; i++)
333 if (param_12rules[i].birth == param.birth &&
334 param_12rules[i].survival == param.survival)
335 return i;
336 return LIFE_12RULES;
337 case 14:
338 for (i = 0; i < LIFE_14RULES; i++)
339 if (param_14rules[i].birth == param.birth &&
340 param_14rules[i].survival == param.survival)
341 return i;
342 return LIFE_14RULES;
343 case 18:
344 for (i = 0; i < LIFE_18RULES; i++)
345 if (param_18rules[i].birth == param.birth &&
346 param_18rules[i].survival == param.survival)
347 return i;
348 return LIFE_18RULES;
349 case -18:
350 for (i = 0; i < LIFE__18RULES; i++)
351 if (param__18rules[i].birth == param.birth &&
352 param__18rules[i].survival == param.survival)
353 return i;
354 return LIFE__18RULES;
355 case 20:
356 for (i = 0; i < LIFE_20RULES; i++)
357 if (param_20rules[i].birth == param.birth &&
358 param_20rules[i].survival == param.survival)
359 return i;
360 return LIFE_20RULES;
361 case 22:
362 for (i = 0; i < LIFE_22RULES; i++)
363 if (param_22rules[i].birth == param.birth &&
364 param_22rules[i].survival == param.survival)
365 return i;
366 return LIFE_22RULES;
367 case 26:
368 for (i = 0; i < LIFE_26RULES; i++)
369 if (param_26rules[i].birth == param.birth &&
370 param_26rules[i].survival == param.survival)
371 return i;
372 return LIFE_26RULES;
373 }
374 return 0;
375 }
376
377 static void
copyFromPatternedRule(int local_neighbors,paramstruct * param,int patterned_rule)378 copyFromPatternedRule(int local_neighbors, paramstruct * param,
379 int patterned_rule)
380 {
381 switch (local_neighbors) {
382 case 12:
383 param->birth = param_12rules[patterned_rule].birth;
384 param->survival = param_12rules[patterned_rule].survival;
385 break;
386 case 14:
387 param->birth = param_14rules[patterned_rule].birth;
388 param->survival = param_14rules[patterned_rule].survival;
389 break;
390 case 18:
391 param->birth = param_18rules[patterned_rule].birth;
392 param->survival = param_18rules[patterned_rule].survival;
393 break;
394 case -18:
395 param->birth = param__18rules[patterned_rule].birth;
396 param->survival = param__18rules[patterned_rule].survival;
397 break;
398 case 20:
399 param->birth = param_20rules[patterned_rule].birth;
400 param->survival = param_20rules[patterned_rule].survival;
401 break;
402 case 22:
403 param->birth = param_22rules[patterned_rule].birth;
404 param->survival = param_22rules[patterned_rule].survival;
405 break;
406 case 26:
407 param->birth = param_26rules[patterned_rule].birth;
408 param->survival = param_26rules[patterned_rule].survival;
409 break;
410 }
411 }
412
413 static void
printRule(int local_neighbors,char * string,paramstruct param,Bool verbose)414 printRule(int local_neighbors, char * string, paramstruct param, Bool verbose)
415 {
416 int i = 1, l;
417
418 string[0] = 'B';
419 if (verbose)
420 (void) fprintf(stdout,
421 "rule (Birth/Survival %d neighborhood): ",
422 local_neighbors);
423 for (l = 0; l <= ABS(local_neighbors) && l < 10; l++) {
424 if (param.birth & (1 << l)) {
425 (void) sprintf(&(string[i]), "%d", l);
426 i++;
427 }
428 }
429 (void) sprintf(&(string[i]), "/S");
430 i += 2;
431 for (l = 0; l <= ABS(local_neighbors) && l < 10; l++) {
432 if (param.survival & (1 << l)) {
433 (void) sprintf(&(string[i]), "%d", l);
434 i++;
435 }
436 }
437 string[i] = '\0';
438 if (verbose)
439 (void) fprintf(stdout,
440 "%s\nbinary rule: Birth 0x%X, Survival 0x%X\n",
441 string, param.birth, param.survival);
442 }
443
444 static void
positionOfNeighbor(life3dstruct * lp,int n,unsigned int * col,unsigned int * row,unsigned int * stack)445 positionOfNeighbor(life3dstruct * lp, int n, unsigned int *col,
446 unsigned int *row, unsigned int *stack)
447 {
448 /* 16 and 22 are tetrahedral, extra space was given to */
449 /* allow for octahedron positions not present here */
450 if (lp->neighbors == 16 || lp->neighbors == 22) {
451 if (rTetra(*col, *row, *stack)) {
452 if (lp->neighbors == 16) {
453 if (n >= 16)
454 return;
455 n = n + 10;
456 } else if (lp->neighbors == 22) {
457 if (n >= 22)
458 return;
459 n = n + 4;
460 }
461 switch(n) {
462 /* edges (tetra) */
463 case 4:
464 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
465 break;
466 case 5:
467 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
468 break;
469 case 6:
470 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
471 break;
472 case 7:
473 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
474 break;
475 case 8:
476 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
477 break;
478 case 9:
479 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
480 break;
481 /* points (tetra) */
482 case 10:
483 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
484 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
485 break;
486 case 11:
487 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
488 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
489 break;
490 case 12:
491 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
492 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
493 break;
494 case 13:
495 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
496 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
497 break;
498 case 14:
499 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
500 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
501 break;
502 case 15:
503 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
504 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
505 break;
506 case 16:
507 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
508 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
509 break;
510 case 17:
511 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
512 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
513 break;
514 case 18:
515 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
516 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
517 break;
518 case 19:
519 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
520 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
521 break;
522 case 20:
523 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
524 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
525 break;
526 case 21:
527 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
528 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
529 break;
530 /* far points (tetra) */
531 case 22:
532 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
533 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
534 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
535 break;
536 case 23:
537 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
538 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
539 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
540 break;
541 case 24:
542 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
543 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
544 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
545 break;
546 case 25:
547 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
548 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
549 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
550 break;
551 default:
552 break;
553 }
554 } else if (lTetra(*col, *row, *stack)) {
555 if (lp->neighbors == 16) {
556 if (n >= 16)
557 return;
558 n = n + 10;
559 } else if (lp->neighbors == 22) {
560 if (n >= 22)
561 return;
562 n = n + 4;
563 }
564 switch(n) {
565 /* edges (tetra) */
566 case 4:
567 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
568 break;
569 case 5:
570 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
571 break;
572 case 6:
573 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
574 break;
575 case 7:
576 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
577 break;
578 case 8:
579 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
580 break;
581 case 9:
582 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
583 break;
584 /* points (tetra) */
585 case 10:
586 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
587 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
588 break;
589 case 11:
590 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
591 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
592 break;
593 case 12:
594 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
595 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
596 break;
597 case 13:
598 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
599 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
600 break;
601 case 14:
602 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
603 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
604 break;
605 case 15:
606 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
607 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
608 break;
609 case 16:
610 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
611 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
612 break;
613 case 17:
614 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
615 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
616 break;
617 case 18:
618 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
619 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
620 break;
621 case 19:
622 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
623 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
624 break;
625 case 20:
626 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
627 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
628 break;
629 case 21:
630 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
631 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
632 break;
633 /* far points (tetra) */
634 case 22:
635 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
636 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
637 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
638 break;
639 case 23:
640 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
641 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
642 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
643 break;
644 case 24:
645 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
646 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
647 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
648 break;
649 case 25:
650 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
651 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
652 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
653 break;
654 default:
655 break;
656 }
657 }
658 return;
659 }
660 /* faces */
661 if (lp->neighbors == 6 || lp->neighbors == 14 || lp->neighbors == -14 ||
662 lp->neighbors == 18 || lp->neighbors == 26) {
663 switch (n) {
664 case 0:
665 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
666 break;
667 case 1:
668 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
669 break;
670 case 2:
671 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
672 break;
673 case 3:
674 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
675 break;
676 case 4:
677 if (lp->neighbors == 14) {
678 if (*stack + 1 == lp->nstacks)
679 *stack = 1;
680 else if (*stack + 2 == lp->nstacks)
681 *stack = 0;
682 else
683 *stack = *stack + 2;
684 } else {
685 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
686 }
687 break;
688 case 5:
689 if (lp->neighbors == 14) {
690 if (*stack == 0)
691 *stack = lp->nstacks - 2;
692 else if ((*stack - 1) == 0)
693 *stack = lp->nstacks - 1;
694 else
695 *stack = *stack - 2;
696 } else {
697 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
698 }
699 break;
700 }
701 } else {
702 n += 6;
703 }
704 /* edges */
705 if (lp->neighbors == 12 || lp->neighbors == 18 || lp->neighbors == -18 ||
706 lp->neighbors == 20 || lp->neighbors == 26) {
707 switch (n) {
708 case 6:
709 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
710 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
711 break;
712 case 7:
713 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
714 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
715 break;
716 case 8:
717 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
718 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
719 break;
720 case 9:
721 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
722 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
723 break;
724 case 10:
725 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
726 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
727 break;
728 case 11:
729 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
730 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
731 break;
732 case 12:
733 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
734 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
735 break;
736 case 13:
737 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
738 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
739 break;
740 case 14:
741 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
742 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
743 break;
744 case 15:
745 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
746 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
747 break;
748 case 16:
749 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
750 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
751 break;
752 case 17:
753 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
754 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
755 break;
756 }
757 } else {
758 n += 12;
759 }
760 /* corners */
761 if (lp->neighbors == 8 || lp->neighbors == 14 || lp->neighbors == -14 ||
762 lp->neighbors == 20 || lp->neighbors == 26) {
763 switch (n) {
764 case 18:
765 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
766 if (lp->neighbors != 14 || (*stack & 1) == 0)
767 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
768 if (lp->neighbors != 14 || (*stack & 1) == 1)
769 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
770 break;
771 case 19:
772 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
773 if (lp->neighbors != 14 || (*stack & 1) == 0)
774 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
775 if (lp->neighbors != 14 || (*stack & 1) == 0)
776 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
777 break;
778 case 20:
779 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
780 if (lp->neighbors != 14 || (*stack & 1) == 1)
781 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
782 if (lp->neighbors != 14 || (*stack & 1) == 1)
783 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
784 break;
785 case 21:
786 *stack = (*stack + 1 == lp->nstacks) ? 0 : *stack + 1;
787 if (lp->neighbors != 14 || (*stack & 1) == 1)
788 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
789 if (lp->neighbors != 14 || (*stack & 1) == 0)
790 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
791 break;
792 case 22:
793 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
794 if (lp->neighbors != 14 || (*stack & 1) == 0)
795 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
796 if (lp->neighbors != 14 || (*stack & 1) == 1)
797 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
798 break;
799 case 23:
800 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
801 if (lp->neighbors != 14 || (*stack & 1) == 0)
802 *col = (*col + 1 == lp->ncols) ? 0 : *col + 1;
803 if (lp->neighbors != 14 || (*stack & 1) == 0)
804 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
805 break;
806 case 24:
807 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
808 if (lp->neighbors != 14 || (*stack & 1) == 1)
809 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
810 if (lp->neighbors != 14 || (*stack & 1) == 1)
811 *row = (*row == 0) ? lp->nrows - 1 : *row - 1;
812 break;
813 case 25:
814 *stack = (*stack == 0) ? lp->nstacks - 1 : *stack - 1;
815 if (lp->neighbors != 14 || (*stack & 1) == 1)
816 *col = (*col == 0) ? lp->ncols - 1 : *col - 1;
817 if (lp->neighbors != 14 || (*stack & 1) == 0)
818 *row = (*row + 1 == lp->nrows) ? 0 : *row + 1;
819 break;
820 }
821 } else {
822 n += 8;
823 }
824 /* far corners */
825 if (neighbors == -18) {
826 switch (n) {
827 case 26:
828 *col = (*col < 2) ? lp->ncols - 2 + *col : *col - 2;
829 break;
830 case 27:
831 *col = (*col + 2 >= lp->ncols) ? *col + 2 - lp->ncols : *col + 2;
832 break;
833 case 28:
834 *row = (*row < 2) ? lp->nrows - 2 + *row : *row - 2;
835 break;
836 case 29:
837 *row = (*row + 2 >= lp->nrows) ? *row + 2 - lp->nrows : *row + 2;
838 break;
839 case 30:
840 *stack = (*stack < 2) ? lp->nstacks - 2 + *stack : *stack - 2;
841 break;
842 case 31:
843 *stack = (*stack + 2 >= lp->nstacks) ? *stack + 2 - lp->nstacks : *stack + 2;
844 break;
845 default:
846 break;
847 }
848 }
849 }
850
851 /*-
852 * This stuff is not good for rules above 9 cubes but it is unlikely that
853 * these modes would be much good anyway.... death assumed.
854 */
855 static void
parseRule(ModeInfo * mi,char * string)856 parseRule(ModeInfo * mi, char * string)
857 {
858 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
859 int n, l = 0;
860 char serving = 0;
861 static Bool foundBirth = False;
862 static Bool foundSurvival = False;
863
864 if (foundBirth && foundSurvival)
865 return;
866 foundBirth = foundSurvival = False;
867 lp->input_param.birth = lp->input_param.survival = 0;
868 if (rule) {
869 n = 0;
870 while (rule[n]) {
871 if (rule[n] == 'P' || rule[n] == 'p') {
872 lp->allPatterns = True;
873 foundBirth = foundSurvival = True;
874 if (MI_IS_VERBOSE(mi))
875 (void) fprintf(stdout, "rule: All rules with known patterns\n");
876 return;
877 } else if (rule[n] == 'G' || rule[n] == 'g') {
878 lp->allGliders = True;
879 foundBirth = foundSurvival = True;
880 if (MI_IS_VERBOSE(mi))
881 (void) fprintf(stdout, "rule: All rules with known gliders\n");
882 return;
883 } else if (rule[n] == 'B' || rule[n] == 'F' ||
884 rule[n] == 'b' || rule[n] == 'f') {
885 serving = 'B';
886 } else if (rule[n] == 'S' || rule[n] == 'E' || rule[n] == 'L' ||
887 rule[n] == 's' || rule[n] == 'e' || rule[n] == 'l') {
888 serving = 'S';
889 } else {
890 l = rule[n] - '0';
891 if (l >= 0 && l <= 9 && l <= ABS(lp->neighbors)) { /* no 10..26 */
892 if (serving == 'B' || rule[n] == 'b') {
893 foundBirth = True;
894 lp->input_param.birth |= (1 << l);
895 } else if (serving == 'S' || rule[n] == 's') {
896 foundSurvival = True;
897 lp->input_param.survival |= (1 << l);
898 }
899 }
900 }
901 n++;
902 }
903 }
904 if (!foundBirth || !foundSurvival ||
905 !(lp->input_param.birth || lp->input_param.survival)) {
906 /* Default to Bays' rules if rule does not make sense */
907 lp->allGliders = True;
908 foundBirth = foundSurvival = True;
909 if (MI_IS_VERBOSE(mi))
910 (void) fprintf(stdout,
911 "rule: Defaulting to all rules with known gliders\n");
912 return;
913 }
914 printRule(lp->neighbors, string, lp->input_param, MI_IS_VERBOSE(mi));
915 }
916
917 #ifndef STANDALONE
918 static void
parseFile(ModeInfo * mi)919 parseFile(ModeInfo *mi)
920 {
921 FILE *file;
922 static Bool done = False;
923 int firstx, firsty, x = 0, y = 0, z = 0, i = 0;
924 int c, cprev = ' ', size;
925 char line[256];
926
927 if (done)
928 return;
929 done = True;
930 if (MI_IS_FULLRANDOM(mi) || !lifefile || !*lifefile)
931 return;
932 if ((file = my_fopenSize(lifefile, "r", &size)) == NULL) {
933 (void) fprintf(stderr, "could not read file \"%s\"\n", lifefile);
934 return;
935 }
936 for (;;) {
937 if (!fgets(line, 256, file)) {
938 (void) fprintf(stderr,
939 "could not read header of file \"%s\"\n",
940 lifefile);
941 (void) fclose(file);
942 return;
943 }
944 if (strncmp(line, "#P", (size_t) 2) == 0 &&
945 sscanf(line, "#P %d %d %d", &x, &y, &z) == 3)
946 break;
947 }
948 c = getc(file);
949 while (c != EOF && !(c == '0' || c == 'O' || c == '*' || c == '.')) {
950 c = getc(file);
951 }
952 if (c == EOF || x <= -127 || y <= -127 || z <= -127 ||
953 x >= 127 || y >= 127 || z >= 127) {
954 (void) fprintf(stderr,
955 "corrupt file \"%s\" or file to large\n", lifefile);
956 (void) fclose(file);
957 return;
958 }
959 firstx = x;
960 firsty = y;
961 if ((filePattern = (char *) malloc((3 * size) *
962 sizeof (char))) == NULL) {
963 (void) fprintf(stderr, "not enough memory\n");
964 (void) fclose(file);
965 }
966
967 while (c != EOF && x < 127 && y < 127 && z < 127 && i < 3 * size) {
968 if (c == '0' || c == 'O' || c == '*') {
969 filePattern[i++] = x++;
970 filePattern[i++] = y;
971 filePattern[i++] = z;
972 } else if (c == '.') {
973 x++;
974 } else if (c == '\n') {
975 if (cprev == '\n') {
976 z++;
977 y = firsty;
978 } else {
979 x = firstx;
980 y++;
981 }
982 }
983 cprev = c;
984 c = getc(file);
985 }
986 (void) fclose(file);
987 filePattern[i] = 127;
988 }
989 #endif
990
991 /*--- list ---*/
992 /* initialise the state of all cells to OFF */
993 static void
initList(life3dstruct * lp)994 initList(life3dstruct * lp)
995 {
996 lp->ptrhead = lp->ptrend = (CellList *) NULL;
997 lp->eraserhead.next = &lp->eraserend;
998 lp->eraserend.prev = &lp->eraserhead;
999 lp->ncells = 0;
1000 }
1001
1002 /*-
1003 * Function that adds the cell (assumed live) at (x,y,z) onto the search
1004 * list so that it is scanned in future generations
1005 */
1006 static Bool
addToList(life3dstruct * lp,unsigned int x,unsigned int y,unsigned int z)1007 addToList(life3dstruct * lp, unsigned int x, unsigned int y, unsigned int z)
1008 {
1009 CellList *tmp;
1010
1011 if ((tmp = (CellList *) malloc(sizeof (CellList))) == NULL)
1012 return False;
1013 tmp->x = x;
1014 tmp->y = y;
1015 tmp->z = z;
1016 if (lp->ptrhead == NULL) {
1017 lp->ptrhead = lp->ptrend = tmp;
1018 tmp->prev = (struct _CellList *) NULL;
1019 } else {
1020 lp->ptrend->next = tmp;
1021 tmp->prev = lp->ptrend;
1022 lp->ptrend = tmp;
1023 }
1024 lp->ncells++;
1025 lp->ptrend->next = (struct _CellList *) NULL;
1026 return True;
1027 }
1028
1029 static void
addToEraseList(life3dstruct * lp,CellList * cell)1030 addToEraseList(life3dstruct * lp, CellList * cell)
1031 {
1032 cell->next = &lp->eraserend;
1033 cell->prev = lp->eraserend.prev;
1034 lp->eraserend.prev->next = cell;
1035 lp->eraserend.prev = cell;
1036 }
1037
1038 static void
delFromList(life3dstruct * lp,CellList * cell)1039 delFromList(life3dstruct * lp, CellList * cell)
1040 {
1041 if (cell != lp->ptrhead) {
1042 cell->prev->next = cell->next;
1043 } else {
1044 lp->ptrhead = cell->next;
1045 if (lp->ptrhead != NULL)
1046 lp->ptrhead->prev = (struct _CellList *) NULL;
1047 }
1048
1049 if (cell != lp->ptrend) {
1050 cell->next->prev = cell->prev;
1051 } else {
1052 lp->ptrend = cell->prev;
1053 if (lp->ptrend != NULL)
1054 lp->ptrend->next = (struct _CellList *) NULL;
1055 }
1056
1057 lp->ncells--;
1058 addToEraseList(lp, cell);
1059 }
1060
1061 static void
delFromEraseList(CellList * cell)1062 delFromEraseList(CellList * cell)
1063 {
1064 cell->next->prev = cell->prev;
1065 cell->prev->next = cell->next;
1066 free(cell);
1067 }
1068
1069 #ifdef DEBUG
1070 static void
printState(ModeInfo * mi,int state)1071 printState(ModeInfo * mi, int state)
1072 {
1073 /* life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
1074 CellList *curr;
1075 int i = 0;
1076
1077 curr = lp->first[state]->next;
1078 (void) printf("state %d\n", state);
1079 while (curr != lp->last[state]) {
1080 (void) printf("%d: position %ld, age %d, state %d, toggle %d\n",
1081 i, curr->info.position, curr->info.age,
1082 curr->info.state, curr->info.toggle);
1083 curr = curr->next;
1084 i++;
1085 } */
1086 }
1087
1088 #endif
1089
1090 static void
printList(life3dstruct * lp,int i)1091 printList(life3dstruct * lp, int i)
1092 {
1093 CellList *ptr, *ptrnextcell;
1094 /* did not make this hack multiscreen ready */
1095 static int tcol[2], trow[2], tstack[2], tcol2[2], trow2[2], tstack2[2];
1096 static int tcount[2];
1097 int hr = lp->nrows / 2;
1098 int hc = lp->ncols / 2;
1099 int hs = lp->nstacks / 2;
1100
1101 tcol[i] = 0;
1102 trow[i] = 0;
1103 tstack[i] = 0;
1104 tcol2[i] = 0;
1105 trow2[i] = 0;
1106 tstack2[i] = 0;
1107 tcount[i] = lp->ncells;
1108 if ((glidersearch || patternsearch) && tcount[0] < 72) {
1109 ptr = lp->ptrend;
1110 while (ptr != NULL) {
1111 int col, row, stack;
1112
1113 ptrnextcell = ptr->prev;
1114 col = ptr->x;
1115 row = ptr->y;
1116 stack = ptr->z;
1117 (void) printf("%d, %d, %d,\n", col - hc,
1118 row - hr, stack - hs);
1119 /* fudging a signature */
1120 tcol[i] += col;
1121 trow[i] += row;
1122 tstack[i] += stack;
1123 tcol2[i] += col * col;
1124 trow2[i] += row * row;
1125 tstack2[i] += stack * stack;
1126 ptr = ptrnextcell;
1127 }
1128
1129 (void) printf("%d#%d, pos_sum %d %d %d %d %d %d\n",
1130 i, tcount[i], tcol[i], trow[i], tstack[i],
1131 tcol2[i], trow2[i], tstack2[i]);
1132 if (i == 1 && (tcount[0] <= NUMPTS || tcount[1] <= NUMPTS) &&
1133 (tcount[0] != tcount[1] ||
1134 tcol[0] != tcol[1] || trow[0] != trow[1] ||
1135 tstack[0] != tstack[1] ||
1136 tcol2[0] != tcol2[1] || trow2[0] != trow2[1] ||
1137 tstack2[0] != tstack2[1]))
1138 (void) printf("found\n");
1139 }
1140 }
1141
1142 /*--- memory ---*/
1143 /*-
1144 * Simulate a large array by dynamically allocating 4x4x4 size cells when
1145 * needed.
1146 */
1147 static void
MemInit(life3dstruct * lp)1148 MemInit(life3dstruct * lp)
1149 {
1150 int i;
1151
1152 for (i = 0; i < BASESIZE; ++i) {
1153 if (lp->base[i] != NULL) {
1154 free(lp->base[i]);
1155 lp->base[i] = (unsigned char *) NULL;
1156 }
1157 }
1158 lp->memstart = 0;
1159 }
1160
1161 #define BASE_OFFSET(x,y,z,b,o) \
1162 b = ((x & 0x7c) << 7) + ((y & 0x7c) << 2) + ((z & 0x7c) >> 2); \
1163 o = (x & 3) + ((y & 3) << 2) + ((z & 3) << 4); \
1164 if (lp->base[b] == NULL) {\
1165 if ((lp->base[b] = (unsigned char *) calloc(64, sizeof (unsigned char))) == NULL) {return False;}}
1166
1167
1168 static Bool
GetMem(life3dstruct * lp,unsigned int x,unsigned int y,unsigned int z,int * m)1169 GetMem(life3dstruct * lp, unsigned int x, unsigned int y, unsigned int z,
1170 int *m)
1171 {
1172 int b, o;
1173
1174 if (lp->memstart) {
1175 MemInit(lp);
1176 }
1177 BASE_OFFSET(x, y, z, b, o);
1178 *m = lp->base[b][o];
1179 return True;
1180 }
1181
1182 static Bool
SetMem(life3dstruct * lp,unsigned int x,unsigned int y,unsigned int z,unsigned int val)1183 SetMem(life3dstruct * lp, unsigned int x, unsigned int y, unsigned int z,
1184 unsigned int val)
1185 {
1186 int b, o;
1187
1188 if (lp->memstart) {
1189 MemInit(lp);
1190 }
1191 #define NBUCKETS ((MAXCOLUMNS+MAXROWS+MAXSTACKS)*BUCKETSIZE)
1192 BASE_OFFSET(x, y, z, b, o);
1193 lp->base[b][o] = val;
1194 return True;
1195 }
1196
1197 static Bool
ChangeMem(life3dstruct * lp,unsigned int x,unsigned int y,unsigned int z,unsigned int val)1198 ChangeMem(life3dstruct * lp,
1199 unsigned int x, unsigned int y, unsigned int z,
1200 unsigned int val)
1201 {
1202 int b, o;
1203
1204 if (lp->memstart) {
1205 MemInit(lp);
1206 }
1207 BASE_OFFSET(x, y, z, b, o);
1208 lp->base[b][o] += val;
1209 return True;
1210 }
1211
1212 static void
ClearMem(life3dstruct * lp)1213 ClearMem(life3dstruct * lp)
1214 {
1215 int i, j, count;
1216
1217 for (i = 0; i < BASESIZE; ++i)
1218 if (lp->base[i] != NULL) {
1219 for (count = j = 0; j < 64 && count == 0; ++j)
1220 if (CellState3D(lp->base[i][j]))
1221 ++count;
1222 if (!count) {
1223 free(lp->base[i]);
1224 lp->base[i] = (unsigned char *) NULL;
1225 }
1226 }
1227 }
1228
1229 /* Checks to make sure there is a cell there */
cellCheck(int neighbors,int x,int y,int z)1230 static Bool cellCheck(int neighbors, int x, int y, int z)
1231 {
1232 if (neighbors == 16 || neighbors == 22)
1233 return tetra(x, y, z);
1234 else
1235 return ((neighbors != 12 && neighbors != -18) ||
1236 ((x + y + z) & 1) == 0);
1237 }
1238
1239 /* Checks to make sure it wraps well */
1240 /*
1241 static Bool boundsCheck12(int neighbors, int x, int y, int z) {
1242 return ((neighbors != 12 && neighbors != -18) ||
1243 ((x + y + z) & 1) == 0);
1244 }
1245
1246 static Bool boundsCheck14(int neighbors, int z) {
1247 return (neighbors != 14 || (z & 1) == 0);
1248 }
1249
1250 static Bool boundsCheck22(int neighbors, int x, int y, int z) {
1251 return (neighbors != 22 || (((x % 4) == 0) &&
1252 ((y % 4) == 0) && ((z % 4) == 0)));
1253 }
1254 */
1255
1256 /*-
1257 * This routine increments the values stored in the 27 cells centered on
1258 * (x,y,z) Note that the offset() macro implements wrapping - the world is a
1259 * 4d torus
1260 */
1261 static Bool
IncrementNbrs3D(life3dstruct * lp,CellList * cell)1262 IncrementNbrs3D(life3dstruct * lp, CellList * cell)
1263 {
1264 unsigned int xc, yc, zc, x, y, z, i;
1265
1266 for (i = 0; i < ABS(lp->neighbors); i++) {
1267 x = xc = cell->x;
1268 y = yc = cell->y;
1269 z = zc = cell->z;
1270 if (!cellCheck(lp->neighbors, x, y, z))
1271 continue;
1272 /*if (patternsearch &&
1273 (x == MAXCOLUMNS / 2 - 1 || y == MAXROWS / 2 - 1 || z == MAXSTACKS / 2 - 1))
1274 continue;*/
1275 positionOfNeighbor(lp, i, &x, &y, &z);
1276 if (x != xc || y != yc || z != zc)
1277 if (!ChangeMem(lp,
1278 (unsigned int) x, (unsigned int) y, (unsigned int) z, 1))
1279 return False;
1280 }
1281 return True;
1282 }
1283
1284 static void
endList(life3dstruct * lp)1285 endList(life3dstruct * lp)
1286 {
1287 CellList *ptr;
1288
1289 while (lp->ptrhead != NULL) {
1290 /* Reset3D(lp->ptrhead->x, lp->ptrhead->y, lp->ptrhead->z); */
1291 delFromList(lp, lp->ptrhead);
1292 }
1293 ptr = lp->eraserhead.next;
1294 while (ptr != &lp->eraserend) {
1295 delFromEraseList(ptr);
1296 ptr = lp->eraserhead.next;
1297 }
1298 MemInit(lp);
1299 }
1300
1301 static Bool
RunLife3D(life3dstruct * lp)1302 RunLife3D(life3dstruct * lp)
1303 {
1304 unsigned int i, x, y, z, xc = 0, yc = 0, zc = 0;
1305 int c;
1306 CellList *ptr, *ptrnextcell;
1307 Bool visible = False;
1308
1309 /* Step 1 - Add 1 to all neighbors of living cells. */
1310 ptr = lp->ptrhead;
1311 while (ptr != NULL) {
1312 if (!IncrementNbrs3D(lp, ptr))
1313 return False;
1314 ptr = ptr->next;
1315 }
1316
1317 /* Step 2 - Scan world and implement Survival rules. We have a list of live
1318 * cells, so do the following:
1319 * Start at the END of the list and work backwards (so we don't have to worry
1320 * about scanning newly created cells since they are appended to the end) and
1321 * for every entry, scan its neighbors for new live cells. If found, add them
1322 * to the end of the list. If the centre cell is dead, unlink it.
1323 * Make sure we do not append multiple copies of cells.
1324 */
1325 ptr = lp->ptrend;
1326 while (ptr != NULL) {
1327 ptrnextcell = ptr->prev;
1328 for (i = 0; i < ABS(lp->neighbors); i++) {
1329 x = xc = ptr->x;
1330 y = yc = ptr->y;
1331 z = zc = ptr->z;
1332 if (!cellCheck(lp->neighbors, x, y, z))
1333 continue;
1334 positionOfNeighbor(lp, i, &x, &y, &z);
1335 if (x != xc || y != yc || z != zc) {
1336 if (!GetMem(lp, x, y, z, &c))
1337 return False;
1338 if (c) {
1339 if (CellState3D(c) == OFF) {
1340 if (lp->param.birth & (1 << CellNbrs3D(c))) {
1341 visible = True;
1342 SetList(x, y, z);
1343 } else {
1344 if (!Reset3D(x, y, z))
1345 return False;
1346 }
1347 }
1348 }
1349 }
1350 }
1351 if (!GetMem(lp, xc, yc, zc, &c))
1352 return False;
1353 if (lp->param.survival & (1 << CellNbrs3D(c))) {
1354 if (!Set3D(xc, yc, zc))
1355 return False;
1356 } else {
1357 if (!Reset3D(ptr->x, ptr->y, ptr->z))
1358 return False;
1359 delFromList(lp, ptr);
1360 }
1361 ptr = ptrnextcell;
1362 }
1363 ClearMem(lp);
1364 if (visible)
1365 lp->noChangeCount = 0;
1366 else
1367 lp->noChangeCount++;
1368 return True;
1369 }
1370
1371 #if 0
1372 static int
1373 CountCells3D(life3dstruct * lp)
1374 {
1375 CellList *ptr;
1376 int count = 0;
1377
1378 ptr = lp->ptrhead;
1379 while (ptr != NULL) {
1380 ++count;
1381 ptr = ptr->next;
1382 }
1383 return count;
1384 }
1385
1386 void
1387 DisplayList(life3dstruct * lp)
1388 {
1389 CellList *ptr;
1390 int count = 0;
1391
1392 ptr = lp->ptrhead;
1393 while (ptr != NULL) {
1394 (void) printf("(%x)=[%d,%d,%d] ", (int) ptr,
1395 ptr->x, ptr->y, ptr->z);
1396 ptr = ptr->next;
1397 ++count;
1398 }
1399 (void) printf("Living cells = %d\n", count);
1400 }
1401
1402 #endif
1403
1404 #define NOSYMRAND 0
1405 #define ODDSYMRAND 1
1406 #define EVENSYMRAND 2
1407 #define ODDANTISYMRAND 3
1408 #define EVENANTISYMRAND 4
1409 #define DIAGSYMRAND 5
1410
1411 static Bool
RandomSoup(ModeInfo * mi,int n,int vx,int vy,int vz)1412 RandomSoup(ModeInfo * mi, int n, int vx, int vy, int vz)
1413 {
1414 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
1415 int row, col, stack;
1416 int xrand, yrand, zrand;
1417 int hr = lp->nrows / 2;
1418 int hc = lp->ncols / 2;
1419 int hs = lp->nstacks / 2;
1420
1421 if (glidersearch) {
1422 xrand = NRAND(3);
1423 yrand = NRAND(3);
1424 zrand = NRAND(3);
1425 } else {
1426 xrand = NRAND(5);
1427 yrand = NRAND(5);
1428 zrand = NRAND(5);
1429 }
1430 if (glidersearch) {
1431 /* single sym or else glider pairs will crash into each other,
1432 hmmm, that may weed out some legitimate cases */
1433 if (xrand > NOSYMRAND && yrand > NOSYMRAND) {
1434 if (LRAND() & 1)
1435 xrand = NOSYMRAND;
1436 else
1437 yrand = NOSYMRAND;
1438 }
1439 if ((xrand > NOSYMRAND || yrand > NOSYMRAND) &&
1440 zrand > NOSYMRAND) {
1441 if (!NRAND(3))
1442 xrand = yrand = NOSYMRAND;
1443 else
1444 zrand = NOSYMRAND;
1445 }
1446 }
1447 if (!NRAND(4)) {
1448 xrand = NOSYMRAND;
1449 yrand = DIAGSYMRAND;
1450 zrand = NRAND(3);
1451 }
1452 if (!NRAND(6)) {
1453 /* Full diagonal */
1454 xrand = NOSYMRAND;
1455 yrand = NOSYMRAND;
1456 zrand = DIAGSYMRAND;
1457 }
1458 if (zrand == DIAGSYMRAND) {
1459 if ((vx != vy) || (vy != vz))
1460 vx = vy = vz = MIN(vx, MIN(vy, vz));
1461 } else if (yrand == DIAGSYMRAND) {
1462 if (vx != vy)
1463 vx = vy = MIN(vx, vy);
1464 }
1465 vx /= 2;
1466 vy /= 2;
1467 vz /= 2;
1468 if (vx < 1)
1469 vx = 1;
1470 if (vy < 1)
1471 vy = 1;
1472 if (vz < 1)
1473 vz = 1;
1474
1475 if (xrand == NOSYMRAND && yrand == NOSYMRAND && zrand == NOSYMRAND) {
1476 for (stack = 0; stack < 2 * vz; ++stack)
1477 for (row = 0; row < 2 * vy; ++row)
1478 for (col = 0; col < 2 * vx; ++col)
1479 if (NRAND(100) < n) {
1480 SetList(col + hc - vx, row + hr - vy, stack + hs - vz);
1481 }
1482 (void) strcpy(lp->nameString, "random pattern");
1483 if (MI_IS_VERBOSE(mi)) {
1484 (void) fprintf(stdout, "%s\n", lp->nameString);
1485 }
1486 return True;
1487 }
1488 if (zrand == DIAGSYMRAND) {
1489 for (stack = 0; stack < 2 * vz; ++stack)
1490 for (row = stack; row < 2 * vy; ++row)
1491 for (col = row; col < 2 * vx; ++col)
1492 if (NRAND(100) < n) {
1493 SetList(col + hc - vx, row + hr - vy, stack + hs - vz);
1494 SetList(row + hc - vx, stack + hr - vy, col + hs - vz);
1495 SetList(stack + hc - vx, col + hr - vy, row + hs - vz);
1496 }
1497 (void) strcpy(lp->nameString, "full diag random pattern");
1498 if (MI_IS_VERBOSE(mi)) {
1499 (void) fprintf(stdout, "%s\n", lp->nameString);
1500 }
1501 return True;
1502 }
1503 #if 0
1504 if (yrand == DIAGSYMRAND) {
1505 for (stack = 0; stack < 2 * vz; ++stack)
1506 for (row = 0; row < 2 * vy; ++row)
1507 for (col = row; col < 2 * vx; ++col) {
1508 if (NRAND(100) < n) {
1509 SetList(col + hc - vx, row + hr - vy, stack + hs - vz);
1510 SetList(row + hc - vx, col + hr - vy, stack + hs - vz);
1511 }
1512 if (zrand == ODDSYMRAND) {
1513 SetList(col + hc - vx, row + hr - vy, vz - stack + hs);
1514 SetList(row + hc - vx, col + hr - vy, vz - stack + hs);
1515 } else if (zrand == EVENSYMRAND) {
1516 SetList(col + hc - vx, row + hr - vy, vz - stack + hs - 1);
1517 SetList(row + hc - vx, col + hr - vy, vz - stack + hs - 1);
1518 }
1519 }
1520 (void) strcpy(lp->nameString, "diag random pattern");
1521 if (MI_IS_VERBOSE(mi)) {
1522 (void) fprintf(stdout, "%s\n", lp->nameString);
1523 }
1524 return True;
1525 }
1526 #endif
1527 if (yrand != DIAGSYMRAND)
1528 zrand = NOSYMRAND; /* change me */
1529 if (yrand == NOSYMRAND) {
1530 if (xrand == NOSYMRAND) {
1531 (void) strcpy(lp->nameString, "full random pattern");
1532 for (stack = hs - vz; stack < hs + vz; ++stack)
1533 for (row = hr - vy; row < hr + vy; ++row)
1534 for (col = hc - vx; col < hc + vx; ++col) {
1535
1536 if (NRAND(100) < n) {
1537 SetList(col, row, stack);
1538 }
1539 }
1540 } else if (xrand == ODDSYMRAND) {
1541 (void) sprintf(lp->nameString, "%s %srandom pattern", "x", "odd ");
1542 for (stack = hs - vz; stack < hs + vz; ++stack)
1543 for (row = hr - vy; row < hr + vy; ++row)
1544 for (col = hc; col < hc + vx; ++col) {
1545
1546 if (NRAND(100) < n / 2) {
1547 SetList(col, row, stack);
1548 SetList(2 * hc - col, row, stack);
1549 }
1550 }
1551 } else if (xrand == EVENSYMRAND) {
1552 (void) sprintf(lp->nameString, "%s even random pattern", "x");
1553 for (stack = hs - vz; stack < hs + vz; ++stack)
1554 for (row = hr - vy; row < hr + vy; ++row)
1555 for (col = hc; col < hc + vx; ++col) {
1556
1557 if (NRAND(100) < n / 2) {
1558 SetList(col, row, stack);
1559 SetList(2 * hc - col - 1, row, stack);
1560 }
1561 }
1562 } else if (xrand == ODDANTISYMRAND) {
1563 (void) sprintf(lp->nameString, "%s %srandom pattern", "x", "odd antisym ");
1564 for (stack = hs - vz; stack < hs + vz; ++stack)
1565 for (row = hr - vy; row < hr + vy; ++row)
1566 for (col = hc; col < hc + vx; ++col) {
1567
1568 if (NRAND(100) < n / 2) {
1569 SetList(col, row, stack);
1570 SetList(2 * hc - col, 2 * hr - row - 1, stack);
1571 }
1572 }
1573 } else if (xrand == EVENANTISYMRAND) {
1574 (void) sprintf(lp->nameString, "%s even antisym pattern", "x");
1575 for (stack = hs - vz; stack < hs + vz; ++stack)
1576 for (row = hr - vy; row < hr + vy; ++row)
1577 for (col = hc; col < hc + vx; ++col) {
1578
1579 if (NRAND(100) < n / 2) {
1580 SetList(col, row, stack);
1581 SetList(2 * hc - col - 1, 2 * hr - row - 1, stack);
1582 }
1583 }
1584 }
1585 } else if (yrand == ODDSYMRAND) {
1586 if (xrand == NOSYMRAND) {
1587 (void) sprintf(lp->nameString, "%s odd random pattern", "y");
1588 for (stack = hs - vz; stack < hs + vz; ++stack)
1589 for (row = hr; row < hr + vy; ++row)
1590 for (col = hc - vx; col < hc + vx; ++col) {
1591
1592 if (NRAND(100) < n / 2) {
1593 SetList(col, row, stack);
1594 SetList(col, 2 * hr - row, stack);
1595 }
1596 }
1597 } else if (xrand == ODDSYMRAND) {
1598 (void) sprintf(lp->nameString, "x %sand y odd random pattern", "");
1599 for (stack = hs - vz; stack < hs + vz; ++stack)
1600 for (row = hr; row < hr + vy; ++row)
1601 for (col = hc; col < hc + vx; ++col) {
1602
1603 if (NRAND(100) < n / 4) {
1604 SetList(col, row, stack);
1605 SetList(col, 2 * hr - row, stack);
1606 SetList(2 * hc - col, row, stack);
1607 SetList(2 * hc - col, 2 * hr - row, stack);
1608 }
1609 }
1610 } else if (xrand == EVENSYMRAND) {
1611 (void) sprintf(lp->nameString, "%s random pattern", "x even and y odd");
1612 for (stack = hs - vz; stack < hs + vz; ++stack)
1613 for (row = hr; row < hr + vy; ++row)
1614 for (col = hc; col < hc + vx; ++col) {
1615 if (NRAND(100) < n / 2) {
1616 SetList(col, row, stack);
1617 SetList(2 * hc - col - 1, row, stack);
1618 SetList(col, 2 * hr - row, stack);
1619 SetList(2 * hc - col - 1, 2 * hr - row, stack);
1620 }
1621 }
1622 }
1623 } else if (yrand == EVENSYMRAND) {
1624 if (xrand == NOSYMRAND) {
1625 (void) sprintf(lp->nameString, "%s even random pattern", "y");
1626 for (stack = hs - vz; stack < hs + vz; ++stack)
1627 for (row = hr; row < hr + vy; ++row)
1628 for (col = hc - vx; col < hc + vx; ++col) {
1629 if (NRAND(100) < n / 2) {
1630 SetList(col, row, stack);
1631 SetList(col, 2 * hr - row - 1, stack);
1632 }
1633 }
1634 } else if (xrand == ODDSYMRAND) {
1635 (void) sprintf(lp->nameString, "%s random pattern", "x odd and y even");
1636 for (stack = hs - vz; stack < hs + vz; ++stack)
1637 for (row = hr; row < hr + vy; ++row)
1638 for (col = hc; col < hc + vx; ++col) {
1639 if (NRAND(100) < n / 4) {
1640 SetList(col, row, stack);
1641 SetList(2 * hc - col, row, stack);
1642 SetList(col, 2 * hr - row - 1, stack);
1643 SetList(2 * hc - col, 2 * hr - row - 1, stack);
1644 }
1645 }
1646 } else if (xrand == EVENSYMRAND) {
1647 (void) sprintf(lp->nameString, "x and y even random pattern");
1648 for (stack = hs - vz; stack < hs + vz; ++stack)
1649 for (row = hr; row < hr + vy; ++row)
1650 for (col = hc; col < hc + vx; ++col) {
1651 if (NRAND(100) < n / 4) {
1652 SetList(col, row, stack);
1653 SetList(2 * hc - col - 1, row, stack);
1654 SetList(col, 2 * hr - row - 1, stack);
1655 SetList(2 * hc - col - 1, 2 * hr - row - 1, stack);
1656 }
1657 }
1658 }
1659 } else if (yrand == ODDANTISYMRAND) {
1660 if (xrand == NOSYMRAND) {
1661 (void) sprintf(lp->nameString, "%s odd antisym pattern", "y");
1662 for (stack = hs - vz; stack < hs + vz; ++stack)
1663 for (row = hr; row < hr + vy; ++row)
1664 for (col = hc - vx; col < hc + vx; ++col) {
1665
1666 if (NRAND(100) < n / 2) {
1667 SetList(col, row, stack);
1668 SetList(2 * hc - col - 1, 2 * hr - row, stack);
1669 }
1670 }
1671 }
1672 } else if (yrand == EVENANTISYMRAND) {
1673 if (xrand == NOSYMRAND) {
1674 (void) sprintf(lp->nameString, "%s even antisym pattern", "y");
1675 for (stack = hs - vz; stack < hs + vz; ++stack)
1676 for (row = hr; row < hr + vy; ++row)
1677 for (col = hc - vx; col < hc + vx; ++col) {
1678
1679 if (NRAND(100) < n / 2) {
1680 SetList(col, row, stack);
1681 SetList(2 * hc - col - 1, 2 * hr - row - 1, stack);
1682 }
1683 }
1684 }
1685 } else if (yrand == DIAGSYMRAND) {
1686 if (glidersearch) {
1687 /* single sym or else glider pairs will crash into each other */
1688 xrand = NRAND(2);
1689 } else {
1690 xrand = NRAND(4);
1691 }
1692 vx = MIN(vx, vy);
1693 if (xrand == 0) {
1694 (void) strcpy(lp->nameString, "\\ random pattern");
1695 for (stack = hs - vz; stack < hs + vz; ++stack)
1696 for (row = hr - vx; row < hr + vx; ++row) {
1697 for (col = row - hr + hc; col < hc + vx; ++col) {
1698 if (NRAND(100) < n / 2) {
1699 SetList(col, row, stack);
1700 SetList(row + hc - hr, col + hr - hc, stack);
1701 }
1702 }
1703 }
1704 } else if (xrand == 1) {
1705 (void) strcpy(lp->nameString, "/ random pattern");
1706 for (stack = hs - vz; stack < hs + vz; ++stack)
1707 for (row = hr - vx; row < hr + vx; ++row) {
1708 for (col = row - hr + hc; col < hc + vx; ++col) {
1709 if (NRAND(100) < n / 2) {
1710 SetList(2 * hc - col, row, stack);
1711 SetList(hc - row + hr, col + hr - hc, stack);
1712 }
1713 }
1714 }
1715 } else if (xrand == 2) {
1716 (void) strcpy(lp->nameString, "symmetric diagonal random pattern");
1717 for (stack = hs - vz; stack < hs + vz; ++stack)
1718 for (row = hr - vx; row < hr + vx; ++row) {
1719 for (col = row - hr + hc; col < hc + vx; ++col) {
1720 if (NRAND(100) < n / 4) {
1721 SetList(2 * hc - col, row, stack);
1722 SetList(hc - row + hr, col + hr - hc, stack);
1723 SetList(col, 2 * hr - row, stack);
1724 SetList(row + hc - hr, hr - col + hc, stack);
1725 }
1726 }
1727 }
1728 } else if (xrand == 3) {
1729 (void) strcpy(lp->nameString, "full symmetric random pattern");
1730 for (stack = hs - vz; stack < hs + vz; ++stack)
1731 for (row = hr; row < hr + vx; ++row) {
1732 for (col = row - hr + hc; col < hc + vx; ++col) {
1733 if (NRAND(100) < n / 8) {
1734 SetList(col, row, stack);
1735 SetList(row + hc - hr, col + hr - hc, stack);
1736 SetList(2 * hc - col, row, stack);
1737 SetList(hc - row + hr, col + hr - hc, stack);
1738 SetList(col, 2 * hr - row, stack);
1739 SetList(row + hc - hr, hr - col + hc, stack);
1740 SetList(2 * hc - col, 2 * hr - row, stack);
1741 SetList(hc - row + hr, hr - col + hc, stack);
1742 }
1743 }
1744 }
1745 }
1746 }
1747
1748
1749 if (MI_IS_VERBOSE(mi)) {
1750 (void) fprintf(stdout, "%s\n", lp->nameString);
1751 }
1752 return True;
1753 }
1754
1755 static Bool
GetPattern(ModeInfo * mi,int pattern_rule,int pattern)1756 GetPattern(ModeInfo * mi, int pattern_rule, int pattern)
1757 {
1758 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
1759 int x, y, z, orient, temp;
1760 char *patptr = (char *) NULL;
1761 #ifdef LIFE_NAMES
1762 int pat = 2 * pattern + 1;
1763 char * patstrg = (char *) "";
1764 #else
1765 int pat = pattern;
1766 #endif
1767
1768 if (filePattern) {
1769 patptr = &filePattern[0];
1770 #ifdef LIFE_NAMES
1771 (void) strcpy(lp->nameString, patstrg);
1772 #endif
1773 } else {
1774 switch (lp->neighbors) {
1775 case 12:
1776 switch (pattern_rule) {
1777 case LIFE_12B3S3:
1778 patptr = &patterns_12B3S3[pat][0];
1779 #ifdef LIFE_NAMES
1780 patstrg = &patterns_12B3S3[2 * pattern][0];
1781 #endif
1782 break;
1783 case LIFE_12B3S456:
1784 patptr = &patterns_12B3S456[pat][0];
1785 #ifdef LIFE_NAMES
1786 patstrg = &patterns_12B3S456[2 * pattern][0];
1787 #endif
1788 break;
1789 }
1790 break;
1791 case 14:
1792 switch (pattern_rule) {
1793 case LIFE_14B4S34:
1794 patptr = &patterns_14B4S34[pat][0];
1795 #ifdef LIFE_NAMES
1796 patstrg = &patterns_14B4S34[2 * pattern][0];
1797 #endif
1798 break;
1799 case LIFE_14B46S34:
1800 patptr = &patterns_14B46S34[pat][0];
1801 #ifdef LIFE_NAMES
1802 patstrg = &patterns_14B46S34[2 * pattern][0];
1803 #endif
1804 break;
1805 case LIFE_14B45S56:
1806 patptr = &patterns_14B45S56[pat][0];
1807 #ifdef LIFE_NAMES
1808 patstrg = &patterns_14B45S56[2 * pattern][0];
1809 #endif
1810 break;
1811 }
1812 break;
1813 case 18:
1814 switch (pattern_rule) {
1815 case LIFE_18B4S45:
1816 patptr = &patterns_18B4S45[pat][0];
1817 #ifdef LIFE_NAMES
1818 patstrg = &patterns_18B4S45[2 * pattern][0];
1819 #endif
1820 break;
1821 }
1822 break;
1823 case -18:
1824 switch (pattern_rule) {
1825 case LIFE__18B4S36:
1826 patptr = &patterns__18B4S36[pat][0];
1827 #ifdef LIFE_NAMES
1828 patstrg = &patterns__18B4S36[2 * pattern][0];
1829 #endif
1830 break;
1831 case LIFE__18B4S45:
1832 patptr = &patterns__18B4S45[pat][0];
1833 #ifdef LIFE_NAMES
1834 patstrg = &patterns__18B4S45[2 * pattern][0];
1835 #endif
1836 break;
1837 case LIFE__18B4S456:
1838 patptr = &patterns__18B4S456[pat][0];
1839 #ifdef LIFE_NAMES
1840 patstrg = &patterns__18B4S456[2 * pattern][0];
1841 #endif
1842 break;
1843 case LIFE__18B4S46:
1844 patptr = &patterns__18B4S46[pat][0];
1845 #ifdef LIFE_NAMES
1846 patstrg = &patterns__18B4S46[2 * pattern][0];
1847 #endif
1848 break;
1849 }
1850 break;
1851 case 20:
1852 switch (pattern_rule) {
1853 case LIFE_20B4S45:
1854 patptr = &patterns_20B4S45[pat][0];
1855 #ifdef LIFE_NAMES
1856 patstrg = &patterns_20B4S45[2 * pattern][0];
1857 #endif
1858 break;
1859 }
1860 break;
1861 case 22:
1862 switch (pattern_rule) {
1863 case LIFE_22B4S3:
1864 patptr = &patterns_22B4S3[pat][0];
1865 #ifdef LIFE_NAMES
1866 patstrg = &patterns_22B4S3[2 * pattern][0];
1867 #endif
1868 break;
1869 case LIFE_22B4S4:
1870 patptr = &patterns_22B4S4[pat][0];
1871 #ifdef LIFE_NAMES
1872 patstrg = &patterns_22B4S4[2 * pattern][0];
1873 #endif
1874 break;
1875 case LIFE_22B4S57:
1876 patptr = &patterns_22B4S57[pat][0];
1877 #ifdef LIFE_NAMES
1878 patstrg = &patterns_22B4S57[2 * pattern][0];
1879 #endif
1880 break;
1881 }
1882 break;
1883 case 26:
1884 switch (pattern_rule) {
1885 case LIFE_26B5S23:
1886 patptr = &patterns_26B5S23[pat][0];
1887 #ifdef LIFE_NAMES
1888 patstrg = &patterns_26B5S23[2 * pattern][0];
1889 #endif
1890 break;
1891 case LIFE_26B5S25:
1892 patptr = &patterns_26B5S25[pat][0];
1893 #ifdef LIFE_NAMES
1894 patstrg = &patterns_26B5S25[2 * pattern][0];
1895 #endif
1896 break;
1897 case LIFE_26B5S27:
1898 patptr = &patterns_26B5S27[pat][0];
1899 #ifdef LIFE_NAMES
1900 patstrg = &patterns_26B5S27[2 * pattern][0];
1901 #endif
1902 break;
1903 case LIFE_26B5S35:
1904 patptr = &patterns_26B5S35[pat][0];
1905 #ifdef LIFE_NAMES
1906 patstrg = &patterns_26B5S35[2 * pattern][0];
1907 #endif
1908 break;
1909 case LIFE_26B5S36:
1910 patptr = &patterns_26B5S36[pat][0];
1911 #ifdef LIFE_NAMES
1912 patstrg = &patterns_26B5S36[2 * pattern][0];
1913 #endif
1914 break;
1915 case LIFE_26B5S37:
1916 patptr = &patterns_26B5S37[pat][0];
1917 #ifdef LIFE_NAMES
1918 patstrg = &patterns_26B5S37[2 * pattern][0];
1919 #endif
1920 break;
1921 case LIFE_26B5S38:
1922 patptr = &patterns_26B5S38[pat][0];
1923 #ifdef LIFE_NAMES
1924 patstrg = &patterns_26B5S38[2 * pattern][0];
1925 #endif
1926 break;
1927 case LIFE_26B5S4:
1928 patptr = &patterns_26B5S4[pat][0];
1929 #ifdef LIFE_NAMES
1930 patstrg = &patterns_26B5S4[2 * pattern][0];
1931 #endif
1932 break;
1933 case LIFE_26B5S45:
1934 patptr = &patterns_26B5S45[pat][0];
1935 #ifdef LIFE_NAMES
1936 patstrg = &patterns_26B5S45[2 * pattern][0];
1937 #endif
1938 break;
1939 case LIFE_26B5S47:
1940 patptr = &patterns_26B5S47[pat][0];
1941 #ifdef LIFE_NAMES
1942 patstrg = &patterns_26B5S47[2 * pattern][0];
1943 #endif
1944 break;
1945 case LIFE_26B5S56:
1946 patptr = &patterns_26B5S56[pat][0];
1947 #ifdef LIFE_NAMES
1948 patstrg = &patterns_26B5S56[2 * pattern][0];
1949 #endif
1950 break;
1951 case LIFE_26B5S58:
1952 patptr = &patterns_26B5S58[pat][0];
1953 #ifdef LIFE_NAMES
1954 patstrg = &patterns_26B5S58[2 * pattern][0];
1955 #endif
1956 break;
1957 case LIFE_26B5S678:
1958 patptr = &patterns_26B5S678[pat][0];
1959 #ifdef LIFE_NAMES
1960 patstrg = &patterns_26B5S678[2 * pattern][0];
1961 #endif
1962 break;
1963 case LIFE_26B5S8:
1964 patptr = &patterns_26B5S8[pat][0];
1965 #ifdef LIFE_NAMES
1966 patstrg = &patterns_26B5S8[2 * pattern][0];
1967 #endif
1968 break;
1969 case LIFE_26B58S58:
1970 patptr = &patterns_26B58S58[pat][0];
1971 #ifdef LIFE_NAMES
1972 patstrg = &patterns_26B58S58[2 * pattern][0];
1973 #endif
1974 break;
1975 case LIFE_26B6S567:
1976 patptr = &patterns_26B6S567[pat][0];
1977 #ifdef LIFE_NAMES
1978 patstrg = &patterns_26B6S567[2 * pattern][0];
1979 #endif
1980 break;
1981 case LIFE_26B6S57:
1982 patptr = &patterns_26B6S57[pat][0];
1983 #ifdef LIFE_NAMES
1984 patstrg = &patterns_26B6S57[2 * pattern][0];
1985 #endif
1986 break;
1987 case LIFE_26B67S57:
1988 patptr = &patterns_26B67S57[pat][0];
1989 #ifdef LIFE_NAMES
1990 patstrg = &patterns_26B67S57[2 * pattern][0];
1991 #endif
1992 break;
1993 case LIFE_26B67S67:
1994 patptr = &patterns_26B67S67[pat][0];
1995 #ifdef LIFE_NAMES
1996 patstrg = &patterns_26B67S67[2 * pattern][0];
1997 #endif
1998 break;
1999 }
2000 break;
2001 }
2002 #ifdef LIFE_NAMES
2003 (void) strcpy(lp->nameString, patstrg);
2004 #endif
2005 }
2006 #ifdef DEBUG
2007 orient = 0;
2008 #else
2009 orient = NRAND(24);
2010 #endif
2011 if (MI_IS_VERBOSE(mi) && !filePattern) {
2012 #ifdef LIFE_NAMES
2013 (void) fprintf(stdout, "%s, ", patstrg);
2014 #endif
2015 (void) fprintf(stdout, "table number %d\n", pattern);
2016 }
2017 while ((x = *patptr++) != 127) {
2018 y = *patptr++;
2019 z = *patptr++;
2020 if (orient >= 16) {
2021 temp = x;
2022 x = y;
2023 if (lp->neighbors == 14) {
2024 y = (z >= 0) ? z / 2 : (z - 1) / 2;
2025 z = (z & 1) + 2 * temp;
2026 } else {
2027 y = z;
2028 z = temp;
2029 }
2030 } else if (orient >= 8) {
2031 temp = x;
2032 if (lp->neighbors == 14) {
2033 x = (z >= 0) ? z / 2 : (z - 1) / 2;
2034 z = (z & 1) + 2 * y;
2035 } else {
2036 x = z;
2037 z = y;
2038 }
2039 y = temp;
2040 }
2041 if (orient % 8 >= 4) {
2042 if (lp->neighbors == 14 && (z & 1) == 1)
2043 x = -x - 1;
2044 else
2045 x = -x;
2046 }
2047 if (orient % 4 >= 2) {
2048 if (lp->neighbors == 14 && (z & 1) == 1)
2049 y = -y - 1;
2050 else
2051 y = -y;
2052 }
2053 if (orient % 2 == 1) {
2054 z = -z;
2055 }
2056
2057 x += lp->ncols / 2;
2058 y += lp->nrows / 2;
2059 z += lp->nstacks / 2;
2060 if (x >= 0 && y >= 0 && z >= 0 &&
2061 x < lp->ncols && y < lp->nrows && z < lp->nstacks) {
2062 SetList(x, y, z);
2063 }
2064 }
2065 return True;
2066 }
2067
2068 static void
NewViewpoint(life3dstruct * lp,double x,double y,double z)2069 NewViewpoint(life3dstruct * lp, double x, double y, double z)
2070 {
2071 double k, l, d1, d2;
2072
2073 k = x * x + y * y;
2074 l = sqrt(k + z * z);
2075 k = sqrt(k);
2076 d1 = (EyeToScreen / HalfScreenD);
2077 d2 = EyeToScreen / (HalfScreenD * lp->height / lp->width);
2078 lp->A = d1 * l * (lp->width / 2) / k;
2079 lp->B = l * l;
2080 lp->C = d2 * (lp->height / 2) / k;
2081 lp->F = k * k;
2082 }
2083
2084 static void
lissajous(life3dstruct * lp)2085 lissajous(life3dstruct * lp)
2086 {
2087 double alt, azm, dist;
2088
2089 alt = 30.0 * sin(lp->metaAlt * IP) + 45.0;
2090 lp->metaAlt += 1.123;
2091 if (lp->metaAlt >= 360.0)
2092 lp->metaAlt -= 360.0;
2093 if (lp->metaAlt < 0.0)
2094 lp->metaAlt += 360.0;
2095 azm = 30.0 * sin(lp->metaAzm * IP) + 45.0;
2096 lp->metaAzm += 0.987;
2097 if (lp->metaAzm >= 360.0)
2098 lp->metaAzm -= 360.0;
2099 if (lp->metaAzm < 0.0)
2100 lp->metaAzm += 360.0;
2101 dist = 10.0 * sin(lp->metaDist * IP) + 50.0;
2102 lp->metaDist += 1.0;
2103 if (lp->metaDist >= 360.0)
2104 lp->metaDist -= 360.0;
2105 if (lp->metaDist < 0.0)
2106 lp->metaDist += 360.0;
2107 #if 0
2108 if (alt >= 90.0)
2109 alt = 90.0;
2110 else if (alt < -90.0)
2111 alt = -90.0;
2112 #endif
2113 lp->azm = azm;
2114 #ifdef DEBUG
2115 (void) printf("dist %g, alt %g, azm %g\n", dist, alt, azm);
2116 #endif
2117 lp->vx = (sin(azm * IP) * cos(alt * IP) * dist);
2118 lp->vy = (cos(azm * IP) * cos(alt * IP) * dist);
2119 lp->vz = (sin(alt * IP) * dist);
2120 NewViewpoint(lp, lp->vx, lp->vy, lp->vz);
2121 }
2122
2123 static void
NewPoint(life3dstruct * lp,double x,double y,double z,register XPoint * pts)2124 NewPoint(life3dstruct * lp, double x, double y, double z,
2125 register XPoint * pts)
2126 {
2127 double p1, E;
2128
2129 p1 = x * lp->vx + y * lp->vy;
2130 E = lp->B - p1 - z * lp->vz;
2131 pts->x = (int) (lp->width / 2 -
2132 lp->A * (lp->vx * y - lp->vy * x) / E);
2133 pts->y = (int) (lp->height / 2 -
2134 lp->C * (z * lp->F - lp->vz * p1) / E);
2135 }
2136
2137
2138 /* Chain together all cells that are at the same distance.
2139 * These cannot mutually overlap. */
2140 static void
SortList(life3dstruct * lp)2141 SortList(life3dstruct * lp)
2142 {
2143 short dist;
2144 double d, x, y, z, rsize;
2145 int i, r;
2146 XPoint point;
2147 CellList *ptr;
2148
2149 for (i = 0; i < NBUCKETS; ++i)
2150 lp->buckethead[i] = lp->bucketend[i] = (CellList *) NULL;
2151
2152 /* Calculate distances and re-arrange pointers to chain off buckets */
2153 ptr = lp->ptrhead;
2154 while (ptr != NULL) {
2155
2156 x = (double) ptr->x - lp->ox;
2157 y = (double) ptr->y - lp->oy;
2158 z = (double) ptr->z - lp->oz;
2159 d = Distance(lp->vx, lp->vy, lp->vz, x, y, z);
2160 if (lp->vx * (lp->vx - x) + lp->vy * (lp->vy - y) +
2161 lp->vz * (lp->vz - z) > 0 && d > 1.5)
2162 ptr->visible = 1;
2163 else
2164 ptr->visible = 0;
2165
2166 ptr->dist = (short) d;
2167 dist = (short) (d * BUCKETSIZE);
2168 if (dist > NBUCKETS - 1)
2169 dist = NBUCKETS - 1;
2170
2171 if (lp->buckethead[dist] == NULL) {
2172 lp->buckethead[dist] = lp->bucketend[dist] = ptr;
2173 ptr->priority = (struct _CellList *) NULL;
2174 } else {
2175 lp->bucketend[dist]->priority = ptr;
2176 lp->bucketend[dist] = ptr;
2177 lp->bucketend[dist]->priority =
2178 (struct _CellList *) NULL;
2179 }
2180 ptr = ptr->next;
2181 }
2182
2183 /* Check for invisibility */
2184 rsize = 0.47 * lp->width / ((double) HalfScreenD * 2);
2185 i = (int) lp->azm;
2186 if (i < 0)
2187 i = -i;
2188 i = i % RT_ANGLE;
2189 if (i > HALFRT_ANGLE)
2190 i = RT_ANGLE - i;
2191 rsize /= cos(i * IP);
2192
2193 lp->visible = 0;
2194 for (i = 0; i < NBUCKETS; ++i)
2195 if (lp->buckethead[i] != NULL) {
2196 ptr = lp->buckethead[i];
2197 while (ptr != NULL) {
2198 if (ptr->visible) {
2199 x = (double) ptr->x - lp->ox;
2200 y = (double) ptr->y - lp->oy;
2201 z = (double) ptr->z - lp->oz;
2202 NewPoint(lp, x, y, z, &point);
2203 r = (int) (rsize * (double) EyeToScreen / (double) ptr->dist);
2204 if (point.x + r >= 0 && point.y + r >= 0 &&
2205 point.x - r < lp->width && point.y - r < lp->height)
2206 lp->visible = 1;
2207 }
2208 ptr = ptr->priority;
2209 }
2210 }
2211 }
2212
2213 static void
drawTri(ModeInfo * mi,int color,XPoint * pts,int p1,int p2,int p3)2214 drawTri(ModeInfo * mi, int color, XPoint * pts,
2215 int p1, int p2, int p3)
2216 {
2217 Display *display = MI_DISPLAY(mi);
2218 GC gc = MI_GC(mi);
2219 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2220 XPoint facepts[4];
2221
2222 facepts[0] = pts[p1];
2223 facepts[1] = pts[p2];
2224 facepts[2] = pts[p3];
2225 facepts[3] = pts[p1];
2226
2227 if (color != BLACK && MI_NPIXELS(mi) <= 2)
2228 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2229 else
2230 XSetForeground(display, gc, lp->colors[color]);
2231 if (!lp->wireframe) {
2232 if (color != BLACK && MI_NPIXELS(mi) <= 2) {
2233 XGCValues gcv;
2234
2235 gcv.stipple = lp->pixmaps[lp->colors[color]];
2236 gcv.foreground = MI_WHITE_PIXEL(mi);
2237 gcv.background = MI_BLACK_PIXEL(mi);
2238 XChangeGC(display, lp->stippledGC,
2239 GCStipple | GCForeground | GCBackground, &gcv);
2240 gc = lp->stippledGC;
2241 }
2242 XFillPolygon(display, (Drawable) lp->dbuf, gc, facepts, 3,
2243 Convex, CoordModeOrigin);
2244 gc = MI_GC(mi);
2245 if (color == BLACK || MI_NPIXELS(mi) <= 2) {
2246 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
2247 } else {
2248 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2249 }
2250 }
2251 XDrawLines(display, (Drawable) lp->dbuf, gc, facepts, 4,
2252 CoordModeOrigin);
2253 }
2254 static void
drawQuad(ModeInfo * mi,int color,XPoint * pts,int p1,int p2,int p3,int p4)2255 drawQuad(ModeInfo * mi, int color, XPoint * pts,
2256 int p1, int p2, int p3, int p4)
2257 {
2258 Display *display = MI_DISPLAY(mi);
2259 GC gc = MI_GC(mi);
2260 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2261 XPoint facepts[5];
2262
2263 facepts[0] = pts[p1];
2264 facepts[1] = pts[p2];
2265 facepts[2] = pts[p3];
2266 facepts[3] = pts[p4];
2267 facepts[4] = pts[p1];
2268
2269 if (color != BLACK && MI_NPIXELS(mi) <= 2)
2270 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2271 else
2272 XSetForeground(display, gc, lp->colors[color]);
2273 if (!lp->wireframe) {
2274 if (color != BLACK && MI_NPIXELS(mi) <= 2) {
2275 XGCValues gcv;
2276
2277 gcv.stipple = lp->pixmaps[lp->colors[color]];
2278 gcv.foreground = MI_WHITE_PIXEL(mi);
2279 gcv.background = MI_BLACK_PIXEL(mi);
2280 XChangeGC(display, lp->stippledGC,
2281 GCStipple | GCForeground | GCBackground, &gcv);
2282 gc = lp->stippledGC;
2283 }
2284 XFillPolygon(display, (Drawable) lp->dbuf, gc, facepts, 4,
2285 Convex, CoordModeOrigin);
2286 gc = MI_GC(mi);
2287 if (color == BLACK || MI_NPIXELS(mi) <= 2) {
2288 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
2289 } else {
2290 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2291 }
2292 }
2293 XDrawLines(display, (Drawable) lp->dbuf, gc, facepts, 5,
2294 CoordModeOrigin);
2295 }
2296
2297 static void
drawHex(ModeInfo * mi,int color,XPoint * pts,int p1,int p2,int p3,int p4,int p5,int p6)2298 drawHex(ModeInfo * mi, int color, XPoint * pts,
2299 int p1, int p2, int p3, int p4, int p5, int p6)
2300 {
2301 Display *display = MI_DISPLAY(mi);
2302 GC gc = MI_GC(mi);
2303 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2304 XPoint facepts[7];
2305
2306 facepts[0] = pts[p1];
2307 facepts[1] = pts[p2];
2308 facepts[2] = pts[p3];
2309 facepts[3] = pts[p4];
2310 facepts[4] = pts[p5];
2311 facepts[5] = pts[p6];
2312 facepts[6] = pts[p1];
2313
2314 if (color != BLACK && MI_NPIXELS(mi) <= 2)
2315 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2316 else
2317 XSetForeground(display, gc, lp->colors[color]);
2318 if (!lp->wireframe) {
2319 if (color != BLACK && MI_NPIXELS(mi) <= 2) {
2320 XGCValues gcv;
2321
2322 gcv.stipple = lp->pixmaps[lp->colors[color]];
2323 gcv.foreground = MI_WHITE_PIXEL(mi);
2324 gcv.background = MI_BLACK_PIXEL(mi);
2325 XChangeGC(display, lp->stippledGC,
2326 GCStipple | GCForeground | GCBackground, &gcv);
2327 gc = lp->stippledGC;
2328 }
2329 XFillPolygon(display, (Drawable) lp->dbuf, gc, facepts, 6,
2330 Convex, CoordModeOrigin);
2331 gc = MI_GC(mi);
2332 if (color == BLACK || MI_NPIXELS(mi) <= 2) {
2333 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
2334 } else {
2335 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
2336 }
2337 }
2338 XDrawLines(display, (Drawable) lp->dbuf, gc, facepts, 7,
2339 CoordModeOrigin);
2340 }
2341
2342 #define LEN_2 0.225
2343 #define LEN 0.45
2344 #define LEN2 0.9
2345
2346 static int
DrawCube(ModeInfo * mi,CellList * cell)2347 DrawCube(ModeInfo * mi, CellList * cell)
2348 {
2349 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2350 XPoint pts[8]; /* screen coords for point */
2351 int i = 0, out = 0;
2352 unsigned int mask;
2353 double x, y, z;
2354 double dx, dy, dz;
2355
2356 x = (double) cell->x - lp->ox;
2357 y = (double) cell->y - lp->oy;
2358 z = (double) cell->z - lp->oz;
2359 for (dz = z - LEN; dz <= z + LEN2; dz += LEN2)
2360 for (dy = y - LEN; dy <= y + LEN2; dy += LEN2)
2361 for (dx = x - LEN; dx <= x + LEN2; dx += LEN2) {
2362 NewPoint(lp, dx, dy, dz, &pts[i]);
2363 if (pts[i].x < 0 ||
2364 pts[i].x >= lp->width ||
2365 pts[i].y < 0 ||
2366 pts[i].y >= lp->height)
2367 ++out;
2368 ++i;
2369 }
2370 if (out == 8)
2371 return (0);
2372
2373 if (cell->visible)
2374 mask = 0xFFFF;
2375 else
2376 mask = 0x0;
2377 /* Only draw those faces that are visible */
2378 dx = lp->vx - x;
2379 dy = lp->vy - y;
2380 dz = lp->vz - z;
2381 /*
2382 6----7
2383 / /|
2384 / / |
2385 2----3 |
2386 | 4 | 5
2387 | | /
2388 0____1/
2389 */
2390 if (lp->wireframe) {
2391 if (dz <= LEN)
2392 drawQuad(mi, (int) (BLUE & mask), pts, 4, 5, 7, 6);
2393 else if (dz >= -LEN)
2394 drawQuad(mi, (int) (BLUE & mask), pts, 0, 1, 3, 2);
2395 if (dx <= LEN)
2396 drawQuad(mi, (int) (GREEN & mask), pts, 1, 3, 7, 5);
2397 else if (dx >= -LEN)
2398 drawQuad(mi, (int) (GREEN & mask), pts, 0, 2, 6, 4);
2399 if (dy <= LEN)
2400 drawQuad(mi, (int) (RED & mask), pts, 2, 3, 7, 6);
2401 else if (dy >= -LEN)
2402 drawQuad(mi, (int) (RED & mask), pts, 0, 1, 5, 4);
2403 }
2404 if (dz > LEN)
2405 drawQuad(mi, (int) (BLUE & mask), pts, 4, 5, 7, 6);
2406 else if (dz < -LEN)
2407 drawQuad(mi, (int) (BLUE & mask), pts, 0, 1, 3, 2);
2408 if (dx > LEN)
2409 drawQuad(mi, (int) (GREEN & mask), pts, 1, 3, 7, 5);
2410 else if (dx < -LEN)
2411 drawQuad(mi, (int) (GREEN & mask), pts, 0, 2, 6, 4);
2412 if (dy > LEN)
2413 drawQuad(mi, (int) (RED & mask), pts, 2, 3, 7, 6);
2414 else if (dy < -LEN)
2415 drawQuad(mi, (int) (RED & mask), pts, 0, 1, 5, 4);
2416 return (1);
2417 }
2418
2419 static int
DrawTetrahedronTrBl(ModeInfo * mi,CellList * cell)2420 DrawTetrahedronTrBl(ModeInfo * mi, CellList * cell)
2421 {
2422 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2423 XPoint pts[4]; /* screen coords for point */
2424 int i = 0, out = 0;
2425 unsigned int mask;
2426 double x, y, z;
2427 double dx, dy, dz;
2428
2429 x = (double) cell->x - lp->ox;
2430 y = (double) cell->y - lp->oy;
2431 z = (double) cell->z - lp->oz;
2432 dz = (z - LEN2) / 2;
2433 dy = (y - LEN2) / 2;
2434 dx = (x + LEN2) / 2;
2435 NewPoint(lp, dx, dy, dz, &pts[i]);
2436 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2437 pts[i].y < 0 || pts[i].y >= lp->height)
2438 ++out;
2439 ++i;
2440 dz = (z - LEN2) / 2;
2441 dy = (y + LEN2) / 2;
2442 dx = (x - LEN2) / 2;
2443 NewPoint(lp, dx, dy, dz, &pts[i]);
2444 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2445 pts[i].y < 0 || pts[i].y >= lp->height)
2446 ++out;
2447 ++i;
2448 dz = (z + LEN2) / 2;
2449 dy = (y - LEN2) / 2;
2450 dx = (x - LEN2) / 2;
2451 NewPoint(lp, dx, dy, dz, &pts[i]);
2452 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2453 pts[i].y < 0 || pts[i].y >= lp->height)
2454 ++out;
2455 ++i;
2456 dz = (z + LEN2) / 2;
2457 dy = (y + LEN2) / 2;
2458 dx = (x + LEN2) / 2;
2459 NewPoint(lp, dx, dy, dz, &pts[i]);
2460 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2461 pts[i].y < 0 || pts[i].y >= lp->height)
2462 ++out;
2463 ++i;
2464 if (out == 4)
2465 return (0);
2466 if (cell->visible)
2467 mask = 0xFFFF;
2468 else
2469 mask = 0x0;
2470 /* Only draw those faces that are visible */
2471 dx = lp->vx - x;
2472 dy = lp->vy - y;
2473 dz = lp->vz - z;
2474 /* back points looking through front
2475 3
2476
2477 2
2478 ----------
2479 front points
2480 1
2481
2482 0
2483 */
2484 if (lp->wireframe) {
2485 if (dx + dy + dz > 0) {
2486 drawTri(mi, (int) (RED & mask), pts, 1, 0, 2);
2487 }
2488 if (dx + dy - dz < 0) {
2489 drawTri(mi, (int) (GREEN & mask), pts, 1, 3, 0);
2490 }
2491 if (dx - dy + dz < 0) {
2492 drawTri(mi, (int) (GREEN & mask), pts, 0, 2, 3);
2493 }
2494 if (-dx + dy + dz < 0) {
2495 drawTri(mi, (int) (BLUE & mask), pts, 1, 3, 2);
2496 }
2497 }
2498 if (dx + dy + dz <= 0) {
2499 drawTri(mi, (int) (RED & mask), pts, 1, 0, 2);
2500 }
2501 if (dx + dy - dz >= 0) {
2502 drawTri(mi, (int) (GREEN & mask), pts, 1, 3, 0);
2503 }
2504 if (dx - dy + dz >= 0) {
2505 drawTri(mi, (int) (GREEN & mask), pts, 0, 2, 3);
2506 }
2507 if (-dx + dy + dz >= 0) {
2508 drawTri(mi, (int) (BLUE & mask), pts, 1, 3, 2);
2509 }
2510 return (1);
2511 }
2512
2513 static int
DrawTetrahedronTlBr(ModeInfo * mi,CellList * cell)2514 DrawTetrahedronTlBr(ModeInfo * mi, CellList * cell)
2515 {
2516 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2517 XPoint pts[4]; /* screen coords for point */
2518 int i = 0, out = 0;
2519 unsigned int mask;
2520 double x, y, z;
2521 double dx, dy, dz;
2522
2523 x = (double) cell->x - lp->ox;
2524 y = (double) cell->y - lp->oy;
2525 z = (double) cell->z - lp->oz;
2526 dz = (z - LEN2) / 2;
2527 dy = (y - LEN2) / 2;
2528 dx = (x - LEN2) / 2;
2529 NewPoint(lp, dx, dy, dz, &pts[i]);
2530 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2531 pts[i].y < 0 || pts[i].y >= lp->height)
2532 ++out;
2533 ++i;
2534 dz = (z - LEN2) / 2;
2535 dy = (y + LEN2) / 2;
2536 dx = (x + LEN2) / 2;
2537 NewPoint(lp, dx, dy, dz, &pts[i]);
2538 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2539 pts[i].y < 0 || pts[i].y >= lp->height)
2540 ++out;
2541 ++i;
2542 dz = (z + LEN2) / 2;
2543 dy = (y - LEN2) / 2;
2544 dx = (x + LEN2) / 2;
2545 NewPoint(lp, dx, dy, dz, &pts[i]);
2546 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2547 pts[i].y < 0 || pts[i].y >= lp->height)
2548 ++out;
2549 ++i;
2550 dz = (z + LEN2) / 2;
2551 dy = (y + LEN2) / 2;
2552 dx = (x - LEN2) / 2;
2553 NewPoint(lp, dx, dy, dz, &pts[i]);
2554 if (pts[i].x < 0 || pts[i].x >= lp->width ||
2555 pts[i].y < 0 || pts[i].y >= lp->height)
2556 ++out;
2557 ++i;
2558 if (out == 4)
2559 return (0);
2560 if (cell->visible)
2561 mask = 0xFFFF;
2562 else
2563 mask = 0x0;
2564 /* Only draw those faces that are visible */
2565 dx = lp->vx - x;
2566 dy = lp->vy - y;
2567 dz = lp->vz - z;
2568 /* back points looking through front
2569 1
2570
2571 0
2572 ----------
2573 front points
2574 3
2575
2576 2
2577 */
2578 if (lp->wireframe) {
2579 if (dx + dy + dz > 0) {
2580 drawTri(mi, (int) (BLUE & mask), pts, 1, 0, 2);
2581 }
2582 if (dx + dy - dz < 0) {
2583 drawTri(mi, (int) (GREEN & mask), pts, 1, 3, 0);
2584 }
2585 if (dx - dy + dz < 0) {
2586 drawTri(mi, (int) (GREEN & mask), pts, 0, 2, 3);
2587 }
2588 if (-dx + dy + dz < 0) {
2589 drawTri(mi, (int) (RED & mask), pts, 1, 3, 2);
2590 }
2591 }
2592 if (dx + dy + dz <= 0) {
2593 drawTri(mi, (int) (BLUE & mask), pts, 1, 0, 2);
2594 }
2595 if (dx + dy - dz >= 0) {
2596 drawTri(mi, (int) (GREEN & mask), pts, 1, 3, 0);
2597 }
2598 if (dx - dy + dz >= 0) {
2599 drawTri(mi, (int) (GREEN & mask), pts, 0, 2, 3);
2600 }
2601 if (-dx + dy + dz >= 0) {
2602 drawTri(mi, (int) (RED & mask), pts, 1, 3, 2);
2603 }
2604 /* if both 1st and 2nd... something wrong, kludge */
2605 if (dx + dy - dz >= 0 && dx - dy + dz >= 0) {
2606 drawTri(mi, (int) (BLUE & mask), pts, 1, 0, 2);
2607 drawTri(mi, (int) (RED & mask), pts, 1, 3, 2);
2608 }
2609 return (1);
2610 }
2611
2612 static int
DrawTetrahedron(ModeInfo * mi,CellList * cell)2613 DrawTetrahedron(ModeInfo * mi, CellList * cell) {
2614 if (rTetra(cell->x, cell->y, cell->z)) {
2615 return DrawTetrahedronTrBl(mi, cell);
2616 } else if (lTetra(cell->x, cell->y, cell->z)) {
2617 return DrawTetrahedronTlBr(mi, cell);
2618 /*} else {
2619 (void) fprintf(stderr, "bad cell %d %d %d\n",
2620 cell->x, cell->y, cell->z); */
2621 }
2622 return (0);
2623 }
2624
2625 static int
DrawRhombicDodecahedron(ModeInfo * mi,CellList * cell)2626 DrawRhombicDodecahedron(ModeInfo * mi, CellList * cell)
2627 {
2628 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2629 XPoint pts[14]; /* screen coords for point */
2630 int i, out = 0, da, db, sortx, sorty, sortz;
2631 unsigned int mask;
2632 double x, y, z;
2633 double dx, dy, dz;
2634
2635 x = (double) cell->x - lp->ox;
2636 y = (double) cell->y - lp->oy;
2637 z = (double) cell->z - lp->oz;
2638 i = 3;
2639 for (dx = x + LEN; dx >= x - LEN2; dx -= LEN2)
2640 for (dy = y + LEN; dy >= y - LEN2; dy -= LEN2)
2641 for (dz = z + LEN; dz >= z - LEN2; dz -= LEN2) {
2642 NewPoint(lp, dx, dy, dz, &pts[i]);
2643 if (pts[i].x < 0 ||
2644 pts[i].x >= lp->width ||
2645 pts[i].y < 0 ||
2646 pts[i].y >= lp->height)
2647 ++out;
2648 ++i;
2649 }
2650 for (da = 0; da < 2; da++) {
2651 if (da == 1) {
2652 i = 0;
2653 } else
2654 i = 11; /* 3 + 8 */
2655 for (db = 0; db < 3; db++) {
2656 if (db == 0) {
2657 dx = ((da == 0) ? -LEN2 : LEN2) + x;
2658 dy = y;
2659 dz = z;
2660 } else if (db == 1) {
2661 dy = ((da == 0) ? -LEN2 : LEN2) + y;
2662 dz = z;
2663 dx = x;
2664 } else {
2665 dz = ((da == 0) ? -LEN2 : LEN2) + z;
2666 dx = x;
2667 dy = y;
2668 }
2669 NewPoint(lp, dx, dy, dz, &pts[i]);
2670 if (pts[i].x < 0 ||
2671 pts[i].x >= lp->width ||
2672 pts[i].y < 0 ||
2673 pts[i].y >= lp->height)
2674 ++out;
2675 ++i;
2676 }
2677 }
2678 if (out == 14)
2679 return (0);
2680
2681 if (cell->visible)
2682 mask = 0xFFFF;
2683 else
2684 mask = 0x0;
2685
2686 /* Only draw those faces that are visible */
2687 dx = lp->vx - x;
2688 dy = lp->vy - y;
2689 dz = lp->vz - z;
2690 /* back points looking through front
2691 8 1 4
2692 7 3
2693 11 2 0
2694 9 5
2695 10 12 6
2696 ---------
2697 front points
2698 7 1 3
2699 8 4
2700 11 13 0
2701 10 6
2702 9 12 5
2703 */
2704 if (lp->wireframe) {
2705 if (dx <= LEN) {
2706 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2707 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2708 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2709 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2710 } else if (dx >= -LEN) {
2711 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2712 drawQuad(mi, (int) (GREEN & mask), pts, 1, 8, 11, 7);
2713 drawQuad(mi, (int) (RED & mask), pts, 8, 13, 10, 11);
2714 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2715 }
2716 if (dy <= LEN) {
2717 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2718 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2719 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2720 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2721 } else if (dy >= -LEN) {
2722 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2723 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2724 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2725 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2726 }
2727 if (dz <= LEN) {
2728 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2729 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2730 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2731 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2732 } else if (dz >= -LEN) {
2733 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2734 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2735 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2736 drawQuad(mi, (int) (GREEN & mask), pts, 8, 13, 10, 11);
2737 }
2738 }
2739 sortx = sorty = sortz = 0;
2740 if (ABS(dz - LEN) > ABS(dy - LEN))
2741 sortz++;
2742 if (ABS(dz - LEN) > ABS(dx - LEN))
2743 sortz++;
2744 if (ABS(dy - LEN) > ABS(dx - LEN))
2745 sorty++;
2746 if (ABS(dy - LEN) > ABS(dz - LEN))
2747 sorty++;
2748 if (ABS(dx - LEN) > ABS(dz - LEN))
2749 sortx++;
2750 if (ABS(dx - LEN) > ABS(dy - LEN))
2751 sortx++;
2752 for (i = 0; i < 3; i++) {
2753 if (sortx == i) {
2754 if (dx > LEN) {
2755 if (sortz > sorty) {
2756 if (dz < 0)
2757 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2758 else
2759 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2760 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2761 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2762 if (dz < 0)
2763 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2764 else
2765 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2766 } else {
2767 if (dy < 0)
2768 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2769 else
2770 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2771 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2772 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2773 if (dy < 0)
2774 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2775 else
2776 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2777 }
2778 } else if (dx < -LEN) {
2779 if (sortz > sorty) {
2780 if (dz < 0)
2781 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2782 else
2783 drawQuad(mi, (int) (GREEN & mask), pts, 8, 13, 10, 11);
2784 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2785 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2786 if (dz < 0)
2787 drawQuad(mi, (int) (GREEN & mask), pts, 8, 13, 10, 11);
2788 else
2789 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2790 } else {
2791 if (dy < 0)
2792 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2793 else
2794 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2795 drawQuad(mi, (int) (GREEN & mask), pts, 8, 13, 10, 11);
2796 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2797 if (dy < 0)
2798 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2799 else
2800 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2801 }
2802 }
2803 }
2804 if (sorty == i) {
2805 if (dy > LEN) {
2806 if (sortx > sortz) {
2807 if (dx < 0)
2808 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2809 else
2810 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2811 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2812 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2813 if (dx < 0)
2814 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2815 else
2816 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2817 } else {
2818 if (dz < 0)
2819 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2820 else
2821 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2822 drawQuad(mi, (int) (RED & mask), pts, 1, 8, 11, 7);
2823 drawQuad(mi, (int) (RED & mask), pts, 0, 4, 1, 3);
2824 if (dz < 0)
2825 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2826 else
2827 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2828 }
2829 } else if (dy < -LEN) {
2830 if (sortx > sortz) {
2831 if (dx < 0)
2832 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2833 else
2834 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2835 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2836 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2837 if (dx < 0)
2838 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2839 else
2840 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2841 } else {
2842 if (dz < 0)
2843 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2844 else
2845 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2846 drawQuad(mi, (int) (RED & mask), pts, 9, 11, 10, 12);
2847 drawQuad(mi, (int) (RED & mask), pts, 0, 5, 12, 6);
2848 if (dz < 0)
2849 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2850 else
2851 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2852 }
2853 }
2854 }
2855 if (sortz == i) {
2856 if (dz > LEN) {
2857 if (sorty > sortx) {
2858 if (dy < 0)
2859 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2860 else
2861 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2862 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2863 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2864 if (dy < 0)
2865 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2866 else
2867 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2868 } else {
2869 if (dx < 0)
2870 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2871 else
2872 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2873 drawQuad(mi, (int) (BLUE & mask), pts, 2, 9, 12, 5);
2874 drawQuad(mi, (int) (BLUE & mask), pts, 1, 7, 2, 3);
2875 if (dx < 0)
2876 drawQuad(mi, (int) (GREEN & mask), pts, 2, 7, 11, 9);
2877 else
2878 drawQuad(mi, (int) (GREEN & mask), pts, 0, 3, 2, 5);
2879 }
2880 } else if (dz < -LEN) {
2881 if (sorty > sortx) {
2882 if (dy < 0)
2883 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2884 else
2885 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2886 drawQuad(mi, (int) (GREEN & mask), pts, 1, 8, 13, 10);
2887 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2888 if (dy < 0)
2889 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2890 else
2891 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2892 } else {
2893 if (dx < 0)
2894 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2895 else
2896 drawQuad(mi, (int) (GREEN & mask), pts, 1, 8, 13, 10);
2897 drawQuad(mi, (int) (BLUE & mask), pts, 6, 12, 10, 13);
2898 drawQuad(mi, (int) (BLUE & mask), pts, 1, 4, 13, 8);
2899 if (dx < 0)
2900 drawQuad(mi, (int) (GREEN & mask), pts, 1, 8, 13, 10);
2901 else
2902 drawQuad(mi, (int) (GREEN & mask), pts, 0, 6, 13, 4);
2903 }
2904 }
2905 }
2906 }
2907 return (1);
2908 }
2909
2910 static int
DrawTruncatedOctahedron(ModeInfo * mi,CellList * cell)2911 DrawTruncatedOctahedron(ModeInfo * mi, CellList * cell)
2912 {
2913 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
2914 XPoint pts[24]; /* screen coords for point */
2915 int i, out = 0;
2916 unsigned int mask;
2917 double x, y, z;
2918 double dx, dy, dz;
2919
2920 x = (double) cell->x - lp->ox;
2921 y = (double) cell->y - lp->oy;
2922 z = ((double) cell->z - lp->oz) / 2.0;
2923 if ((cell->z & 1) == 1) {
2924 x += 0.5;
2925 y += 0.5;
2926 }
2927 NewPoint(lp, x + LEN_2, y, z + LEN, &pts[0]);
2928 NewPoint(lp, x, y + LEN_2, z + LEN, &pts[1]);
2929 NewPoint(lp, x - LEN_2, y, z + LEN, &pts[2]);
2930 NewPoint(lp, x, y - LEN_2, z + LEN, &pts[3]);
2931
2932 NewPoint(lp, x + LEN, y, z + LEN_2, &pts[4]);
2933 NewPoint(lp, x + LEN, y - LEN_2, z, &pts[15]);
2934 NewPoint(lp, x + LEN, y, z - LEN_2, &pts[16]);
2935 NewPoint(lp, x + LEN, y + LEN_2, z, &pts[8]);
2936
2937 NewPoint(lp, x, y + LEN, z + LEN_2, &pts[5]);
2938 NewPoint(lp, x + LEN_2, y + LEN, z, &pts[9]);
2939 NewPoint(lp, x, y + LEN, z - LEN_2, &pts[17]);
2940 NewPoint(lp, x - LEN_2, y + LEN, z, &pts[10]);
2941
2942 NewPoint(lp, x - LEN, y, z + LEN_2, &pts[6]);
2943 NewPoint(lp, x - LEN, y + LEN_2, z, &pts[11]);
2944 NewPoint(lp, x - LEN, y, z - LEN_2, &pts[18]);
2945 NewPoint(lp, x - LEN, y - LEN_2, z, &pts[12]);
2946
2947 NewPoint(lp, x, y - LEN, z + LEN_2, &pts[7]);
2948 NewPoint(lp, x - LEN_2, y - LEN, z, &pts[13]);
2949 NewPoint(lp, x, y - LEN, z - LEN_2, &pts[19]);
2950 NewPoint(lp, x + LEN_2, y - LEN, z, &pts[14]);
2951
2952 NewPoint(lp, x + LEN_2, y, z - LEN, &pts[20]);
2953 NewPoint(lp, x, y + LEN_2, z - LEN, &pts[21]);
2954 NewPoint(lp, x - LEN_2, y, z - LEN, &pts[22]);
2955 NewPoint(lp, x, y - LEN_2, z - LEN, &pts[23]);
2956
2957 for (i = 0; i < 24; i++) {
2958 if (pts[i].x < 0 ||
2959 pts[i].x >= lp->width ||
2960 pts[i].y < 0 ||
2961 pts[i].y >= lp->height)
2962 ++out;
2963 }
2964 if (out == 24)
2965 return (0);
2966
2967 if (cell->visible)
2968 mask = 0xFFFF;
2969 else
2970 mask = 0x0;
2971
2972 /* Only draw those faces that are visible */
2973 dx = lp->vx - x;
2974 dy = lp->vy - y;
2975 dz = lp->vz - z;
2976 /* back points looking through front
2977 10 5 9
2978 11 1 8
2979 6 2 0 4
2980 12 3 15
2981 13 7 14
2982 ----------
2983 front points
2984 10 17 9
2985 11 21 8
2986 18 22 20 16
2987 12 23 15
2988 13 19 14
2989 */
2990 if (lp->wireframe) {
2991 if (dz <= LEN)
2992 drawQuad(mi, (int) (BLUE & mask), pts, 0, 1, 2, 3);
2993 else if (dz >= -LEN)
2994 drawQuad(mi, (int) (BLUE & mask), pts, 23, 22, 21, 20);
2995 if (dy <= LEN)
2996 drawQuad(mi, (int) (GREEN & mask), pts, 5, 9, 17, 10);
2997 else if (dy >= -LEN)
2998 drawQuad(mi, (int) (GREEN & mask), pts, 7, 14, 19, 13);
2999 if (dx <= LEN)
3000 drawQuad(mi, (int) (RED & mask), pts, 4, 8, 16, 15);
3001 else if (dx >= -LEN)
3002 drawQuad(mi, (int) (RED & mask), pts, 6, 11, 18, 12);
3003 if (dx + dy + dz < 0) {
3004 drawHex(mi, (int) (UV & mask), pts, 1, 0, 4, 8, 9, 5);
3005 } else {
3006 drawHex(mi, (int) (UV & mask), pts, 22, 23, 19, 13, 12, 18);
3007 }
3008 if (dx + dy - dz < 0) {
3009 drawHex(mi, (int) (GREEN & mask), pts, 20, 21, 17, 9, 8, 16);
3010 } else {
3011 drawHex(mi, (int) (GREEN & mask), pts, 3, 2, 6, 12, 13, 7);
3012 }
3013 if (dx - dy + dz < 0) {
3014 drawHex(mi, (int) (RED & mask), pts, 0, 3, 7, 14, 15, 4);
3015 } else {
3016 drawHex(mi, (int) (RED & mask), pts, 21, 22, 18, 11, 10, 17);
3017 }
3018 if (-dx + dy + dz < 0) {
3019 drawHex(mi, (int) (BLUE & mask), pts, 2, 1, 5, 10, 11, 6);
3020 } else {
3021 drawHex(mi, (int) (BLUE & mask), pts, 23, 20, 16, 15, 14, 19);
3022 }
3023 }
3024 if (dx + dy + dz >= 0) {
3025 drawHex(mi, (int) (UV & mask), pts, 1, 0, 4, 8, 9, 5);
3026 } else {
3027 drawHex(mi, (int) (UV & mask), pts, 22, 23, 19, 13, 12, 18);
3028 }
3029 if (dx + dy - dz >= 0) {
3030 drawHex(mi, (int) (GREEN & mask), pts, 20, 21, 17, 9, 8, 16);
3031 } else {
3032 drawHex(mi, (int) (GREEN & mask), pts, 3, 2, 6, 12, 13, 7);
3033 }
3034 if (dx - dy + dz >= 0) {
3035 drawHex(mi, (int) (RED & mask), pts, 0, 3, 7, 14, 15, 4);
3036 } else {
3037 drawHex(mi, (int) (RED & mask), pts, 21, 22, 18, 11, 10, 17);
3038 }
3039 if (-dx + dy + dz >= 0) {
3040 drawHex(mi, (int) (BLUE & mask), pts, 2, 1, 5, 10, 11, 6);
3041 } else {
3042 drawHex(mi, (int) (BLUE & mask), pts, 23, 20, 16, 15, 14, 19);
3043 }
3044 if (dz > LEN)
3045 drawQuad(mi, (int) (BLUE & mask), pts, 0, 1, 2, 3);
3046 else if (dz < -LEN)
3047 drawQuad(mi, (int) (BLUE & mask), pts, 23, 22, 21, 20);
3048 if (dy > LEN)
3049 drawQuad(mi, (int) (GREEN & mask), pts, 5, 9, 17, 10);
3050 else if (dy < -LEN)
3051 drawQuad(mi, (int) (GREEN & mask), pts, 7, 14, 19, 13);
3052 if (dx > LEN)
3053 drawQuad(mi, (int) (RED & mask), pts, 4, 8, 16, 15);
3054 else if (dx < -LEN)
3055 drawQuad(mi, (int) (RED & mask), pts, 6, 11, 18, 12);
3056 return (1);
3057 }
3058
3059 static void
DrawScreen(ModeInfo * mi)3060 DrawScreen(ModeInfo * mi)
3061 {
3062 life3dstruct *lp = &life3ds[MI_SCREEN(mi)];
3063 Display *display = MI_DISPLAY(mi);
3064 GC gc = MI_GC(mi);
3065 CellList *ptr;
3066 CellList *eraserptr;
3067 int i;
3068
3069 SortList(lp);
3070
3071 if (draw) {
3072 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
3073 XFillRectangle(display, (Drawable) lp->dbuf, gc, 0, 0,
3074 lp->width, lp->height);
3075 }
3076 /* Erase dead cubes */
3077 eraserptr = lp->eraserhead.next;
3078 while (eraserptr != &lp->eraserend) {
3079 eraserptr->visible = 0;
3080 if (draw) {
3081 if (lp->neighbors == 12 || lp->neighbors == -18)
3082 (void) DrawRhombicDodecahedron(mi, eraserptr);
3083 else if (lp->neighbors == 14)
3084 (void) DrawTruncatedOctahedron(mi, eraserptr);
3085 else if (lp->neighbors == 22)
3086 (void) DrawTetrahedron(mi, eraserptr);
3087 else
3088 (void) DrawCube(mi, eraserptr);
3089 }
3090 delFromEraseList(eraserptr);
3091 eraserptr = lp->eraserhead.next;
3092 }
3093 if (!draw)
3094 return;
3095
3096 /* draw furthest cubes first */
3097 for (i = NBUCKETS - 1; i >= 0; --i) {
3098 ptr = lp->buckethead[i];
3099 while (ptr != NULL) {
3100 /*if (ptr->visible) */
3101 if (lp->neighbors == 12 || lp->neighbors == -18)
3102 (void) DrawRhombicDodecahedron(mi, ptr);
3103 else if (lp->neighbors == 14)
3104 (void) DrawTruncatedOctahedron(mi, ptr);
3105 else if (lp->neighbors == 22)
3106 (void) DrawTetrahedron(mi, ptr);
3107 else
3108 /* v += */ (void) DrawCube(mi, ptr);
3109 ptr = ptr->priority;
3110 /* ++count; */
3111 }
3112 }
3113 if (label) {
3114 int size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
3115
3116 if (size >= 10 * FONT_WIDTH) {
3117 char ruleString[120];
3118
3119 /* hard code these to corners */
3120 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
3121 (void) sprintf(ruleString, "N%d:%s",
3122 lp->neighbors, lp->ruleString);
3123 XDrawString(display, (Drawable) lp->dbuf, gc,
3124 16 + lp->labelOffsetX,
3125 16 + lp->labelOffsetY + FONT_HEIGHT,
3126 ruleString, strlen(ruleString));
3127 XDrawString(display, (Drawable) lp->dbuf, gc,
3128 16 + lp->labelOffsetX, MI_HEIGHT(mi) - 16 -
3129 lp->labelOffsetY - FONT_HEIGHT / 2,
3130 lp->nameString, strlen(lp->nameString));
3131 }
3132 }
3133 XFlush(display);
3134 XCopyArea(display, (Drawable) lp->dbuf, MI_WINDOW(mi), gc,
3135 0, 0, lp->width, lp->height, 0, 0);
3136
3137 #if 0
3138 {
3139 int count = 0, v = 0;
3140
3141
3142 (void) printf("Pop=%-4d Viewpoint (%3d,%3d,%3d) Origin (%3d,%3d,%3d) Mode %dx%d\
3143 (%d,%d) %d\n",
3144 count, (int) (lp->vx + lp->ox), (int) (lp->vy + lp->oy),
3145 (int) (lp->vz + lp->oz), (int) lp->ox, (int) lp->oy, (int) lp->oz,
3146 lp->width, lp->height, lp->alt, lp->azm, v);
3147 }
3148 #endif
3149 }
3150
3151 static Bool
orthogonal(life3dstruct * lp)3152 orthogonal(life3dstruct * lp) /* or full diagonal */
3153 {
3154 if (lp->neighbors == 12)
3155 return (lp->patterned_rule == LIFE_12B3S456);
3156 else if (lp->neighbors == 18)
3157 return ((lp->patterned_rule == LIFE_18B4S45) &&
3158 (LRAND() & 1));
3159 else if (lp->neighbors == -18)
3160 return ((lp->patterned_rule == LIFE__18B4S36) ||
3161 (lp->patterned_rule == LIFE__18B4S46));
3162 else if (lp->neighbors == 20)
3163 return (lp->patterned_rule == LIFE_20B4S45);
3164 else if (lp->neighbors == 22)
3165 return (((lp->patterned_rule == LIFE_22B4S3) &&
3166 (NRAND(3) == 0)) ||
3167 (lp->patterned_rule == LIFE_22B4S4));
3168 else if (lp->neighbors == 26)
3169 return ((lp->patterned_rule == LIFE_26B5S23) ||
3170 (lp->patterned_rule == LIFE_26B5S25) ||
3171 (lp->patterned_rule == LIFE_26B5S27) ||
3172 (lp->patterned_rule == LIFE_26B5S35) ||
3173 (lp->patterned_rule == LIFE_26B5S36) ||
3174 (lp->patterned_rule == LIFE_26B5S37) ||
3175 (lp->patterned_rule == LIFE_26B5S4) ||
3176 (lp->patterned_rule == LIFE_26B5S47) ||
3177 ((lp->patterned_rule == LIFE_26B5S56) &&
3178 (LRAND() & 1)) ||
3179 ((lp->patterned_rule == LIFE_26B6S57) &&
3180 (NRAND(4) == 0)) ||
3181 ((lp->patterned_rule == LIFE_26B5S58) &&
3182 (NRAND(4) == 0)) ||
3183 ((lp->patterned_rule == LIFE_26B5S678) &&
3184 (LRAND() & 1)) ||
3185 ((lp->patterned_rule == LIFE_26B58S58) &&
3186 (NRAND(4) != 0)));
3187 return False;
3188 }
3189
3190 static Bool
populateGlider(life3dstruct * lp,char * glider,int offsetSwitch,int hsp,int vsp,int asp,int hoff,int voff,int aoff)3191 populateGlider(life3dstruct * lp, char *glider, int offsetSwitch,
3192 int hsp, int vsp, int asp, int hoff, int voff, int aoff)
3193 {
3194 int x, y, z, temp;
3195
3196 while ((x = *glider++) != 127) {
3197 int offx = 0, offy = 0, offz;
3198 y = *glider++;
3199 z = *glider++;
3200 if (offsetSwitch == 1) {
3201 temp = x;
3202 x = y;
3203 if (lp->neighbors == 14) {
3204 y = (z >= 0) ? z / 2 : (z - 1) / 2;
3205 z = (z & 1) + 2 * temp;
3206 } else {
3207 y = z;
3208 z = temp;
3209 }
3210 } else if (offsetSwitch == 2) {
3211 temp = z;
3212 if (lp->neighbors == 14) {
3213 z = (z & 1) + 2 * y;
3214 y = x;
3215 x = (temp >= 0) ? temp / 2 : (temp - 1) / 2;
3216 } else {
3217 z = y;
3218 y = x;
3219 x = temp;
3220 }
3221 }
3222 offz = asp + z * aoff;
3223 if (lp->neighbors == 14 && (offz & 1) == 1) {
3224 if (hoff == -1)
3225 offx = -1;
3226 if (voff == -1)
3227 offy = -1;
3228 }
3229 SetList(hsp + x * hoff + offx, vsp + y * voff + offy, offz);
3230 }
3231 return True;
3232 }
3233
3234 /* My rule of thumb is if there is an 18 cell (or less) glider add it here */
3235 static void
populateGliders(life3dstruct * lp,int dim,int orth,int hsp,int vsp,int asp,int hoff,int voff,int aoff)3236 populateGliders(life3dstruct * lp, int dim, int orth,
3237 int hsp, int vsp, int asp, int hoff, int voff, int aoff)
3238 {
3239 if (lp->neighbors == 12 && lp->patterned_rule == LIFE_12B3S3) {
3240 (void) populateGlider(lp, glider_12B3S3[2], dim,
3241 hsp, vsp, asp, hoff, voff, aoff);
3242 if (NRAND(3)) {
3243 (void) populateGlider(lp, glider_12B3S3[0], dim,
3244 hsp, vsp, asp, hoff, voff, aoff);
3245 } else if (NRAND(3)) {
3246 (void) populateGlider(lp, glider_12B3S3[1], dim,
3247 hsp, vsp, asp, hoff, voff, aoff);
3248 } else if (NRAND(2)) { /* lower probability of big gliders */
3249 (void) populateGlider(lp, glider_12B3S3[2], dim,
3250 hsp, vsp, asp, hoff, voff, aoff);
3251 } else {
3252 (void) populateGlider(lp, glider_12B3S3[3], dim,
3253 hsp, vsp, asp, hoff, voff, aoff);
3254 }
3255 } else if (lp->neighbors == 12 && lp->patterned_rule == LIFE_12B3S456) {
3256 (void) populateGlider(lp, glider_12B3S456[0], dim,
3257 hsp, vsp, asp, hoff, voff, aoff);
3258 } else if (lp->neighbors == 14 && lp->patterned_rule == LIFE_14B4S34) {
3259 (void) populateGlider(lp, glider_14B4S34[0], dim,
3260 hsp, vsp, asp, hoff, voff, aoff);
3261 } else if (lp->neighbors == 14 && lp->patterned_rule == LIFE_14B46S34) {
3262 (void) populateGlider(lp, glider_14B46S34[0], dim,
3263 hsp, vsp, asp, hoff, voff, aoff);
3264 } else if (lp->neighbors == 18 && lp->patterned_rule == LIFE_18B4S45) {
3265 if (orth) {
3266 if (LRAND() & 1) {
3267 (void) populateGlider(lp, glider_18B4S45[0], dim,
3268 hsp, vsp, asp, hoff, voff, aoff);
3269 } else {
3270 (void) populateGlider(lp, glider_18B4S45[1], dim,
3271 hsp, vsp, asp, hoff, voff, aoff);
3272 }
3273 } else {
3274 (void) populateGlider(lp, glider_18B4S45[2], dim,
3275 hsp, vsp, asp, hoff, voff, aoff);
3276 }
3277 } else if (lp->neighbors == -18 && lp->patterned_rule == LIFE__18B4S36) {
3278 (void) populateGlider(lp, glider__18B4S36[0], dim,
3279 hsp, vsp, asp, hoff, voff, aoff);
3280 } else if (lp->neighbors == -18 && lp->patterned_rule == LIFE__18B4S46) {
3281 (void) populateGlider(lp, glider__18B4S46[0], dim,
3282 hsp, vsp, asp, hoff, voff, aoff);
3283 } else if (lp->neighbors == 20 && lp->patterned_rule == LIFE_20B4S45) {
3284 if (LRAND() & 1) {
3285 (void) populateGlider(lp, glider_20B4S45[0], dim,
3286 hsp, vsp, asp, hoff, voff, aoff);
3287 } else {
3288 (void) populateGlider(lp, glider_20B4S45[1], dim,
3289 hsp, vsp, asp, hoff, voff, aoff);
3290 }
3291 } else if (lp->neighbors == 22 && lp->patterned_rule == LIFE_22B4S3) {
3292 if (orth) {
3293 (void) populateGlider(lp, glider_22B4S3[0], dim,
3294 hsp, vsp, asp, hoff, voff, aoff);
3295 } else {
3296 if (NRAND(3)) {
3297 (void) populateGlider(lp, glider_22B4S3[2], dim,
3298 hsp, vsp, asp, hoff, voff, aoff);
3299 } else {
3300 (void) populateGlider(lp, glider_22B4S3[1], dim,
3301 hsp, vsp, asp, hoff, voff, aoff);
3302 }
3303 }
3304 } else if (lp->neighbors == 22 && lp->patterned_rule == LIFE_22B4S4) {
3305 if (NRAND(3)) {
3306 (void) populateGlider(lp, glider_22B4S4[1], dim,
3307 hsp, vsp, asp, hoff, voff, aoff);
3308 } else {
3309 (void) populateGlider(lp, glider_22B4S4[0], dim,
3310 hsp, vsp, asp, hoff, voff, aoff);
3311 }
3312 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S23) {
3313 (void) populateGlider(lp, glider_26B5S23[0], dim,
3314 hsp, vsp, asp, hoff, voff, aoff);
3315 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S25) {
3316 (void) populateGlider(lp, glider_26B5S25[0], dim,
3317 hsp, vsp, asp, hoff, voff, aoff);
3318 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S27) {
3319 (void) populateGlider(lp, glider_26B5S27[0], dim,
3320 hsp, vsp, asp, hoff, voff, aoff);
3321 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S35) {
3322 (void) populateGlider(lp, glider_26B5S35[0], dim,
3323 hsp, vsp, asp, hoff, voff, aoff);
3324 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S36) {
3325 (void) populateGlider(lp, glider_26B5S36[0], dim,
3326 hsp, vsp, asp, hoff, voff, aoff);
3327 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S37) {
3328 (void) populateGlider(lp, glider_26B5S37[0], dim,
3329 hsp, vsp, asp, hoff, voff, aoff);
3330 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S38) {
3331 if (LRAND() & 1) {
3332 (void) populateGlider(lp, glider_26B5S38[0], dim,
3333 hsp, vsp, asp, hoff, voff, aoff);
3334 } else {
3335 (void) populateGlider(lp, glider_26B5S38[1], dim,
3336 hsp, vsp, asp, hoff, voff, aoff);
3337 }
3338 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S4) {
3339 (void) populateGlider(lp, glider_26B5S4[0], dim,
3340 hsp, vsp, asp, hoff, voff, aoff);
3341 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S45) {
3342 (void) populateGlider(lp, glider_26B5S45[0], dim,
3343 hsp, vsp, asp, hoff, voff, aoff);
3344 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S47) {
3345 (void) populateGlider(lp, glider_26B5S47[0], dim,
3346 hsp, vsp, asp, hoff, voff, aoff);
3347 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S56) {
3348 if (orth) {
3349 if (LRAND() & 1) {
3350 (void) populateGlider(lp, glider_26B5S56[0], dim,
3351 hsp, vsp, asp, hoff, voff, aoff);
3352 } else {
3353 (void) populateGlider(lp, glider_26B5S56[1], dim,
3354 hsp, vsp, asp, hoff, voff, aoff);
3355 }
3356 } else {
3357 (void) populateGlider(lp, glider_26B5S56[2], dim,
3358 hsp, vsp, asp, hoff, voff, aoff);
3359 }
3360 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S58) {
3361 if (orth)
3362 (void) populateGlider(lp, glider_26B5S58[4], dim,
3363 hsp, vsp, asp, hoff, voff, aoff);
3364 else if (NRAND(3)) {
3365 if (LRAND() & 1)
3366 (void) populateGlider(lp, glider_26B5S58[0], dim,
3367 hsp, vsp, asp, hoff, voff, aoff);
3368 else if (LRAND() & 1)
3369 (void) populateGlider(lp, glider_26B5S58[1], dim,
3370 hsp, vsp, asp, hoff, voff, aoff);
3371 else
3372 (void) populateGlider(lp, glider_26B5S58[2], dim,
3373 hsp, vsp, asp, hoff, voff, aoff);
3374 } else
3375 (void) populateGlider(lp, glider_26B5S58[3], dim,
3376 hsp, vsp, asp, hoff, voff, aoff);
3377 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S678) {
3378 if (orth) {
3379 (void) populateGlider(lp, glider_26B5S678[1], dim,
3380 hsp, vsp, asp, hoff, voff, aoff);
3381 } else {
3382 (void) populateGlider(lp, glider_26B5S678[0], dim,
3383 hsp, vsp, asp, hoff, voff, aoff);
3384 }
3385 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B5S8) {
3386 if (LRAND() & 1) {
3387 (void) populateGlider(lp, glider_26B5S8[0], dim,
3388 hsp, vsp, asp, hoff, voff, aoff);
3389 } else {
3390 if (LRAND() & 1) {
3391 (void) populateGlider(lp, glider_26B5S8[1], dim,
3392 hsp, vsp, asp, hoff, voff, aoff);
3393 } else {
3394 (void) populateGlider(lp, glider_26B5S8[2], dim,
3395 hsp, vsp, asp, hoff, voff, aoff);
3396 }
3397 }
3398 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B58S58) {
3399 if (orth) {
3400 if (LRAND() & 1) {
3401 if (LRAND() & 1)
3402 (void) populateGlider(lp, glider_26B58S58[1], dim,
3403 hsp, vsp, asp, hoff, voff, aoff);
3404 else
3405 (void) populateGlider(lp, glider_26B58S58[2], dim,
3406 hsp, vsp, asp, hoff, voff, aoff);
3407 } else {
3408 if (LRAND() & 1)
3409 (void) populateGlider(lp, glider_26B58S58[3], dim,
3410 hsp, vsp, asp, hoff, voff, aoff);
3411 else if (NRAND(3))
3412 (void) populateGlider(lp, glider_26B58S58[4], dim,
3413 hsp, vsp, asp, hoff, voff, aoff);
3414 else if (LRAND() & 1)
3415 (void) populateGlider(lp, glider_26B58S58[5], dim,
3416 hsp, vsp, asp, hoff, voff, aoff);
3417 else
3418 (void) populateGlider(lp, glider_26B58S58[6], dim,
3419 hsp, vsp, asp, hoff, voff, aoff);
3420 }
3421 } else {
3422 (void) populateGlider(lp, glider_26B58S58[0], dim,
3423 hsp, vsp, asp, hoff, voff, aoff);
3424 }
3425 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B6S567) {
3426 (void) populateGlider(lp, glider_26B6S567[0], dim,
3427 hsp, vsp, asp, hoff, voff, aoff);
3428 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B6S57) {
3429 if (orth) {
3430 if (LRAND() & 1) {
3431 (void) populateGlider(lp, glider_26B6S57[1], dim,
3432 hsp, vsp, asp, hoff, voff, aoff);
3433 } else {
3434 (void) populateGlider(lp, glider_26B6S57[2], dim,
3435 hsp, vsp, asp, hoff, voff, aoff);
3436 }
3437 } else {
3438 (void) populateGlider(lp, glider_26B6S57[0], dim,
3439 hsp, vsp, asp, hoff, voff, aoff);
3440 }
3441 } else if (lp->neighbors == 26 && lp->patterned_rule == LIFE_26B67S57) {
3442 (void) populateGlider(lp, glider_26B67S57[0], dim,
3443 hsp, vsp, asp, hoff, voff, aoff);
3444 }
3445 }
3446
3447 static Bool
shooter(life3dstruct * lp)3448 shooter(life3dstruct * lp)
3449 {
3450 int hsp, vsp, asp, hoff = 1, voff = 1, aoff = 1, dim, c2, r2, s2, orth;
3451
3452 /* Generate the glider at the edge of the screen */
3453 int V = (lp->neighbors == 22) ? 20 : 10;
3454 int V2 = V / 2;
3455 c2 = lp->ncols / 2;
3456 r2 = lp->nrows / 2;
3457 s2 = lp->nstacks / 2;
3458 dim = NRAND(3);
3459 orth = orthogonal(lp);
3460 if (!dim) {
3461 if (orth) {
3462 hsp = (LRAND() & 1) ? c2 - V : c2 + V;
3463 vsp = NRAND(V2) + r2 - V2 / 2;
3464 asp = NRAND(V2) + s2 - V2 / 2;
3465 } else {
3466 hsp = NRAND(V2) + c2 - V2 / 2;
3467 vsp = (LRAND() & 1) ? r2 - V : r2 + V;
3468 asp = (LRAND() & 1) ? s2 - V : s2 + V;
3469 }
3470 if (asp > s2)
3471 aoff = -1;
3472 if (vsp > r2)
3473 voff = -1;
3474 if (hsp > c2)
3475 hoff = -1;
3476 if (lp->neighbors == 12 || lp->neighbors == -18) {
3477 /* Must ensure we have only odd cells (x+y+z=odd)
3478 for glider, so this must be even */
3479 if ((asp + vsp + hsp) & 1)
3480 hsp--;
3481 populateGliders(lp, dim, orth,
3482 hsp, vsp, asp, hoff, voff, aoff);
3483 } else if (lp->neighbors == 14) {
3484 /* Must ensure we have only z odd cells (z=odd)
3485 for glider, so this must be even */
3486 if (asp & 1)
3487 asp--;
3488 populateGliders(lp, dim, orth,
3489 hsp, vsp, asp, hoff, voff, aoff);
3490 } else if (lp->neighbors == 18 || lp->neighbors == 20 || lp->neighbors == 26) {
3491 populateGliders(lp, dim, orth,
3492 hsp, vsp, asp, hoff, voff, aoff);
3493 } else if (lp->neighbors == 22) {
3494 if (hsp & 1)
3495 hsp--;
3496 if (vsp & 1)
3497 vsp--;
3498 if (asp & 1)
3499 asp--;
3500 if ((hsp + vsp + asp) % 4)
3501 hsp++, vsp++;
3502 populateGliders(lp, dim, orth,
3503 hsp, vsp, asp, hoff, voff, aoff);
3504 }
3505 } else if (dim == 1) {
3506 if (orth) {
3507 hsp = NRAND(V2) + c2 - V2 / 2;
3508 vsp = NRAND(V2) + r2 - V2 / 2;
3509 asp = (LRAND() & 1) ? s2 - V : s2 + V;
3510 } else {
3511 hsp = (LRAND() & 1) ? c2 - V : c2 + V;
3512 vsp = (LRAND() & 1) ? r2 - V : r2 + V;
3513 asp = NRAND(V2) + s2 - V2 / 2;
3514 }
3515 if (asp > s2)
3516 aoff = -1;
3517 if (vsp > r2)
3518 voff = -1;
3519 if (hsp > c2)
3520 hoff = -1;
3521 if (lp->neighbors == 12 || lp->neighbors == -18) {
3522 /* Must ensure we have only odd cells (x+y+z=odd)
3523 for glider, so this must be even */
3524 if ((asp + vsp + hsp) & 1)
3525 asp--;
3526 populateGliders(lp, dim, orth,
3527 hsp, vsp, asp, hoff, voff, aoff);
3528 } else if (lp->neighbors == 14) {
3529 /* Must ensure we have only z odd cells (z=odd)
3530 for glider, so this must be even */
3531 if (asp & 1)
3532 asp--;
3533 populateGliders(lp, dim, orth,
3534 hsp, vsp, asp, hoff, voff, aoff);
3535 } else if (lp->neighbors == 18 || lp->neighbors == 20 || lp->neighbors == 26) {
3536 populateGliders(lp, dim, orth,
3537 hsp, vsp, asp, hoff, voff, aoff);
3538 } else if (lp->neighbors == 22) {
3539 if (hsp & 1)
3540 hsp--;
3541 if (vsp & 1)
3542 vsp--;
3543 if (asp & 1)
3544 asp--;
3545 if ((hsp + vsp + asp) % 4)
3546 hsp++, vsp++;
3547 populateGliders(lp, dim, orth,
3548 hsp, vsp, asp, hoff, voff, aoff);
3549 }
3550 } else {
3551 if (orth) {
3552 hsp = NRAND(V2) + c2 - V2 / 2;
3553 vsp = (LRAND() & 1) ? r2 - V : r2 + V;
3554 asp = NRAND(V2) + s2 - V2 / 2;
3555 } else {
3556 hsp = (LRAND() & 1) ? c2 - V : c2 + V;
3557 vsp = NRAND(V2) + r2 - V2 / 2;
3558 asp = (LRAND() & 1) ? s2 - V : s2 + V;
3559 }
3560 if (asp > s2)
3561 aoff = -1;
3562 if (vsp > r2)
3563 voff = -1;
3564 if (hsp > c2)
3565 hoff = -1;
3566 if (lp->neighbors == 12 || lp->neighbors == -18) {
3567 /* Must ensure we have only odd cells (x+y+z=odd)
3568 for glider, so this must be even */
3569 if ((asp + vsp + hsp) & 1)
3570 vsp--;
3571 populateGliders(lp, dim, orth,
3572 hsp, vsp, asp, hoff, voff, aoff);
3573 } else if (lp->neighbors == 14) {
3574 /* Must ensure we have only z odd cells (z=odd)
3575 for glider, so this must be even */
3576 if (asp & 1)
3577 asp--;
3578 populateGliders(lp, dim, orth,
3579 hsp, vsp, asp, hoff, voff, aoff);
3580 } else if (lp->neighbors == 18 || lp->neighbors == 20 || lp->neighbors == 26) {
3581 populateGliders(lp, dim, orth,
3582 hsp, vsp, asp, hoff, voff, aoff);
3583 } else if (lp->neighbors == 22) {
3584 if (hsp & 1)
3585 hsp--;
3586 if (vsp & 1)
3587 vsp--;
3588 if (asp & 1)
3589 asp--;
3590 if ((hsp + vsp + asp) % 4)
3591 hsp++, vsp++;
3592 populateGliders(lp, dim, orth,
3593 hsp, vsp, asp, hoff, voff, aoff);
3594 }
3595 }
3596 return True;
3597 }
3598
3599 static void
free_life3d_screen(Display * display,life3dstruct * lp)3600 free_life3d_screen(Display *display, life3dstruct *lp)
3601 {
3602 int shade;
3603
3604 if (lp == NULL) {
3605 return;
3606 }
3607 if (lp->eraserhead.next != NULL)
3608 endList(lp);
3609 if (lp->dbuf != None) {
3610 XFreePixmap(display, lp->dbuf);
3611 lp->dbuf = None;
3612 }
3613 if (lp->stippledGC != None) {
3614 XFreeGC(display, lp->stippledGC);
3615 lp->stippledGC = None;
3616 }
3617 for (shade = 0; shade < lp->init_bits; shade++) {
3618 XFreePixmap(display, lp->pixmaps[shade]);
3619 }
3620 lp->init_bits = 0;
3621 lp = NULL;
3622 }
3623
3624 ENTRYPOINT void
free_life3d(ModeInfo * mi)3625 free_life3d(ModeInfo * mi)
3626 {
3627 free_life3d_screen(MI_DISPLAY(mi), &life3ds[MI_SCREEN(mi)]);
3628 }
3629
3630 ENTRYPOINT void
init_life3d(ModeInfo * mi)3631 init_life3d(ModeInfo * mi)
3632 {
3633 Display *display = MI_DISPLAY(mi);
3634 Window window = MI_WINDOW(mi);
3635 life3dstruct *lp;
3636 int i, npats;
3637
3638 MI_INIT(mi, life3ds);
3639 lp = &life3ds[MI_SCREEN(mi)];
3640
3641 if (MI_NPIXELS(mi) <= 2) {
3642 if (lp->stippledGC == None) {
3643 XGCValues gcv;
3644 gcv.fill_style = FillOpaqueStippled;
3645 if ((lp->stippledGC = XCreateGC(display, window,
3646 GCFillStyle, &gcv)) == None) {
3647 free_life3d_screen(display, lp);
3648 return;
3649 }
3650 }
3651 if (lp->init_bits == 0) {
3652 for (i = 1; i < NUMSTIPPLES; i++) {
3653 LIFE3DBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
3654 }
3655 }
3656 }
3657 lp->generation = 0;
3658 if (MI_IS_FULLRANDOM(mi)) {
3659 int r12n1 = patterns_12rules[0];
3660 int r12n2 = r12n1 + patterns_12rules[1];
3661 int r14n1 = patterns_14rules[0];
3662 int r14n2 = r14n1 + patterns_14rules[1];
3663 int r18n1 = patterns_18rules[0];
3664 int r_18n1 = patterns__18rules[0];
3665 int r_18n2 = r_18n1 + patterns__18rules[1];
3666 int r20n1 = patterns_20rules[0];
3667 int r22n1 = patterns_22rules[0];
3668 int r22n2 = r22n1 + patterns_22rules[1];
3669 int r26n1 = patterns_26rules[0];
3670 int r26n2 = r26n1 + patterns_26rules[1];
3671 int r26n3 = r26n2 + patterns_26rules[2];
3672 int r26n4 = r26n3 + patterns_26rules[3];
3673 #if 1
3674 lp->neighbors =
3675 (NRAND(r12n2 + r14n2 + r18n1 + r_18n2 + r20n1 + r22n2 + r26n4) < r12n2) ? 12 :
3676 (NRAND(r14n2 + r18n1 + r_18n2 + r20n1 + r22n2 + r26n4) < r14n2) ? 14 :
3677 (NRAND(r18n1 + r_18n2 + r20n1 + r22n2 + r26n4) < r18n1) ? 18 :
3678 (NRAND(r_18n2 + r20n1 + r22n2 + r26n4) < r18n1) ? -18 :
3679 (NRAND(r20n1 + r22n2 + r26n4) < r20n1) ? 20 :
3680 (NRAND(r22n2 + r26n4) < r22n2) ? 22 : 26;
3681 lp->allGliders = True;
3682 #else
3683 lp->neighbors = 26;
3684 #endif
3685 }
3686 if (!lp->neighbors) {
3687 for (i = 0; i < NEIGHBORKINDS; i++) {
3688 if (neighbors == plots[i]) {
3689 lp->neighbors = neighbors;
3690 break;
3691 }
3692 if (i == NEIGHBORKINDS - 1) {
3693 #if 0
3694 lp->neighbors = plots[NRAND(NEIGHBORKINDS)];
3695 lp->neighbors = (LRAND() & 1) ? 12 : 26;
3696 #else
3697 lp->neighbors = 26;
3698 #endif
3699 break;
3700 }
3701 }
3702 }
3703
3704 lp->labelOffsetX = NRAND(8);
3705 lp->labelOffsetY = NRAND(8);
3706 parseRule(mi, lp->ruleString);
3707 #ifndef STANDALONE
3708 parseFile(mi);
3709 #endif
3710 if (lp->allPatterns) {
3711 switch (lp->neighbors) {
3712 case 12:
3713 lp->patterned_rule = NRAND(LIFE_12RULES);
3714 break;
3715 case 14:
3716 lp->patterned_rule = NRAND(LIFE_14RULES);
3717 break;
3718 case 18:
3719 lp->patterned_rule = 0; /* only one rule */
3720 break;
3721 case -18:
3722 lp->patterned_rule = NRAND(LIFE__18RULES);
3723 break;
3724 case 20:
3725 lp->patterned_rule = 0; /* only one rule */
3726 break;
3727 case 22:
3728 lp->patterned_rule = NRAND(LIFE_22RULES);
3729 break;
3730 case 26:
3731 lp->patterned_rule = NRAND(LIFE_26RULES);
3732 break;
3733 }
3734 copyFromPatternedRule(lp->neighbors, &lp->param,
3735 lp->patterned_rule);
3736 printRule(lp->neighbors, lp->ruleString, lp->param,
3737 MI_IS_VERBOSE(mi));
3738 } else if (lp->allGliders) {
3739 switch (lp->neighbors) {
3740 case 12:
3741 lp->patterned_rule = NRAND(LIFE_12GLIDERS);
3742 break;
3743 case 14:
3744 lp->patterned_rule = NRAND(LIFE_14GLIDERS);
3745 break;
3746 case 18:
3747 lp->patterned_rule = 0; /* only one rule */
3748 break;
3749 case -18:
3750 lp->patterned_rule = NRAND(LIFE__18GLIDERS);
3751 break;
3752 case 20:
3753 lp->patterned_rule = 0; /* only one rule */
3754 break;
3755 case 22:
3756 lp->patterned_rule = NRAND(LIFE_22GLIDERS);
3757 break;
3758 case 26:
3759 lp->patterned_rule = NRAND(LIFE_26GLIDERS);
3760 break;
3761 }
3762 copyFromPatternedRule(lp->neighbors, &lp->param,
3763 lp->patterned_rule);
3764 printRule(lp->neighbors, lp->ruleString, lp->param,
3765 MI_IS_VERBOSE(mi));
3766 } else {
3767 lp->param.birth = lp->input_param.birth;
3768 lp->param.survival = lp->input_param.survival;
3769 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
3770 printRule(lp->neighbors, lp->ruleString, lp->param,
3771 MI_IS_VERBOSE(mi));
3772 }
3773 if (!lp->eraserhead.next) {
3774 lp->metaDist = (double) NRAND(360);
3775 lp->metaAlt = (double) NRAND(360);
3776 lp->metaAzm = (double) NRAND(360);
3777 lp->ncols = MAXCOLUMNS;
3778 lp->nrows = MAXROWS;
3779 lp->nstacks = MAXSTACKS;
3780 lp->ox = lp->ncols / 2;
3781 lp->oy = lp->nrows / 2;
3782 lp->oz = lp->nstacks / 2;
3783
3784 initList(lp);
3785 } else {
3786 endList(lp);
3787 }
3788 lp->colors[0] = MI_BLACK_PIXEL(mi);
3789 if (MI_NPIXELS(mi) > 2) {
3790 #ifdef DISTRIB_COLOR
3791 i = NRAND(3);
3792
3793 lp->colors[i + 1] = MI_PIXEL(mi,
3794 NRAND(MI_NPIXELS(mi) / COLORBASE));
3795 lp->colors[(i + 1) % 3 + 1] = MI_PIXEL(mi,
3796 NRAND(MI_NPIXELS(mi) / COLORBASE) +
3797 MI_NPIXELS(mi) / COLORBASE);
3798 lp->colors[(i + 2) % 3 + 1] = MI_PIXEL(mi,
3799 NRAND(MI_NPIXELS(mi) / COLORBASE) +
3800 2 * MI_NPIXELS(mi) / COLORBASE);
3801 #else
3802 int j = NRAND(MI_NPIXELS(mi));
3803 i = NRAND(3);
3804 lp->colors[i + 1] = MI_PIXEL(mi, j);
3805 lp->colors[(i + 1) % 3 + 1] =
3806 MI_PIXEL(mi, (j + 2) % MI_NPIXELS(mi));
3807 lp->colors[(i + 2) % 3 + 1] =
3808 MI_PIXEL(mi, (j + 4) % MI_NPIXELS(mi));
3809 #endif
3810 } else {
3811 /*lp->colors[1] = lp->colors[2] = lp->colors[3] =
3812 MI_WHITE_PIXEL(mi);*/
3813 i = NRAND(3);
3814
3815 lp->colors[1] = NRAND(NUMSTIPPLES - 1);
3816 lp->colors[2] = NRAND(NUMSTIPPLES - 1);
3817 while (lp->colors[2] == lp->colors[1])
3818 lp->colors[2] = NRAND(NUMSTIPPLES - 1);
3819 lp->colors[3] = NRAND(NUMSTIPPLES - 1);
3820 while (lp->colors[3] == lp->colors[1] ||
3821 lp->colors[3] == lp->colors[2])
3822 lp->colors[3] = NRAND(NUMSTIPPLES - 1);
3823 }
3824 lp->colors[4] = MI_WHITE_PIXEL(mi);
3825 lp->width = MI_WIDTH(mi);
3826 lp->height = MI_HEIGHT(mi);
3827 lp->memstart = 1;
3828 lp->noChangeCount = False;
3829 /*lp->tablesMade = 0; */
3830
3831 if (MI_IS_FULLRANDOM(mi)) {
3832 lp->wireframe = (NRAND(16) == 0);
3833 } else {
3834 lp->wireframe = MI_IS_WIREFRAME(mi);
3835 }
3836
3837 MI_CLEARWINDOW(mi);
3838 lp->painted = False;
3839
3840 lissajous(lp);
3841
3842 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
3843 npats = 0;
3844 switch (lp->neighbors) {
3845 case 12:
3846 if ((unsigned) lp->patterned_rule < LIFE_12RULES)
3847 npats = patterns_12rules[lp->patterned_rule];
3848 break;
3849 case 14:
3850 if ((unsigned) lp->patterned_rule < LIFE_14RULES)
3851 npats = patterns_14rules[lp->patterned_rule];
3852 break;
3853 case 18:
3854 if ((unsigned) lp->patterned_rule < LIFE_18RULES)
3855 npats = patterns_18rules[lp->patterned_rule];
3856 break;
3857 case -18:
3858 if ((unsigned) lp->patterned_rule < LIFE__18RULES)
3859 npats = patterns__18rules[lp->patterned_rule];
3860 break;
3861 case 20:
3862 if ((unsigned) lp->patterned_rule < LIFE_20RULES)
3863 npats = patterns_20rules[lp->patterned_rule];
3864 break;
3865 case 22:
3866 if ((unsigned) lp->patterned_rule < LIFE_22RULES)
3867 npats = patterns_22rules[lp->patterned_rule];
3868 break;
3869 case 26:
3870 if ((unsigned) lp->patterned_rule < LIFE_26RULES)
3871 npats = patterns_26rules[lp->patterned_rule];
3872 break;
3873 }
3874 if (glidersearch || patternsearch) {
3875 /* trying to find new patterns, formerly 10x10x10 */
3876 RandomSoup(mi, SOUPPERCENT, SOUPSIZE(lp->ncols),
3877 SOUPSIZE(lp->nrows), SOUPSIZE(lp->nstacks));
3878 } else {
3879 if (!filePattern)
3880 lp->pattern = NRAND(npats + 2);
3881 if (lp->pattern >= npats && !filePattern) {
3882 if (!RandomSoup(mi, SOUPPERCENT, SOUPSIZE(lp->ncols),
3883 SOUPSIZE(lp->nrows), SOUPSIZE(lp->nstacks))) {
3884 if (lp->eraserhead.next != NULL)
3885 endList(lp);
3886 return;
3887 }
3888 } else {
3889 if (!GetPattern(mi, lp->patterned_rule, lp->pattern)) {
3890 if (lp->eraserhead.next != NULL)
3891 endList(lp);
3892 return;
3893 }
3894 }
3895 }
3896
3897 if (lp->dbuf != None) {
3898 XFreePixmap(display, lp->dbuf);
3899 lp->dbuf = None;
3900 }
3901 if ((lp->dbuf = XCreatePixmap(display, window,
3902 lp->width, lp->height, MI_DEPTH(mi))) == None) {
3903 free_life3d_screen(display, lp);
3904 return;
3905 }
3906 DrawScreen(mi);
3907 }
3908
3909 ENTRYPOINT void
draw_life3d(ModeInfo * mi)3910 draw_life3d(ModeInfo * mi)
3911 {
3912 life3dstruct *lp;
3913
3914 if (life3ds == NULL)
3915 return;
3916 lp = &life3ds[MI_SCREEN(mi)];
3917 if (lp->eraserhead.next == NULL)
3918 return;
3919
3920 if (!RunLife3D(lp)) {
3921 if (lp->eraserhead.next != NULL)
3922 endList(lp);
3923 return;
3924 }
3925 lissajous(lp);
3926 if (lp->visible) /* kill static life also */
3927 DrawScreen(mi);
3928
3929 MI_IS_DRAWN(mi) = True;
3930
3931 if (!lp->visible || lp->noChangeCount >= 8) {
3932 /*CountCells3D(lp) == 0) */
3933 init_life3d(mi);
3934 } else if (++lp->generation > MI_CYCLES(mi)) {
3935 if (patternsearch || glidersearch)
3936 printList(lp, 1);
3937 init_life3d(mi);
3938 } else {
3939 if (MI_IS_VERBOSE(mi))
3940 (void) fprintf(stdout, "%s (%d cells)\n",
3941 lp->nameString, lp->ncells);
3942 if (patternsearch || glidersearch) {
3943 if (lp->generation == MI_CYCLES(mi) - repeat + 1)
3944 printList(lp, 0);
3945 }
3946 lp->painted = True;
3947 }
3948
3949 /*
3950 * generate a randomized shooter aimed roughly toward the center of the
3951 * screen after batchcount.
3952 */
3953
3954 if (MI_COUNT(mi)) {
3955 if (lp->generation && lp->generation %
3956 ((MI_COUNT(mi) < 0) ? 1 : MI_COUNT(mi)) == 0)
3957 if (!shooter(lp)) {
3958 if (lp->eraserhead.next != NULL)
3959 endList(lp);
3960 }
3961 }
3962 }
3963
3964 ENTRYPOINT void
release_life3d(ModeInfo * mi)3965 release_life3d(ModeInfo * mi)
3966 {
3967 if (life3ds != NULL) {
3968 int screen;
3969
3970 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
3971 free_life3d_screen(MI_DISPLAY(mi), &life3ds[screen]);
3972 free(life3ds);
3973 life3ds = (life3dstruct *) NULL;
3974 }
3975 }
3976
3977 #ifndef STANDALONE
3978 ENTRYPOINT void
refresh_life3d(ModeInfo * mi)3979 refresh_life3d(ModeInfo * mi)
3980 {
3981 life3dstruct *lp;
3982
3983 if (life3ds == NULL)
3984 return;
3985 lp = &life3ds[MI_SCREEN(mi)];
3986
3987 if (lp->painted) {
3988 MI_CLEARWINDOW(mi);
3989 }
3990 }
3991
3992 ENTRYPOINT void
change_life3d(ModeInfo * mi)3993 change_life3d(ModeInfo * mi)
3994 {
3995 int npats;
3996 life3dstruct *lp;
3997
3998 if (life3ds == NULL)
3999 return;
4000 lp = &life3ds[MI_SCREEN(mi)];
4001
4002 lp->generation = 0;
4003
4004 if (lp->eraserhead.next != NULL)
4005 endList(lp);
4006 /*lp->tablesMade = 0; */
4007
4008 MI_CLEARWINDOW(mi);
4009
4010 if (!filePattern)
4011 lp->pattern++;
4012 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
4013 npats = 0;
4014 switch (lp->neighbors) {
4015 case 12:
4016 if ((unsigned) lp->patterned_rule < LIFE_12RULES)
4017 npats = patterns_12rules[lp->patterned_rule];
4018 break;
4019 case 14:
4020 if ((unsigned) lp->patterned_rule < LIFE_14RULES)
4021 npats = patterns_14rules[lp->patterned_rule];
4022 break;
4023 case 18:
4024 if ((unsigned) lp->patterned_rule < LIFE_18RULES)
4025 npats = patterns_18rules[lp->patterned_rule];
4026 break;
4027 case -18:
4028 if ((unsigned) lp->patterned_rule < LIFE__18RULES)
4029 npats = patterns__18rules[lp->patterned_rule];
4030 break;
4031 case 20:
4032 if ((unsigned) lp->patterned_rule < LIFE_20RULES)
4033 npats = patterns_20rules[lp->patterned_rule];
4034 break;
4035 case 22:
4036 if ((unsigned) lp->patterned_rule < LIFE_22RULES)
4037 npats = patterns_22rules[lp->patterned_rule];
4038 break;
4039 case 26:
4040 if ((unsigned) lp->patterned_rule < LIFE_26RULES)
4041 npats = patterns_26rules[lp->patterned_rule];
4042 break;
4043 }
4044 if (lp->pattern >= npats + 2) {
4045 lp->pattern = 0;
4046 if (lp->allPatterns) {
4047 lp->patterned_rule++;
4048 switch (lp->neighbors) {
4049 case 12:
4050 if ((unsigned) lp->patterned_rule >= LIFE_12RULES)
4051 lp->patterned_rule = 0;
4052 break;
4053 case 14:
4054 if ((unsigned) lp->patterned_rule >= LIFE_14RULES)
4055 lp->patterned_rule = 0;
4056 break;
4057 case 18:
4058 if ((unsigned) lp->patterned_rule >= LIFE_18RULES)
4059 lp->patterned_rule = 0;
4060 break;
4061 case -18:
4062 if ((unsigned) lp->patterned_rule >= LIFE__18RULES)
4063 lp->patterned_rule = 0;
4064 break;
4065 case 20:
4066 if ((unsigned) lp->patterned_rule >= LIFE_20RULES)
4067 lp->patterned_rule = 0;
4068 break;
4069 case 22:
4070 if ((unsigned) lp->patterned_rule >= LIFE_22RULES)
4071 lp->patterned_rule = 0;
4072 break;
4073 case 26:
4074 if ((unsigned) lp->patterned_rule >= LIFE_26RULES)
4075 lp->patterned_rule = 0;
4076 break;
4077 }
4078 copyFromPatternedRule(lp->neighbors, &lp->param,
4079 lp->patterned_rule);
4080 printRule(lp->neighbors, lp->ruleString, lp->param,
4081 MI_IS_VERBOSE(mi));
4082 } else if (lp->allGliders) {
4083 lp->patterned_rule++;
4084 switch (lp->neighbors) {
4085 case 12:
4086 if ((unsigned) lp->patterned_rule >= LIFE_12GLIDERS)
4087 lp->patterned_rule = 0;
4088 break;
4089 case 14:
4090 if ((unsigned) lp->patterned_rule >= LIFE_14GLIDERS)
4091 lp->patterned_rule = 0;
4092 break;
4093 case 18:
4094 if ((unsigned) lp->patterned_rule >= LIFE_18GLIDERS)
4095 lp->patterned_rule = 0;
4096 break;
4097 case -18:
4098 if ((unsigned) lp->patterned_rule >= LIFE__18GLIDERS)
4099 lp->patterned_rule = 0;
4100 break;
4101 case 20:
4102 if ((unsigned) lp->patterned_rule >= LIFE_20GLIDERS)
4103 lp->patterned_rule = 0;
4104 break;
4105 case 22:
4106 if ((unsigned) lp->patterned_rule >= LIFE_22GLIDERS)
4107 lp->patterned_rule = 0;
4108 break;
4109 case 26:
4110 if ((unsigned) lp->patterned_rule >= LIFE_26GLIDERS)
4111 lp->patterned_rule = 0;
4112 break;
4113 }
4114 copyFromPatternedRule(lp->neighbors, &lp->param,
4115 lp->patterned_rule);
4116 printRule(lp->neighbors, lp->ruleString, lp->param,
4117 MI_IS_VERBOSE(mi));
4118 }
4119 }
4120 if (!serial && !filePattern)
4121 lp->pattern = NRAND(npats + 2);
4122 if (lp->pattern >= npats) {
4123 if (!RandomSoup(mi, SOUPPERCENT, SOUPSIZE(lp->ncols),
4124 SOUPSIZE(lp->nrows), SOUPSIZE(lp->nstacks))) {
4125 if (lp->eraserhead.next != NULL)
4126 endList(lp);
4127 return;
4128 }
4129 } else {
4130 if (!GetPattern(mi, lp->patterned_rule, lp->pattern)) {
4131 if (lp->eraserhead.next != NULL)
4132 endList(lp);
4133 return;
4134 }
4135 }
4136 DrawScreen(mi);
4137 }
4138 #endif
4139
4140 XSCREENSAVER_MODULE ("Life3d", life3d)
4141
4142 #endif /* MODE_life3d */
4143