/* Automalab.c: */


/*       AutomaLab         
             by            
       Michael Creutz      
   creutz@wind.phy.bnl.gov         */

/* This program simulates totalistic cellular automata.  
   Each cell is updated according to the number of    
   active neighbors.  The number of neighbors for a   
   birth or for survival are set with corresponding   
   gadgets.  Either a 4 or 8 neighborhood can also    
   be selected. Conway's life uses an eight cell      
   neighborhood with births on 3 and survival on      
   2 or 3.  The program directly accesses the blitter 
   for speed.  It compiles with PDC.  New live cells  
   can be added by sketching with the mouse.          */

/* these are the standard Commodore include files,
   obtainable from CATS */
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <hardware/custom.h>
#include <hardware/blit.h>
#include <exec/memory.h>

#include <stdio.h> 

/* size parameters: lattice is SX by SY */
#define XMIN 16L
#define YMIN 15L
#define SX 192L
#define SY 180L

    /* IDCMPFlags */
#define windowflags=VANILLAKEY|MOUSEBUTTONS|MENUVERIFY|GADGETDOWN|MENUPICK
#define safeflags=VANILLAKEY|MOUSEBUTTONS|GADGETDOWN|MENUPICK

/* positions for gadgets */
#define NGTOP 58
#define RGTOP 75

/* birth and survivor words */
short birth=1<<3, survivor=((1<<2)|(1<<3)), neighborhood;

short boundary=0; /* start periodic */

/* parameters for blitter */
short modulo=(320-SX)/8, 
      size=(0x40*SY)+SX/16,
      displacement=40*YMIN+XMIN/8;

/* plane pointers */
char *bplane, *historyplane, *workplane[]
  ={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};

/* structure containing blitter registers */
struct Custom *custom = (struct Custom *) 0xdff000; 

/* other structure pointers */
struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase       *GfxBase      =NULL;
struct Screen        *screen       =NULL;
struct Window        *window       =NULL;
struct RastPort      *rastport;
struct MsgPort       *userport;
struct IntuiMessage  *message;

struct TextAttr topaz=
{(STRPTR)"topaz.font",TOPAZ_EIGHTY,0,0};

struct NewScreen newscreen =
{0,0,320,200,        /* dimensions */
 3,                  /* depth */
 5,6,                /* pens */
 0,                  /* viewmodes */
 CUSTOMSCREEN,       /* type */
 &topaz,             /* font */
 "  AutomaLab",      /* title */
 0,                  /* gadgets */
 0                   /* bitmap */
};

struct NewWindow newwindow =
{0,0,320,200,        /* dimensions */
 4,2,                /* pens */ 
 windowflags,        /* IDCMPFlags */
 ACTIVATE|SMART_REFRESH|NOCAREREFRESH
  |BACKDROP|BORDERLESS, /* Flags */
 0,                  /* *FirstGadget */
 0,                  /* *CheckMark */
 "AutomaLab",        /* *Title */
 0,                  /* Screen */
 0,                  /* BitMap */ 
 80,24,-1,-1,        /* min dimensions */
 CUSTOMSCREEN        /* Type */ 
};

/* vectors for pause and clear boxes */
short vectors[]=
{41,0, 41,10, 0,10, 0,0, 41,0},
/* vectors for a small box */
smallvectors[]=
{9,0,9,9,0,9,0,0,9,0};

struct Border moreborder =
{-1,-1,
  1,0,JAM1,
  3,
  &(vectors[4]),
  NULL
},
myborder =
{-1,-1,
 2,0,JAM1,
 3,
 vectors,
 &moreborder
},
moresmallborder =
{-1,-1,
  1,0,JAM1,
  3,
  &(smallvectors[4]),
  NULL
},
smallbox=
{-1,-1,
 2,0,JAM1,
 3,
 smallvectors,
 &moresmallborder
};

