home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- * BlitDemons by Walter Strickler
- * This program and all its source code are in the public domain and are
- * freely distributable and usable for any purpose, private or commercial.
- ******************************************************************************/
- #include "bdemon.h"
- #include <hardware/custom.h>
- #include <hardware/blit.h>
-
-
- /* This is what it's all about: THE ALGORITHM without the Intuition fluff */
-
- /*******************************************************************************
- * Local prototypes...
- ******************************************************************************/
- void BlitIncrement(struct DoBlitNode *, struct BDMainStruct *);
- void BlitCompare(struct DoBlitNode *, struct BDMainStruct *, int, int);
- void UpdateEqual(struct DoBlitNode *, struct BDMainStruct *);
- void BlitOutput(struct DoBlitNode *, struct BDMainStruct *);
- void InitBlitData();
- void Blit(struct DoBlitNode *,
- WORD *, int, int,
- WORD *, int, int,
- WORD *, int,
- WORD *, int,
- int, int, int, int, int);
- void DoBlit(struct DoBlitNode *);
-
-
- /*******************************************************************************
- * These defines will be used in the Blit() calls in this file.
- ******************************************************************************/
- #define NEG_A NANBNC | NANBC | NABNC | NABC /* Negate A */
- #define A_XOR_B NABC | NABNC | ANBC | ANBNC /* A ^ B */
- #define A_XOR_BANDC ANBNC | ANBC | NABC | ABNC /* A ^ (B&C) */
- #define A_EQUIV_B NANBNC | NANBC | ABNC | ABC /* ~(A^B) */
- #define COMPARE NANBC | ABC
- #define OUTPUT_FUNC ABC | NABC | NANBC | ABNC
-
-
- /*******************************************************************************
- * Define the number of blits in each step.
- ******************************************************************************/
- #define INCR_BLITS 5
- #define COMPARE_BLITS 4
- #define UPDATE_BLITS 1
- #define OUTPUT_BLITS 4
- #define TOTAL_BLITS (INCR_BLITS + COMPARE_BLITS * 4 + OUTPUT_BLITS + \
- UPDATE_BLITS * 3)
-
-
- /**************************************************************************
- * OneGen() performs one demons generation on the planes in PlaneData,
- * using the DoBlitNode pointed at by BlitNodes. Performs TOTAL_BLITS
- * blits.
- *************************************************************************/
- void OneGen(BDSchtoff)
- struct BDMainStruct *BDSchtoff;
-
- {
- int i;
- struct DoBlitNode *BlitNodes;
-
- OwnBlitter();
- BlitNodes = BDSchtoff -> BDBlitNodes;
- for (i = 0; i < TOTAL_BLITS; i++)
- {
- DoBlit(&(BlitNodes[i]));
- }
- DisownBlitter();
- }
-
-
- /**************************************************************************
- * InitBlits() allocates an array of DoBlitNodes, then fills it so that
- * when OneGen() is run on this array, it does a demons generation on
- * the given bitplanes.
- * The actual blitter algorithm came from the Apex version, written by
- * Loren Blaney.
- *************************************************************************/
- struct DoBlitNode *InitBlits (PlaneData)
- struct BDMainStruct *PlaneData;
-
- {
- struct DoBlitNode *BlitData;
- int NodeCount;
-
- InitBlitData(); /* Need to do this somewhere */
- BlitData = (struct DoBlitNode *) malloc(sizeof(struct DoBlitNode) *
- TOTAL_BLITS);
- if (BlitData != NULL)
- {
- NodeCount = 0;
- /* Step 1: Increment Display[] into Incr[]
- * Incr[] = Display[] + 1
- */
- BlitIncrement(&(BlitData[NodeCount]), PlaneData);
- NodeCount = NodeCount + INCR_BLITS;
-
- /* Step 2: Compare a cell's incremented value (Incr[])
- * with its 4 nearest neighbors. If any are equal, then set
- * Equal[] flag.
- */
- BlitCompare(&(BlitData[NodeCount]), PlaneData, TO_EQUAL, UP_NEIGHBOR);
- NodeCount = NodeCount + COMPARE_BLITS;
- /* Now Equal = (Incr == Up) */
-
- BlitCompare(&(BlitData[NodeCount]), PlaneData, TO_TEMP, LEFT_NEIGHBOR);
- NodeCount = NodeCount + COMPARE_BLITS;
- UpdateEqual(&(BlitData[NodeCount]), PlaneData);
- NodeCount = NodeCount + UPDATE_BLITS;
- /* Now Equal = (Incr == Up) | (Incr == Left) */
-
- BlitCompare(&(BlitData[NodeCount]), PlaneData, TO_TEMP, RIGHT_NEIGHBOR);
- NodeCount = NodeCount + COMPARE_BLITS;
- UpdateEqual(&(BlitData[NodeCount]), PlaneData);
- NodeCount = NodeCount + UPDATE_BLITS;
- /* Now Equal = (Incr == Up) | (Incr == Left) | (Incr == Right) */
-
- BlitCompare(&(BlitData[NodeCount]), PlaneData, TO_TEMP, DOWN_NEIGHBOR);
- NodeCount = NodeCount + COMPARE_BLITS;
- UpdateEqual(&(BlitData[NodeCount]), PlaneData);
- NodeCount = NodeCount + UPDATE_BLITS;
- /* Now Equal = 1 if ANY neighbor(s) is/are equal to Incr */
-
- /* Step 3: Blit the results (Equal) to the display as follows:
- * if (Equal == 0) { Display[] = Display[]; }
- * else { Display[] = Incr[]; }
- */
- BlitOutput(&(BlitData[NodeCount]), PlaneData);
- /* Bimbo! */
- }
- else
- {
- BlitData = NULL; /* Error return */
- }
- return BlitData;
- }
-
-
- /*******************************************************************************
- * BlitIncrement() increments the bitplane array pointed at by
- * Planes -> Display, and stores the result in Planes -> Incr. Uses the
- * blitter. Make sure you own the blitter before calling this.
- *******************************************************************************/
- void BlitIncrement(BlitData, Planes)
- struct DoBlitNode *BlitData;
- struct BDMainStruct *Planes;
-
- {
- WORD **Disp,
- **Incr,
- *Temp;
-
- Disp = Planes -> Display;
- Incr = Planes -> Incr;
- Temp = Planes -> Temp;
-
- /* Increment Blit #1.
- * Incr[0] = ~Disp[0]
- * D = ~A
- */
- Blit(&(BlitData[0]),
- Disp[0], 0, 0,
- NULL, 0, 0,
- NULL, 0,
- Incr[0], 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, NEG_A);
-
- /* Increment Blit #2.
- * Incr[1] = Disp1 ^ Disp0
- * D = A ^ B
- */
- Blit(&(BlitData[1]),
- Disp[1], 0, 0,
- Disp[0], 0, 0,
- NULL, 0,
- Incr[1], 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, A_XOR_B);
-
- /* Increment Blit #3.
- * Incr[2] = Disp[2] ^ (Disp[1] & Disp[0])
- * D = A ^ (B & C)
- */
- Blit(&(BlitData[2]),
- Disp[2], 0, 0,
- Disp[1], 0, 0,
- Disp[0], 0,
- Incr[2], 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, A_XOR_BANDC);
-
- /* Increment Blit #4. Determine if low 3 bits are set.
- * Temp = (Disp[0] & Disp[1] & Disp[2])
- * D = A & B & C
- */
- Blit(&(BlitData[3]),
- Disp[0], 0, 0,
- Disp[1], 0, 0,
- Disp[2], 0,
- Temp, 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, ABC);
-
- /* Blit 5. Add in 3-bit carry.
- * Incr[3] = (Disp3 ^ Temp)
- * D = A ^ B
- */
- Blit(&(BlitData[4]),
- Disp[3], 0, 0,
- Temp, 0, 0,
- NULL, 0,
- Incr[3], 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, A_XOR_B);
- }
-
-
-
- /*******************************************************************************
- * BlitCompare() compares, using the blitter, the 4 bitplane number at
- * each pixel location in Incr with the 4 bitplanes in Neighbor. Neighbor
- * is one of 4 nearest neighbors (WhichNeighbor = UP_NEIGHBOR, DOWN_NEIGHBOR,
- * LEFT_NEIGHBOR, or RIGHT_NEIGHBOR) of pixels in Planes -> Display. The
- * result is written to a bitplane (Temp or Equal) specified by WhereTo.
- * A pixel is set in the result if Incr is equal to the neighbor, otherwise
- * is is cleared.
- *******************************************************************************/
- void BlitCompare(BlitData, Planes, WhereTo, WhichNeighbor)
- struct DoBlitNode *BlitData;
- struct BDMainStruct *Planes;
- int WhereTo,
- WhichNeighbor;
-
- {
- WORD **Source,
- **Neighbor,
- *Dest;
- int i,
- ShiftX,
- ShiftY;
-
- switch (WhichNeighbor)
- {
- case UP_NEIGHBOR:
- ShiftX = 0;
- ShiftY = -1;
- break;
- case LEFT_NEIGHBOR:
- ShiftX = -1;
- ShiftY = 0;
- break;
- case RIGHT_NEIGHBOR:
- ShiftX = 1;
- ShiftY = 0;
- break;
- case DOWN_NEIGHBOR:
- ShiftX = 0;
- ShiftY = 1;
- break;
- default:
- assert(FALSE); /* Shouldn't be here */
- break;
- }
- Source = Planes -> Incr;
- Neighbor = Planes -> Display;
- switch (WhereTo)
- {
- case TO_EQUAL:
- Dest = Planes -> Equal;
- break;
- case TO_TEMP:
- Dest = Planes -> Temp;
- break;
- default:
- assert(FALSE); /* Shouldn't be here */
- break;
- }
-
- /* Compare Blit #1. Set Dest if Neighbor[0] = Source[0]
- * Dest = ~(Source[0] ^ Neighbor[0])
- * D = ~(A ^ B)
- */
- Blit(&(BlitData[0]),
- Source[0], 0, 0,
- Neighbor[0], ShiftX, ShiftY,
- NULL, 0,
- Dest, 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, A_EQUIV_B);
-
- /* Compare Blit #2-4. Compare bits 1-3 as in prev blit, but include Dest
- * Dest = ~(Source[i] ^ Neighbor[i]) & Dest
- * D = ~(A ^ B) & C
- */
- /* Do next blit on the upper 3 bitplanes */
- for (i = 1; i <= 3; i++)
- {
- Blit(&(BlitData[i]),
- Source[i], 0, 0,
- Neighbor[i], ShiftX, ShiftY,
- Dest, 0,
- Dest, 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, COMPARE);
- }
- /* NOW: Dest = 1 if (Source[] == Neighbor[]) */
- }
-
-
- /*******************************************************************************
- * UpdateEqual() is a quicky function whose entire purpose was to clean up
- * OneGen(). It OR's the bitplanes (Planes -> Equal) and (Planes -> Temp)
- * and stores the result in (Planes -> Equal).
- *******************************************************************************/
- void UpdateEqual(BlitData, Planes)
- struct DoBlitNode *BlitData;
- struct BDMainStruct *Planes;
-
- {
- Blit(BlitData,
- Planes -> Equal, 0, 0,
- Planes -> Temp, 0, 0,
- NULL, 0,
- Planes -> Equal, 0,
- 0, Planes -> Mod, Planes -> XSize, Planes -> YSize, A_OR_B);
- }
-
- /*******************************************************************************
- * Output to the display planes the final result, as follows:
- * if (Equal == 0) { Display[] = Display[]; }
- * else { Display[] = Incr[]; }
- * By moving Equal to A and changing the function accordingly, we can mask
- * a border out of A and leave it unchanged. Intuition Borders have a width
- * of two, but we'll use LRBorder just in case something changes.
- *******************************************************************************/
- void BlitOutput(BlitData, Planes)
- struct DoBlitNode *BlitData;
- struct BDMainStruct *Planes;
- {
- int i;
-
- /* Display[i] =
- * Equal&Incr[i]&Dis[i] | ~Equal&Incr[i]&Dis[i] | ~Equal&~Incr[i]&Dis[i] |
- * Equal&Incr[i]&~Dis[i]
- * Determined using a truth table.
- */
- /* Output displayed bitplane 0 */
- for (i = 0; i <= 3; i++)
- {
- Blit(&(BlitData[i]),
- Planes -> Equal, 0, 0,
- Planes -> Incr[i], 0, 0,
- Planes -> Display[i], 0,
- Planes -> Display[i], 0,
- Planes -> LRBorder, Planes -> Mod,
- Planes -> XSize, Planes -> YSize, OUTPUT_FUNC);
- }
- }
-
-
- /**************************************************************************
- * Blit() and InitBlitData() are based loosely on the ones by the same names
- * from PopLife, written by Tomas Rockkiki(?) and/or Olaf Seibert. I saw no
- * copyright notice or anything similar in that code, so I presume it's safe
- * to use.
- * I simplified Blit() and changed InitBlitData() to suit.
- * -wss
- **************************************************************************/
-
- /* --------------------------------------------------------------------- *
- *
- * Static data for the BLITTER routine.
- *
- * We need an array which tells what to use
- * for all 256 possible operations.
- *
- * --------------------------------------------------------------------- */
-
- UBYTE ToUse[256]; /* Which DMA channels we need per minterm */
- UWORD FwmA[16]; /* First word mask for A source */
- UWORD LwmA[16]; /* Last word mask for A source */
-
- /*
- * Call InitBlitData() once on startup before you ever call Blit().
- * Have a look in the Hardware Reference Manual for the mysterious
- * bit patterns. They are quite obvious then!
- */
-
- void InitBlitData()
- {
- register WORD i;
- register UWORD s,
- First,
- Last;
-
- /* I sure hope this works! I have no idea what's going on here! -wss */
- for (i=0; i<256; i++)
- {
- s = DEST >> 8;
- if ((i >> 4) != (i & 15)) /* 15 is 0000 1111 */
- {
- s += SRCA >> 8;
- }
- if (((i >> 2) & 51) != (i & 51)) /* 51 is 0011 0011 */
- {
- s += SRCB >> 8;
- }
- if (((i >> 1) & 85) != (i & 85)) /* 85 is 0101 0101 */
- {
- s += SRCC >> 8;
- }
- ToUse[i] = s;
- }
- /*
- * I like the concept of having a FwmA[] & LwmA[], but not the
- * implementation. This will define a left and right border
- * for A. (This just happens to be what I want.)
- * Example: Border = 2, then mask out 2 bits on the left
- * and 2 bits on the right of A. -wss
- */
- First = 0xFFFF;
- Last = 0xFFFF;
- for (i=0; i<16; i++) {
- FwmA[i] = First;
- LwmA[i] = Last;
- First = First >> 1;
- Last = Last << 1;
- }
- }
-
- /* --------------------------------------------------------------------- *
- * Arguments:
- * BNode: Pointer to a DoBlitNode structure to fill.
- * AAddress: The address of the A source before shifting.
- * Ax: Number of BITS to shift A left (-) or right (+).
- * Ay: Number of LINES to shift A up (-) or down (+).
- * BAddress: The address of the A source before shifting.
- * Ax: Number of BITS to shift B left (-) or right (+).
- * By: Number of LINES to shift B up (-) or down (+).
- * CAddress: The address of the C source (no pun) before shifting.
- * WSS: Took out cx due to blitter limitations (no C shifting).
- * Actually, I could shift Cx/16 words. If we need it...
- * Cy: Number of LINES to shift C up (-) or down (+).
- * DAddress: The address of the dest. before shifting.
- * WSS: Took out dx due to blitter limitations (no D shifting)
- * Actually, I could shift Cx/16 words. If we need it...
- * Dy: Number of LINES to shift D up (-) or down (+).
- * Border:(WSS)The number of pixels (0-15) to mask on either side of A.
- * Modulo: The REAL modulo (see HRM) in bits.
- * XSize: Horizontal size of the blit in pixels.
- * YSize: Vertical size of the blit in pixels.
- * Function: The function to perform (BLTLFx)
- *
- * Blit() has changed quite alot since its PopLife days. It now fills
- * up one DoBlitNode (pointed at by BNode) structure with blitter register
- * values, to be used by QBlit.
- * -wss
- * --------------------------------------------------------------------- */
-
- void Blit (BNode,
- AAddress, Ax, Ay,
- BAddress, Bx, By,
- CAddress, Cy,
- DAddress, Dy,
- Border,
- Modulo, XSize, YSize, Function)
- struct DoBlitNode *BNode;
- WORD *AAddress, *BAddress, *CAddress, *DAddress;
- int Ax, Ay, Bx, By, Cy, Dy, Border, Modulo, XSize, YSize, Function;
-
- {
- WORD *t,
- AShiftBits,
- BShiftBits;
-
- Modulo >>= 4; /* Divide the Modulo By 16 because we need words. */
- /* Poke the addresses for D and C: */
- BNode -> dsource = DAddress;
- BNode -> csource = CAddress;
- /* WSS: Create a nice little border around A: */
- BNode -> afwm = FwmA[Border];
- BNode -> alwm = LwmA[Border];
- /*
- * Now calculate the shifts for the A and B operands. The barrel
- * shifter counts appear to be to the left instead of the more
- * intuitive to the right. Note that I take Dx into account.
- * WSS: No ya don't.
- * Note that shift right = positive (relative to parameters
- * passed in). Thus, word shift is "+= Ax / 16", and bitshifting
- * requires negation of Ax, since pos. is to left for blitter.
- */
-
- /* Gross shift of A by whole WORDS: */
- t = AAddress + (Modulo + (XSize / 16)) * Ay + (Ax / 16);
- AShiftBits = (-Ax) & 0xf; /* Too clever: see big comment below */
- if (Ax > 0) /* Right shift */
- {
- t++; /* Add 16 bits to the right, then shift AShiftBits to the left.
- * Note that (X & 0xf) = 16 - (abs(X) & 0xf), if X is negative.
- * This is what we want in AShiftBits for right shifting!
- */
- }
- BNode -> asource = t;
-
- /* Repeat for B source: */
- t = BAddress + (Modulo + (XSize / 16)) * By + (Bx / 16);
- BShiftBits = (-Bx) & 0xf;
- if (Bx > 0)
- {
- t++;
- }
- BNode -> bsource = t;
- /*
- * Now calculate the two control words. If you want to do
- * the addresses in reverse order, set the appropriate bit in con1.
- */
- BNode -> con0 = (AShiftBits << 12) + (ToUse[Function] << 8) + Function;
- BNode -> con1 = (BShiftBits << 12);
- /*
- * Calculate the final total XSize in words, and the modulos. The
- * modulos are in Bytes when written from the 68000.
- */
- XSize = (XSize + 15) >> 4; /* Round up to next word */
- BNode -> amod = BNode -> bmod = BNode -> cmod = BNode -> dmod =
- 2 * Modulo;
- /*
- * This last assignment merely assigns the size value in the DoBlitNode.
- */
- BNode -> bltsize = (YSize << 6) + XSize;
- } /* End of Blit() */
-
-
- extern struct Custom custom; /* I guess this comes from Amiga.lib... */
- struct Custom *HWRegs = &custom; /* Alas: must be external for Blink */
- /*******************************************************************************
- * DoBlit routine is quite simple. It merely takes the register contents in
- * the DoBlitNode struct pointed at by BlitInfo and stuffs it into the blitter
- * registers, kicking the blitter off with a poke to bltsize.
- ******************************************************************************/
- void DoBlit(BlitInfo)
- struct DoBlitNode *BlitInfo;
-
- {
- WaitBlit(); /* Wait for the previous blit */
- HWRegs -> bltcon0 = BlitInfo -> con0;
- HWRegs -> bltcon1 = BlitInfo -> con1;
- HWRegs -> bltafwm = BlitInfo -> afwm;
- HWRegs -> bltalwm = BlitInfo -> alwm;
- HWRegs -> bltcpt = (APTR) BlitInfo -> csource;
- HWRegs -> bltbpt = (APTR) BlitInfo -> bsource;
- HWRegs -> bltapt = (APTR) BlitInfo -> asource;
- HWRegs -> bltdpt = (APTR) BlitInfo -> dsource;
- HWRegs -> bltcmod = BlitInfo -> cmod;
- HWRegs -> bltbmod = BlitInfo -> bmod;
- HWRegs -> bltamod = BlitInfo -> amod;
- HWRegs -> bltdmod = BlitInfo -> dmod;
-
- HWRegs -> bltsize = BlitInfo -> bltsize; /* This sets the blitter off */
- }
-