xenocara/app/xlockmore/modes/ant3d.c
2006-11-26 11:07:42 +00:00

1521 lines
38 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* ant3d --- Extension to Langton's generalized turing machine ants */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)ant3d.c 5.13 2004/07/23 xlockmore";
#endif
/*-
* Copyright (c) 1999 by David Bagley.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Revision History:
* 28-Jun-2004: A few more features added, need better "eyes" on leading
* cube (instead of a small black face)
* 08-Jun-2004: Resurrected code after seeing Heiko Hamann's "Definition
* Behavior of Langton's Ant in Three Dimensions", Complex
* Systems Volume 14, Issue 3, (2003) pp 264-268
* heiko.hamann AT gmx.de
* 12-Aug-1999: Coded from life3d.c and ant.c probably will not work but...
*/
#ifdef STANDALONE
#define PROGCLASS "Ant3D"
#define HACK_INIT init_ant3d
#define HACK_DRAW draw_ant3d
#define ant3d_opts xlockmore_opts
#define DEFAULTS "*delay: 5000 \n" \
"*count: -3 \n" \
"*cycles: 100000 \n" \
"*ncolors: 200 \n" \
"*wireframe: False \n" \
"*fullrandom: False \n" \
"*verbose: False \n"
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#include "automata.h"
#ifdef MODE_ant3d
#define DEF_LABEL "True"
#define FONT_HEIGHT 19
#define FONT_WIDTH 15
#define DEF_RULE "A" /* All rules */
#define DEF_EYES "False"
static char *rule;
static Bool eyes;
static Bool label;
static XrmOptionDescRec opts[] =
{
{(char *) "-label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+label", (char *) ".ant3d.label", XrmoptionNoArg, (caddr_t) "off"},
{(char *) "-rule", (char *) ".ant3d.rule", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "on"}
,
{(char *) "+eyes", (char *) ".ant3d.eyes", XrmoptionNoArg, (caddr_t) "off"}
};
static argtype vars[] =
{
{(void *) & label, (char *) "label", (char *) "Label", (char *) DEF_LABEL, t_Bool},
{(void *) & rule, (char *) "rule", (char *) "Rule", (char *) DEF_RULE, t_String},
{(void *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool}
};
static OptionStruct desc[] =
{
{(char *) "-/+label", (char *) "turn on/off rule labeling"},
{(char *) "-rule string", (char *) "base 4 string for Turk's Ant"},
{(char *) "-/+eyes", (char *) "turn on/off eyes"}
};
ModeSpecOpt ant3d_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct ant3d_description =
{"ant3d", "init_ant3d", "draw_ant3d", "release_ant3d",
"refresh_ant3d", "init_ant3d", NULL, &ant3d_opts,
5000, -3, 100000, 1, 64, 1.0, "",
"Shows 3D ants", 0, NULL};
#endif
#define ANT3DBITS(n,w,h)\
if ((ap->pixmaps[ap->init_bits]=\
XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
free_ant3d(display,ap); return;} else {ap->init_bits++;}
/* If you change the table you may have to change the following 2 constants */
#define STATES 2
#define MINANTS 1
#define REDRAWSTEP 2000 /* How much tape to draw per cycle */
#define ANGLES 360
/* Don't change these numbers without changing the offset() macro below! */
#define MAXSTACKS 64
#define MAXROWS 128
#define MAXCOLUMNS 128
#define BASESIZE ((MAXCOLUMNS*MAXROWS*MAXSTACKS)>>6)
#define RT_ANGLE 90
#define HALFRT_ANGLE 45
/* Store state of cell in top bit. Reserve low bits for count of living nbrs */
#define Set3D(x,y,z,c) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)
#define Reset3D(x,y,z) SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,0)
#define SetList3D(x,y,z,c) if (!SetMem(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False; \
if (!AddToList(ap,(unsigned int)x,(unsigned int)y,(unsigned int)z,c)) return False
#define EyeToScreen 72.0 /* distance from eye to screen */
#define HalfScreenD 20.0 /* 1/2 the diameter of screen */
#define BUCKETSIZE 10
#define NBUCKETS ((MAXCOLUMNS+MAXROWS+MAXSTACKS)*BUCKETSIZE)
#define Distance(x1,y1,z1,x2,y2,z2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
#define IP (M_PI / 180.0)
#define NCOLORS 14
typedef struct {
unsigned char color;
short turn;
unsigned char next;
} statestruct;
typedef struct _antstruct {
int column, row, stack;
unsigned char color;
char visible;
short direction; /* Direction facing */
short gravity; /* Need to know which way is down */
unsigned char state;
short dist; /* dist from cell to eye */
struct _antstruct *next; /* pointer to next entry on linked list */
struct _antstruct *prev;
struct _antstruct *priority;
} antstruct;
typedef struct {
Bool painted;
int ox, oy, oz; /* origin */
double vx, vy, vz; /* viewpoint */
int generation;
int ncolumns, nrows, nstacks;
int memstart;
unsigned char *base[BASESIZE];
double A, B, C, F;
int width, height;
unsigned char ncolors, nstates;
int n;
double azm;
double metaAlt, metaAzm, metaDist;
antstruct *ants;
antstruct *ptrhead, *ptrend, eraserhead, eraserend;
antstruct *buckethead[NBUCKETS], *bucketend[NBUCKETS];
Bool wireframe, eyes;
Pixmap dbuf;
statestruct machine[NCOLORS * STATES];
unsigned char *tape;
int init_bits;
unsigned long colors[NCOLORS - 1];
GC stippledGC;
Pixmap pixmaps[NCOLORS - 1];
int nInvisible;
int labelOffsetX, labelOffsetY;
char ruleString[40];
} antfarm3dstruct;
/* Coordinate ant moves */
#define NU -1 /* Not used */
#define XN 0
#define XP 1
#define YN 2
#define YP 3
#define ZN 4
#define ZP 5
/* Relative ant moves */
#define TRS 0 /* Turn right, then step */
#define TLS 1 /* Turn left, then step */
#define TUS 2 /* Turn up, then step */
#define TDS 3 /* Turn down, then step */
#define FS 4 /* Step */
#define TBS 5 /* Turn back, then step */
/* Uhhh for completeness I guess there are some yaw moves and a 180 TU */
#define STR 6 /* Step then turn right */
#define STL 7 /* Step then turn left */
#define STU 8 /* Step then turn up */
#define STD 9 /* Step then turn down */
#define SF 10 /* Step */
#define STB 11 /* Step then turn back */
/* turnDirection, oldGravity, oldDirection */
static int newDirectionMap[4][6][6] = {
{ /* TRS */
{NU, NU, ZP, ZN, YN, YP}, /* oldGravity = XN */
{NU, NU, ZN, ZP, YP, YN},
{ZN, ZP, NU, NU, XP, XN}, /* oldGravity = YN */
{ZP, ZN, NU, NU, XN, XP},
{YP, YN, XN, XP, NU, NU}, /* oldGravity = ZN */
{YN, YP, XP, XN, NU, NU}
},
{ /* TLS */
{NU, NU, ZN, ZP, YP, YN}, /* oldGravity = XN */
{NU, NU, ZP, ZN, YN, YP},
{ZP, ZN, NU, NU, XN, XP}, /* oldGravity = YN */
{ZN, ZP, NU, NU, XP, XN},
{YN, YP, XP, XN, NU, NU}, /* oldGravity = ZN */
{YP, YN, XN, XP, NU, NU}
},
{ /* TUS */
{NU, NU, XP, XP, XP, XP}, /* oldGravity = XN */
{NU, NU, XN, XN, XN, XN},
{YP, YP, NU, NU, YP, YP}, /* oldGravity = YN */
{YN, YN, NU, NU, YN, YN},
{ZP, ZP, ZP, ZP, NU, NU}, /* oldGravity = ZN */
{ZN, ZN, ZN, ZN, NU, NU}
},
{ /* TDS */
{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
{NU, NU, XP, XP, XP, XP},
{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
{YP, YP, NU, NU, YP, YP},
{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
{ZP, ZP, ZP, ZP, NU, NU}
}
};
/* turnDirection, oldGravity, oldDirection */
static int newGravityMap[4][6][6] = {
{ /* TRS */
{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
{NU, NU, XP, XP, XP, XP},
{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
{YP, YP, NU, NU, YP, YP},
{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
{ZP, ZP, ZP, ZP, NU, NU}
},
{ /* TLS */
{NU, NU, XN, XN, XN, XN}, /* oldGravity = XN */
{NU, NU, XP, XP, XP, XP},
{YN, YN, NU, NU, YN, YN}, /* oldGravity = YN */
{YP, YP, NU, NU, YP, YP},
{ZN, ZN, ZN, ZN, NU, NU}, /* oldGravity = ZN */
{ZP, ZP, ZP, ZP, NU, NU}
},
{ /* TUS */
{NU, NU, YN, YP, ZN, ZP}, /* oldGravity = XN */
{NU, NU, YN, YP, ZN, ZP},
{XN, XP, NU, NU, ZN, ZP}, /* oldGravity = YN */
{XN, XP, NU, NU, ZN, ZP},
{XN, XP, YN, YP, NU, NU}, /* oldGravity = ZN */
{XN, XP, YN, YP, NU, NU}
},
{ /* TDS */
{NU, NU, YP, YN, ZP, ZN}, /* oldGravity = XN */
{NU, NU, YP, YN, ZP, ZN},
{XP, XN, NU, NU, ZP, ZN}, /* oldGravity = YN */
{XP, XN, NU, NU, ZP, ZN},
{XP, XN, YP, YN, NU, NU}, /* oldGravity = ZN */
{XP, XN, YP, YN, NU, NU}
}
};
static antfarm3dstruct *antfarm3ds = NULL;
static unsigned char tables[][3 * NCOLORS * STATES + 2] =
{
#if 0
/* Generated */
{ /* 0: RLU */
3, 1,
1, TRS, 0, 2, TLS, 0, 0, TUS, 0
},
{ /* 1: RUL */
3, 1,
1, TRS, 0, 2, TUS, 0, 0, TLS, 0
},
{ /* 2: RUD */
3, 1,
1, TRS, 0, 2, TUS, 0, 0, TDS, 0
},
{ /* 3: RLUU */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
},
{ /* 4: RRLU 32 */
4, 1,
1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 0, TUS, 0
},
{ /* 5: RRUL ? */
4, 1,
1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TLS, 0
},
{ /* 6: RRUD 22 */
4, 1,
1, TRS, 0, 2, TRS, 0, 3, TUS, 0, 0, TDS, 0
},
{ /* 7: RLRU 188 */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 0, TUS, 0
},
{ /* 8: RLLU ? */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TLS, 0, 0, TUS, 0
},
{ /* 9: RLUR 46 ! */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TRS, 0
},
{ /* 10: RLUL 32 */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TLS, 0
},
{ /* 11: RLUU 102 */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TUS, 0
},
{ /* 12: RLUD 28 */
4, 1,
1, TRS, 0, 2, TLS, 0, 3, TUS, 0, 0, TDS, 0
},
{ /* 13: RURL 30 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TLS, 0
},
{ /* 14: RURD ? */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TRS, 0, 0, TDS, 0
},
{ /* 15: RULL 22 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TLS, 0
},
{ /* 16: RULR 22 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TRS, 0
},
{ /* 17: RULU 22 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TUS, 0
},
{ /* 18: RUUL 26 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TLS, 0
},
{ /* 19: RULD 22 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TLS, 0, 0, TDS, 0
},
{ /* 20: RUUD 22 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TUS, 0, 0, TDS, 0
},
{ /* 21: RUDR 14 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TRS, 0
},
{ /* 22: RUDL ? */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TLS, 0
},
{ /* 23: RUDU 114 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TUS, 0
},
{ /* 24: RUDD 40 */
4, 1,
1, TRS, 0, 2, TUS, 0, 3, TDS, 0, 0, TDS, 0
},
{ /* 25: RRRULL ? */
6, 1,
1, TRS, 0, 2, TRS, 0, 3, TRS, 0, 4, TUS, 0,
5, TLS, 0, 0, TLS, 0,
}
{ /* 26: RLRUUUL 25436 */
7, 1,
1, TRS, 0, 2, TLS, 0, 3, TRS, 0, 4, TUS, 0,
5, TUS, 0, 6, TUS, 0, 0, TLS, 0,
},
#endif
{ /* 27: RRLDDDULRRLLLL * */
14, 1,
1, TRS, 0, 2, TRS, 0, 3, TLS, 0, 4, TDS, 0,
5, TDS, 0, 6, TDS, 0, 7, TUS, 0, 8, TLS, 0,
9, TRS, 0, 10, TRS, 0, 11, TLS, 0, 12, TLS, 0,
13, TLS, 0, 0, TLS, 0,
}
};
#define NTABLES (sizeof tables / sizeof tables[0])
#ifdef DEBUG
static char * printDir(int d)
{
switch (d) {
case XN: return (char *) "XN";
case XP: return (char *) "XP";
case YN: return (char *) "YN";
case YP: return (char *) "YP";
case ZN: return (char *) "ZN";
case ZP: return (char *) "ZP";
default: return (char *) "NU";
}
}
static char * printTurn(int d)
{
switch (d) {
case TRS: return (char *) "TRS";
case TLS: return (char *) "TLS";
case TUS: return (char *) "TUS";
case TDS: return (char *) "TDS";
default: return (char *) "TXX";
}
}
#endif
static void heading(short * direction, short * gravity, short turn)
{
short oldDirection = *direction;
short oldGravity = *gravity;
if (turn < 6) {
if (turn == TBS) {
if (oldDirection & 1)
*direction = oldDirection - 1;
else
*direction = oldDirection + 1;
} else if (turn < 4) {
*gravity = newGravityMap
[turn][oldGravity][oldDirection];
*direction = newDirectionMap
[turn][oldGravity][oldDirection];
}
}
if (*gravity == NU)
(void) fprintf(stderr, "gravity corruption\n");
if (*direction == NU)
(void) fprintf(stderr, "direction corruption\n");
#ifdef DEBUG
(void) printf(
"odirection %s, ogravity %s, turn %s, direction %s, gravity %s\n",
printDir(oldDirection), printDir(oldGravity),
printTurn(turn), printDir(*direction), printDir(*gravity));
#endif
}
static void
position_of_neighbor(antfarm3dstruct * ap, int dir,
int *pcolumn, int *prow, int *pstack)
{
int column = *pcolumn, row = *prow, stack = *pstack;
switch (dir) {
case XN:
column = (!column) ? ap->ncolumns - 1 : column - 1;
break;
case XP:
column = (column + 1 == ap->ncolumns) ? 0 : column + 1;
break;
case YN:
row = (!row) ? ap->nrows - 1 : row - 1;
break;
case YP:
row = (row + 1 == ap->nrows) ? 0 : row + 1;
break;
case ZN:
stack = (!stack) ? ap->nstacks - 1 : stack - 1;
break;
case ZP:
stack = (stack + 1 == ap->nstacks) ? 0 : stack + 1;
break;
default:
(void) fprintf(stderr, "wrong direction %d\n", dir);
}
*pcolumn = column;
*prow = row;
*pstack = stack;
}
/*--- list ---*/
/* initialise the state of all cells to OFF */
static void
Init3D(antfarm3dstruct * ap)
{
ap->ptrhead = ap->ptrend = NULL;
ap->eraserhead.next = &ap->eraserend;
ap->eraserend.prev = &ap->eraserhead;
}
/*-
* Function that adds the cell (assumed live) at (x,y,z) onto the search
* list so that it is scanned in future generations
*/
static Bool
AddToList(antfarm3dstruct * ap,
unsigned int x, unsigned int y, unsigned int z, unsigned int c)
{
antstruct *tmp;
if ((tmp = (antstruct *) malloc(sizeof (antstruct))) == NULL)
return False;
tmp->column = x;
tmp->row = y;
tmp->stack = z;
tmp->color = c;
if (ap->ptrhead == NULL) {
ap->ptrhead = ap->ptrend = tmp;
tmp->prev = NULL;
} else {
ap->ptrend->next = tmp;
tmp->prev = ap->ptrend;
ap->ptrend = tmp;
}
ap->ptrend->next = NULL;
return True;
}
static void
AddToEraseList(antfarm3dstruct * ap, antstruct * cell)
{
cell->next = &ap->eraserend;
cell->prev = ap->eraserend.prev;
ap->eraserend.prev->next = cell;
ap->eraserend.prev = cell;
}
static void
DelFromList(antfarm3dstruct * ap, antstruct * cell)
{
if (cell != ap->ptrhead) {
cell->prev->next = cell->next;
} else {
ap->ptrhead = cell->next;
if (ap->ptrhead != NULL)
ap->ptrhead->prev = NULL;
}
if (cell != ap->ptrend) {
cell->next->prev = cell->prev;
} else {
ap->ptrend = cell->prev;
if (ap->ptrend != NULL)
ap->ptrend->next = NULL;
}
AddToEraseList(ap, cell);
}
static void
DelFromEraseList(antstruct * cell)
{
cell->next->prev = cell->prev;
cell->prev->next = cell->next;
free(cell);
}
/*--- memory ---*/
/*-
* Simulate a large array by dynamically allocating 4x4x4 size cells when
* needed.
*/
static void
MemInit(antfarm3dstruct * ap)
{
int i;
for (i = 0; i < BASESIZE; ++i) {
if (ap->base[i] != NULL) {
free(ap->base[i]);
ap->base[i] = (unsigned char *) NULL;
}
}
ap->memstart = 0;
}
#define BASE_OFFSET(x,y,z,b,o) \
b = ((x & 0x7c) << 7) + ((y & 0x7c) << 2) + ((z & 0x7c) >> 2); \
o = (x & 3) + ((y & 3) << 2) + ((z & 3) << 4); \
if (ap->base[b] == NULL) {\
if ((ap->base[b] = (unsigned char *) calloc(64, sizeof (unsigned char))) == NULL) {return False;}}
#if 0
static Bool
GetMem(antfarm3dstruct * ap, unsigned int x, unsigned int y, unsigned int z,
int *m)
{
int b, o;
if (ap->memstart) {
MemInit(ap);
}
BASE_OFFSET(x, y, z, b, o);
*m = ap->base[b][o];
return True;
}
#endif
static Bool
SetMem(antfarm3dstruct * ap,
unsigned int x, unsigned int y, unsigned int z, unsigned int val)
{
int b, o;
if (ap->memstart) {
MemInit(ap);
}
BASE_OFFSET(x, y, z, b, o);
ap->base[b][o] = val;
return True;
}
#if 0
static Bool
ChangeMem(antfarm3dstruct * ap,
unsigned int x, unsigned int y, unsigned int z,
unsigned int val)
{
int b, o;
if (ap->memstart) {
MemInit(ap);
}
BASE_OFFSET(x, y, z, b, o);
ap->base[b][o] += val;
return True;
}
#endif
static void
End3D(antfarm3dstruct * ap)
{
antstruct *ptr;
while (ap->ptrhead != NULL) {
/* Reset3D(ap->ptrhead->column, ap->ptrhead->row,
ap->ptrhead->stack); */
DelFromList(ap, ap->ptrhead);
}
ptr = ap->eraserhead.next;
while (ptr != &ap->eraserend) {
DelFromEraseList(ptr);
ptr = ap->eraserhead.next;
}
MemInit(ap);
}
static Bool
RunAnt3D(antfarm3dstruct * ap)
{
antstruct *anant;
statestruct *status;
int i, state_pos, tape_pos;
unsigned char color;
if (ap->ants == NULL)
return False;
ap->painted = True;
for (i = 0; i < ap->n; i++) {
anant = &ap->ants[i];
tape_pos = anant->column + anant->row * ap->ncolumns +
anant->stack * ap->nrows * ap->ncolumns;
color = ap->tape[tape_pos]; /* read tape */
state_pos = color + anant->state * ap->ncolors;
status = &(ap->machine[state_pos]);
#ifdef DEBUG
(void) printf("status: color %d, turn %s, state %d, colors %d\n",
status->color, printTurn(status->turn), anant->state, ap->ncolors);
#endif
SetList3D(anant->column, anant->row, anant->stack,
status->color);
ap->tape[tape_pos] = status->color; /* write on tape */
#ifdef DEBUG
(void) printf("gen %d: ", ap->generation);
#endif
heading(&(anant->direction), &(anant->gravity), status->turn);
/* Find direction of Bees or Ants. */
/* Translate relative direction to actual direction */
/*chg_dir = (2 * ANGLES - status->direction) % ANGLES;
anant->direction = (chg_dir + old_dir) % ANGLES; */
anant->state = status->next;
/* Allow step first then turn */
/*old_dir = ((status->direction < ANGLES) ?
anant->direction : old_dir);*/
#ifdef DEBUG
(void) printf("state %d, column %d, row %d, stack %d",
anant->state, anant->column, anant->row, anant->stack);
#endif
position_of_neighbor(ap, anant->direction,
&(anant->column), &(anant->row), &(anant->stack));
SetList3D(anant->column, anant->row, anant->stack,
NCOLORS);
/*draw_anant(mi, anant->direction,
anant->column, anant->row, anant->stack);*/
}
return True;
}
#if 0
static int
CountCells3D(antfarm3dstruct * ap)
{
antstruct *ptr;
int count = 0;
ptr = ap->ptrhead;
while (ptr != NULL) {
++count;
ptr = ptr->next;
}
return count;
}
void
DisplayList(antfarm3dstruct * ap)
{
antstruct *ptr;
int count = 0;
ptr = ap->ptrhead;
while (ptr != NULL) {
(void) printf("(%x)=[%d,%d,%d] ", (int) ptr,
ptr->x, ptr->y, ptr->z);
ptr = ptr->next;
++count;
}
(void) printf("Living cells = %d\n", count);
}
#endif
static void
getTable(ModeInfo * mi, int i)
{
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
int j, total;
unsigned char *patptr;
statestruct *status;
patptr = &tables[i][0];
ap->ncolors = *patptr++;
ap->nstates = *patptr++;
total = ap->ncolors * ap->nstates;
if (MI_IS_VERBOSE(mi))
(void) fprintf(stdout,
"ants %d, table number %d, colors %d, states %d\n",
ap->n, i, ap->ncolors, ap->nstates);
if (label)
(void) sprintf(ap->ruleString, "table number %d", i);
for (j = 0; j < total; j++) {
status = &(ap->machine[j]);
status->color = *patptr++;
status->turn = *patptr++;
status->next = *patptr++;
#ifdef DEBUG
(void) printf("Status: color %d, turn %d, colors %d\n",
status->color, status->turn, ap->ncolors);
#endif
}
}
static void
getTurk(ModeInfo * mi, int logClass, int number)
{
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
int power4, j, total;
power4 = 1 << (2 * logClass);
ap->ncolors = logClass;
ap->nstates = 1;
total = ap->ncolors * ap->nstates;
for (j = 0; j < total; j++) {
power4 >>= 2;
ap->machine[j].color = (j + 1) % total;
ap->machine[j].turn = ((power4 * 3) & number) / power4;
#ifdef DEBUG
(void) printf("turn %d\n", ap->machine[j].turn);
#endif
ap->machine[j].next = 0;
}
if (MI_IS_VERBOSE(mi))
(void) fprintf(stdout,
"ants %d, Turk's number 0x%x, colors %d\n",
ap->n, number, ap->ncolors);
if (label)
(void) sprintf(ap->ruleString, "Turk's number 0x%x", number);
}
static void
parseRule(ModeInfo * mi)
{
if (rule) {
int n = 0, l, number = 0, logClass = 0, power4;
int bucket[4];
bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
while (rule[n]) {
if (rule[n] == 'T' || rule[n] == 't') {
n++;
while (rule[n]) {
number = number * 10 +
(int) (rule[n] - '0');
n++;
}
getTable(mi, number);
return;
}
if (rule[n] == 'A' || rule[n] == 'a') {
if (!NRAND(NUMSTIPPLES)) {
getTable(mi, (int) (NRAND(NTABLES)));
return;
} else {
int mask = 3, shiftNumber, j;
logClass = (int) (NRAND(NUMSTIPPLES - 4)) + 4;
/* <logClass = 4;> has 4 quadranary digits */
power4 = 1 << (2 * (logClass - 1));
do {
bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
number = NRAND(power4);
#ifdef DEBUG
(void) printf("number 0x%x, power4 0x%x, logClass %d\n",
number, power4, logClass);
#endif
/* Want to make sure 3 of 4 quadranary digits are here */
shiftNumber = number;
for (j = 0; j < logClass - 1; j++) {
bucket[mask & shiftNumber]++;
shiftNumber = shiftNumber >> 2;
}
#ifdef DEBUG
(void) printf("Buckets: %d %d %d %d\n",
bucket[0], bucket[1], bucket[2], bucket[3]);
#endif
} while ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
(!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
(!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3]));
getTurk(mi, logClass, number);
return;
}
} else {
l = rule[n] - '0';
if (l >= 0 && l <= 3) {
number = (number << 2) + l;
if (logClass > 0 || l != 0)
logClass++;
bucket[l]++;
}
}
n++;
}
#ifdef DEBUG
(void) printf("Buckets: %d %d %d %d\n",
bucket[0], bucket[1], bucket[2], bucket[3]);
#endif
if ((!bucket[0] && !bucket[1]) || (!bucket[0] && !bucket[2]) ||
(!bucket[0] && !bucket[3]) || (!bucket[1] && !bucket[2]) ||
(!bucket[1] && !bucket[3]) || (!bucket[2] && !bucket[3])) {
switch (NRAND(3)) {
case 0: getTurk(mi, 3, 0x21);
break;
case 1: getTurk(mi, 3, 0x27);
break;
default: getTurk(mi, 3, 0x2d);
break;
}
} else {
getTurk(mi, logClass, number);
}
}
}
static void
NewViewpoint(antfarm3dstruct * ap, double x, double y, double z)
{
double k, l, d1, d2;
k = x * x + y * y;
l = sqrt(k + z * z);
k = sqrt(k);
d1 = (EyeToScreen / HalfScreenD);
d2 = EyeToScreen / (HalfScreenD * ap->height / ap->width);
ap->A = d1 * l * (ap->width / 2) / k;
ap->B = l * l;
ap->C = d2 * (ap->height / 2) / k;
ap->F = k * k;
}
static void
lissajous(antfarm3dstruct * ap)
{
double alt, azm, dist;
alt = 44.0 * sin(ap->metaAlt * IP) + 45.0;
ap->metaAlt += 1.123;
if (ap->metaAlt >= 360.0)
ap->metaAlt -= 360.0;
if (ap->metaAlt < 0.0)
ap->metaAlt += 360.0;
azm = 44.0 * sin(ap->metaAzm * IP) + 45.0;
ap->metaAzm += 0.987;
if (ap->metaAzm >= 360.0)
ap->metaAzm -= 360.0;
if (ap->metaAzm < 0.0)
ap->metaAzm += 360.0;
dist = 10.0 * sin(ap->metaDist * IP) + 50.0;
ap->metaDist += 1.0;
if (ap->metaDist >= 360.0)
ap->metaDist -= 360.0;
if (ap->metaDist < 0.0)
ap->metaDist += 360.0;
#if 0
if (alt >= 90.0)
alt = 90.0;
else if (alt < -90.0)
alt = -90.0;
#endif
ap->azm = azm;
#ifdef DEBUG
(void) printf("dist %g, alt %g, azm %g\n", dist, alt, azm);
#endif
ap->vx = (sin(azm * IP) * cos(alt * IP) * dist);
ap->vy = (cos(azm * IP) * cos(alt * IP) * dist);
ap->vz = (sin(alt * IP) * dist);
NewViewpoint(ap, ap->vx, ap->vy, ap->vz);
}
static void
NewPoint(antfarm3dstruct * ap, double x, double y, double z,
register XPoint * cubepts)
{
double p1, E;
p1 = x * ap->vx + y * ap->vy;
E = ap->B - p1 - z * ap->vz;
cubepts->x = (int) (ap->width / 2 -
ap->A * (ap->vx * y - ap->vy * x) / E);
cubepts->y = (int) (ap->height / 2 -
ap->C * (z * ap->F - ap->vz * p1) / E);
}
/* Chain together all cells that are at the same distance.
* These cannot mutually overlap. */
static void
SortList(antfarm3dstruct * ap)
{
short dist;
double d, column, row, stack, rsize;
int i, r;
XPoint point;
antstruct *ptr;
for (i = 0; i < NBUCKETS; ++i)
ap->buckethead[i] = ap->bucketend[i] = NULL;
/* Calculate distances and re-arrange pointers to chain off buckets */
ptr = ap->ptrhead;
while (ptr != NULL) {
column = (double) ptr->column - ap->ox;
row = (double) ptr->row - ap->oy;
stack = (double) ptr->stack - ap->oz;
d = Distance(ap->vx, ap->vy, ap->vz, column, row, stack);
if (ap->vx * (ap->vx - column) + ap->vy * (ap->vy - row) +
ap->vz * (ap->vz - stack) > 0 && d > 1.5)
ptr->visible = 1;
else
ptr->visible = 0;
ptr->dist = (short) d;
dist = (short) (d * BUCKETSIZE);
if (dist > NBUCKETS - 1)
dist = NBUCKETS - 1;
if (ap->buckethead[dist] == NULL) {
ap->buckethead[dist] = ap->bucketend[dist] = ptr;
ptr->priority = NULL;
} else {
ap->bucketend[dist]->priority = ptr;
ap->bucketend[dist] = ptr;
ap->bucketend[dist]->priority = NULL;
}
ptr = ptr->next;
}
/* Check for invisibility */
rsize = 0.47 * ap->width / ((double) HalfScreenD * 2);
i = (int) ap->azm;
if (i < 0)
i = -i;
i = i % RT_ANGLE;
if (i > HALFRT_ANGLE)
i = RT_ANGLE - i;
rsize /= cos(i * IP);
for (i = 0; i < NBUCKETS; ++i)
if (ap->buckethead[i] != NULL) {
ptr = ap->buckethead[i];
while (ptr != NULL) {
if (ptr->visible) {
column = (double) ptr->column - ap->ox;
row = (double) ptr->row - ap->oy;
stack = (double) ptr->stack - ap->oz;
NewPoint(ap, column, row, stack, &point);
r = (int) (rsize *
(double) EyeToScreen /
(double) ptr->dist);
if (point.x + r < 0 ||
point.y + r < 0 ||
point.x - r >= ap->width ||
point.y - r >= ap->height) {
ap->nInvisible++;
} else if (ap->nInvisible) {
ap->nInvisible = 0;
}
}
ptr = ptr->priority;
}
}
}
static void
DrawFace(ModeInfo * mi, int color, XPoint * cubepts,
int p1, int p2, int p3, int p4)
{
Display *display = MI_DISPLAY(mi);
GC gc;
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
XPoint facepts[5];
facepts[0] = cubepts[p1];
facepts[1] = cubepts[p2];
facepts[2] = cubepts[p3];
facepts[3] = cubepts[p4];
facepts[4] = cubepts[p1];
if (color == NCOLORS) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
gc = MI_GC(mi);
} else if (!color) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
gc = MI_GC(mi);
} else if (MI_NPIXELS(mi) > 2) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
MI_PIXEL(mi, ap->colors[color - 1]));
gc = MI_GC(mi);
} else {
XGCValues gcv;
gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
gcv.foreground = MI_WHITE_PIXEL(mi);
gcv.background = MI_BLACK_PIXEL(mi);
XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
GCStipple | GCForeground | GCBackground, &gcv);
gc = ap->stippledGC;
}
if (!ap->wireframe)
XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
Convex, CoordModeOrigin);
gc = MI_GC(mi);
if (!ap->wireframe) {
if (color == NCOLORS) {
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
} else {
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
}
}
XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5, CoordModeOrigin);
}
static void
DrawEyes(ModeInfo * mi, int color, XPoint * cubepts,
int p1, int p2, int p3, int p4)
{
Display *display = MI_DISPLAY(mi);
GC gc;
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
XPoint facepts[5];
XPoint av;
av.x = (cubepts[p1].x + cubepts[p2].x + cubepts[p3].x + cubepts[p4].x) / 4;
av.y = (cubepts[p1].y + cubepts[p2].y + cubepts[p3].y + cubepts[p4].y) / 4;
facepts[0] = cubepts[p1];
facepts[1] = cubepts[p2];
facepts[2] = cubepts[p3];
facepts[3] = cubepts[p4];
facepts[4] = cubepts[p1];
facepts[0].x = (av.x + facepts[0].x) / 2;
facepts[0].y = (av.y + facepts[0].y) / 2;
facepts[1].x = (av.x + facepts[1].x) / 2;
facepts[1].y = (av.y + facepts[1].y) / 2;
facepts[2].x = (av.x + facepts[2].x) / 2;
facepts[2].y = (av.y + facepts[2].y) / 2;
facepts[3].x = (av.x + facepts[3].x) / 2;
facepts[3].y = (av.y + facepts[3].y) / 2;
facepts[4].x = (av.x + facepts[4].x) / 2;
facepts[4].y = (av.y + facepts[4].y) / 2;
if (color == NCOLORS) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
gc = MI_GC(mi);
} else if (!color) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
gc = MI_GC(mi);
} else if (MI_NPIXELS(mi) > 2) {
XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
MI_PIXEL(mi, ap->colors[color - 1]));
gc = MI_GC(mi);
} else {
XGCValues gcv;
gcv.stipple = ap->pixmaps[(color - 1) % NUMSTIPPLES];
gcv.foreground = MI_WHITE_PIXEL(mi);
gcv.background = MI_BLACK_PIXEL(mi);
XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
GCStipple | GCForeground | GCBackground, &gcv);
gc = ap->stippledGC;
}
if (!ap->wireframe)
XFillPolygon(display, (Drawable) ap->dbuf, gc, facepts, 4,
Convex, CoordModeOrigin);
gc = MI_GC(mi);
if (!ap->wireframe) {
if (color == NCOLORS) {
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
} else {
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
}
}
XDrawLines(display, (Drawable) ap->dbuf, gc, facepts, 5,
CoordModeOrigin);
}
#define LEN 0.45
#define LEN2 0.9
static int
DrawCube(ModeInfo * mi, antstruct * cell)
{
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
XPoint cubepts[8]; /* screen coords for point */
int i, out;
unsigned int mask;
double column, row, stack;
double dx, dy, dz;
int color;
column = (double) cell->column - ap->ox;
row = (double) cell->row - ap->oy;
stack = (double) cell->stack - ap->oz;
color = cell->color;
out = 0;
i = 0;
for (dz = stack - LEN; dz <= stack + LEN2; dz += LEN2)
for (dy = row - LEN; dy <= row + LEN2; dy += LEN2)
for (dx = column - LEN; dx <= column + LEN2; dx += LEN2) {
NewPoint(ap, dx, dy, dz, &cubepts[i]);
if (cubepts[i].x < 0 ||
cubepts[i].x >= ap->width ||
cubepts[i].y < 0 ||
cubepts[i].y >= ap->height)
++out;
++i;
}
if (out == 8)
return (0);
if (cell->visible)
mask = 0xFFFF;
else
mask = 0x0;
/* Only draw those faces that are visible */
dx = ap->vx - column;
dy = ap->vy - row;
dz = ap->vz - stack;
if (ap->wireframe) {
if (dz <= LEN)
DrawFace(mi, (int) (color & mask), cubepts, 4, 5, 7, 6);
else if (dz >= -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 1, 3, 2);
if (dx <= LEN)
DrawFace(mi, (int) (color & mask), cubepts, 1, 3, 7, 5);
else if (dx >= -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 2, 6, 4);
if (dy <= LEN)
DrawFace(mi, (int) (color & mask), cubepts, 2, 3, 7, 6);
else if (dy >= -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 1, 5, 4);
}
if (dz > LEN)
DrawFace(mi, (int) (color & mask), cubepts, 4, 5, 7, 6);
else if (dz < -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 1, 3, 2);
if (dx > LEN)
DrawFace(mi, (int) (color & mask), cubepts, 1, 3, 7, 5);
else if (dx < -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 2, 6, 4);
if (dy > LEN)
DrawFace(mi, (int) (color & mask), cubepts, 2, 3, 7, 6);
else if (dy < -LEN)
DrawFace(mi, (int) (color & mask), cubepts, 0, 1, 5, 4);
if (ap->eyes && color == NCOLORS) {
antstruct *anant;
for (i = 0; i < ap->n; i++) {
anant = &ap->ants[i];
if (anant->column == cell->column &&
anant->row == cell->row &&
anant->stack == cell->stack) {
#if 0
(void) printf("%d: direction %d, gravity %d\n",
i, anant->direction, anant->gravity);
#endif
/* TODO: use gravity to position better eyes */
if (dz > LEN && anant->direction == ZP)
DrawEyes(mi, 0, cubepts, 4, 5, 7, 6);
else if (dz < -LEN && anant->direction == ZN)
DrawEyes(mi, 0, cubepts, 0, 1, 3, 2);
if (dx > LEN && anant->direction == XP)
DrawEyes(mi, 0, cubepts, 1, 3, 7, 5);
else if (dx < -LEN && anant->direction == XN)
DrawEyes(mi, 0, cubepts, 0, 2, 6, 4);
if (dy > LEN && anant->direction == YP)
DrawEyes(mi, 0, cubepts, 2, 3, 7, 6);
else if (dy < -LEN && anant->direction == YN)
DrawEyes(mi, 0, cubepts, 0, 1, 5, 4);
}
}
}
return (1);
}
static void
DrawScreen(ModeInfo * mi)
{
antfarm3dstruct *ap = &antfarm3ds[MI_SCREEN(mi)];
Display *display = MI_DISPLAY(mi);
GC gc = MI_GC(mi);
antstruct *ptr;
antstruct *eraserptr;
int i;
SortList(ap);
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XFillRectangle(display, (Drawable) ap->dbuf, gc, 0, 0,
ap->width, ap->height);
/* Erase dead cubes */
eraserptr = ap->eraserhead.next;
while (eraserptr != &ap->eraserend) {
eraserptr->visible = 0;
(void) DrawCube(mi, eraserptr);
DelFromEraseList(eraserptr);
eraserptr = ap->eraserhead.next;
}
/* draw furthest cubes first */
for (i = NBUCKETS - 1; i >= 0; --i) {
ptr = ap->buckethead[i];
while (ptr != NULL) {
/*if (ptr->visible) */
/* v += */ (void) DrawCube(mi, ptr);
ptr = ptr->priority;
/* ++count; */
}
}
if (label) {
int size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
if (size >= 10 * FONT_WIDTH) {
/* hard code these to corners */
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
/*XDrawString(display, ap->dbuf, gc,
16 + ap->labelOffsetX,
16 + ap->labelOffsetY + FONT_HEIGHT,
ap->ruleString, strlen(ap->ruleString)); */
XDrawString(display, (Drawable) ap->dbuf, gc,
16 + ap->labelOffsetX, MI_HEIGHT(mi) - 16 -
ap->labelOffsetY - FONT_HEIGHT / 2,
ap->ruleString, strlen(ap->ruleString));
}
}
XFlush(display);
XCopyArea(display, (Drawable) ap->dbuf, MI_WINDOW(mi), gc,
0, 0, ap->width, ap->height, 0, 0);
#if 0
{
int count = 0, v = 0;
(void) printf("Pop=%-4d Viewpoint (%3d,%3d,%3d) Origin (%3d,%3d,%3d) Mode %dx%d\
(%d,%d) %d\n",
count, (int) (ap->vx + ap->ox), (int) (ap->vy + ap->oy),
(int) (ap->vz + ap->oz), (int) ap->ox, (int) ap->oy, (int) ap->oz,
ap->width, ap->height, ap->alt, ap->azm, v);
}
#endif
}
static void
free_ant3d(Display *display, antfarm3dstruct *ap)
{
if (ap->eraserhead.next != NULL) {
End3D(ap);
}
if (ap->dbuf != None) {
XFreePixmap(display, ap->dbuf);
ap->dbuf = None;
}
if (ap->tape != NULL) {
free(ap->tape);
ap->tape = (unsigned char *) NULL;
}
if (ap->ants != NULL) {
free(ap->ants);
ap->ants = (antstruct *) NULL;
}
}
void
init_ant3d(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
antfarm3dstruct *ap;
int i;
if (antfarm3ds == NULL) {
if ((antfarm3ds = (antfarm3dstruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (antfarm3dstruct))) == NULL)
return;
}
ap = &antfarm3ds[MI_SCREEN(mi)];
ap->nInvisible = 0;
if (MI_NPIXELS(mi) <= 2) {
if (ap->stippledGC == None) {
XGCValues gcv;
gcv.fill_style = FillOpaqueStippled;
if ((ap->stippledGC = XCreateGC(display, window,
GCFillStyle, &gcv)) == None) {
free_ant3d(display, ap);
return;
}
}
if (ap->init_bits == 0) {
for (i = 1; i < NUMSTIPPLES; i++) {
ANT3DBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
}
}
}
ap->generation = 0;
ap->n = MI_COUNT(mi);
if (ap->n < -MINANTS) {
/* if ap->n is random ... the size can change */
if (ap->ants != NULL) {
free(ap->ants);
ap->ants = NULL;
}
ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
} else if (ap->n < MINANTS)
ap->n = MINANTS;
if (!ap->eraserhead.next) {
ap->metaDist = (double) NRAND(360);
ap->metaAlt = (double) NRAND(360);
ap->metaAzm = (double) NRAND(360);
ap->ncolumns = MAXCOLUMNS;
ap->nrows = MAXROWS;
ap->nstacks = MAXSTACKS;
ap->ox = ap->ncolumns / 2;
ap->oy = ap->nrows / 2;
ap->oz = ap->nstacks / 2;
Init3D(ap);
} else {
End3D(ap);
}
ap->labelOffsetX = NRAND(8);
ap->labelOffsetY = NRAND(8);
parseRule(mi);
if (MI_NPIXELS(mi) > 2)
for (i = 0; i < (int) ap->ncolors - 1; i++)
ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
if (ap->tape != NULL)
free(ap->tape);
if ((ap->tape = (unsigned char *) calloc(
ap->ncolumns * ap->nrows * ap->nstacks,
sizeof (unsigned char))) == NULL) {
free_ant3d(display, ap);
return;
}
ap->width = MI_WIDTH(mi);
ap->height = MI_HEIGHT(mi);
ap->memstart = 1;
/*ap->tablesMade = 0; */
if (MI_IS_FULLRANDOM(mi)) {
ap->wireframe = (NRAND(8) == 0);
} else {
ap->wireframe = MI_IS_WIREFRAME(mi);
}
MI_CLEARWINDOW(mi);
ap->painted = False;
lissajous(ap);
if (ap->ants == NULL) {
if ((ap->ants = (antstruct *) malloc(ap->n *
sizeof (antstruct))) == NULL) {
free_ant3d(display, ap);
return;
}
}
for (i = 0; i < ap->n; i++) {
ap->ants[i].row = ap->nrows / 2;
ap->ants[i].column = ap->ncolumns / 2;
ap->ants[i].stack = ap->nstacks / 2;
ap->ants[i].direction = NRAND(6);
ap->ants[i].gravity = NRAND(6);
while ((ap->ants[i].gravity / 2) % 3 ==
(ap->ants[i].direction / 2) % 3)
ap->ants[i].gravity = NRAND(6);
ap->ants[i].state = 0;
}
if (ap->dbuf != None) {
XFreePixmap(display, ap->dbuf);
ap->dbuf = None;
}
if ((ap->dbuf = XCreatePixmap(display, window,
ap->width, ap->height, MI_DEPTH(mi))) == None) {
free_ant3d(display, ap);
return;
}
if (MI_IS_FULLRANDOM(mi)) {
ap->eyes = (Bool) (LRAND() & 1);
} else {
ap->eyes = eyes;
}
DrawScreen(mi);
}
void
draw_ant3d(ModeInfo * mi)
{
antfarm3dstruct *ap;
if (antfarm3ds == NULL)
return;
ap = &antfarm3ds[MI_SCREEN(mi)];
if (ap->eraserhead.next == NULL)
return;
if (!RunAnt3D(ap)) {
if (ap->eraserhead.next != NULL)
End3D(ap);
return;
}
lissajous(ap);
DrawScreen(mi);
MI_IS_DRAWN(mi) = True;
if (++ap->generation > MI_CYCLES(mi) || ap->nInvisible > 32) {
/*CountCells3D(ap) == 0) */
init_ant3d(mi);
} else
ap->painted = True;
}
void
release_ant3d(ModeInfo * mi)
{
if (antfarm3ds != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_ant3d(MI_DISPLAY(mi), &antfarm3ds[screen]);
free(antfarm3ds);
antfarm3ds = (antfarm3dstruct *) NULL;
}
}
void
refresh_ant3d(ModeInfo * mi)
{
antfarm3dstruct *ap;
if (antfarm3ds == NULL)
return;
ap = &antfarm3ds[MI_SCREEN(mi)];
if (ap->painted) {
MI_CLEARWINDOW(mi);
}
}
#endif /* MODE_ant3d */