/* text attached to gadgets and menus */
struct IntuiText pausetext=
{2,6,JAM1,0,1,&topaz,"Pause",0},
cleartext = 
{2,6,JAM1,0,1,&topaz,"Clear",0},
morespeed=
{1,0,JAM1,-12,2,&topaz,"S          F",0},
speedtext=
{1,0,JAM1,15,-10,&topaz,"Speed",&morespeed},
projecttext[]=
{{2,1,JAM2,0,0,&topaz,"  Author ",NULL},
 {2,1,JAM2,0,0,&topaz,"  Quit   ",NULL}
},
boundarytext[]=
{{2,1,JAM2,CHECKWIDTH,0,&topaz,"Periodic",NULL},
 {2,1,JAM2,CHECKWIDTH,0,&topaz,"Dead    ",NULL},
 {2,1,JAM2,CHECKWIDTH,0,&topaz,"Live    ",NULL}
},
requesttext[]=
{{2,1,JAM2,4,4,&topaz,"continue",NULL},
 {2,1,JAM2,4,8 ,&topaz,"Totalistic Cellular Automaton",&requesttext[2]},
 {2,1,JAM2,4,20,&topaz,"         Simulator           ",&requesttext[3]},
 {2,1,JAM2,4,30,&topaz,"            by               ",&requesttext[4]},
 {2,1,JAM2,4,40,&topaz,"       Michael Creutz        ",&requesttext[5]},
 {2,1,JAM2,4,50,&topaz,"          BNL 510A           ",&requesttext[6]},
 {2,1,JAM2,4,60,&topaz,"       Upton, NY 11973       ",&requesttext[7]},
 {2,1,JAM2,4,70,&topaz,"   creutz@wind.phy.bnl.gov   ",NULL}
};

#define IWIDTH 82
#define IHEIGHT 8

struct MenuItem projectitem[]=
{
  {&projectitem[1],0,0,IWIDTH,IHEIGHT,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,0,
   (APTR) &projecttext[0],NULL,NULL,NULL,MENUNULL
  },  
  {NULL,0,8,IWIDTH,IHEIGHT,
   ITEMTEXT|ITEMENABLED|HIGHCOMP,0,
   (APTR) &projecttext[1],NULL,NULL,NULL,MENUNULL
  }
},  
   boundaryitem[]=
{
  {&boundaryitem[1],0,0,IWIDTH,IHEIGHT,
   ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT|CHECKED,2|4,
   (APTR) &boundarytext[0],NULL,NULL,NULL,MENUNULL
  },  
  {&boundaryitem[2],0,8,IWIDTH,IHEIGHT,
   ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT,1|4,
   (APTR) &boundarytext[1],NULL,NULL,NULL,MENUNULL
  },
  {NULL,0,16,IWIDTH,IHEIGHT,
   ITEMTEXT|ITEMENABLED|HIGHCOMP|CHECKIT,1|2,
   (APTR) &boundarytext[2],NULL,NULL,NULL,MENUNULL
  }
};  

struct Menu mymenus[]=
{
 {&mymenus[1],10,0,63,8,MENUENABLED,"Project",&(projectitem[0])},
 {NULL,       160,0,63,8,MENUENABLED,"Boundary",&(boundaryitem[0])}
};

/* needed for speed gadget */
struct PropInfo speedinfo =
{AUTOKNOB|FREEHORIZ, /*Flags*/
 0x8000, /* HorizPot */
 0xffff, /* VertPot */
 50, /* HorizBody */
 0, /* VertBody */
0,0,0,0,0,0
}; 
struct Image image;

/* gadget structures */
struct Gadget pausegadget =
 {
  0,  /* next gadget in the list */
  223,36,40,9,
  GADGHCOMP,     /* Flags */
  GADGIMMEDIATE|TOGGLESELECT,   /* Activation */
  BOOLGADGET, /* GadgetType */
  &myborder,  /* GadgetRender */
  0,  /* SelectRender */
  &pausetext,  /* GadgetText */
  0,  /* MutualExclude */
  0,0,0
 },
