1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ant3d --- Extension to Langton's generalized turing machine ants */
3 
4 #if 0
5 static const char sccsid[] = "@(#)ant3d.c	5.13 2004/07/23 xlockmore";
6 
7 #endif
8 /*-
9  * Copyright (c) 1999 by David Bagley.
10  *
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * Revision History:
24  *   28-Jun-2004: A few more features added, need better "eyes" on leading
25  *                cube (instead of a small black face)
26  *   08-Jun-2004: Resurrected code after seeing Heiko Hamann's "Definition
27  *                Behavior of Langton's Ant in Three Dimensions", Complex
28  *                Systems Volume 14, Issue 3, (2003) pp 264-268
29  *                heiko.hamann AT gmx.de
30  *   12-Aug-1999: Coded from life3d.c and ant.c probably will not work but...
31  */
32 
33 #ifdef STANDALONE
34 # define MODE_ant3d
35 # define DEFAULTS	"*delay: 5000 \n" \
36 			"*count: -3 \n" \
37 			"*cycles: 10000 \n" \
38 			"*ncolors: 200 \n" \
39 			"*wireframe: False \n" \
40 			"*fullrandom: False \n" \
41 			"*verbose: False \n"\
42 
43 # define reshape_ant3d 0
44 # define ant3d_handle_event 0
45 # include "xlockmore.h"		/* in xscreensaver distribution */
46 #else /* STANDALONE */
47 # include "xlock.h"		/* in xlockmore distribution */
48 #endif /* STANDALONE */
49 #define DO_STIPPLE
50 #include "automata.h"
51 
52 #ifdef MODE_ant3d
53 
54 #define DEF_LABEL "True"
55 #define FONT_HEIGHT 19
56 #define FONT_WIDTH 15
57 
58 /*-
59  * neighbors of 0 randomizes it for 6, 8, 12, 14, 18, 20, 26
60  */
61 #define DEF_NEIGHBORS  "0"      /* choose random value */
62 #define DEF_RULE "A" /* All rules */
63 #define DEF_EYES  "False"
64 
65 static Bool label;
66 static int  neighbors;
67 static char *rule;
68 static Bool eyes;
69 
70 static XrmOptionDescRec opts[] =
71 {
72 	{(char *) "-label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "on"},
73 	{(char *) "+label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "off"},
74 	{(char *) "-neighbors", (char *) ".ant3d.neighbors", XrmoptionSepArg, (caddr_t) NULL},
75 	{(char *) "-rule", (char *) ".ant3d.rule", XrmoptionSepArg, (caddr_t) NULL},
76 	{(char *) "-eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "on"}
77 ,
78         {(char *) "+eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "off"}
79 };
80 static argtype vars[] =
81 {
82 	{(void *) & label, (char *) "label", (char *) "Label", (char *) DEF_LABEL, t_Bool},
83 	{(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
84 	{(void *) & rule, (char *) "rule", (char *) "Rule", (char *) DEF_RULE, t_String},
85 	{(void *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool}
86 };
87 static OptionStruct desc[] =
88 {
89 	{(char *) "-/+label", (char *) "turn on/off rule labeling"},
90 	{(char *) "-neighbors num", (char *) "cubes 6, 8, 14, 18, 20, 26, or rhombic dodecahedron 12"},
91 	{(char *) "-rule string", (char *) "base 4 string for Turk's Ant"},
92 	{(char *) "-/+eyes", (char *) "turn on/off eyes"}
93 };
94 
95 ENTRYPOINT ModeSpecOpt ant3d_opts =
96 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
97 
98 #ifdef USE_MODULES
99 ModStruct   ant3d_description =
100 {"ant3d", "init_ant3d", "draw_ant3d", "release_ant3d",
101  "refresh_ant3d", "init_ant3d", "free_ant3d", &ant3d_opts,
102  5000, -3, 10000, 1, 64, 1.0, "",
103  "Shows 3D ants", 0, NULL};
104 
105 #endif
106 
107 #define ANT3DBITS(n,w,h)\
108   if ((ap->pixmaps[ap->init_bits]=\
109   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
110   free_ant3d_screen(display,ap); return;} else {ap->init_bits++;}
111 
112 /* If you change the table you may have to change the following 2 constants */
113 #define STATES 2
114 #define MINANTS 1
115 #define REDRAWSTEP 2000		/* How much tape to draw per cycle */
116 
117 /* Don't change these numbers without changing the offset() macro below! */
118 #define MAXSTACKS 64
119 #define	MAXROWS 128
120 #define MAXCOLUMNS 128
121 #define BASESIZE ((MAXCOLUMNS*MAXROWS*MAXSTACKS)>>6)
122 
123 #define RT_ANGLE 90
124 #define HALFRT_ANGLE 45
125 
126 /* Store state of cell in top bit. Reserve low bits for count of living nbrs */
127 #define Set3D(x,y,z,c) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)
128 #define Reset3D(x,y,z) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,0)
129 
130 #define SetList3D(x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False; \
131 if (!AddToList(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False
132 #define InitSetList3D(x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return; \
133 if (!AddToList(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return
134 
135 #define ChangeList3D(i,x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False; \
136 ChangeInList(ap,i,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)
137 
138 #define EyeToScreen 72.0	/* distance from eye to screen */
139 #define HalfScreenD 20.0	/* 1/2 the diameter of screen */
140 #define BUCKETSIZE 10
141 #define NBUCKETS ((MAXCOLUMNS+MAXROWS+MAXSTACKS)*BUCKETSIZE)
142 #define Distance(x1,y1,z1,x2,y2,z2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
143 
144 #define IP (M_PI / 180.0)
145 #define NCOLORS 14
146 
147 typedef struct {
148 	unsigned char color;
149 	short   turn;
150 	unsigned char next;
151 } statestruct;
152 
153 typedef struct _antstruct {
154 	int         col, row, stack;
155 	unsigned char color;
156 	char        visible;
157 	short       direction; /* Direction facing */
158 	short       gravity; /* Need to know which way is down */
159 	unsigned char state;
160 	short       dist; /* dist from cell to eye */
161 	struct _antstruct *next; /* pointer to next entry on linked list */
162 	struct _antstruct *prev;
163 	struct _antstruct *priority;
164 } antstruct;
165 
166 typedef struct {
167 	Bool        painted;
168 	int         neighbors;
169 	int         ox, oy, oz;	/* origin */
170 	double      vx, vy, vz;	/* viewpoint */
171 	int         generation;
172 	int         ncols, nrows, nstacks;
173 	int         memstart;
174 	unsigned char *base[BASESIZE];
175 	double      A, B, C, F;
176 	int         width, height;
177 	unsigned char ncolors, nstates;
178 	int         n;
179 	double      azm;
180 	double      metaAlt, metaAzm, metaDist;
181 	antstruct  *ants;
182 	antstruct  **antList;
183 	antstruct  *ptrhead, *ptrend, eraserhead, eraserend;
184 	antstruct  *buckethead[NBUCKETS], *bucketend[NBUCKETS];
185 	Bool        wireframe, eyes;
186 	Pixmap      dbuf;
187 	statestruct machine[NCOLORS * STATES];
188 	unsigned char *tape;
189 	int         init_bits;
190 	unsigned long colors[NCOLORS - 1];
191 	GC          stippledGC;
192 	Pixmap      pixmaps[NCOLORS - 1];
193 	int         nInvisible;
194 	int         labelOffsetX, labelOffsetY;
195 	char        ruleString[50];
196 } antfarm3dstruct;
197 
198 static char plots[] =
199 {12, 26};
200 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
201 
202 /* Coordinate ant moves */
203 #define NU -1 /* Not used */
204 #define XN 0
205 #define XP 1
206 #define YN 2
207 #define YP 3
208 #define ZN 4
209 #define ZP 5
210 #define XNYN 0 /* Rhombic Dodecahedron */
211 #define XPYN 1
212 #define XNYP 2
213 #define XPYP 3
214 #define YNZN 4
215 #define YPZN 5
216 #define YNZP 6
217 #define YPZP 7
218 #define ZNXN 8
219 #define ZPXN 9
220 #define ZNXP 10
221 #define ZPXP 11
222 
223 /* Relative ant moves */
224 #define TRS 0			/* Turn right, then step */
225 #define TLS 1			/* Turn left, then step */
226 #define TUS 2			/* Turn up, then step */
227 #define TDS 3			/* Turn down, then step */
228 #define FS  4			/* Step */
229 #define TBS 5			/* Turn back, then step */
230 /* Uhhh for completeness I guess  there are some yaw moves and a 180 TU */
231 #define STR 6			/* Step then turn right */
232 #define STL 7			/* Step then turn left */
233 #define STU 8			/* Step then turn up */
234 #define STD 9			/* Step then turn down */
235 #define SF  10			/* Step */
236 #define STB 11			/* Step then turn back */
237 /* Relative bee moves, leading R for Rhombic */
238 #define RTRS 0			/* Turn right, then step */
239 #define RTLS 1			/* Turn left, then step */
240 /* can also  include hard turns but did not yet */
241 #define RTURS 2			/* Turn up-right, then step */
242 #define RTDRS 3			/* Turn down-right, then step */
243 #define RTULS 4			/* Turn up-left, then step */
244 #define RTDLS 5			/* Turn down-left, then step */
245 #define RFS  6			/* Step */
246 #define RTBS 7			/* Turn back, then step */
247 /* Uhhh for completeness I guess  there are some yaw moves and a 180 TU */
248 #define RSTR 8			/* Step then turn right */
249 #define RSTL 9			/* Step then turn left */
250 #define RSTUR 10		/* Step then turn up-right */
251 #define RSTDR 11		/* Step then turn down-right */
252 #define RSTUL 12		/* Step then turn up-left */
253 #define RSTDL 13		/* Step then turn down-left */
254 #define RSF  14			/* Step */
255 /* turnDirection, oldGravity, oldDirection */
256 /*gravity XN, traveling along a direction YN, get TRS, now ZP */
257 static int newDirectionMap[4][6][6] = {
258 { /* TRS */
259 	{NU, NU, ZP, ZN, YN, YP}, /* oldGravity = XN */
260 	{NU, NU, ZN, ZP, YP, YN},
261 	{ZN, ZP, NU, NU, XP, XN}, /* oldGravity = YN */
262 	{ZP, ZN, NU, NU, XN, XP},
263 	{YP, YN, XN, XP, NU, NU}, /* oldGravity = ZN */
264 	{YN, YP, XP, XN, NU, NU}
265 },
266 { /* TLS */
267 	{NU, NU, ZN, ZP, YP, YN}, /* oldGravity = XN */
268 	{NU, NU, ZP, ZN, YN, YP},
269 	{ZP, ZN, NU, NU, XN, XP}, /* oldGravity = YN */
270 	{ZN, ZP, NU, NU, XP, XN},
271 	{YN, YP, XP, XN, NU, NU}, /* oldGravity = ZN */
272 	{YP, YN, XN, XP, NU, NU}
273 },
274 { /* TUS */
275 	{NU, NU, XP, XP, XP, XP}, /* oldGravity = XN */
276 	{NU, NU, XN, XN, XN, XN},
277 	{YP, YP, NU, NU, YP, YP}, /* oldGravity = YN */
278 	{YN, YN, NU, NU, YN, YN},
279 	{ZP, ZP, ZP, ZP, NU, NU}, /* oldGravity = ZN */
280 	{ZN, ZN, ZN, ZN, NU, NU}
281 },
282 { /* TDS */
283 	{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
284 	{NU, NU, XP, XP, XP, XP},
285 	{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
286 	{YP, YP, NU, NU, YP, YP},
287 	{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
288 	{ZP, ZP, ZP, ZP, NU, NU}
289 }
290 };
291 /* turnDirection, oldGravity, oldDirection */
292 static int newGravityMap[4][6][6] = {
293 { /* TRS */
294 	{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
295 	{NU, NU, XP, XP, XP, XP},
296 	{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
297 	{YP, YP, NU, NU, YP, YP},
298 	{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
299 	{ZP, ZP, ZP, ZP, NU, NU}
300 },
301 { /* TLS */
302 	{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
303 	{NU, NU, XP, XP, XP, XP},
304 	{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
305 	{YP, YP, NU, NU, YP, YP},
306 	{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
307 	{ZP, ZP, ZP, ZP, NU, NU}
308 },
309 { /* TUS */
310 	{NU, NU, YN, YP, ZN, ZP}, /* oldGravity = XN */
311 	{NU, NU, YN, YP, ZN, ZP},
312 	{XN, XP, NU, NU, ZN, ZP}, /* oldGravity = YN */
313 	{XN, XP, NU, NU, ZN, ZP},
314 	{XN, XP, YN, YP, NU, NU}, /* oldGravity = ZN */
315 	{XN, XP, YN, YP, NU, NU}
316 },
317 { /* TDS */
318 	{NU, NU, YP, YN, ZP, ZN}, /* oldGravity = XN */
319 	{NU, NU, YP, YN, ZP, ZN},
320 	{XP, XN, NU, NU, ZP, ZN}, /* oldGravity = YN */
321 	{XP, XN, NU, NU, ZP, ZN},
322 	{XP, XN, YP, YN, NU, NU}, /* oldGravity = ZN */
323 	{XP, XN, YP, YN, NU, NU}
324 }
325 };
326 /* turnDirection, oldGravity, oldDirection */
327 /* XNYN 0, XPYN 1, XNYP 2, XPYP 3
328    YNZN 4, YPZN 5, YNZP 6, YPZP 7
329    ZNXN 8, ZPXN 9, ZNXP 10,ZPXP 11 */
330 /*gravity XN, traveling along a direction YNZN, get RTRS, now YNZP */
331 static int newRDirectionMap[6][6][4] = {
332 { /* RTRS:YNZN YPZN YNZP YPZP */
333 	{YPZN, YPZP, YNZN, YNZP}, /* YZ, oldGravity = XN */
334 	{YNZP, YNZN, YPZP, YPZN},
335 	{ZPXN, ZPXP, ZNXN, ZNXP}, /* ZX, oldGravity = YN */
336 	{ZNXP, ZNXN, ZPXP, ZPXN},
337 	{XPYN, XPYP, XNYN, XNYP}, /* XY, oldGravity = ZN */
338 	{XNYP, XNYN, XPYP, XPYN}
339 },
340 { /* RTLS */
341 	{YNZP, YNZN, YPZP, YPZN}, /* oldGravity = XN */
342 	{YPZN, YPZP, YNZN, YNZP},
343 	{ZNXP, ZNXN, ZPXP, ZPXN}, /* oldGravity = YN */
344 	{ZPXN, ZPXP, ZNXN, ZNXP},
345 	{XNYP, XNYN, XPYP, XPYN}, /* oldGravity = ZN */
346 	{XPYN, XPYP, XNYN, XNYP}
347 },
348 { /* RTURS */
349 	{ZNXN, XNYP, XNYN, ZPXN}, /* oldGravity = XN */
350 	{XPYN, ZNXP, ZPXP, XPYP},
351 	{XNYN, YNZP, YNZN, XPYN}, /* oldGravity = YN */
352 	{YPZN, XNYP, XPYP, YPZP},
353 	{YNZN, ZNXP, ZNXN, YPZN}, /* oldGravity = ZN */
354 	{ZPXN, YNZP, YPZP, ZPXP}
355 },
356 { /* RTDRS */
357 	{ZNXP, XPYP, XPYN, ZPXP}, /* oldGravity = XN */
358 	{XNYN, ZNXN, ZPXN, XNYP},
359 	{XNYP, YPZP, YPZN, XPYP}, /* oldGravity = YN */
360 	{YNZN, XNYN, XPYN, YNZP},
361 	{YNZP, ZPXP, ZPXN, YPZP}, /* oldGravity = ZN */
362 	{ZNXN, YNZN, YPZN, ZNXP}
363 },
364 { /* RTULS */
365 	{XNYN, ZNXN, ZPXN, XNYP}, /* oldGravity = XN */
366 	{ZNXP, XPYP, XPYN, ZPXP},
367 	{YNZN, XNYN, XPYN, YNZP}, /* oldGravity = YN */
368 	{XNYP, YPZP, YPZN, XPYP},
369 	{ZNXN, YNZN, YPZN, ZNXP}, /* oldGravity = ZN */
370 	{YNZP, ZPXP, ZPXN, YPZP}
371 },
372 { /* RTDLS */
373 	{XPYN, ZNXP, ZPXP, XPYP}, /* oldGravity = XN */
374 	{ZNXN, XNYP, XNYN, ZPXN},
375 	{YPZN, XNYP, XPYP, YPZP}, /* oldGravity = YN */
376 	{XNYN, YNZP, YNZN, XPYN},
377 	{ZPXN, YNZP, YPZP, ZPXP}, /* oldGravity = ZN */
378 	{YNZN, ZNXP, ZNXN, YPZN}
379 }
380 };
381 /* turnDirection, oldGravity, oldDirection */
382 /* XNYN 0, XPYN 1, XNYP 2, XPYP 3
383    YNZN 4, YPZN 5, YNZP 6, YPZP 7
384    ZNXN 8, ZPXN 9, ZNXP 10,ZPXP 11 */
385 static int newRGravityMap[6][6][4] = {
386 { /* RTRS:YNZN YPZN YNZP YPZP */
387 	{XN, XN, XN, XN}, /* oldGravity = XN */
388 	{XP, XP, XP, XP},
389 	{YN, YN, YN, YN}, /* oldGravity = YN */
390 	{YP, YP, YP, YP},
391 	{ZN, ZN, ZN, ZN}, /* oldGravity = ZN */
392 	{ZP, ZP, ZP, ZP}
393 },
394 { /* RTLS */
395 	{XN, XN, XN, XN}, /* oldGravity = XN */
396 	{XP, XP, XP, XP},
397 	{YN, YN, YN, YN}, /* oldGravity = YN */
398 	{YP, YP, YP, YP},
399 	{ZN, ZN, ZN, ZN}, /* oldGravity = ZN */
400 	{ZP, ZP, ZP, ZP}
401 },
402 { /* RTURS */
403 	{YP, ZP, ZN, YN}, /* oldGravity = XN */
404 	{ZP, YN, YP, ZN},
405 	{ZP, XP, XN, ZN}, /* oldGravity = YN */
406 	{XP, ZN, ZP, XN},
407 	{XP, YP, YN, XN}, /* oldGravity = ZN */
408 	{YP, XN, XP, YN}
409 },
410 { /* RTDRS */
411 	{YN, ZN, ZP, YP}, /* oldGravity = XN */
412 	{ZN, YP, YN, ZP},
413 	{ZN, XN, XP, ZP}, /* oldGravity = YN */
414 	{XN, ZP, ZN, XP},
415 	{XN, YN, YP, XP}, /* oldGravity = ZN */
416 	{YN, XP, XN, YP}
417 },
418 { /* RTULS */
419 	{ZP, YN, YP, ZN}, /* oldGravity = XN */
420 	{YP, ZP, ZN, YN},
421 	{XP, ZN, ZP, XN}, /* oldGravity = YN */
422 	{ZP, XP, XN, ZN},
423 	{YP, XN, XP, YN}, /* oldGravity = ZN */
424 	{XP, YP, YN, XN}
425 },
426 { /* RTDLS */
427 	{ZN, YP, YN, ZP}, /* oldGravity = XN */
428 	{YN, ZN, ZP, YP},
429 	{XN, ZP, ZN, XP}, /* oldGravity = YN */
430 	{ZN, XN, XP, ZP},
431 	{YN, XP, XN, YP}, /* oldGravity = ZN */
432 	{XN, YN, YP, XP}
433 }
434 };
435 static antfarm3dstruct *antfarm3ds = NULL;
436 
437 static unsigned char tables[][3 * NCOLORS * STATES + 2] =
438 {
439 #if 0
440 /* Generated */
441 	{		/* 0: RLU */
442 		3, 1,
443 		1, TRS, 0, 2, TLS, 0, 0, TUS, 0
444 	},
445 	{		/* 1: RUL */
446 		3, 1,
447 		1, TRS, 0, 2, TUS, 0, 0, TLS, 0
448 	},
449 	{		/* 2: RUD */
450 		3, 1,
451 		1, TRS, 0, 2, TUS, 0, 0, TDS, 0
452 	},
453 	{		/* 3: RLUU */
454 		4, 1,
455 		1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
456 	},
457 	{		/* 4: RRLU 32 */
458 		4, 1,
459 		1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 0, TUS, 0
460 	},
461 	{		/* 5: RRUL ? */
462 		4, 1,
463 		1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TLS, 0
464 	},
465 	{		/* 6: RRUD 22 */
466 		4, 1,
467 		1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TDS, 0
468 	},
469 	{		/* 7: RLRU 188 */
470 		4, 1,
471 		1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 0, TUS, 0
472 	},
473 	{		/* 8: RLLU ? */
474 		4, 1,
475 		1, TRS, 0, 2, TLS, 0, 3, TLS, 0, 0, TUS, 0
476 	},
477 	{		/* 9: RLUR 46 ! */
478 		4, 1,
479 		1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TRS, 0
480 	},
481 	{		/* 10: RLUL 32 */
482 		4, 1,
483 		1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TLS, 0
484 	},
485 	{		/* 11: RLUU 102 */
486 		4, 1,
487 		1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
488 	},
489 	{		/* 12: RLUD 28 */
490 		4, 1,
491 		1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TDS, 0
492 	},
493 	{		/* 13: RURL 30 */
494 		4, 1,
495 		1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TLS, 0
496 	},
497 	{		/* 14: RURD ? */
498 		4, 1,
499 		1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TDS, 0
500 	},
501 	{		/* 15: RULL 22 */
502 		4, 1,
503 		1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TLS, 0
504 	},
505 	{		/* 16: RULR 22 */
506 		4, 1,
507 		1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TRS, 0
508 	},
509 	{		/* 17: RULU 22 */
510 		4, 1,
511 		1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TUS, 0
512 	},
513 	{		/* 18: RUUL 26 */
514 		4, 1,
515 		1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TLS, 0
516 	},
517 	{		/* 19: RULD 22 */
518 		4, 1,
519 		1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TDS, 0
520 	},
521 	{		/* 20: RUUD 22 */
522 		4, 1,
523 		1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TDS, 0
524 	},
525 	{		/* 21: RUDR 14 */
526 		4, 1,
527 		1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TRS, 0
528 	},
529 	{		/* 22: RUDL ? */
530 		4, 1,
531 		1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TLS, 0
532 	},
533 	{		/* 23: RUDU 114 */
534 		4, 1,
535 		1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TUS, 0
536 	},
537 	{		/* 24: RUDD 40 */
538 		4, 1,
539 		1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TDS, 0
540 	},
541 	{		/* 25: RRRULL ? */
542 		6, 1,
543 		1, TRS, 0, 2, TRS, 0, 3, TRS, 0, 4, TUS, 0,
544 		5, TLS, 0, 0, TLS, 0
545 	},
546 	{		/* 26: RLRUUUL 25436 */
547 		7, 1,
548 		1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 4, TUS, 0,
549 		5, TUS, 0, 6, TUS, 0, 0, TLS, 0
550 	},
551 #endif
552 	{		/* 27: RRLDDDULRRLLLL * */
553 		14, 1,
554 		1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 4, TDS, 0,
555 		5, TDS, 0, 6, TDS, 0, 7, TUS, 0, 8, TLS, 0,
556 		9, TRS, 0, 10, TRS, 0, 11, TLS, 0, 12, TLS, 0,
557 		13, TLS, 0, 0, TLS, 0
558 	}
559 };
560 
561 #define NTABLES   (sizeof tables / sizeof tables[0])
562 
563 #ifdef gDEBUG
printDir(int dir,Bool omega)564 static char * printDir(int dir, Bool omega)
565 {
566 	if (omega) {
567 		switch (dir) {
568 		case XNYN: return (char *) "XNYN";
569 		case XPYN: return (char *) "XPYN";
570 		case XNYP: return (char *) "XNYP";
571 		case XPYP: return (char *) "XPYP";
572 		case YNZN: return (char *) "YNZN";
573 		case YPZN: return (char *) "YPZN";
574 		case YNZP: return (char *) "YNZP";
575 		case YPZP: return (char *) "YPZP";
576 		case ZNXN: return (char *) "ZNXN";
577 		case ZPXN: return (char *) "ZPXN";
578 		case ZNXP: return (char *) "ZNXP";
579 		case ZPXP: return (char *) "ZPXP";
580 		default: return (char *) "NUNU";
581 		}
582 	} else {
583 		switch (dir) {
584 		case XN: return (char *) "XN";
585 		case XP: return (char *) "XP";
586 		case YN: return (char *) "YN";
587 		case YP: return (char *) "YP";
588 		case ZN: return (char *) "ZN";
589 		case ZP: return (char *) "ZP";
590 		default: return (char *) "NU";
591 		}
592 	}
593 }
594 
printTurn(antfarm3dstruct * ap,int dir)595 static char * printTurn(antfarm3dstruct * ap, int dir)
596 {
597 	if (ap->neighbors == 12) {
598 		switch (dir) {
599 		case RTRS: return (char *) "RTRS";
600 		case RTLS: return (char *) "RTLS";
601 		case RTURS: return (char *) "RTURS";
602 		case RTDRS: return (char *) "RTDRS";
603 		case RTULS: return (char *) "RTULS";
604 		case RTDLS: return (char *) "RTDLS";
605 		default: return (char *) "RTXX";
606 		}
607 	} else {
608 		switch (dir) {
609 		case TRS: return (char *) "TRS";
610 		case TLS: return (char *) "TLS";
611 		case TUS: return (char *) "TUS";
612 		case TDS: return (char *) "TDS";
613 		default: return (char *) "TXX";
614 		}
615 	}
616 }
617 #endif
618 
heading(antfarm3dstruct * ap,short * direction,short * gravity,short turn)619 static void heading(antfarm3dstruct * ap, short * direction, short * gravity,
620 		short turn)
621 {
622 	short oldDirection = *direction;
623 	short oldGravity = *gravity;
624 
625 	if (ap->neighbors == 12) {
626 		if (turn < 8) {
627 			if (turn == RTBS) {
628 				if (oldDirection & 1)
629 					*direction = oldDirection - 1;
630 				else
631 					*direction = oldDirection + 1;
632 			} else if (turn < 6) {
633 				*gravity = newRGravityMap
634 					[turn][oldGravity][oldDirection % 4];
635 				*direction = newRDirectionMap
636 					[turn][oldGravity][oldDirection % 4];
637 			}
638 		}
639 	} else {
640 		if (turn < 6) {
641 			if (turn == TBS) {
642 				if (oldDirection & 1)
643 					*direction = oldDirection - 1;
644 				else
645 					*direction = oldDirection + 1;
646 			} else if (turn < 4) {
647 				*gravity = newGravityMap
648 					[turn][oldGravity][oldDirection];
649 				*direction = newDirectionMap
650 					[turn][oldGravity][oldDirection];
651 			}
652 		}
653 	}
654 	if (*gravity == NU)
655 		(void) fprintf(stderr, "gravity corruption\n");
656 	if (*direction == NU)
657 		(void) fprintf(stderr, "direction corruption\n");
658 #ifdef gDEBUG
659 	(void) printf(
660 		"odirection %s, ogravity %s, turn %s, direction %s, gravity %s\n",
661 		printDir(oldDirection, (ap->neighbors == 12)),
662 		printDir(oldGravity, False),
663 		printTurn(ap, turn),
664 		printDir(*direction, (ap->neighbors == 12)),
665 		printDir(*gravity, False));
666 #endif
667 }
668 
669 static void
positionOfNeighbor(antfarm3dstruct * ap,int dir,int * pcol,int * prow,int * pstack)670 positionOfNeighbor(antfarm3dstruct * ap, int dir,
671 		int *pcol, int *prow, int *pstack)
672 {
673 	int col = *pcol, row = *prow, stack = *pstack;
674 
675 	if (ap->neighbors == 12) {
676 		switch (dir) {
677 		case XNYN:
678 			col = (!col) ? ap->ncols - 1 : col - 1;
679 			row = (!row) ? ap->nrows - 1 : row - 1;
680 			break;
681 		case XPYN:
682 			col = (col + 1 == ap->ncols) ? 0 : col + 1;
683 			row = (!row) ? ap->nrows - 1 : row - 1;
684 			break;
685 		case XNYP:
686 			col = (!col) ? ap->ncols - 1 : col - 1;
687 			row = (row + 1 == ap->nrows) ? 0 : row + 1;
688 			break;
689 		case XPYP:
690 			col = (col + 1 == ap->ncols) ? 0 : col + 1;
691 			row = (row + 1 == ap->nrows) ? 0 : row + 1;
692 			break;
693 		case YNZN:
694 			row = (!row) ? ap->nrows - 1 : row - 1;
695 			stack = (!stack) ? ap->nstacks - 1 : stack - 1;
696 			break;
697 		case YPZN:
698 			row = (row + 1 == ap->nrows) ? 0 : row + 1;
699 			stack = (!stack) ? ap->nstacks - 1 : stack - 1;
700 			break;
701 		case YNZP:
702 			row = (!row) ? ap->nrows - 1 : row - 1;
703 			stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
704 			break;
705 		case YPZP:
706 			row = (row + 1 == ap->nrows) ? 0 : row + 1;
707 			stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
708 			break;
709 		case ZNXN:
710 			stack = (!stack) ? ap->nstacks - 1 : stack - 1;
711 			col = (!col) ? ap->ncols - 1 : col - 1;
712 			break;
713 		case ZPXN:
714 			stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
715 			col = (!col) ? ap->ncols - 1 : col - 1;
716 			break;
717 		case ZNXP:
718 			stack = (!stack) ? ap->nstacks - 1 : stack - 1;
719 			col = (col + 1 == ap->ncols) ? 0 : col + 1;
720 			break;
721 		case ZPXP:
722 			stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
723 			col = (col + 1 == ap->ncols) ? 0 : col + 1;
724 			break;
725 		default:
726 			(void) fprintf(stderr, "wrong direction %d\n", dir);
727 		}
728 	} else {
729 		switch (dir) {
730 		case XN:
731 			col = (!col) ? ap->ncols - 1 : col - 1;
732 			break;
733 		case XP:
734 			col = (col + 1 == ap->ncols) ? 0 : col + 1;
735 			break;
736 		case YN:
737 			row = (!row) ? ap->nrows - 1 : row - 1;
738 			break;
739 		case YP:
740 			row = (row + 1 == ap->nrows) ? 0 : row + 1;
741 			break;
742 		case ZN:
743 			stack = (!stack) ? ap->nstacks - 1 : stack - 1;
744 			break;
745 		case ZP:
746 			stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
747 			break;
748 		default:
749 			(void) fprintf(stderr, "wrong direction %d\n", dir);
750 		}
751 	}
752 	*pcol = col;
753 	*prow = row;
754 	*pstack = stack;
755 }
756 
757 /*--- list ---*/
758 /* initialise the state of all cells to OFF */
759 static void
Init3D(antfarm3dstruct * ap)760 Init3D(antfarm3dstruct * ap)
761 {
762 	ap->ptrhead = ap->ptrend = NULL;
763 	ap->eraserhead.next = &ap->eraserend;
764 	ap->eraserend.prev = &ap->eraserhead;
765 }
766 
767 /*-
768  * Function that adds the cell (assumed live) at (x,y,z) onto the search
769  * list so that it is scanned in future generations
770  */
771 static Bool
AddToList(antfarm3dstruct * ap,unsigned int x,unsigned int y,unsigned int z,unsigned int c)772 AddToList(antfarm3dstruct * ap,
773 		unsigned int x, unsigned int y, unsigned int z, unsigned int c)
774 {
775 	antstruct  *tmp;
776 
777 	if ((tmp = (antstruct *) malloc(sizeof (antstruct))) == NULL)
778 		return False;
779 	tmp->col = x;
780 	tmp->row = y;
781 	tmp->stack = z;
782 	tmp->color = c;
783 	if (ap->ptrhead == NULL) {
784 		ap->ptrhead = ap->ptrend = tmp;
785 		tmp->prev = NULL;
786 	} else {
787 		ap->ptrend->next = tmp;
788 		tmp->prev = ap->ptrend;
789 		ap->ptrend = tmp;
790 	}
791 	ap->ptrend->next = NULL;
792 	return True;
793 }
794 
795 static void
ChangeInList(antfarm3dstruct * ap,int i,unsigned int x,unsigned int y,unsigned int z,unsigned int c)796 ChangeInList(antfarm3dstruct * ap, int i,
797 		unsigned int x, unsigned int y, unsigned int z, unsigned int c)
798 {
799 	antstruct  *ant = ap->antList[i];
800 	ant->col = x;
801 	ant->row = y;
802 	ant->stack = z;
803 	ant->color = c;
804 }
805 
806 static void
AddToEraseList(antfarm3dstruct * ap,antstruct * cell)807 AddToEraseList(antfarm3dstruct * ap, antstruct * cell)
808 {
809 	cell->next = &ap->eraserend;
810 	cell->prev = ap->eraserend.prev;
811 	ap->eraserend.prev->next = cell;
812 	ap->eraserend.prev = cell;
813 }
814 
815 static void
DelFromList(antfarm3dstruct * ap,antstruct * cell)816 DelFromList(antfarm3dstruct * ap, antstruct * cell)
817 {
818 	if (cell != ap->ptrhead) {
819 		cell->prev->next = cell->next;
820 	} else {
821 		ap->ptrhead = cell->next;
822 		if (ap->ptrhead != NULL)
823 			ap->ptrhead->prev = NULL;
824 	}
825 
826 	if (cell != ap->ptrend) {
827 		cell->next->prev = cell->prev;
828 	} else {
829 		ap->ptrend = cell->prev;
830 		if (ap->ptrend != NULL)
831 			ap->ptrend->next = NULL;
832 	}
833 }
834 
835 static void
EraseFromList(antfarm3dstruct * ap,antstruct * cell)836 EraseFromList(antfarm3dstruct * ap, antstruct * cell)
837 {
838 	DelFromList(ap, cell);
839 	AddToEraseList(ap, cell);
840 }
841 
842 static void
DelFromEraseList(antstruct * cell)843 DelFromEraseList(antstruct * cell)
844 {
845 	cell->next->prev = cell->prev;
846 	cell->prev->next = cell->next;
847 	free(cell);
848 }
849 
850 /*--- memory ---*/
851 /*-
852  * Simulate a large array by dynamically allocating 4x4x4 size cells when
853  * needed.
854  */
855 static void
MemInit(antfarm3dstruct * ap)856 MemInit(antfarm3dstruct * ap)
857 {
858 	int         i;
859 
860 	for (i = 0; i < BASESIZE; ++i) {
861 		if (ap->base[i] != NULL) {
862 			free(ap->base[i]);
863 			ap->base[i] = (unsigned char *) NULL;
864 		}
865 	}
866 	ap->memstart = 0;
867 }
868 
869 #define BASE_OFFSET(x,y,z,b,o) \
870 b = ((x & 0x7c) << 7) + ((y & 0x7c) << 2) + ((z & 0x7c) >> 2); \
871 o = (x & 3) + ((y & 3) << 2) + ((z & 3) << 4); \
872 if (ap->base[b] == NULL) {\
873 if ((ap->base[b] = (unsigned char *) calloc(64, sizeof (unsigned char))) == NULL) {return False;}}
874 
875 #if 0
876 static Bool
877 GetMem(antfarm3dstruct * ap, unsigned int x, unsigned int y, unsigned int z,
878 		int *m)
879 {
880 	int         b, o;
881 
882 	if (ap->memstart) {
883 		MemInit(ap);
884 	}
885 	BASE_OFFSET(x, y, z, b, o);
886 	*m = ap->base[b][o];
887 	return True;
888 }
889 #endif
890 
891 static Bool
SetMem(antfarm3dstruct * ap,unsigned int x,unsigned int y,unsigned int z,unsigned int val)892 SetMem(antfarm3dstruct * ap,
893 	unsigned int x, unsigned int y, unsigned int z, unsigned int val)
894 {
895 	int         b, o;
896 
897 	if (ap->memstart) {
898 		MemInit(ap);
899 	}
900 	BASE_OFFSET(x, y, z, b, o);
901 	ap->base[b][o] = val;
902 	return True;
903 }
904 
905 #if 0
906 static Bool
907 ChangeMem(antfarm3dstruct * ap,
908 		unsigned int x, unsigned int y, unsigned int z,
909 		unsigned int val)
910 {
911 	int         b, o;
912 
913 	if (ap->memstart) {
914 		MemInit(ap);
915 	}
916 	BASE_OFFSET(x, y, z, b, o);
917 	ap->base[b][o] += val;
918 	return True;
919 }
920 #endif
921 
922 static void
End3D(antfarm3dstruct * ap)923 End3D(antfarm3dstruct * ap)
924 {
925 	antstruct  *ptr;
926 
927 	while (ap->ptrhead != NULL) {
928 		/* Reset3D(ap->ptrhead->col, ap->ptrhead->row,
929 			ap->ptrhead->stack); */
930 		EraseFromList(ap, ap->ptrhead);
931 	}
932 	ptr = ap->eraserhead.next;
933 	while (ptr != &ap->eraserend) {
934 		DelFromEraseList(ptr);
935 		ptr = ap->eraserhead.next;
936 	}
937 	MemInit(ap);
938 }
939 
940 #if 0
941 /* This does not seem to be needed */
942 static void
943 condenseList(antfarm3dstruct * ap) {
944 	antstruct  *ptr1 = ap->ptrhead;
945 	antstruct  *ptr2 = ap->ptrhead;
946 	antstruct  *tmp = NULL;
947 	while (ptr2->next != NULL) {
948 		ptr2 = ptr2->next;
949 		while (ptr1 != ptr2) {
950 			if (ptr1->col == ptr2->col &&
951 					ptr1->row == ptr2->row &&
952 					ptr1->stack == ptr2->stack) {
953 				int found = 0;
954 				int i;
955 
956 				for (i = 0; i < ap->n; i++) {
957 					if (ap->antList[i] == ptr1) {
958 						found = 1;
959 						break;
960 					}
961 				}
962 				if (found == 0)
963 					tmp = ptr1;
964 			}
965 			ptr1 = ptr1->next;
966 			if (tmp != NULL) {
967 				DelFromList(ap, tmp);
968 				free(tmp);
969 				tmp = NULL;
970 			}
971 		}
972 	}
973 }
974 #endif
975 
976 #ifndef BLACK_CELLS
977 static void
eraseEmpty(antfarm3dstruct * ap)978 eraseEmpty (antfarm3dstruct * ap) {
979 	antstruct  *ptr1 = ap->ptrhead;
980 	antstruct  *ptr2 = ap->ptrhead;
981 	antstruct  *tmp = NULL;
982 	int col, row, stack;
983 	while (ptr1->next != NULL) {
984 		if (ptr1->color == 0) {
985 			int found = 0;
986 			int i;
987 
988 			for (i = 0; i < ap->n; i++) {
989 				if (ap->antList[i] == ptr1) {
990 					found = 1;
991 					break;
992 				}
993 			}
994 			if (found == 0)
995 				tmp = ptr1;
996 		}
997 		col = ptr1->col;
998 		row = ptr1->row;
999 		stack = ptr1->stack;
1000 		ptr1 = ptr1->next;
1001 		if (tmp != NULL) {
1002 			DelFromList(ap, tmp);
1003 			free(tmp);
1004 			tmp = NULL;
1005 			/* may have to delete all in that position */
1006 			ptr2 = ap->ptrhead;
1007 			while (ptr1 != ptr2) {
1008 				if (ptr2->col == col &&
1009 						ptr2->row == row &&
1010 						ptr2->stack == stack) {
1011 					int found = 0;
1012 					int i;
1013 
1014 					for (i = 0; i < ap->n; i++) {
1015 						if (ap->antList[i] == ptr2) {
1016 							found = 1;
1017 							break;
1018 						}
1019 					}
1020 					if (found == 0)
1021 						tmp = ptr2;
1022 				}
1023 				ptr2 = ptr2->next;
1024 				if (tmp != NULL) {
1025 					DelFromList(ap, tmp);
1026 					free(tmp);
1027 					tmp = NULL;
1028 				}
1029 			}
1030 		}
1031 	}
1032 }
1033 #endif
1034 
1035 static Bool
RunAnt3D(antfarm3dstruct * ap)1036 RunAnt3D(antfarm3dstruct * ap)
1037 {
1038 	antstruct  *anant;
1039 	statestruct *status;
1040 	int         i, state_pos, tape_pos;
1041 	unsigned char color;
1042 
1043 	if (ap->ants == NULL)
1044 		return False;
1045 
1046 	ap->painted = True;
1047 	for (i = 0; i < ap->n; i++) {
1048 		anant = &ap->ants[i];
1049 		tape_pos = anant->col + anant->row * ap->ncols +
1050 			anant->stack * ap->nrows * ap->ncols;
1051 		color = ap->tape[tape_pos];     /* read tape */
1052 		state_pos = color + anant->state * ap->ncolors;
1053 		status = &(ap->machine[state_pos]);
1054 #ifdef gDEBUG
1055 		(void) printf("status: color %d, turn %s, state %d, colors %d\n",
1056 			status->color, printTurn(ap, status->turn),
1057 			anant->state, ap->ncolors);
1058 #endif
1059 		ChangeList3D(i, anant->col, anant->row, anant->stack,
1060 			status->color);
1061 		ap->tape[tape_pos] = status->color;     /* write on tape */
1062 #ifdef gDEBUG
1063 		(void) printf("gen %d: ", ap->generation);
1064 #endif
1065 		heading(ap, &(anant->direction), &(anant->gravity), status->turn);
1066 		/* Find direction of Bees or Ants. */
1067 		/* Translate relative direction to actual direction */
1068 		anant->state = status->next;
1069 
1070 		/* Allow step first then turn */
1071 #ifdef gDEBUG
1072 		(void) printf("state %d, col %d, row %d, stack %d",
1073 			anant->state, anant->col, anant->row, anant->stack);
1074 #endif
1075 		positionOfNeighbor(ap, anant->direction,
1076 			&(anant->col), &(anant->row), &(anant->stack));
1077 		SetList3D(anant->col, anant->row, anant->stack,
1078 			NCOLORS);
1079 		ap->antList[i] = ap->ptrend;
1080 	}
1081 	/*condenseList(ap);*/
1082 #ifndef BLACK_CELLS
1083 	eraseEmpty(ap);
1084 #endif
1085 	return True;
1086 }
1087 
1088 #if 0
1089 static int
1090 CountCells3D(antfarm3dstruct * ap)
1091 {
1092 	antstruct  *ptr;
1093 	int         count = 0;
1094 
1095 	ptr = ap->ptrhead;
1096 	while (ptr != NULL) {
1097 		++count;
1098 		ptr = ptr->next;
1099 	}
1100 	return count;
1101 }
1102 
1103 void
1104 DisplayList(antfarm3dstruct * ap)
1105 {
1106 	antstruct  *ptr;
1107 	int         count = 0;
1108 
1109 	ptr = ap->ptrhead;
1110 	while (ptr != NULL) {
1111 		(void) printf("(%x)=[%d,%d,%d] ", (int) ptr,
1112 			ptr->x, ptr->y, ptr->z);
1113 		ptr = ptr->next;
1114 		++count;
1115 	}
1116 	(void) printf("Living cells = %d\n", count);
1117 }
1118 
1119 #endif
1120 
1121 static void
getTable(ModeInfo * mi,int i)1122 getTable(ModeInfo * mi, int i)
1123 {
1124 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1125 	int         j, total;
1126 	unsigned char *patptr;
1127 	statestruct *status;
1128 
1129 	patptr = &tables[i][0];
1130 	ap->ncolors = *patptr++;
1131 	ap->nstates = *patptr++;
1132 	total = ap->ncolors * ap->nstates;
1133 	if (MI_IS_VERBOSE(mi))
1134 		(void) fprintf(stdout,
1135 			"ants %d, table number %d, colors %d, states %d\n",
1136 			ap->n, i, ap->ncolors, ap->nstates);
1137 	if (label)
1138 		(void) sprintf(ap->ruleString, "%d table number %d", ap->n, i);
1139 	for (j = 0; j < total; j++) {
1140 		status = &(ap->machine[j]);
1141 		status->color = *patptr++;
1142 		status->turn = *patptr++;
1143 		status->next = *patptr++;
1144 #ifdef DEBUG
1145 		(void) printf("Status: color %d, turn %d, colors %d\n",
1146 			status->color, status->turn, ap->ncolors);
1147 #endif
1148 	}
1149 }
1150 
1151 static void
getTurk(ModeInfo * mi,int logClass,int number)1152 getTurk(ModeInfo * mi, int logClass, int number)
1153 {
1154 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1155 	int power4, j, total;
1156 	char rule[NCOLORS * STATES + 1];
1157 
1158 #ifdef DEBUG
1159 	(void) printf("logClass %d, number %d\n", logClass, number);
1160 #endif
1161 	power4 = 1 << ((logClass - 1) << 1);
1162 	ap->ncolors = logClass;
1163 	ap->nstates = 1;
1164 	total = ap->ncolors * ap->nstates;
1165 	for (j = 0; j < total; j++) {
1166 		ap->machine[j].color = (j + 1) % total;
1167 		ap->machine[j].turn = ((power4 * 3) & number) / power4;
1168 		rule[j] = ap->machine[j].turn + '0';
1169 		ap->machine[j].next = 0;
1170 		power4 >>= 2;
1171 	}
1172 	rule[total] = '\0';
1173 	if (MI_IS_VERBOSE(mi))
1174 		(void) fprintf(stdout,
1175 	 		"ants %d, Turk's number 0x%x (0%s)B4, colors %d\n",
1176 			ap->n, number, rule, ap->ncolors);
1177 	if (label)
1178 		(void) sprintf(ap->ruleString, "%d Turk's number 0x%x",
1179 			ap->n, number);
1180 }
1181 
1182 static void
parseRule(ModeInfo * mi)1183 parseRule(ModeInfo * mi)
1184 {
1185 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1186 
1187 	if (rule) {
1188 		int n = 0, l, number = 0, logClass = 0, power4;
1189 		int bucket[4];
1190 
1191 		bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
1192 		while (rule[n]) {
1193 			if (rule[n] == 'T' || rule[n] == 't') {
1194 				n++;
1195 				while (rule[n]) {
1196 					number = number * 10 +
1197 						(int) (rule[n] - '0');
1198 					n++;
1199 				}
1200 				getTable(mi, number);
1201 				return;
1202 			}
1203 			if (rule[n] == 'A' || rule[n] == 'a') {
1204 				if (!NRAND(2 * NUMSTIPPLES)) {
1205 					getTable(mi, (int) (NRAND(NTABLES)));
1206 					return;
1207 				} else {
1208 					int mask = 3, shiftNumber, j;
1209 
1210 					logClass = (int) (NRAND(NUMSTIPPLES - 4)) + 4;
1211 					/* <logClass = 4;> has 4 quadranary digits */
1212 					power4 = 1 << (2 * (logClass - 1));
1213 					do {
1214 						bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
1215 						number = NRAND(power4 - 1) + power4 *
1216 						((ap->neighbors == 12) ? 1 : (NRAND(3) + 1));
1217 						/* leading 2 or 3 just cause boring spirals */
1218 #ifdef DEBUG
1219 						(void) printf("number 0x%x, power4 0x%x, logClass %d\n",
1220 							number, power4, logClass);
1221 #endif
1222 						/* Want to make sure 3 of 4 quadranary digits are here */
1223 						shiftNumber = number;
1224 						for (j = 0; j < logClass; j++) {
1225 							bucket[mask & shiftNumber]++;
1226 							shiftNumber = shiftNumber >> 2;
1227 						}
1228 #ifdef DEBUG
1229 						(void) printf("Buckets: %d %d %d %d\n",
1230 							bucket[0], bucket[1], bucket[2], bucket[3]);
1231 #endif
1232 					} while ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
1233 						 (!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
1234 						 (!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3]));
1235 
1236 					getTurk(mi, logClass, number);
1237 					return;
1238 				}
1239 			} else {
1240 				l = rule[n] - '0';
1241 				if (l >= 0 && l <= 3) {
1242 					number = (number << 2) + l;
1243 					if (logClass > 0 || l != 0)
1244 						logClass++;
1245 					bucket[l]++;
1246 				}
1247 			}
1248 			n++;
1249 		}
1250 #ifdef DEBUG
1251 		(void) printf("Buckets: %d %d %d %d\n",
1252 			bucket[0], bucket[1], bucket[2], bucket[3]);
1253 #endif
1254 		if ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
1255 			(!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
1256 			(!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3])) {
1257 			if (ap->neighbors == 12) {
1258 				switch (NRAND(5)) {
1259 				case 0: getTurk(mi, 3, 0x12);
1260 					break;
1261 				case 1: getTurk(mi, 3, 0x13);
1262 					break;
1263 				case 2: getTurk(mi, 3, 0x18);
1264 					break;
1265 				case 3: getTurk(mi, 3, 0x1b);
1266 					break;
1267 				default: getTurk(mi, 4, 0x47);
1268 					break;
1269 				}
1270 			} else {
1271 				switch (NRAND(7)) {
1272 				case 0: getTurk(mi, 3, 0x12);
1273 					break;
1274 				case 1: getTurk(mi, 3, 0x13);
1275 					break;
1276 				case 2: getTurk(mi, 3, 0x18);
1277 					break;
1278 				case 3: getTurk(mi, 3, 0x1b);
1279 					break;
1280 				case 4: getTurk(mi, 3, 0x21);
1281 					break;
1282 				case 5: getTurk(mi, 3, 0x27);
1283 					break;
1284 				default: getTurk(mi, 3, 0x2d);
1285 					break;
1286 				}
1287 			}
1288 		} else {
1289 			getTurk(mi, logClass, number);
1290 		}
1291 	}
1292 }
1293 
1294 static void
NewViewpoint(antfarm3dstruct * ap,double x,double y,double z)1295 NewViewpoint(antfarm3dstruct * ap, double x, double y, double z)
1296 {
1297 	double      k, l, d1, d2;
1298 
1299 	k = x * x + y * y;
1300 	l = sqrt(k + z * z);
1301 	k = sqrt(k);
1302 	d1 = (EyeToScreen / HalfScreenD);
1303 	d2 = EyeToScreen / (HalfScreenD * ap->height / ap->width);
1304 	ap->A = d1 * l * (ap->width / 2) / k;
1305 	ap->B = l * l;
1306 	ap->C = d2 * (ap->height / 2) / k;
1307 	ap->F = k * k;
1308 }
1309 
1310 
1311 static void
lissajous(antfarm3dstruct * ap)1312 lissajous(antfarm3dstruct * ap)
1313 {
1314 	double alt, azm, dist;
1315 
1316 	alt = 44.0 * sin(ap->metaAlt * IP) + 45.0;
1317 	ap->metaAlt += 1.123;
1318 	if (ap->metaAlt >= 360.0)
1319 		ap->metaAlt -= 360.0;
1320 	if (ap->metaAlt < 0.0)
1321 		ap->metaAlt += 360.0;
1322 	azm = 44.0 * sin(ap->metaAzm * IP) + 45.0;
1323 	ap->metaAzm += 0.987;
1324 	if (ap->metaAzm >= 360.0)
1325 		ap->metaAzm -= 360.0;
1326 	if (ap->metaAzm < 0.0)
1327 		ap->metaAzm += 360.0;
1328 	dist = 10.0 * sin(ap->metaDist * IP) + 50.0;
1329 	ap->metaDist += 1.0;
1330 	if (ap->metaDist >= 360.0)
1331 		ap->metaDist -= 360.0;
1332 	if (ap->metaDist < 0.0)
1333 		ap->metaDist += 360.0;
1334 #if 0
1335 	if (alt >= 90.0)
1336 		alt = 90.0;
1337 	else if (alt < -90.0)
1338 		alt = -90.0;
1339 #endif
1340 	ap->azm = azm;
1341 #ifdef FDEBUG
1342 	(void) printf("dist %g, alt %g, azm %g\n", dist, alt, azm);
1343 #endif
1344 	ap->vx = (sin(azm * IP) * cos(alt * IP) * dist);
1345 	ap->vy = (cos(azm * IP) * cos(alt * IP) * dist);
1346 	ap->vz = (sin(alt * IP) * dist);
1347 	NewViewpoint(ap, ap->vx, ap->vy, ap->vz);
1348 }
1349 
1350 static void
NewPoint(antfarm3dstruct * ap,double x,double y,double z,register XPoint * pts)1351 NewPoint(antfarm3dstruct * ap, double x, double y, double z,
1352 	 register XPoint * pts)
1353 {
1354 	double      p1, E;
1355 
1356 	p1 = x * ap->vx + y * ap->vy;
1357 	E = ap->B - p1 - z * ap->vz;
1358 	pts->x = (int) (ap->width / 2 -
1359 		ap->A * (ap->vx * y - ap->vy * x) / E);
1360 	pts->y = (int) (ap->height / 2 -
1361 		ap->C * (z * ap->F - ap->vz * p1) / E);
1362 }
1363 
1364 
1365 /* Chain together all cells that are at the same distance.
1366  * These cannot mutually overlap. */
1367 static void
SortList(antfarm3dstruct * ap)1368 SortList(antfarm3dstruct * ap)
1369 {
1370 	short       dist;
1371 	double      d, col, row, stack, rsize;
1372 	int         i, r;
1373 	XPoint      point;
1374 	antstruct  *ptr;
1375 
1376 	for (i = 0; i < NBUCKETS; ++i)
1377 		ap->buckethead[i] = ap->bucketend[i] = NULL;
1378 
1379 	/* Calculate distances and re-arrange pointers to chain off buckets */
1380 	ptr = ap->ptrhead;
1381 	while (ptr != NULL) {
1382 
1383 		col = (double) ptr->col - ap->ox;
1384 		row = (double) ptr->row - ap->oy;
1385 		stack = (double) ptr->stack - ap->oz;
1386 		d = Distance(ap->vx, ap->vy, ap->vz, col, row, stack);
1387 		if (ap->vx * (ap->vx - col) + ap->vy * (ap->vy - row) +
1388 		    ap->vz * (ap->vz - stack) > 0 && d > 1.5)
1389 			ptr->visible = 1;
1390 		else
1391 			ptr->visible = 0;
1392 
1393 		ptr->dist = (short) d;
1394 		dist = (short) (d * BUCKETSIZE);
1395 		if (dist > NBUCKETS - 1)
1396 			dist = NBUCKETS - 1;
1397 
1398 		if (ap->buckethead[dist] == NULL) {
1399 			ap->buckethead[dist] = ap->bucketend[dist] = ptr;
1400 			ptr->priority = NULL;
1401 		} else {
1402 			ap->bucketend[dist]->priority = ptr;
1403 			ap->bucketend[dist] = ptr;
1404 			ap->bucketend[dist]->priority = NULL;
1405 		}
1406 		ptr = ptr->next;
1407 	}
1408 
1409 	/* Check for invisibility */
1410 	rsize = 0.47 * ap->width / ((double) HalfScreenD * 2);
1411 	i = (int) ap->azm;
1412 	if (i < 0)
1413 		i = -i;
1414 	i = i % RT_ANGLE;
1415 	if (i > HALFRT_ANGLE)
1416 		i = RT_ANGLE - i;
1417 	rsize /= cos(i * IP);
1418 
1419 	for (i = 0; i < NBUCKETS; ++i)
1420 		if (ap->buckethead[i] != NULL) {
1421 			ptr = ap->buckethead[i];
1422 			while (ptr != NULL) {
1423 				if (ptr->visible) {
1424 					col = (double) ptr->col - ap->ox;
1425 					row = (double) ptr->row - ap->oy;
1426 					stack = (double) ptr->stack - ap->oz;
1427 					NewPoint(ap, col, row, stack, &point);
1428 
1429 					r = (int) (rsize *
1430 						(double) EyeToScreen /
1431 						(double) ptr->dist);
1432 					if (point.x + r < 0 ||
1433 					    point.y + r < 0 ||
1434 					    point.x - r >= ap->width ||
1435 					    point.y - r >= ap->height) {
1436 						ap->nInvisible++;
1437 					} else if (ap->nInvisible) {
1438 						ap->nInvisible = 0;
1439 					}
1440 				}
1441 				ptr = ptr->priority;
1442 			}
1443 		}
1444 }
1445 
1446 static void
DrawEyes(ModeInfo * mi,int color,XPoint * pts,int p1,int p2,int p3,int p4)1447 DrawEyes(ModeInfo * mi, int color, XPoint * pts,
1448 		int p1, int p2, int p3, int p4)
1449 {
1450 	Display    *display = MI_DISPLAY(mi);
1451 	GC          gc;
1452 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1453 	XPoint      facepts[5];
1454 	XPoint      av;
1455 
1456 	av.x = (pts[p1].x + pts[p2].x + pts[p3].x + pts[p4].x) / 4;
1457 	av.y = (pts[p1].y + pts[p2].y + pts[p3].y + pts[p4].y) / 4;
1458 	facepts[0] = pts[p1];
1459 	facepts[1] = pts[p2];
1460 	facepts[2] = pts[p3];
1461 	facepts[3] = pts[p4];
1462 	facepts[4] = pts[p1];
1463 	facepts[0].x = (av.x + facepts[0].x) / 2;
1464 	facepts[0].y = (av.y + facepts[0].y) / 2;
1465 	facepts[1].x = (av.x + facepts[1].x) / 2;
1466 	facepts[1].y = (av.y + facepts[1].y) / 2;
1467 	facepts[2].x = (av.x + facepts[2].x) / 2;
1468 	facepts[2].y = (av.y + facepts[2].y) / 2;
1469 	facepts[3].x = (av.x + facepts[3].x) / 2;
1470 	facepts[3].y = (av.y + facepts[3].y) / 2;
1471 	facepts[4].x = (av.x + facepts[4].x) / 2;
1472 	facepts[4].y = (av.y + facepts[4].y) / 2;
1473 
1474 	if (color == NCOLORS) {
1475 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
1476 		gc = MI_GC(mi);
1477 	} else if (!color) {
1478 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
1479 		gc = MI_GC(mi);
1480 	} else if (MI_NPIXELS(mi) > 2) {
1481 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
1482 			MI_PIXEL(mi, ap->colors[color - 1]));
1483 		gc = MI_GC(mi);
1484 	} else {
1485 		XGCValues   gcv;
1486 
1487 		gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
1488 		gcv.foreground = MI_WHITE_PIXEL(mi);
1489 		gcv.background = MI_BLACK_PIXEL(mi);
1490 		XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
1491 			GCStipple | GCForeground | GCBackground, &gcv);
1492 		gc = ap->stippledGC;
1493 	}
1494 	if (!ap->wireframe)
1495 		XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
1496 			Convex, CoordModeOrigin);
1497 	gc = MI_GC(mi);
1498 	if (!ap->wireframe) {
1499 		if (color == NCOLORS) {
1500 			XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1501 		} else {
1502 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1503 		}
1504 	}
1505 	XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5,
1506 		CoordModeOrigin);
1507 }
1508 
1509 static void
drawQuad(ModeInfo * mi,int dir,int color,antstruct * cell,XPoint * pts,int p1,int p2,int p3,int p4)1510 drawQuad(ModeInfo * mi, int dir, int color, antstruct * cell, XPoint * pts,
1511 		int p1, int p2, int p3, int p4)
1512 {
1513 	Display    *display = MI_DISPLAY(mi);
1514 	GC          gc;
1515 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1516 	XPoint      facepts[5];
1517 
1518 	facepts[0] = pts[p1];
1519 	facepts[1] = pts[p2];
1520 	facepts[2] = pts[p3];
1521 	facepts[3] = pts[p4];
1522 	facepts[4] = pts[p1];
1523 
1524 	if (color == NCOLORS) {
1525 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
1526 		gc = MI_GC(mi);
1527 	} else if (!color) {
1528 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
1529 		gc = MI_GC(mi);
1530 	} else if (MI_NPIXELS(mi) > 2) {
1531 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
1532 			MI_PIXEL(mi, ap->colors[color - 1]));
1533 		gc = MI_GC(mi);
1534 	} else {
1535 		XGCValues   gcv;
1536 
1537 		gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
1538 		gcv.foreground = MI_WHITE_PIXEL(mi);
1539 		gcv.background = MI_BLACK_PIXEL(mi);
1540 		XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
1541 			GCStipple | GCForeground | GCBackground, &gcv);
1542 		gc = ap->stippledGC;
1543 	}
1544 	if (!ap->wireframe)
1545 		XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
1546 			Convex, CoordModeOrigin);
1547 	gc = MI_GC(mi);
1548 	if (!ap->wireframe) {
1549 		if (color == NCOLORS) {
1550 			XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1551 		} else {
1552 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1553 		}
1554 	}
1555 	XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5, CoordModeOrigin);
1556 	if (!ap->wireframe && ap->eyes && color == NCOLORS && dir >= 0) {
1557 		antstruct  *anant;
1558 		int i;
1559 
1560 		for (i = 0; i < ap->n; i++) {
1561 			anant = &ap->ants[i];
1562 			if (anant->col == cell->col &&
1563 					anant->row == cell->row &&
1564 					anant->stack == cell->stack) {
1565 #if 0
1566 				(void) printf("%d: direction %d, gravity %d\n",
1567 					i, anant->direction, anant->gravity);
1568 #endif
1569 				/* TODO: use gravity to position better eyes */
1570 				if (anant->direction == dir)
1571 					DrawEyes(mi, 0, pts, p1, p2, p3, p4);
1572 			}
1573 		}
1574 	}
1575 }
1576 
1577 #define LEN 0.45
1578 #define LEN2 0.9
1579 
1580 static int
DrawCube(ModeInfo * mi,antstruct * cell)1581 DrawCube(ModeInfo * mi, antstruct * cell)
1582 {
1583 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1584 	XPoint pts[8];	/* screen coords for point */
1585 	int i = 0, out = 0;
1586 	unsigned int mask;
1587 	double x, y, z;
1588 	double dx, dy, dz;
1589 	int color = cell->color;
1590 
1591 	x = (double) cell->col - ap->ox;
1592 	y = (double) cell->row - ap->oy;
1593 	z = (double) cell->stack - ap->oz;
1594 	for (dz = z - LEN; dz <= z + LEN2; dz += LEN2)
1595 		for (dy = y - LEN; dy <= y + LEN2; dy += LEN2)
1596 			for (dx = x - LEN; dx <= x + LEN2; dx += LEN2) {
1597 				NewPoint(ap, dx, dy, dz, &pts[i]);
1598 				if (pts[i].x < 0 ||
1599 				    pts[i].x >= ap->width ||
1600 				    pts[i].y < 0 ||
1601 				    pts[i].y >= ap->height)
1602 					++out;
1603 				++i;
1604 			}
1605 	if (out == 8)
1606 		return (0);
1607 
1608 	if (cell->visible)
1609 		mask = 0xFFFF;
1610 	else
1611 		mask = 0x0;
1612 
1613 	/* Only draw those faces that are visible */
1614 	dx = ap->vx - x;
1615 	dy = ap->vy - y;
1616 	dz = ap->vz - z;
1617 	/*
1618 		6----7
1619 	       /    /|
1620 	      /    / |
1621 	     2----3  |
1622 	    |  4 |  5
1623 	    |    | /
1624 	    0____1/
1625 	*/
1626 	if (ap->wireframe) {
1627 		if (dz <= LEN)
1628 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 4, 5, 7, 6);
1629 		else if (dz >= -LEN)
1630 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 1, 3, 2);
1631 		if (dx <= LEN)
1632 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 3, 7, 5);
1633 		else if (dx >= -LEN)
1634 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 2, 6, 4);
1635 		if (dy <= LEN)
1636 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 3, 7, 6);
1637 		else if (dy >= -LEN)
1638 			drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 1, 5, 4);
1639 	}
1640 	if (dz > LEN)
1641 		drawQuad(mi, ZP, (int) (color & mask), cell, pts, 4, 5, 7, 6);
1642 	else if (dz < -LEN)
1643 		drawQuad(mi, ZN, (int) (color & mask), cell, pts, 0, 1, 3, 2);
1644 	if (dx > LEN)
1645 		drawQuad(mi, XP, (int) (color & mask), cell, pts, 1, 3, 7, 5);
1646 	else if (dx < -LEN)
1647 		drawQuad(mi, XN, (int) (color & mask), cell, pts, 0, 2, 6, 4);
1648 	if (dy > LEN)
1649 		drawQuad(mi, YP, (int) (color & mask), cell, pts, 2, 3, 7, 6);
1650 	else if (dy < -LEN)
1651 		drawQuad(mi, YN, (int) (color & mask), cell, pts, 0, 1, 5, 4);
1652 	return (1);
1653 }
1654 
1655 static int
DrawRhombicDodecahedron(ModeInfo * mi,antstruct * cell)1656 DrawRhombicDodecahedron(ModeInfo * mi, antstruct * cell)
1657 {
1658 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1659 	XPoint pts[14];	/* screen coords for point */
1660 	int i, out = 0, da, db, sortx, sorty, sortz; unsigned int mask;
1661 	double x, y, z;
1662 	double dx, dy, dz;
1663 	int color;
1664 
1665 	x = (double) cell->col - ap->ox;
1666 	y = (double) cell->row - ap->oy;
1667 	z = (double) cell->stack - ap->oz;
1668 	color = cell->color;
1669 	i = 3;
1670 	for (dx = x + LEN; dx >= x - LEN2; dx -= LEN2)
1671 		for (dy = y + LEN; dy >= y - LEN2; dy -= LEN2)
1672 			for (dz = z + LEN; dz >= z - LEN2; dz -= LEN2) {
1673 				NewPoint(ap, dx, dy, dz, &pts[i]);
1674 				if (pts[i].x < 0 ||
1675 				    pts[i].x >= ap->width ||
1676 				    pts[i].y < 0 ||
1677 				    pts[i].y >= ap->height)
1678 					++out;
1679 				++i;
1680 			}
1681 	for (da = 0; da < 2; da++) {
1682 		if (da == 1) {
1683 			i = 0;
1684 		} else
1685 			i = 11; /* 3 + 8 */
1686 		for (db = 0; db < 3; db++) {
1687 			if (db == 0) {
1688 				dx = ((da == 0) ? -LEN2 : LEN2) + x;
1689 				dy = y;
1690 				dz = z;
1691 			} else if (db == 1) {
1692 				dy = ((da == 0) ? -LEN2 : LEN2) + y;
1693 				dz = z;
1694 				dx = x;
1695 			} else {
1696 				dz = ((da == 0) ? -LEN2 : LEN2) + z;
1697 				dx = x;
1698 				dy = y;
1699 			}
1700 			NewPoint(ap, dx, dy, dz, &pts[i]);
1701 			if (pts[i].x < 0 ||
1702 			    pts[i].x >= ap->width ||
1703 			    pts[i].y < 0 ||
1704 			    pts[i].y >= ap->height)
1705 				++out;
1706 			++i;
1707 		}
1708 	}
1709 	if (out == 14)
1710 		return (0);
1711 
1712 	if (cell->visible)
1713 		mask = 0xFFFF;
1714 	else
1715 		mask = 0x0;
1716 
1717 	/* Only draw those faces that are visible */
1718 	dx = ap->vx - x;
1719 	dy = ap->vy - y;
1720 	dz = ap->vz - z;
1721 	/* back points looking through front
1722 	   8   1  4
1723 	     7  3
1724 	  11   2  0
1725 	     9  5
1726 	  10  12  6
1727 	  ---------
1728 	   front points
1729 	  7    1  3
1730 	     8  4
1731 	  11  13  0
1732 	    10  6
1733 	  9   12  5
1734 	*/
1735 	if (ap->wireframe) {
1736 		if (dx <= LEN) {
1737 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1738 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1739 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1740 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1741 		} else if (dx >= -LEN) {
1742 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1743 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1744 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1745 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1746 		}
1747 		if (dy <= LEN) {
1748 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1749 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1750 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1751 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1752 		} else if (dy >= -LEN) {
1753 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1754 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1755 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1756 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1757 		}
1758 		if (dz <= LEN) {
1759 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1760 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1761 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1762 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1763 		} else if (dz >= -LEN) {
1764 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1765 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1766 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1767 		drawQuad(mi, -1, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1768 		}
1769 	}
1770 	sortx = sorty = sortz = 0;
1771 	if (ABS(dz - LEN) > ABS(dy - LEN))
1772 		sortz++;
1773 	if (ABS(dz - LEN) > ABS(dx - LEN))
1774 		sortz++;
1775 	if (ABS(dy - LEN) > ABS(dx - LEN))
1776 		sorty++;
1777 	if (ABS(dy - LEN) > ABS(dz - LEN))
1778 		sorty++;
1779 	if (ABS(dx - LEN) > ABS(dz - LEN))
1780 		sortx++;
1781 	if (ABS(dx - LEN) > ABS(dy - LEN))
1782 		sortx++;
1783 	for (i = 0; i < 3; i++) {
1784 	  if (sortx == i) {
1785 	    if (dx > LEN) {
1786 	      if (sortz > sorty) {
1787 		if (dz < 0)
1788 		  drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1789 		else
1790 		  drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1791 		drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1792 		drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1793 		if (dz < 0)
1794 		  drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1795 		else
1796 		  drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1797 	      } else {
1798 		if (dy < 0)
1799 		  drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1800 		else
1801 		  drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1802 		drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1803 		drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1804 		if (dy < 0)
1805 		  drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1806 		else
1807 		  drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1808 	      }
1809 	    } else if (dx < -LEN) {
1810 	      if (sortz > sorty) {
1811 		if (dz < 0)
1812 		  drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1813 		else
1814 		  drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1815 		drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1816 		drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1817 		if (dz < 0)
1818 		  drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1819 		else
1820 		  drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1821 	      } else {
1822 		if (dy < 0)
1823 		  drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1824 		else
1825 	  	  drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1826 		drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1827 		drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1828 		if (dy < 0)
1829 	  	  drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1830 		else
1831 		  drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1832 	      }
1833 	    }
1834 	  }
1835 	  if (sorty == i) {
1836 	    if (dy > LEN) {
1837 	      if (sortx > sortz) {
1838 		if (dx < 0)
1839 		  drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1840 		else
1841 		  drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1842 		drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1843 		drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1844 		if (dx < 0)
1845 		  drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1846 		else
1847 		  drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1848 	      } else {
1849 		if (dz < 0)
1850 		  drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1851 		else
1852 		  drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1853 		drawQuad(mi, XNYP, (int) (color & mask), cell, pts, 1, 8, 11, 7);
1854 		drawQuad(mi, XPYP, (int) (color & mask), cell, pts, 0, 4, 1, 3);
1855 		if (dz < 0)
1856 		  drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1857 		else
1858 		  drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1859 	      }
1860 	    } else if (dy < -LEN) {
1861 	      if (sortx > sortz) {
1862 		if (dx < 0)
1863 		  drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1864 		else
1865 		  drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1866 		drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1867 		drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1868 		if (dx < 0)
1869 		  drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1870 		else
1871 		  drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1872 	      } else {
1873 		if (dz < 0)
1874 		  drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1875 		else
1876 		  drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1877 		drawQuad(mi, XNYN, (int) (color & mask), cell, pts, 9, 11, 10, 12);
1878 		drawQuad(mi, XPYN, (int) (color & mask), cell, pts, 0, 5, 12, 6);
1879 		if (dz < 0)
1880 		  drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1881 		else
1882 		  drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1883 	      }
1884 	    }
1885 	  }
1886 	  if (sortz == i) {
1887 	    if (dz > LEN) {
1888 	      if (sorty > sortx) {
1889 		if (dy < 0)
1890 		  drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1891 		else
1892 		  drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1893 		drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1894 		drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1895 		if (dy < 0)
1896 		  drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1897 		else
1898 		  drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1899 	      } else {
1900 		if (dx < 0)
1901 		  drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1902 		else
1903 		  drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1904 		drawQuad(mi, YNZP, (int) (color & mask), cell, pts, 2, 9, 12, 5);
1905 		drawQuad(mi, YPZP, (int) (color & mask), cell, pts, 1, 7, 2, 3);
1906 		if (dx < 0)
1907 		  drawQuad(mi, ZPXN, (int) (color & mask), cell, pts, 2, 7, 11, 9);
1908 		else
1909 		  drawQuad(mi, ZPXP, (int) (color & mask), cell, pts, 0, 3, 2, 5);
1910 	      }
1911 	    } else if (dz < -LEN) {
1912 	      if (sorty > sortx) {
1913 		if (dy < 0)
1914 		  drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1915 		else
1916 		  drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1917 		drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1918 		drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1919 		if (dy < 0)
1920 		  drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1921 		else
1922 		  drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1923 	      } else {
1924 		if (dx < 0)
1925 		  drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1926 		else
1927 		  drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1928 		drawQuad(mi, YNZN, (int) (color & mask), cell, pts, 6, 12, 10, 13);
1929 		drawQuad(mi, YPZN, (int) (color & mask), cell, pts, 1, 4, 13, 8);
1930 		if (dx < 0)
1931 		  drawQuad(mi, ZNXN, (int) (color & mask), cell, pts, 8, 13, 10, 11);
1932 		else
1933 		  drawQuad(mi, ZNXP, (int) (color & mask), cell, pts, 0, 6, 13, 4);
1934 	      }
1935 	    }
1936 	  }
1937 	}
1938 	return (1);
1939 }
1940 
1941 static void
DrawScreen(ModeInfo * mi)1942 DrawScreen(ModeInfo * mi)
1943 {
1944 	antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
1945 	Display    *display = MI_DISPLAY(mi);
1946 	GC          gc = MI_GC(mi);
1947 	antstruct  *ptr;
1948 	antstruct  *eraserptr;
1949 	int         i;
1950 
1951 	SortList(ap);
1952 
1953 	XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1954 	XFillRectangle(display, (Drawable) ap->dbuf, gc, 0, 0,
1955 		ap->width, ap->height);
1956 
1957 	/* Erase dead cubes */
1958 	eraserptr = ap->eraserhead.next;
1959 	while (eraserptr != &ap->eraserend) {
1960 		eraserptr->visible = 0;
1961 		if (ap->neighbors == 12)
1962 			(void) DrawRhombicDodecahedron(mi, eraserptr);
1963 		else
1964 			(void) DrawCube(mi, eraserptr);
1965 		DelFromEraseList(eraserptr);
1966 		eraserptr = ap->eraserhead.next;
1967 	}
1968 
1969 	/* draw furthest cubes first */
1970 	for (i = NBUCKETS - 1; i >= 0; --i) {
1971 		ptr = ap->buckethead[i];
1972 		while (ptr != NULL) {
1973 			if (ap->neighbors == 12)
1974 				(void) DrawRhombicDodecahedron(mi, ptr);
1975 			else
1976 			/*if (ptr->visible) */
1977 			/* v += */ (void) DrawCube(mi, ptr);
1978 			ptr = ptr->priority;
1979 			/* ++count; */
1980 		}
1981 	}
1982 	if (label) {
1983 		int size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
1984 
1985 		if (size >= 10 * FONT_WIDTH) {
1986 			/* hard code these to corners */
1987 			XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1988 			/*XDrawString(display, ap->dbuf, gc,
1989 				16 + ap->labelOffsetX,
1990 				16 + ap->labelOffsetY + FONT_HEIGHT,
1991 				ap->ruleString, strlen(ap->ruleString)); */
1992 			XDrawString(display, (Drawable) ap->dbuf, gc,
1993 				16 + ap->labelOffsetX, MI_HEIGHT(mi) - 16 -
1994 				ap->labelOffsetY - FONT_HEIGHT / 2,
1995 				ap->ruleString, strlen(ap->ruleString));
1996 		}
1997 	}
1998 	XFlush(display);
1999 	XCopyArea(display, (Drawable) ap->dbuf, MI_WINDOW(mi), gc,
2000 		0, 0, ap->width, ap->height, 0, 0);
2001 #if 0
2002 	{
2003 		int         count = 0, v = 0;
2004 
2005 
2006 		(void) printf("Pop=%-4d  Viewpoint (%3d,%3d,%3d)  Origin (%3d,%3d,%3d)  Mode %dx%d\
2007 (%d,%d) %d\n",
2008 		     count, (int) (ap->vx + ap->ox), (int) (ap->vy + ap->oy),
2009 			      (int) (ap->vz + ap->oz), (int) ap->ox, (int) ap->oy, (int) ap->oz,
2010 			      ap->width, ap->height, ap->alt, ap->azm, v);
2011 	}
2012 #endif
2013 }
2014 
2015 static void
free_ant3d_screen(Display * display,antfarm3dstruct * ap)2016 free_ant3d_screen(Display *display, antfarm3dstruct *ap)
2017 {
2018 	int shade;
2019 
2020 	if (ap == NULL) {
2021 		return;
2022 	}
2023 	if (ap->eraserhead.next != NULL) {
2024 		End3D(ap);
2025 	}
2026 	if (ap->stippledGC != None) {
2027 		XFreeGC(display, ap->stippledGC);
2028 		ap->stippledGC = None;
2029 	}
2030 	for (shade = 0; shade < ap->init_bits; shade++) {
2031 		XFreePixmap(display, ap->pixmaps[shade]);
2032 	}
2033 	ap->init_bits = 0;
2034 	if (ap->dbuf != None) {
2035 		XFreePixmap(display, ap->dbuf);
2036 		ap->dbuf = None;
2037 	}
2038 	if (ap->tape != NULL) {
2039 		free(ap->tape);
2040 		ap->tape = (unsigned char *) NULL;
2041 	}
2042 	if (ap->antList != NULL) {
2043 		free(ap->antList);
2044 		ap->antList = (antstruct **) NULL;
2045 	}
2046 	if (ap->ants != NULL) {
2047 		free(ap->ants);
2048 		ap->ants = (antstruct *) NULL;
2049 	}
2050 	ap = NULL;
2051 }
2052 
2053 ENTRYPOINT void
free_ant3d(ModeInfo * mi)2054 free_ant3d(ModeInfo * mi)
2055 {
2056 	free_ant3d_screen(MI_DISPLAY(mi), &antfarm3ds[MI_SCREEN(mi)]);
2057 }
2058 
2059 ENTRYPOINT void
init_ant3d(ModeInfo * mi)2060 init_ant3d(ModeInfo * mi)
2061 {
2062 	Display *display = MI_DISPLAY(mi);
2063 	Window window = MI_WINDOW(mi);
2064 	antfarm3dstruct *ap;
2065 	int i;
2066 
2067 	MI_INIT(mi, antfarm3ds);
2068 	ap = &antfarm3ds[MI_SCREEN(mi)];
2069 
2070 	ap->nInvisible = 0;
2071 #ifdef DO_STIPPLE
2072 	if (MI_NPIXELS(mi) <= 2) {
2073 		if (ap->stippledGC == None) {
2074 			XGCValues   gcv;
2075 
2076 			gcv.fill_style = FillOpaqueStippled;
2077 			if ((ap->stippledGC = XCreateGC(display, window,
2078 					GCFillStyle, &gcv)) == None) {
2079 				free_ant3d_screen(display, ap);
2080 				return;
2081 			}
2082 		}
2083 		if (ap->init_bits == 0) {
2084 			for (i = 1; i < NUMSTIPPLES; i++) {
2085 				ANT3DBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
2086 			}
2087 		}
2088 	}
2089 #endif /* DO_STIPPLE */
2090 	ap->generation = 0;
2091 	ap->n = MI_COUNT(mi);
2092 	if (ap->n < -MINANTS) {
2093 		/* if ap->n is random ... the size can change */
2094 		if (ap->ants != NULL) {
2095 			free(ap->ants);
2096 			ap->ants = NULL;
2097 		}
2098 		/*ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;*/
2099 		/* skew so that 1 is more likely */
2100 		ap->n = -ap->n - (int) (sqrt(NRAND(ap->n *ap->n - 1))) - 1 +
2101 			MINANTS;
2102 	} else if (ap->n < MINANTS)
2103 		ap->n = MINANTS;
2104 
2105 	for (i = 0; i < NEIGHBORKINDS; i++) {
2106 		if (neighbors == plots[i]) {
2107 			ap->neighbors = plots[i];
2108 			break;
2109 		}
2110 		if (i == NEIGHBORKINDS - 1) {
2111 			ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
2112 			break;
2113 		}
2114 	}
2115 
2116 	if (!ap->eraserhead.next) {
2117 		ap->metaDist = (double) NRAND(360);
2118 		ap->metaAlt = (double) NRAND(360);
2119 		ap->metaAzm = (double) NRAND(360);
2120 		ap->ncols = MAXCOLUMNS;
2121 		ap->nrows = MAXROWS;
2122 		ap->nstacks = MAXSTACKS;
2123 		ap->ox = ap->ncols / 2;
2124 		ap->oy = ap->nrows / 2;
2125 		ap->oz = ap->nstacks / 2;
2126 
2127 		Init3D(ap);
2128 	} else {
2129 		End3D(ap);
2130 	}
2131 	ap->labelOffsetX = NRAND(8);
2132 	ap->labelOffsetY = NRAND(8);
2133 	parseRule(mi);
2134 	if (MI_NPIXELS(mi) > 2) {
2135 		int offset = NRAND(MI_NPIXELS(mi));
2136 
2137 		for (i = 0; i < (int) ap->ncolors - 1; i++) {
2138 			ap->colors[i] = (unsigned char) ((offset +
2139 				(i * MI_NPIXELS(mi) /
2140 				(int) (ap->ncolors - 1))) % MI_NPIXELS(mi));
2141 		}
2142 	}
2143 	if (ap->tape != NULL)
2144 		free(ap->tape);
2145 	if ((ap->tape = (unsigned char *) calloc(
2146 			ap->ncols * ap->nrows * ap->nstacks,
2147 			sizeof (unsigned char))) == NULL) {
2148 		free_ant3d_screen(display, ap);
2149 		return;
2150 	}
2151 	ap->width = MI_WIDTH(mi);
2152 	ap->height = MI_HEIGHT(mi);
2153 	ap->memstart = 1;
2154 	/*ap->tablesMade = 0; */
2155 
2156 	if (MI_IS_FULLRANDOM(mi)) {
2157 		ap->wireframe = (NRAND(8) == 0);
2158 	} else {
2159 		ap->wireframe = MI_IS_WIREFRAME(mi);
2160 	}
2161 
2162 	MI_CLEARWINDOW(mi);
2163 	ap->painted = False;
2164 
2165 	lissajous(ap);
2166 	if (ap->ants == NULL) {
2167 		if ((ap->ants = (antstruct *) malloc(ap->n *
2168 				sizeof (antstruct))) == NULL) {
2169 			free_ant3d_screen(display, ap);
2170 			return;
2171 		}
2172 	}
2173 	if (ap->antList == NULL) {
2174 		if ((ap->antList = (antstruct **) malloc(ap->n *
2175 				sizeof (antstruct *))) == NULL) {
2176 			free_ant3d_screen(display, ap);
2177 			return;
2178 		}
2179 	}
2180 
2181 	for (i = 0; i < ap->n; i++) {
2182 		antstruct *anant = &ap->ants[i];
2183 		anant->col = ap->ncols / 2;
2184 		anant->row = ap->nrows / 2;
2185 		anant->stack = ap->nstacks / 2;
2186 		anant->direction = NRAND((ap->neighbors == 12) ? 12 : 6);
2187 		anant->gravity = NRAND(6);
2188 		if (ap->neighbors == 12) {
2189 			if (anant->direction / 4 == 0) {
2190 				anant->gravity = NRAND(2) + ZN;
2191 			} else if (anant->direction / 4 == 1) {
2192 				anant->gravity = NRAND(2) + XN;
2193 			} else {
2194 				anant->gravity = NRAND(2) + YN;
2195 			}
2196 		} else {
2197 			while ((anant->gravity / 2) % 3 ==
2198 					(anant->direction / 2) % 3)
2199 				anant->gravity = NRAND(6);
2200 		}
2201 		anant->state = 0;
2202 		InitSetList3D(anant->col, anant->row, anant->stack,
2203 			NCOLORS);
2204 		ap->antList[i] = ap->ptrend;
2205 	}
2206 	if (ap->dbuf != None) {
2207 		XFreePixmap(display, ap->dbuf);
2208 		ap->dbuf = None;
2209 	}
2210 	if ((ap->dbuf = XCreatePixmap(display, window,
2211 		ap->width, ap->height, MI_DEPTH(mi))) == None) {
2212 		free_ant3d_screen(display, ap);
2213 		return;
2214 	}
2215 	if (MI_IS_FULLRANDOM(mi)) {
2216 		ap->eyes = (Bool) (LRAND() & 1);
2217 	} else {
2218 		ap->eyes = eyes;
2219 	}
2220 	DrawScreen(mi);
2221 }
2222 
2223 ENTRYPOINT void
draw_ant3d(ModeInfo * mi)2224 draw_ant3d(ModeInfo * mi)
2225 {
2226 	antfarm3dstruct *ap;
2227 
2228 	if (antfarm3ds == NULL)
2229 		return;
2230 	ap = &antfarm3ds[MI_SCREEN(mi)];
2231 	if (ap->eraserhead.next == NULL)
2232 		return;
2233 
2234 	if (!RunAnt3D(ap)) {
2235 		if (ap->eraserhead.next != NULL)
2236 			 End3D(ap);
2237 		return;
2238 	}
2239 	lissajous(ap);
2240 	DrawScreen(mi);
2241 	MI_IS_DRAWN(mi) = True;
2242 
2243 	if (++ap->generation > MI_CYCLES(mi) / ap->n || ap->nInvisible > 32) {
2244 		/*CountCells3D(ap) == 0) */
2245 		init_ant3d(mi);
2246 	} else
2247 		ap->painted = True;
2248 }
2249 
2250 ENTRYPOINT void
release_ant3d(ModeInfo * mi)2251 release_ant3d(ModeInfo * mi)
2252 {
2253 	if (antfarm3ds != NULL) {
2254 		int         screen;
2255 
2256 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
2257 			free_ant3d_screen(MI_DISPLAY(mi), &antfarm3ds[screen]);
2258 		free(antfarm3ds);
2259 		antfarm3ds = (antfarm3dstruct *) NULL;
2260 	}
2261 }
2262 
2263 #ifndef STANDALONE
2264 ENTRYPOINT void
refresh_ant3d(ModeInfo * mi)2265 refresh_ant3d(ModeInfo * mi)
2266 {
2267 	antfarm3dstruct *ap;
2268 
2269 	if (antfarm3ds == NULL)
2270 		return;
2271 	ap = &antfarm3ds[MI_SCREEN(mi)];
2272 
2273 	if (ap->painted) {
2274 		MI_CLEARWINDOW(mi);
2275 	}
2276 }
2277 #endif
2278 
2279 XSCREENSAVER_MODULE ("Ant3d", ant3d)
2280 
2281 #endif /* MODE_ant3d */
2282