home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d111 / poplife.lha / PopLife / PopLife.c < prev    next >
C/C++ Source or Header  |  1987-11-15  |  28KB  |  990 lines

  1. /* ===================================================================== *
  2.  *                            +-----------+     *
  3.  *    :ts=8                        | V15.08.87 |     *
  4.  *                            +-----------+     *
  5.  *    POPLIFE, by Olaf Seibert (KosmoSoft)                 *
  6.  *                                     *
  7.  *    Based on both Life by Tomas Rokicki (Fish #31) and         *
  8.  *    the PDP-11 code presented in "Life Algorithms" by Mark Niemieck, *
  9.  *    in Byte 4:1, January 1979, and                     *
  10.  *    Popcli II by John Toebes and the Software Distillery (Fish #40). *
  11.  *                                     *
  12.  * ===================================================================== */
  13.  
  14.  
  15. #include "structures.h"
  16.  
  17. /* --------------------------------------------------------------------- *
  18.  *     Static data for the DoGeneration() routine.             *
  19.  *    Also used by Initialize() and Cleanup().             *
  20.  * --------------------------------------------------------------------- */
  21.  
  22. WORD *Plane0, *Plane1, *Plane2, *Plane3, *Plane4;
  23. WORD *Temp1=NULL, *Temp2=NULL, *Temp3=NULL, *Temp4=NULL, *Temp5=NULL;
  24. short NoPlanes = 1;
  25. BOOL UseBlitter = TRUE;
  26. struct AdresRegs {
  27.     LONG A0;    /* Current longword pointer */
  28.     LONG A1;    /* Current longword pointer in new generation */
  29.     LONG A2;    /* End of screen, sortof */
  30.     LONG A3;    /* One line above current longword */
  31.     LONG A4;    /* One line below current longword */
  32. } ARegs;
  33.  
  34. int GlobHSizeMin2;
  35. int GlobVSize;
  36. int GlobVSizeMin2;
  37. int GlobModulo;
  38.  
  39. /* --------------------------------------------------------------------- *
  40.  *    Library Base Pointers.                         *
  41.  * --------------------------------------------------------------------- */
  42.  
  43. struct GfxBase *GfxBase = NULL;            /* the GfxBase */
  44. struct IntuitionBase *IntuitionBase = NULL;    /* the IntuitionBase */
  45.  
  46. /* --------------------------------------------------------------------- *
  47.  *    External Routines and Data Structures.                 *
  48.  * --------------------------------------------------------------------- */
  49.  
  50. extern struct CommandLineInterface *_argcli;
  51. /* extern struct Custom custom; */    /* Aztec 3.40a doesn't need this */
  52.  
  53. /* extern APTR             AllocMem(); */
  54. /* extern struct MsgPort  *CreatePort(); */
  55. /* extern void             DeletePort(); */
  56. /* extern struct IOStdReq *CreateStdIO(); */
  57. /* extern void             DeleteStdIO(); */
  58. /* extern struct task     *FindTask(); */
  59.  
  60. /* --------------------------------------------------------------------- *
  61.  *    Forward Declarations.                         *
  62.  * --------------------------------------------------------------------- */
  63.  
  64. VOID        InitBlitData();
  65. VOID        Blit();
  66. BOOL        Initialize();
  67. VOID        Cleanup();
  68. VOID        DoGeneration();
  69. ULONG        LookForKeys();
  70. VOID            HandlerInterface();
  71.  
  72. /* --------------------------------------------------------------------- */
  73.  
  74. /*
  75.  *   This include file includes the defines for all the blitter functions.
  76.  *   It only allows use of the `blit' operations; for area fills or line
  77.  *   drawing, it will need to be extended.
  78.  *
  79.  *   Information gleaned from the Hardware Reference Manual.
  80.  *   [A little to much, so too little compatibility... [Olaf Seibert]]
  81.  */
  82.  
  83. #define BLTADD (&custom.bltcon0)
  84.  
  85. /*
  86.  *   This structure contains everything we need to know.
  87.  *   Do not do a structure copy into this!  Instead, assign
  88.  *   each field.  The last field assigned must be bltsize; that
  89.  *   starts up the blitter.  Also note that all of these are
  90.  *   write only, and you can't read them.
  91.  */
  92.  
  93. struct BltStruct {
  94.     WORD con0;
  95.     WORD con1;
  96.     WORD afwm;
  97.     WORD alwm;
  98.     WORD *csource, *bsource, *asource, *dsource;
  99.     WORD bltsize;
  100.     WORD dmy1, dmy2, dmy3;
  101.     WORD cmod, bmod, amod, dmod;
  102. };
  103. struct BltStruct *Blitter = (struct BltStruct *)BLTADD;
  104.  
  105. /* --------------------------------------------------------------------- *
  106.  *
  107.  *   Static data for the BLITTER routine.
  108.  *
  109.  *   We need an array which tells what to use
  110.  *   for all 256 possible operations.
  111.  *
  112.  * --------------------------------------------------------------------- */
  113.  
  114. UBYTE ToUse[256];    /* Which DMA channels we need per minterm */
  115. UWORD FwmA[16];        /* First word mask for A source */
  116. UWORD LwmA[16];        /* Last word mask for A source */
  117.  
  118. /*
  119.  *   Call InitBlitData() once on startup before you ever call Blit().
  120.  *   Have a look in the Hardware Reference Manual for the mysterious
  121.  *   bit patterns. They are quite obvious then!
  122.  */
  123.  
  124. VOID InitBlitData()
  125. {
  126.     register WORD i;
  127.     register UWORD s;
  128.  
  129.     for (i=0; i<256; i++) {
  130.         s = DEST >> 8;
  131.         if ((i >> 4) != (i & 15))      /* 15 is 0000 1111 */
  132.             s += SRCA >> 8;
  133.         if (((i >> 2) & 51) != (i & 51))  /* 51 is 0011 0011 */
  134.             s += SRCB >> 8;
  135.         if (((i >> 1) & 85) != (i & 85))  /* 85 is 0101 0101 */
  136.             s += SRCC >> 8;
  137.         ToUse[i] = s;
  138.     }
  139.     s = 0xFFFF;
  140.     for (i=0; i<16; i++) {
  141.         FwmA[i] = s;
  142.         s >>= 1;
  143.         LwmA[i] = 0xffff - s;
  144.     }
  145. }
  146.  
  147. /* --------------------------------------------------------------------- *
  148.  *
  149.  *   This is the major user interface.  Takes addresses and offsets for
  150.  *   all four locations, a modulo and sizes, and a function.
  151.  *   Assumes the modulos for all sources and destination are the same.
  152.  *   You might want to add some arguments or delete some.
  153.  *
  154.  *   All arguments are in pixels (except the addresses and function.)
  155.  *
  156.  *   Before you call this routine, call OwnBlitter(); after you have
  157.  *   called it as many times as you need, call DisownBlitter().  Remember
  158.  *   that you cannot do any printf's or anything else which requires the
  159.  *   blitter when you own the blitter, so be careful with the debug code.
  160.  *   The machine will lock but will not crash.
  161.  *
  162.  *   Note that only the A and B source can be shifted, and that only A
  163.  *   has a first- and last word mask.
  164.  *   Because of this, it is in general recommendable that the low 4 bits
  165.  *   of the C and D x position are the same.
  166.  *   Also note that the complete words that fall in the D area are touched.
  167.  *
  168.  * --------------------------------------------------------------------- */
  169.  
  170. VOID Blit(    aaddress, ax, ay,
  171.         baddress, bx, by,
  172.         caddress, cx, cy,
  173.         daddress, dx, dy,
  174.         modulo, xsize, ysize, function)
  175. WORD *aaddress, *baddress, *caddress, *daddress;
  176. int ax, ay, bx, by, cx, cy, dx, dy, modulo, xsize, ysize, function;
  177. {
  178.     WORD *t;
  179.  
  180. /*
  181.  *   Divide the modulo by 16 because we need words.
  182.  */
  183.     modulo >>= 4;
  184. /*
  185.  *   Wait for the blitter to finish whatever it needs to do.
  186.  */
  187.     WaitBlit();
  188. /*
  189.  *   Calculate the real addresses for d and c.
  190.  */
  191.     Blitter->dsource = daddress + modulo * dy + (dx >> 4);
  192.     Blitter->csource = caddress + modulo * cy + (cx >> 4);
  193. /*
  194.  *   Mask out the low order bits of dx; add these to the xsize.  (The
  195.  *   first bits will be masked using the first word mask.)
  196.  */
  197.     dx &= 15;
  198.     xsize += dx;
  199.     Blitter->afwm = FwmA[dx];
  200.     Blitter->alwm = LwmA[(xsize - 1) & 15];
  201. /*
  202.  *   Now calculate the shifts for the A and B operands.  The barrel
  203.  *   shifter counts appear to be to the left instead of the more
  204.  *   intuitive to the right.  Note that I take dx into account.
  205.  */
  206.     t = aaddress + modulo * ay + (ax >> 4);
  207.     ax = dx - (ax & 15);
  208.     if (ax < 0) {
  209.         t++;
  210.         ax += 16;
  211.     }
  212.     Blitter->asource = t;
  213.     t = baddress + modulo * by + (bx >> 4);
  214.     bx = dx - (bx & 15);
  215.     if (bx < 0) {
  216.         t++;
  217.         bx += 16;
  218.     }
  219.     Blitter->bsource = t;
  220. /*
  221.  *   Now calculate the two control words.  If you want to do
  222.  *   the addresses in reverse order, set the appropriate bit in con1.
  223.  */
  224.     Blitter->con0 = (ax << 12) + (ToUse[function] << 8) + function;
  225.     Blitter->con1 = (bx << 12);
  226. /*
  227.  *   Calculate the final total xsize in words, and the modulos.  The
  228.  *   modulos are in bytes when written from the 68000.
  229.  */
  230.     xsize = (xsize + 15) >> 4;
  231.     Blitter->amod = Blitter->bmod = Blitter->cmod = Blitter->dmod =
  232.         2 * (modulo - xsize);
  233. /*
  234.  *   This last assignment starts up the blitter.
  235.  */
  236.     Blitter->bltsize = (ysize << 6) + xsize;
  237. }
  238.  
  239. /* --------------------------------------------------------------------- */
  240.  
  241. /*
  242.  *   Here we set things up. (Or do we upset them? :-)
  243.  */
  244.  
  245. BOOL Initialize(Screen)
  246. struct Screen *Screen;
  247. {
  248.     register struct BitMap *BitMap = &Screen->BitMap;
  249.     register long Xsize, Ysize;
  250.     register long BytesPerRow;
  251.  
  252.     InitBlitData();
  253.  
  254.     Plane0 = (WORD *) (BitMap->Planes[0]);
  255.     Plane1 = (WORD *) (BitMap->Planes[1]);
  256.     Plane2 = (WORD *) (BitMap->Planes[2]);
  257.     Plane3 = (WORD *) (BitMap->Planes[3]);
  258.     Plane4 = (WORD *) (BitMap->Planes[4]);
  259.  
  260.     /* NoPlanes = BitMap->Depth; */
  261.  
  262.     BytesPerRow = BitMap->BytesPerRow;
  263.     Xsize = BytesPerRow * 8;
  264.     Ysize = BitMap->Rows;
  265.  
  266.     GlobHSizeMin2 = Xsize - 2;
  267.     GlobVSize = Ysize;
  268.     GlobVSizeMin2 = Ysize - 2;
  269.     GlobModulo = (Xsize + 15) & ~15;
  270.  
  271.     if (Temp1)    /* This really shouldn't happen... */
  272.         return FALSE;
  273.  
  274.     Temp1 = AllocRaster(Xsize, Ysize);
  275.  
  276.     if (UseBlitter && Temp1) {
  277.         Temp2 = AllocRaster(Xsize, Ysize);
  278.         Temp3 = AllocRaster(Xsize, Ysize);
  279.         Temp4 = AllocRaster(Xsize, Ysize);
  280.         Temp5 = AllocRaster(Xsize, Ysize);
  281.  
  282.         if (Temp2 && Temp3 && Temp4 && Temp5) {
  283.             SetAPen(&Screen->RastPort, 0L);
  284.             SetDrMd(&Screen->RastPort, JAM1);
  285.             Move(&Screen->RastPort, 0L, 0L);
  286.             Draw(&Screen->RastPort, Xsize-1, 0L);
  287.             Move(&Screen->RastPort, 0L, Ysize-1);
  288.             Draw(&Screen->RastPort, Xsize-1, Ysize-1);
  289.             return FALSE;
  290.         }
  291.  
  292.     } 
  293.     
  294.     if (Temp1) {    /* We can use the slower algorithm */
  295.         if (Temp2) FreeRaster(Temp2, Xsize, Ysize);
  296.         if (Temp3) FreeRaster(Temp3, Xsize, Ysize);
  297.         if (Temp4) FreeRaster(Temp4, Xsize, Ysize);
  298.         if (Temp5) FreeRaster(Temp5, Xsize, Ysize);
  299.  
  300.         Temp2 = Temp3 = Temp4 = Temp5 = NULL;
  301.  
  302.         ARegs.A1 = ((LONG) Temp1) + BytesPerRow;
  303.         ARegs.A2 = ((LONG) Plane0) + BytesPerRow * (Ysize - 1L);
  304.         ARegs.A3 = (LONG) Plane0;
  305.         ARegs.A0 = ARegs.A3 + BytesPerRow;
  306.         ARegs.A4 = ARegs.A0 + BytesPerRow;
  307.  
  308.         return FALSE;
  309.     }
  310.  
  311.     Cleanup(Screen);
  312.     return TRUE;
  313. }
  314.  
  315.  
  316. /*
  317.  *   Deallocation routine.
  318.  */
  319.  
  320. VOID Cleanup(Screen)
  321. struct Screen *Screen;
  322. {
  323.     register struct BitMap *BitMap = &Screen->BitMap;
  324.     register long Xsize, Ysize;
  325.  
  326.     Xsize = BitMap->BytesPerRow * 8;
  327.     Ysize = BitMap->Rows;
  328.  
  329.     if (Temp1) FreeRaster(Temp1, Xsize, Ysize);
  330.     if (Temp2) FreeRaster(Temp2, Xsize, Ysize);
  331.     if (Temp3) FreeRaster(Temp3, Xsize, Ysize);
  332.     if (Temp4) FreeRaster(Temp4, Xsize, Ysize);
  333.     if (Temp5) FreeRaster(Temp5, Xsize, Ysize);
  334.  
  335.     Temp1 = Temp2 = Temp3 = Temp4 = Temp5 = NULL;
  336. }
  337.  
  338. /* --------------------------------------------------------------------- *
  339.  *                   --   - -   --
  340.  *   SUM3:    D = ABC + ABC + ABC + ABC = A XOR B XOR C.
  341.  *    Adds the value of the pixels in A, B and C. Ignores carry.
  342.  *                -    -    -
  343.  *   CARRY3:    D = ABC + ABC + ABC + ABC.
  344.  *    Gets the carry for SUM3.
  345.  *             -   - 
  346.  *   SUM2:    D = AB + AB = A XOR C.
  347.  *    Adds the value of the pixels in A and B. Ignores carry.
  348.  *
  349.  *   CARRY2:    D = AB.
  350.  *    Gets the carry for SUM2.
  351.  *             --   --
  352.  *   SPECIAL1:    D = ABC + ABC.
  353.  *    A = Temp1  (2) low bit of high sum
  354.  *    B = Temp4  (4) high bit of high sum
  355.  *    C = Temp3  (2) high bit of low sum, carry
  356.  *    D = Temp2  Only 1 if sum is 2 or 3: Not 4 and exactly one 2 value
  357.  *                -    -
  358.  *   SPECIAL2:    D = ABC + ABC + ABC.
  359.  *    A = Temp2  Only 1 if 2 or 3 neighbours: only place where can be a cell
  360.  *    B = Temp5  Only 1 if odd # of neighbours
  361.  *    C = last generation
  362.  *    D = new generation
  363.  *
  364.  * --------------------------------------------------------------------- */
  365.  
  366. #define    SUM3        (int) (ABC   | ANBNC | NABNC | NANBC)    /* 0x96 */
  367. #define    CARRY3        (int) (ABC   | ABNC  | ANBC  | NABC)    /* 0xE8 */
  368. #define    SUM2        (int) (ANBC  | ANBNC | NABC  | NABNC)    /* 0x3C */
  369. #define    CARRY2        (int) (ABC   | ABNC)            /* 0xC0 */
  370. #define    SPECIAL1    (int) (ANBNC | NANBC)            /* 0x12 */
  371. #define    SPECIAL2    (int) (ABC   | ABNC  | ANBC)        /* 0xE0 */
  372. #define    COPY        (int) (A_TO_D)                /* 0xF0 */
  373.  
  374. /* --------------------------------------------------------------------- *
  375.  *                                     *
  376.  *   Does one LIFE generation.  Fancy algorithm uses only 10 blits.  If  *
  377.  *   anyone can improve this, please let me know.             *
  378.  *   [If only I could determine `3 or 4' in one blit: it would save     *
  379.  *   TWO blits!]                             *
  380.  *                                     *
  381.  * --------------------------------------------------------------------- */
  382.  
  383. VOID DoGeneration()
  384. {
  385.     register int HSizeMin2 = GlobHSizeMin2;
  386.     register int VSize     = GlobVSize;
  387.     register int VSizeMin2 = GlobVSizeMin2;
  388.     register int Modulo    = GlobModulo;
  389.  
  390.     if (Temp2) {    /* We have 5 temporary planes. Use the blitter! */
  391.     OwnBlitter();
  392. /*
  393.  *   Take horizontal sums.
  394.  *   Every pair of pixels in Temp1/Temp2 is the sum of the three horizontal
  395.  *   pixels of which that one is the middle.
  396.  */
  397.     Blit(    Plane0, 0, 0,    /* A pixel left */
  398.         Plane0, 2, 0,    /* A pixel right */
  399.         Plane0, 1, 0,    /* The middle pixel */
  400.         Temp1,  1, 0,    /* Low bit of the sum */
  401.         Modulo, HSizeMin2, VSize, SUM3);
  402.     Blit(    Plane0, 0, 0,
  403.         Plane0, 2, 0,
  404.         Plane0, 1, 0,
  405.         Temp2,  1, 0,    /* High bit of the same */
  406.         Modulo, HSizeMin2, VSize, CARRY3);
  407. /*
  408.  *   Take sums for middle row.
  409.  *   Every pair of pixels in Temp3/Temp4 is the sum of the two horizontal
  410.  *   pixels next to the one in the middle.
  411.  */
  412.     Blit(    Plane0, 0, 0,    /* Pixel left */
  413.         Plane0, 2, 0,    /* Pixel right */
  414.         NULL,   0, 0,    /* This is ignored */
  415.         Temp3,  1, 0,    /* Low bit of the sum */
  416.         Modulo, HSizeMin2, VSize, SUM2);
  417.     Blit(    Plane0, 0, 0,
  418.         Plane0, 2, 0,
  419.         NULL,   0, 0,
  420.         Temp4,  1, 0,    /* High bit of the same */
  421.         Modulo, HSizeMin2, VSize, CARRY2);
  422. /*
  423.  *   Now, sum each of the three columns.
  424.  *   Add vertically low bits of up -o+, down -o+, and -+, to Temp5/Temp3.
  425.  *   For a proper addition, this carry should be added to
  426.  *   the sum of the high bits.
  427.  */
  428.     Blit(    Temp1, 1, 0,    /* 3 bits above */
  429.         Temp1, 1, 2,    /* 3 bits below */
  430.         Temp3, 1, 1,    /* 2 bits left and right */
  431.         Temp5, 1, 1,    /* Low bit of sum of low bits, value 1 */
  432.         Modulo, HSizeMin2, VSizeMin2, SUM3);
  433.     Blit(    Temp1, 1, 0,
  434.         Temp1, 1, 2,
  435.         Temp3, 1, 1,
  436.         Temp3, 1, 1,    /* Carry of sum of low bits, value 2 */
  437.         Modulo, HSizeMin2, VSizeMin2, CARRY3);
  438. /*
  439.  *   Add the high bits of the same to Temp1/Temp4.
  440.  */
  441.     Blit(    Temp2, 1, 0,    /* 3 bits above, high bit */
  442.         Temp2, 1, 2,    /* 3 bits below, high bit */
  443.         Temp4, 1, 1,    /* 2 bits left & right, high bit */
  444.         Temp1, 1, 1,    /* Low bit of sum of high bits, value 2 */
  445.         Modulo, HSizeMin2, VSizeMin2, SUM3);
  446.     Blit(    Temp2, 1, 0,
  447.         Temp2, 1, 2,
  448.         Temp4, 1, 1,
  449.         Temp4, 1, 1,    /* High bit of sum of high bits, value 4 */
  450.         Modulo, HSizeMin2, VSizeMin2, CARRY3);
  451. /*
  452.  *   Now, the situation is as follows: If the number of neighbours is
  453.  *        0  1  2  2  3  3  4  4  5  5  6  6  7  7  8  Value
  454.  *   Temp5 | 0  1  0  0  1  1  0  0  1  1  0  0  1  1  0   = 1 Low sum
  455.  *   Temp3 | 0  0  1  0  1  0  1  0  1  0  1  0  1  0  1   = 2 Low carry
  456.  *   Temp1 | 0  0  0  1  0  1  1  0  1  0  0  1  0  1  1   = 2 High sum
  457.  *   Temp4 | 0  0  0  0  0  0  0  1  0  1  1  1  1  1  1   = 4 High carry
  458.  *
  459.  *   Now, check high two order bits, then combine with original and
  460.  *   low order bit.    ANBNC + NANBC. -- Temp1./Temp4./Temp3 + /Temp1./Temp4.Temp3
  461.  */
  462.     Blit(    Temp1, 1, 1,    /* Either Temp1 or Temp3 must be 1 */
  463.         Temp4, 1, 1,    /* but Temp4 certainly not, */
  464.         Temp3, 1, 1,    /* so the result */
  465.         Temp2, 1, 1,    /* gets 1 if the sum is 2 or 3. */
  466.         Modulo, HSizeMin2, VSizeMin2, SPECIAL1);
  467. /*
  468.  *   Before we do the final write, we copy bits down one generation.
  469.  *   Pushing zeros for ignored arguments is faster than any
  470.  *   other value.
  471.  */
  472.     switch (NoPlanes) {
  473.     case 5:
  474.         Blit(    Plane3, 1, 1,
  475.             NULL,   0, 0,
  476.             NULL,   0, 0,
  477.             Plane4, 1, 1,
  478.             Modulo, HSizeMin2, VSizeMin2, COPY);
  479.     case 4:
  480.         Blit(    Plane2, 1, 1,
  481.             NULL,   0, 0,
  482.             NULL,   0, 0,
  483.             Plane3, 1, 1,
  484.             Modulo, HSizeMin2, VSizeMin2, COPY);
  485.     case 3:
  486.         Blit(    Plane1, 1, 1,
  487.             NULL,   0, 0,
  488.             NULL,   0, 0,
  489.             Plane2, 1, 1,
  490.             Modulo, HSizeMin2, VSizeMin2, COPY);
  491.     case 2:
  492.         Blit(    Plane0, 1, 1,
  493.             NULL,   0, 0,
  494.             NULL,   0, 0,
  495.             Plane1, 1, 1,
  496.             Modulo, HSizeMin2, VSizeMin2, COPY);
  497.     default: 
  498.         ;
  499.     }
  500.  
  501.     Blit(    Temp2,  1, 1,
  502.         Temp5,  1, 1,
  503.         Plane0, 1, 1,
  504.         Plane0, 1, 1,
  505.         Modulo, HSizeMin2, VSizeMin2, SPECIAL2);
  506.  
  507.     DisownBlitter();
  508.     } else {    /* Not enough Temp space. Use processor instead. */
  509. #asm
  510.     xdef    slow
  511.     xdef    again
  512. slow:
  513.     movem.l    D2-D4/D7/A2-A4,-(sp)    ;Save registers except A0, A1, D0, D1
  514.  
  515. ;;    Register usage:
  516. ;;    A0 = pointer to current longword in screen
  517. ;;    A1 = pointer to current longword in temp storage
  518. ;;    A2 = pointer beyond last longword in screen we use
  519. ;;    A3 = pointer to -80(A0) for hires and -40(A0) for lores: line above
  520. ;;    A4 = pointer to 80(A0) for hires and 40(A0) for lores: line below
  521.  
  522.     movem.l    _ARegs,A0-A4        ;Get precalculated pointers
  523.  
  524. ;;    From this point on, DO NOT access memory 'absolute'ly 
  525. ;;    since the assembler wants to use A4 as a base register.
  526. ;;    Fortunately, we don't need to.
  527. ;;
  528. ;;    1 2 3    The cells are numbered like this.
  529. ;;    7 . 8
  530. ;;    4 5 6
  531.  
  532. ;;    (D1,D0) = neighbours 1+2. D1 contains the 32 high bits.
  533.  
  534. again:
  535.     move.l    (A3),D0            ;Get the bits above
  536.     move.l    D0,D1
  537.     move.l    D0,D2            ;Save this for #3
  538.     move.b    -1(A3),D7        ;Get number 1
  539.     roxr.b    #1,D7            ; and shift it into D0
  540.     roxr.l    #1,D0
  541.  
  542.     eor.l    D1,D0            ;trick to add 2 bits x 32: low bit
  543.     or.l    D0,D1
  544.     eor.l    D0,D1            ;high bit of sum
  545.  
  546. ;;    (D1,D0) = neighbours 1+2+3.
  547.  
  548.     move.b    4(A3),D7        ;Get bit for # 3
  549.     roxl.b    #1,D7            ; into X bit
  550.     roxl.l    #1,D2            ; to D2
  551.  
  552.     eor.l    D2,D0            ;low bit of new number
  553.     or.l    D0,D2
  554.     eor.l    D0,D2
  555.     or.l    D2,D1            ;high bit of sum
  556.  
  557. ;;    (D3,D2) = neighbours 4+5
  558.  
  559.     move.l    (A4),D2
  560.     move.l    D2,D3
  561.     move.l    D2,D4
  562.     move.b    -1(A4),D7
  563.     roxr.b    #1,D7
  564.     roxr.l    #1,D2            ;# 4 shifted right
  565.  
  566.     eor.l    D3,D2            ;low bit of sum
  567.     or.l    D2,D3
  568.     eor.l    D2,D3
  569.  
  570. ;;    (D3,D2) = neighbours 4+5+6
  571.  
  572.     move.b    4(A4),D7
  573.     roxl.b    #1,D7
  574.     roxl.l    #1,D4            ;#6 shifted left
  575.  
  576.     eor.l    D4,D2            ;low bits
  577.     or.l    D2,D4
  578.     eor.l    D2,D4
  579.     or.l    D4,D3            ;carry over
  580.  
  581.  
  582. ;;    (D2,D1,D0) = neighbours 1+2+3+4+5+6
  583. ;;    Add (D3,D2) to (D1,D0)
  584.  
  585.     eor.l    D2,D0            ;low bits
  586.     or.l    D0,D2
  587.     eor.l    D0,D2            ;carry of low bits
  588.  
  589.     eor.l    D2,D1            ;carry of low bits to high bits
  590.     or.l    D1,D2
  591.     eor.l    D1,D2
  592.  
  593.     eor.l    D3,D1            ;sum high bits
  594.     or.l    D1,D3
  595.     eor.l    D1,D3
  596.     or.l    D3,D2            
  597.  
  598. ;;    (D4,D3) = neighbours 7+8
  599.  
  600.     move.l    (A0),D3
  601.     move.l    D3,D4
  602.     move.b    -1(A0),D7
  603.     roxr.b    #1,D7
  604.     roxr.l    #1,D3            ;bits for #7 shifted right
  605.     move.b    4(A0),D7
  606.  
  607.     roxl.b    #1,D7
  608.     roxl.l    #1,D4            ;bits for #8 shifted left
  609.  
  610.     eor.l    D4,D3
  611.     or.l    D3,D4
  612.     eor.l    D3,D4
  613.  
  614. ;;    (D2,D1,D0) = neighbours 1+2+3+4+5+6+7+8
  615. ;;    Note that carry is ignored, so 8 == 0, but fortunately
  616. ;;    both are wrong, and so is 1.
  617.  
  618.     eor.l    D3,D0            ;low bits
  619.     or.l    D0,D3
  620.     eor.l    D0,D3
  621.  
  622.     eor.l    D3,D1            ;carry over to mid bits
  623.     or.l    D1,D3
  624.     eor.l    D1,D3
  625.  
  626.     eor.l    D4,D1            ;sum mid bits
  627.     or.l    D1,D4
  628.     eor.l    D1,D4
  629.  
  630.     or.l    D3,D2
  631.     or.l    D4,D2
  632.  
  633. ;;    Next generation
  634.  
  635.     or.l    (A0)+,D0        ;Give existing cells an odd # (2->3)
  636.     not.l    D2            ;A 4-worth bit is wrong
  637.     and.l    D2,D0            ;and both the 1-worth and the
  638.     and.l    D1,D0            ;2-worth must be 1 for a sum of 3
  639.  
  640.     move.l    D0,(A1)+        ;Get it into the destination
  641.  
  642.     lea    4(A3),A3        ;Advance other pointers
  643.     lea    4(A4),A4
  644.  
  645.     cmp.l    A2,A0            ;See if we are done yet
  646.     blt    again
  647.  
  648.     movem.l    (sp)+,D2-D4/D7/A2-A4    ;Restore registers
  649.  
  650. #endasm
  651.         OwnBlitter();
  652.         Blit(    Temp1,  1, 1,
  653.             NULL,   0, 0,
  654.             NULL,   0, 0,
  655.             Plane0, 1, 1,
  656.             Modulo, HSizeMin2, VSizeMin2, COPY);
  657.         DisownBlitter();
  658.     }    /* End if we may use blitter */
  659. }
  660.  
  661. /* --------------------------------------------------------------------- */
  662. /* --------------------------------------------------------------------- */
  663. /* --------------------------------------------------------------------- */
  664.  
  665. #define    ACTIVATEKEY    0x55    /* F6 */
  666. #define    GENERATIONKEY    0x56    /* F7 */
  667. #define    DYNASTYKEY    0x57    /* F8 */
  668.  
  669. /* --------------------------------------------------------------------- *
  670.  *
  671.  *    HandlerInterface()
  672.  *
  673.  *    This code is needed to convert the calling sequence performed by
  674.  *    the input.task for the  input stream  management into  something
  675.  *    that a C program can understand.
  676.  *
  677.  *    This routine expects a pointer to an InputEvent in A0, a pointer
  678.  *    to a data area in A1.  These values are transferred to the stack
  679.  *    in the order that a C program would need to find them. Since the
  680.  *    actual handler is written in C, this works out fine. 
  681.  *    If it wouldn't, we would do it another way :-)
  682.  *
  683.  *    Author: Rob Peck, 12/1/85
  684.  *    Manxified by Olaf Seibert (KosmoSoft) (Not very much work...)
  685.  *
  686.  * --------------------------------------------------------------------- */
  687.  
  688. #asm
  689.     xref    _MyHandler
  690.  
  691. _HandlerInterface:
  692.     movem.L    A0/A1,-(SP)
  693.     jsr    _MyHandler
  694.     addq.L    #8,SP
  695.     rts
  696.  
  697. #endasm
  698.  
  699. /* --------------------------------------------------------------------- *
  700.  *    Global variables shared by the interrupt code.             *
  701.  * --------------------------------------------------------------------- */
  702.  
  703. typedef struct
  704. {
  705.     struct Task    *LifeTask;    /* Actually, Process */
  706.     ULONG         Activate;    /* Signal masks */
  707.     ULONG         Generation;
  708.     ULONG         Dynasty;
  709.     BYTE         Active;    /* Are we active (mem. allocated) */
  710.     BYTE         Padding00;
  711.     struct Screen    *Screen;    /* Front screen */
  712.     struct IntuitionBase *IBase;    /* Share the tasks pointer */
  713. } GLOBAL_DATA;
  714.  
  715. GLOBAL_DATA        Global;
  716. struct Interrupt    handlerStuff;
  717.  
  718. /* --------------------------------------------------------------------- */
  719.  
  720. ULONG LookForKeys(Code, gptr)
  721. UBYTE Code;
  722. register GLOBAL_DATA *gptr;
  723. {
  724.     if (Code == ACTIVATEKEY) {
  725.         gptr->Screen = gptr->IBase->FirstScreen;
  726.         gptr->Active = !gptr->Active;
  727.         return gptr->Activate;
  728.     }
  729.  
  730.     if (Code == GENERATIONKEY && gptr->Active)
  731.         return gptr->Generation;
  732.  
  733.     if (Code == DYNASTYKEY && gptr->Active)
  734.         return gptr->Dynasty;
  735.  
  736.     return 0;
  737. }
  738.  
  739. /* --------------------------------------------------------------------- *
  740.  * The handler subroutine - Called through the handler stub.         *
  741.  * --------------------------------------------------------------------- */
  742.  
  743. struct InputEvent *MyHandler(ev, gptr)
  744. struct InputEvent *ev;        /* and a pointer to a list of events */
  745. register GLOBAL_DATA *gptr;    /* Everything we need to know about */
  746. {
  747.     register struct InputEvent *ep, *laste;
  748.     register ULONG Signals;
  749.  
  750.     int_start();    /* Manx peculiarity. Saves D2-D3 and A4. */
  751.  
  752.     /* Run down the list of events to see if they pressed    */
  753.     /* one of the magic buttons.                */
  754.     for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
  755.     {
  756.         if ((ep->ie_Class == IECLASS_RAWKEY) &&
  757.             (ep->ie_Qualifier & IEQUALIFIER_LCOMMAND))
  758.         {
  759.             if (Signals = LookForKeys(ep->ie_Code, gptr)) {
  760.                 /* We can handle this event so take it off the chain */
  761.                 if (laste == NULL)
  762.                     ev = ep->ie_NextEvent;
  763.                 else
  764.                     laste->ie_NextEvent = ep->ie_NextEvent;
  765.                 /* Now tell him to do its thing */
  766.                 Signal(gptr->LifeTask, Signals);
  767.             }
  768.         }
  769.         else
  770.             laste = ep;
  771.  
  772.     }
  773.  
  774.     int_end();    /* Manx peculiarity */
  775.  
  776.     /* Pass on the pointer to the event */
  777.     return ev;
  778. }
  779.  
  780. /* --------------------------------------------------------------------- *
  781.  *     Our initial greeting messages for the user.             *
  782.  *    PopLife - a joke thrown together by Olaf Seibert, KosmoSoft     *
  783.  * --------------------------------------------------------------------- */
  784.  
  785. char Header[] = "\n\
  786. \x9B0;1;33mPopLife\x9B0;31m - a joke thrown together by \x9B33mOlaf Seibert, KosmoSoft\x9B31m\n\
  787. ";
  788.  
  789. char Greetings[] = "\
  790. \x9B33mUsage:\x9B31m \x9B1mRUN PopLife\x9B0m\n\
  791. \x9B33mKeys:\x9B31m  \x9B1mLeft Amiga F6:\x9B0m Initialize & Cleanup temporary storage\n\
  792.        \x9B1mLeft Amiga F7:\x9B0m Single generation\n\
  793.        \x9B1mLeft Amiga F8:\x9B0m Many generations\n\
  794. ";
  795.  
  796. char GoodBye[] = "\
  797. \n\
  798. Killing the other PopLife incarnation...\n\
  799. ";
  800.  
  801. char PortName[] = "poplife.input.device.port";
  802.  
  803. /* --------------------------------------------------------------------- *
  804.  *     A Cleanup support function. Close the IO if we are not a CLI.     *
  805.  * --------------------------------------------------------------------- */
  806.  
  807. VOID CloseFiles()
  808. {
  809.     register struct FileHandle *input, *output;
  810.  
  811.     /* - From  Workbench.  Let 'em read  the message. - */
  812.  
  813.     if (!_argcli) {
  814.         input = Input();
  815.         output = Output();
  816.  
  817.         if (IsInteractive(input))
  818.             WaitForChar(input, 10 * 1000000);
  819.  
  820.         /* Unfortunately from the CLI we can't Close those files */
  821.         /* because they are `given' to us. */
  822.         /* (Unless we want to crash after we exit...) */
  823.         /* Besides, it won't help because there is always an open */
  824.         /* file to the console left: _argcli->cli_CurrentOutput */
  825.         /* EVEN if we RUN PopLife <NIL: >NIL: */
  826.  
  827.         if (input != output)
  828.             Close(input);
  829.         Close(output);
  830.     }
  831. }
  832.  
  833. /* --------------------------------------------------------------------- *
  834.  *     The main program to do the PopLife stuff.             *
  835.  * --------------------------------------------------------------------- */
  836.  
  837. VOID main(argc, argv)
  838. int argc;        /* This should always be -1, since */
  839. char *argv;        /* I use my own startup module */
  840. {
  841.     register struct Screen *Screen = NULL;
  842.     struct MsgPort *inputDevPort;
  843.     struct IOStdReq *inputRequestBlock;
  844.     register ULONG WaitMask;
  845.     ULONG Sig1 = 0, Sig2 = 0, Sig3 = 0;
  846.  
  847.     /* ------------------------------------------------------------- *
  848.      *    First find out if there is already another PopLife
  849.      *    hanging around. If so, kick it out of existance.
  850.      *    Handy for Workbench users, and our own protection.
  851.      *    There is a possibility of a race here ==> Forbid()...
  852.      * ------------------------------------------------------------- */
  853.  
  854.     Forbid();
  855.  
  856.     if (inputDevPort = FindPort(PortName)) {
  857.         Signal(inputDevPort->mp_SigTask, SIGBREAKF_CTRL_C);
  858.         Write(Output(), Header,  (long) sizeof(Header));
  859.         Write(Output(), GoodBye, (long) sizeof(GoodBye));
  860.         goto abortp;
  861.     }
  862.  
  863.     if ((inputDevPort = CreatePort(PortName,0L)) == NULL) {
  864.         goto abortp;
  865.     }
  866.  
  867.     Permit();
  868.  
  869.     if ((inputRequestBlock = CreateStdIO(inputDevPort)) == NULL)
  870.         goto abort;
  871.  
  872.     if ((GfxBase = (struct GfxBase *)
  873.         OpenLibrary("graphics.library", 0)) == NULL)
  874.         goto abort;
  875.  
  876.     if ((IntuitionBase = (struct IntuitionBase *)
  877.         OpenLibrary("intuition.library", 0)) == NULL)
  878.         goto abort;
  879.  
  880.     Global.IBase = IntuitionBase;
  881.  
  882.     Sig1 = AllocSignal(-1L);
  883.     Sig2 = AllocSignal(-1L);
  884.     Sig3 = AllocSignal(-1L);
  885.     if (Sig1 < 0 || Sig2 < 0 || Sig3 < 0)
  886.         goto abort;
  887.  
  888.     Global.Activate   = 1L << Sig1;
  889.     Global.Generation = 1L << Sig2;
  890.     Global.Dynasty    = 1L << Sig3;
  891.  
  892.     handlerStuff.is_Data = (APTR)&Global;
  893.     handlerStuff.is_Code = HandlerInterface;
  894.     handlerStuff.is_Node.ln_Succ =
  895.     handlerStuff.is_Node.ln_Pred = NULL;
  896.     handlerStuff.is_Node.ln_Type = NT_INTERRUPT;
  897.     handlerStuff.is_Node.ln_Pri = 51;
  898.     handlerStuff.is_Node.ln_Name = "PopLife.input.handler";
  899.  
  900.     if (OpenDevice("input.device",0L,inputRequestBlock,0L))
  901.         goto abort;
  902.  
  903.     inputRequestBlock->io_Command = IND_ADDHANDLER;
  904.     inputRequestBlock->io_Data    = (APTR)&handlerStuff;
  905.  
  906.     DoIO(inputRequestBlock);
  907.  
  908.     Global.LifeTask = FindTask(NULL);
  909.     Global.Active = FALSE;
  910.  
  911.     /* - See if we should not use the blitter, to save memory - */
  912.  
  913.     if (argv[0] == '1')
  914.         UseBlitter = FALSE;
  915.  
  916.     /* - Time to greet the user - if AmigaDOG will let us. - */
  917.  
  918.     {
  919.         struct FileHandle *File;
  920.  
  921.         File = Output();
  922.         Write(File, Header,    (long) sizeof(Header));
  923.         Write(File, Greetings, (long) sizeof(Greetings));
  924.         CloseFiles();
  925.     }
  926.  
  927.     WaitMask = Global.Activate | Global.Generation | Global.Dynasty |
  928.            SIGBREAKF_CTRL_C;
  929.  
  930.     for(;;) {    /* - FOREVER - */
  931.         ULONG Sig = Wait(WaitMask);
  932.  
  933.         if (Sig & SIGBREAKF_CTRL_C)
  934.             break;
  935.  
  936.         if (Sig & Global.Activate) {
  937.             if (Global.Active) {
  938.                 Screen = Global.Screen;
  939.                 if (Initialize(Screen)) {
  940.                     Global.Active = FALSE;
  941.                     DisplayBeep(NULL);
  942.                     Screen = NULL;
  943.                     continue;
  944.                 }
  945.             } else {
  946.                 Cleanup(Screen);
  947.                 Screen = NULL;
  948.                 continue;
  949.             }
  950.         }
  951.  
  952.         if (Sig & Global.Dynasty) {
  953.             do {    /* - Quite a dynasty! - */
  954.                 DoGeneration();
  955.             } while (! (SetSignal(0L, 0L) & WaitMask));
  956.             /* - Forget a second hit of the Dynasty key - */
  957.             SetSignal(0L, Global.Dynasty);
  958.             continue;
  959.         }
  960.  
  961.         if (Sig & Global.Generation) {
  962.             DoGeneration();
  963.         }
  964.  
  965.     }    /* - End FOREVER - */
  966.  
  967.     inputRequestBlock->io_Command = IND_REMHANDLER;
  968.  
  969.     DoIO(inputRequestBlock);
  970.  
  971. abort:
  972.     if (Screen)    Cleanup(Screen);
  973.  
  974.     if (Sig1 >= 0)    FreeSignal(Sig1);
  975.     if (Sig2 >= 0)    FreeSignal(Sig2);
  976.     if (Sig3 >= 0)    FreeSignal(Sig3);
  977.  
  978.     if (inputRequestBlock != NULL)    DeleteStdIO(inputRequestBlock);
  979.     if (inputDevPort != NULL)    DeletePort(inputDevPort);
  980.  
  981.     if (IntuitionBase != NULL)    CloseLibrary(IntuitionBase);
  982.     if (GfxBase != NULL)        CloseLibrary(GfxBase);
  983.  
  984.     return;
  985.  
  986. abortp:
  987.     Permit();
  988.     CloseFiles();
  989. }
  990.