cleargadget =
 {
  0,     /* next gadget in the list */
  270,36,40,9,
  GADGHCOMP,     /* Flags */
  RELVERIFY|GADGIMMEDIATE, /* Activation */
  BOOLGADGET, /* GadgetType */
  &myborder,  /* GadgetRender */
  0,  /* SelectRender */
  &cleartext,  /* GadgetText */
  0,  /* MutualExclude */
  0,1,0
},
speedgadget =
{
 NULL,	/* next gadget in the list */
 230,21,70,10,
 GADGHNONE,     /* Flags */
 RELVERIFY|GADGIMMEDIATE,   /* Activation */
 PROPGADGET, /* GadgetType */
 &image,  /* GadgetRender */
 0,  /* SelectRender */
 &speedtext,  /* GadgetText */
 0,  /* MutualExclude */
 &speedinfo,  /* SpecialInfo */
 3,0
},
neighborgadget =
{NULL, /* next gadget in the list */
 260,NGTOP,8,8,
 GADGHCOMP,     /* Flags */
 GADGIMMEDIATE,   /* Activation */
 BOOLGADGET, /* GadgetType */
 &smallbox,  /* GadgetRender */
 0,  /* SelectRender */
 0,  /* GadgetText */
 0,  /* MutualExclude */
 0,  /* SpecialInfo */
 4,0
},
birthgadgets[9],
survivorgadgets[9];

main()
{ULONG class;
 USHORT code;
 short i,g,speed,menu,item,menuwaiting;
 void *iaddress;
 long mx,my;
 char label;

menuwaiting=0;
openup();
while (1) /* main loop */
{
message=GetMsg(userport); /* check for messages */
if (message)  
{ class   =message-> Class;
  code    =message-> Code;
  iaddress=message-> IAddress;
  mx      =message-> MouseX;
  my      =message-> MouseY;
  ReplyMsg(message);
  switch (class) /* what kind of message */
  {case VANILLAKEY  : /* quit if <esc> or a control character */
       if (code<32) cleanup(" all done");
       break;
   case MENUVERIFY:
       menuwaiting=-1;
       break;
   case MENUPICK:
      menuwaiting=0;
      while ( (code&0xffff) != MENUNULL) 
        {item=ITEMNUM(code);
         menu=MENUNUM(code);
         switch (menu)
          {case 0:
            if (item==1) cleanup (" all done");
            if (item==0) /* show credits */
             {ModifyIDCMP(window,safeflags);
              AutoRequest(window,&requesttext[1],
               NULL,&requesttext[0],
               0,0,260,120);  
              ModifyIDCMP(window,windowflags);
             };   
            break;
           case 1: /* boundary menu */
            if (item>=0 && item<=2)
             {boundary=item;
              if (0==boundary)
               SetAPen(rastport,0);
              else if (1==boundary)
               SetAPen(rastport,2);
              else if (2==boundary)
               SetAPen(rastport,7);
              Move(rastport,XMIN+SX, YMIN-1);
              Draw(rastport,XMIN+SX,YMIN+SY);
              Draw(rastport,XMIN-1 ,YMIN+SY);
              Draw(rastport,XMIN-1 , YMIN-1);
              Draw(rastport,XMIN+SX, YMIN-1);             
             } 
            break;
          }; 
         code=( (struct MenuItem *) ItemAddress
              (&(mymenus[0]),(long) code) ) -> NextSelect;
        }; /* end menu searching loop */
      break;
   case GADGETDOWN  :
     switch ( g=(((struct Gadget *) iaddress)->GadgetID) )
      { case 0 :    /* pause gadget */
          WaitPort(userport);
          break; 
        case 1 :    /* clear gadget */ 
          SetAPen(rastport,2);
          RectFill(rastport,XMIN,YMIN,XMIN+SX-1,YMIN+SY-1);
          SetAPen(rastport,1);
          break;
        case 4 :    /* neighborhood gadget */
           neighborhood=12-neighborhood;
           label=neighborhood+'0';
           Move(rastport,260L,NGTOP+6L);
           SetAPen(rastport,7);
           SetBPen(rastport,0);
           SetDrMd(rastport,JAM2);
           Text(rastport,&label,1); 
           break;
        default :   /* check for rule gadget */
          if ( (g<=18) && (g>=10))
            {if (birthgadgets[i=g-10].Flags & SELECTED)
              birth |= (1<<i);
             else
              birth &= (~(1<<i));
            }
          if ( (g<=28) && (g>=20))
            {if (survivorgadgets[i=g-20].Flags & SELECTED)
              survivor |= (1<<i);
             else
              survivor &= (~(1<<i));
            }
          break;             
      } 
     break;
   case MOUSEBUTTONS:   /* sketch if in box */
     if (code==SELECTDOWN)
       if( (mx>=XMIN)&&(my>=YMIN)
         &&(mx<XMIN+SX)&&(my<YMIN+SY)) 
          {SetAPen(rastport,3);
           WritePixel(rastport,mx,my);
           Move(rastport,mx,my);
           while(GetMsg(userport)==0) 
            { mx=(*window).MouseX;
              my=(*window).MouseY;
              if( (mx>=XMIN)&&(my>=YMIN)
                &&(mx<XMIN+SX)&&(my<YMIN+SY)) 
                 Draw(rastport,mx,my);
             }
            SetAPen(rastport,1);
           }
     break; 
  }
} /* end  of if (message) */

if ( ((pausegadget.Flags)&SELECTED)||menuwaiting ) 
 WaitPort(userport);
else 
 {update();
  /* nonlinear delay looks better */
  speed=(0xffff-speedinfo.HorizPot)/0x100;
  if (speed) Delay((speed*speed)/0x400);
 }
}/* end of while */
}/* end of main */

