home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff256.lzh
/
BlitDemons
/
bdblit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-19
|
20KB
|
556 lines
/*******************************************************************************
* 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 */
}