update()
{short i;
OwnBlitter();
if (8==neighborhood)
{  /* add up, middle, down to work planes 0,1 */
 myblit(bplane,bplane-40,
       bplane+40,workplane[0],
       0,ANBNC|NABNC|NANBC|ABC);
 myblit(bplane,bplane-40,
       bplane+40,workplane[1],
       0,ABNC|NABC|ANBC|ABC);
  /* add up, down to 3 west neighbors; result in 5,6,7 */
 myblit(workplane[0],bplane-40,
       bplane+40,workplane[5],
       1,ANBNC|NABNC|NANBC|ABC);
 myblit(workplane[0],bplane-40,
       bplane+40,workplane[6],
       1,ABNC|ANBC|NABC|ABC);
  /* add in workplane 1 */
 myblit(workplane[1],workplane[6],
       0,workplane[7],
       1,ABNC|ABC);
 myblit(workplane[1],workplane[6],
       0,workplane[6],
       1,NABC|ANBC|NABNC|ANBNC);
  /* add in 3 east neighbors; result in 5,6,7,8 */
  /* plane 1, cannot carry into 8 yet */
 myblit(workplane[1],workplane[6],
       workplane[7],workplane[7],
       -1,ABNC|ANBC|NABC|NANBC);
  myblit(workplane[1],workplane[6],
       0,workplane[6],
       -1,ANBC|NABC|ANBNC|NABNC);
  /* add in workplane 0; use 9 for carry  to 7 */
 myblit(workplane[0],workplane[5],
       workplane[6],workplane[9],
       -1,ABC); /* carry */
 myblit(workplane[0],workplane[5],
       workplane[6],workplane[6],
       -1,NABC|ANBC|NANBC|ABNC);
 myblit(workplane[0],workplane[5],
       0,workplane[5],
       -1,NABC|ANBC|NABNC|ANBNC);
   /* add in carry */
 myblit(workplane[9],workplane[7],
       0,workplane[8],
       0,ABC|ABNC);
 myblit(workplane[9],workplane[7],
       0,workplane[7],
       0,NABC|ANBC|NABNC|ANBNC);
/* sum of eight neighbors now in 5,6,7,8 */
/* now set workplane[i] where i neighbors */
if ( (birth|survivor)&1) /* 0 neighbors */ 
 { myblit(workplane[5],workplane[6],
       workplane[7],workplane[0],
       0,NANBNC);
   myblit(workplane[0],workplane[8],
       0,workplane[0],
       0,ANBC|ANBNC);
 }
if ( (birth|survivor)&((1<<1)|(1<<5))) /* 1 neighbor */
  myblit(workplane[5],workplane[6],
       workplane[7],workplane[1],
       0,ANBNC);
if ( (birth|survivor)&((1<<2)|(1<<6)) ) /* 2 neighbors */
  myblit(workplane[5],workplane[6],
       workplane[7],workplane[2],
       0,NABNC);
if ( (birth|survivor)&((1<<3)|(1<<6)) ) /* 3 neighbors */
  myblit(workplane[5],workplane[6],
       workplane[7],workplane[3],
       0,ABNC);
if ( (birth|survivor)&(1<<4))          /* 4 neighbors */
  myblit(workplane[5],workplane[6],
       workplane[7],workplane[4],
       0,NANBC);
if ( (birth|survivor)&((1<<7)|(1<<6))) /* 7 neighbors */
  myblit(workplane[5],workplane[6],
       workplane[7],workplane[7],
       0,ABC);
if ( (birth|survivor)&(1<<5))          /* 5 neighbors */
  myblit(workplane[5],workplane[6],
       workplane[1],workplane[5],
       0,ANBNC);
if ( (birth|survivor)&(1<<6))          /* 6 neighbors */
 { myblit(workplane[6],workplane[2],
       workplane[3],workplane[6],
       0,ANBNC);
   myblit(workplane[6],workplane[7],
       0,workplane[6],
       0,ANBC|ANBNC);
 }
} /* end of if 8 */
 
if (4==neighborhood) /* less work if only 4 neighbors to count */
{
/* add left, top and bottom neighbors to planes 5,6,4 */
/* first bit (plane 0)*/
  myblit(bplane,bplane-40,
         bplane+40,workplane[5],
         1,ANBNC|NABNC|NANBC|ABC);
/* second bit */
  myblit(bplane,bplane-40,
         bplane+40,workplane[6],
         1,ABNC|ANBC|NABC|ABC);
/* add in right neighbor */
/* calculate plane 2 */
if ( (birth|survivor)&((1<<4)|(1)))
  myblit(bplane,workplane[5],
         workplane[6],workplane[4],
         -1,ABC);
/* calculate plane 1 */
  myblit(bplane,workplane[5],
         workplane[6],workplane[6],
         -1,ABNC|ANBC|NABC|NANBC);
/* calculate plane 0 */
  myblit(bplane,workplane[5],
         0,workplane[5],
         -1,NABC|NABNC|ANBC|ANBNC);
/* sum of four nearest neighbors now in planes 5,6,4 */
/* put in respective planes */
if ( (birth|survivor)&1)
  myblit(workplane[5],workplane[6],
         workplane[4],workplane[0],
         0,NANBNC);
if ( (birth|survivor)&(1<<1))
  myblit(workplane[5],workplane[6],
         0,workplane[1],
         0,ANBC|ANBNC);
if ( (birth|survivor)&(1<<2))
  myblit(workplane[5],workplane[6],
         0,workplane[2],
         0,NABC|NABNC);
if ( (birth|survivor)&(1<<3))
  myblit(workplane[5],workplane[6],
         0,workplane[3],
         0,ABC|ABNC);
} /* end of if 4 */

/* accumulate births in plane 9 */
if (birth & 1) /* copy 0 to 9 */
   myblit(workplane[0],0,
       0,workplane[9],
       0,ABC|ABNC|ANBC|ANBNC);
else /* clear 9 */
   myblit(0,0,
       0,workplane[9],
       0,0);
for (i=1;i<=neighborhood;i++)
 if ( (birth & (1<<i) )!=0) /* add in more births */
   myblit(workplane[i],workplane[9],
       0,workplane[9],
       0,ANBC|NABC|ABC|ANBNC|NABNC|ABNC);

/* survivors to plane 0 */
if (0==(survivor&1)) /* clear plane 0 */
   myblit(0,0,
       0,workplane[0],
       0,0);
for (i=1;i<=neighborhood;i++)
 if ( (survivor & (1<<i) )!=0) /* add in more survivors */
   myblit(workplane[i],workplane[0],
       0,workplane[0],
       0,ANBC|NABC|ABC|ANBNC|NABNC|ABNC);
/* final result */
WaitTOF(); /* to cut down flicker */
myblit(bplane,0,
       0,historyplane,
       0,ABC|ABNC|ANBC|ANBNC);
myblit(bplane,workplane[0],
       workplane[9],bplane,
       0,ABNC|ABC|NANBC|NABC);
DisownBlitter();
if (boundary == 0) periodic(0xc0);
else if (boundary == 2) periodic(0xf0);
}

myblit(a,b,c,d,shift,minterm)
/* This blits from sources a,b,c to destination d         */
/* with a shifted by shift bits.  Size and modulo's fixed */
/* by global variables. */
 UBYTE *a,*b,*c,*d;
 int shift,minterm; 
{int con1=0,lwm=0xffff;
 if (a) minterm|=SRCA;
 if (b) minterm|=SRCB;
 if (c) minterm|=SRCC;
 if (d) minterm|=DEST;
 if (shift==-1) 
   {minterm|=0x1000;  /* shift for a */
    con1=2;           /* descending mode */
    lwm=0x7fff;
    a+=((SY-1)*40+(SX-16)/8);
    b+=((SY-1)*40+(SX-16)/8);
    c+=((SY-1)*40+(SX-16)/8);
    d+=((SY-1)*40+(SX-16)/8);
   }

 if (shift==1) 
   {minterm|=0x1000;
    lwm=0xfffe;
   }
 WaitBlit();
 custom->bltamod=modulo;
 custom->bltbmod=modulo;
 custom->bltcmod=modulo;
 custom->bltdmod=modulo;
 custom->bltafwm=0xffff;
 custom->bltalwm=lwm;
 custom->bltdpt=d;
 custom->bltapt=a;
 custom->bltbpt=b;
 custom->bltcpt=c;
 custom->bltcon1=con1;
 custom->bltcon0=minterm; 
 custom->bltsize=size; /* start blit */
}

periodic(minterm)
/* If argument =0xc0 make lattice periodic by copying 
from one line inside edge to other edge. 
If arguement =0xf0 then make edge hot. */
{ClipBlit(rastport,XMIN+1,YMIN,rastport,XMIN+SX-1,YMIN,1,SY,minterm);
 ClipBlit(rastport,XMIN+SX-2,YMIN,rastport,XMIN,YMIN,1,SY,minterm);
 ClipBlit(rastport,XMIN,YMIN+1,rastport,XMIN,YMIN+SY-1,SX,1,minterm);
 ClipBlit(rastport,XMIN,YMIN+SY-2,rastport,XMIN,YMIN,SX,1,minterm);
}

openup()
/* this opens screen, window, and draws things */
{
int i;
char label;
short colormap[8];
colormap[0]=0x00f; /* background  blue */
colormap[1]=0xfff; /* foreground  white */
colormap[2]=0x000; /* field background  black */
colormap[3]=0xff0; /* newborn yellow */
colormap[4]=0x0aa; /* dark cyan */
colormap[5]=0x440; /* brown */
colormap[6]=0xf0f; /* moribund magenta */
colormap[7]=0xf00; /* living red */
IntuitionBase=(struct IntuitionBase *) OpenLibrary("intuition.library",33);
 if (IntuitionBase==NULL) cleanup("trouble opening intuition");
GfxBase=(struct GfxBase *) OpenLibrary("graphics.library",33);
 if (GfxBase==NULL) cleanup("trouble opening graphics");
screen=OpenScreen(&newscreen);
 if (screen==NULL) cleanup("trouble opening screen"); 
LoadRGB4(&((*screen).ViewPort),colormap,8L);
newwindow.Screen=screen;
window=OpenWindow(&newwindow);
 if (window==NULL) cleanup("trouble opening window");

userport=(*window).UserPort;
rastport=(*window).RPort;
bplane=((*(*rastport).BitMap).Planes)[0]+displacement;
historyplane=((*(*rastport).BitMap).Planes)[2]+displacement;

/* put down gadgets */
AddGadget(window,&pausegadget,-1);
AddGadget(window,&cleargadget,-1);
AddGadget(window,&speedgadget,-1);

/* set up neighborhood gadget */
neighborhood=8;
Move(rastport,260L,NGTOP+6L);
SetAPen(rastport,7);
SetDrMd(rastport,JAM1);
label=neighborhood+'0';
Text(rastport,&label,1); 
AddGadget(window,&neighborgadget,-1);
SetAPen(rastport,2);
Move(rastport,216,NGTOP-4);
Text(rastport,"Neighborhood:",13);

/* set up birth and survivor gadgets */
Move(rastport,220,RGTOP);
Text(rastport,"born|survive",12);
SetAPen(rastport,2);
for (i=0;i<9;i++)
 {label='0'+i;
  Move(rastport,257,RGTOP+11+10*i);
  Text(rastport,&label,1);

  birthgadgets[i].LeftEdge=235;
  birthgadgets[i].TopEdge=RGTOP+5+10*i;
  birthgadgets[i].Width=8;
  birthgadgets[i].Height=8;
  birthgadgets[i].Flags=GADGHCOMP;
  birthgadgets[i].Activation=GADGIMMEDIATE|TOGGLESELECT;
  birthgadgets[i].GadgetType=BOOLGADGET;
  birthgadgets[i].GadgetRender=&smallbox;
  birthgadgets[i].SelectRender=NULL;
  birthgadgets[i].GadgetText=NULL;
  birthgadgets[i].MutualExclude=NULL;
  birthgadgets[i].GadgetID=10+i;
  if (birth & (1<<i)) birthgadgets[i].Flags|=SELECTED;
  AddGadget(window,&(birthgadgets[i]),-1);

  survivorgadgets[i].LeftEdge=280;
  survivorgadgets[i].TopEdge=RGTOP+5+10*i;
  survivorgadgets[i].Width=8;
  survivorgadgets[i].Height=8;
  survivorgadgets[i].Flags=GADGHCOMP;
  survivorgadgets[i].Activation=GADGIMMEDIATE|TOGGLESELECT;
  survivorgadgets[i].GadgetType=BOOLGADGET;
  survivorgadgets[i].GadgetRender=&smallbox;
  survivorgadgets[i].SelectRender=NULL;
  survivorgadgets[i].GadgetText=NULL;
  survivorgadgets[i].MutualExclude=NULL;
  survivorgadgets[i].GadgetID=20+i;
  if (survivor & (1<<i)) survivorgadgets[i].Flags|=SELECTED;
  AddGadget(window,&(survivorgadgets[i]),-1);
 }
RefreshGadgets(&pausegadget,window,0);

/* get working planes */
for (i=0;i<10;i++)
{workplane[i]=AllocMem(SY*40,MEMF_CHIP);
 if (workplane[i]==0) cleanup("trouble getting memory"); 
}

/* draw initial working region */
SetAPen(rastport,2);
RectFill(rastport,XMIN,YMIN,XMIN+SX-1,YMIN+SY-1);
/* draw an active box to get started */
SetAPen(rastport,3);
RectFill(rastport,XMIN+SX/4,YMIN+SY/4,XMIN+SX-1-SX/4,YMIN+SY-1-SY/4);

/* draw a nice border */
for (i=1;i<4;i++)
{SetAPen(rastport,4);
 Move(rastport,XMIN+SX+i, YMIN-1-i);
 Draw(rastport,XMIN+SX+i,YMIN+SY+i);
 Draw(rastport,XMIN-1-i ,YMIN+SY+i);
 SetAPen(rastport,1);
 Draw(rastport,XMIN-1-i , YMIN-1-i);
 Draw(rastport,XMIN+SX+i, YMIN-1-i);
};

/* show meaning of colors */ 
Move(rastport,218,184);
SetAPen(rastport,3);
SetBPen(rastport,2);
SetDrMd(rastport,JAM2);
Text(rastport," Young",6);
SetAPen(rastport,7);
Text(rastport,"  Old ",6);
Move(rastport,218,192);  
SetAPen(rastport,6);
Text(rastport,"  Moribund  ",12);
for (i=1;i<3;i++)
{SetAPen(rastport,4);
 Move(rastport,218+8*12+i-1, 178-i);
 Draw(rastport,218+8*12+i-1, 193+i);
 Draw(rastport,218-i  , 193+i);
 SetAPen(rastport,1);
 Draw(rastport,218-i , 178-i);
 Draw(rastport,218+8*12+i, 178-i);
}

  SetMenuStrip(window,&(mymenus[0]));   
}/* end of openup */

cleanup(char *closing)
/* release memory and close everything */
{
int i;
/* get rid of any remaining messages */
while (message=GetMsg(userport)) ReplyMsg(message);
/* free allocated memory */
for (i=0;i<10;i++)
 if (workplane[i]) FreeMem(workplane[i],SY*40);
/* close up */
if (window) 
 {if (window->MenuStrip) ClearMenuStrip(window);
  CloseWindow(window);
 }
if (screen) CloseScreen(screen);
if (GfxBase) CloseLibrary((struct Library *) GfxBase);
if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase);
printf("%s\n",closing);
exit(0);
}
