home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
progmisc
/
acksrc.zip
/
ACKENG.C
< prev
next >
Wrap
Text File
|
1993-06-18
|
21KB
|
700 lines
/**************** ACK-3D ( Animation Construction Kit 3D ) *******************/
/* Engine Code */
/* Author: Lary Myers */
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "ackext.h"
/****************************************************************************
** **
****************************************************************************/
char xRay(int x,int y,int angle)
{
char Color;
int i,j,mx,my;
int TablePosn;
int MapPosn,CurPosn;
int xBeg;
long xPos,xNext;
int BitmapColumn;
int xCenter,yCenter,xAdj;
int ObjPosn;
int oBegX,oBegY;
long yPos;
long yNext;
long xd,yd,sy;
long ObjDist;
xBeg = x & 0xFFC0; /* Get upper left corner of square */
yNext = yNextTable[angle]; /* PreCalc'd value of 64 * Tan(angle) */
if (angle > INT_ANGLE_270 || angle < INT_ANGLE_90)
{
xPos = xBeg + GRID_SIZE; /* Looking to the right */
xNext = GRID_SIZE; /* Positive direction */
}
else
{
xPos = xBeg; /* Looking to the left */
xNext = -GRID_SIZE; /* Negative direction */
yNext = -yNext;
}
/* Calculate the Y coordinate for the current square */
yPos = (((long)xPos - (long)x) * LongTanTable[angle]) + ((long)y << FP_SHIFT);
while (1)
{
if (xPos < 0 || xPos > GRID_XMAX ||
yPos < 0 || yPos > GRID_YMAXLONG)
break;
/************** Fixed point Y/64 * 64 X / 64 ***********/
MapPosn = ((yPos >> FP_SHIFT) & 0xFFC0) + (xPos >> 6);
/* First check for an object that has not been seen yet */
if ((Color = xObjGrid[MapPosn]) > 0 && !(ObjFlags[Color] & 3))
{
ObjFlags[Color] |= 1; /* Indicate object has been seen */
xd = ObjList[Color].x - x;
yd = ObjList[Color].y - y;
ObjDist = (xd * xd) + (yd * yd); /* Calc relative distance */
/* Place the object in the array according to distance, with the ones closer */
/* being drawn last. This will allow closer objects to hide farther objects */
j = TotalObjects;
for (i = 0; i < TotalObjects; i++)
{
if (ObjDist > ObjRelDist[i])
{
for (j = TotalObjects; j > i; j--)
{
ObjRelDist[j] = ObjRelDist[j-1];
ObjNumber[j] = ObjNumber[j-1];
ObjMapPosn[j] = ObjMapPosn[j-1];
}
j = i;
i = TotalObjects;
}
}
/* Hold onto relavant data for the object found */
ObjNumber[j] = Color;
ObjRelDist[j] = ObjDist;
ObjMapPosn[j] = MapPosn;
TotalObjects++;
ObjRelDist[TotalObjects] = 3200000;
}
/* Now check to see if a wall is being struck by the ray */
if ((Color = xGrid[MapPosn]) != 0)
{
xMapPosn = MapPosn; /* Hold onto the map location */
iLastX = xPos;
LastY1 = yPos;
if (Color == DOOR_XCODE) /* Is this a door? */
{
yd = (yPos >> FP_SHIFT) & 0xFFC0; /* Get the left side */
xd = yd + GRID_SIZE; /* And the right side */
ObjDist = (yPos + (yNext >> 1)) >> FP_SHIFT; /* Calc door distance */
if (ObjDist < yd || ObjDist > xd) /* Is door visible? */
{
xPos += xNext; /* Nope, continue casting */
yPos += yNext; /* the ray as before */
continue;
}
LastY1 = yPos + (yNext >> 1); /* Adjust the X,Y values so */
iLastX += (xNext >> 1); /* the door is halfway in sq. */
}
if (Color == DOOR_SECRETCODE)
{
if (xSecretColumn != 0)
{
sy = xSecretColumn * LongTanTable[angle];
ObjDist = (yPos + sy) >> FP_SHIFT;
yd = (yPos >> FP_SHIFT) & 0xFFC0; /* Get the left side */
xd = yd + GRID_SIZE; /* And the right side */
if (ObjDist < yd || ObjDist > xd) /* Is door visible? */
{
xPos += xNext; /* Nope, continue casting */
yPos += yNext; /* the ray as before */
continue;
}
LastY1 = yPos + sy;
iLastX += xSecretColumn;
}
}
return(Color);
}
xPos += xNext; /* Next X coordinate (fixed at 64 or -64) */
yPos += yNext; /* Next calculated Y coord for a delta of X */
}
return(0); /* Return that no wall was found */
}
/****************************************************************************
** **
****************************************************************************/
char yRay(int x,int y,int angle)
{
char Color;
int i,j,mx,my;
int MapPosn;
int yBeg;
long yPos,yNext;
int BitmapColumn;
int xCenter,yCenter,yAdj;
int ObjPosn;
int oBegX;
long xPos;
long xNext;
long xd,yd,ObjDist,sx;
yBeg = y & 0xFFC0; /* Same as div 64 then mul 64 */
xNext = xNextTable[angle]; /* Pre-calc'd value of 64 / tan(angle) */
if (angle < INT_ANGLE_180)
{
yPos = yBeg + GRID_SIZE; /* Looking down */
yNext = GRID_SIZE; /* Positive direction */
}
else
{
yPos = yBeg; /* Looking up */
yNext = -GRID_SIZE; /* Negative direction */
xNext = -xNext;
}
/* Calculate the X coordinate for the current square */
xPos = (((long)yPos - (long)y) * LongInvTanTable[angle]) + ((long)x << FP_SHIFT);
oBegX = 0;
while (1)
{
if (xPos < 0 || xPos > GRID_XMAXLONG ||
yPos < 0 || yPos > GRID_YMAX)
break;
/*********** Y/64 * 64 Fixed point and /64 ******/
MapPosn = (yPos & 0xFFC0) + (xPos >> (FP_SHIFT+6));
/* Check for unseen objects first */
if ((Color = yObjGrid[MapPosn]) > 0 && !(ObjFlags[Color] & 3))
{
ObjFlags[Color] |= 2; /* Signal object seen on Y cast */
xd = ObjList[Color].x - x;
yd = ObjList[Color].y - y;
yd = (xd * xd) + (yd * yd); /* Calc relative distance to object */
/* Place the object in the array according to distance, with the ones closer */
/* being drawn last. This will allow closer objects to hide farther objects */
j = TotalObjects;
for (i = 0; i < TotalObjects; i++)
{
if (yd > ObjRelDist[i])
{
for (j = TotalObjects; j > i; j--)
{
ObjRelDist[j] = ObjRelDist[j-1];
ObjNumber[j] = ObjNumber[j-1];
ObjMapPosn[j] = ObjMapPosn[j-1];
}
j = i;
i = TotalObjects;
}
}
ObjNumber[j] = Color; /* Hold onto object data for later */
ObjRelDist[j] = yd;
ObjMapPosn[j] = MapPosn;
TotalObjects++;
ObjRelDist[TotalObjects] = 3200000;
}
/** Check for a wall being struck **/
if ((Color = yGrid[MapPosn]) != 0)
{
yMapPosn = MapPosn; /* Hold onto map position */
LastX1 = xPos;
iLastY = yPos;
if (Color == DOOR_YCODE) /* Is this a door? */
{
yd = (xPos >> FP_SHIFT) & 0xFFC0; /* Calc top side of square */
xd = yd + GRID_SIZE; /* And bottom side of square */
ObjDist = (xPos + (xNext >> 1)) >> FP_SHIFT;
if (ObjDist < yd || ObjDist > xd) /* Is door visible? */
{
xPos += xNext; /* No, continue on with ray cast */
yPos += yNext;
continue;
}
LastX1 = xPos + (xNext >> 1); /* Adjust coordinates so door is */
iLastY += (yNext >> 1); /* Halfway into wall */
}
if (Color == DOOR_SECRETCODE)
{
if (ySecretColumn != 0)
{
sx = ySecretColumn * LongInvTanTable[angle];
ObjDist = (xPos + sx) >> FP_SHIFT;
yd = (xPos >> FP_SHIFT) & 0xFFC0; /* Get the top side */
xd = yd + GRID_SIZE; /* And the bottom side */
if (ObjDist < yd || ObjDist > xd) /* Is door visible? */
{
xPos += xNext; /* Nope, continue casting */
yPos += yNext; /* the ray as before */
continue;
}
LastX1 = xPos + sx;
iLastY += ySecretColumn;
}
}
return(Color);
}
xPos += xNext; /* Next calculated X value for delta Y */
yPos += yNext; /* Next fixed value of 64 or -64 */
if (++oBegX > 64) /* Check a maximum number of squares */
break;
}
return(0); /* Return here if no Y wall is found */
}
/****************************************************************************
** This is the heart of the engine. This routine will cast two rays for **
** each column of the screen. The first ray will look for any walls that **
** fall on the X boundaries (vertical walls). The second ray will look for **
** walls on the Y boundaries (horizontal walls). The wall with the shorter **
** distance will be used to draw a sliver of the bitmap at the current **
** screen column (0-319). A 60 degree field of view was selected to give **
** a realistic perspective to the walls. **
** **
****************************************************************************/
void DrawView(int xPlayer,int yPlayer,int PlayerAngle)
{
int i,j,index;
unsigned char xBitmap,yBitmap,BitmapNumber;
int ViewAngle;
long xDistance,yDistance;
long WallDistance;
int distance;
unsigned int BitmapColumn,yBitmapColumn;
int WallCode,OldMapPosn,OldMapPosn1;
long xd,yd;
unsigned char *Video;
unsigned int offset;
/* Clear out the object seen flags so objects can be found */
memset(ObjFlags,0,MaxObjects);
/* Begin looking 30 degrees to the left of our current angle */
ViewAngle = PlayerAngle - INT_ANGLE_30;
if (ViewAngle < 0)
ViewAngle += INT_ANGLE_360;
/* Reset total objects found on last DrawView pass */
TotalObjects = 0;
MaxDistance = 0;
/* Cast two rays for each column of the video display */
for (i = 0; i < VIEW_WIDTH; i++)
{
WallDistance = 3000000; /* Set to a ridiculous distance */
BitmapColumn = -1; /* Set to no walls found */
WallCode = 0; /* Set to no shadowing */
/* Don't even cast an X ray if impossible to intersect the X walls */
if (ViewAngle != INT_ANGLE_90 && ViewAngle != INT_ANGLE_270)
{
yd = CLOCK_PTR;
BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle);
if (BitmapNumber) /* A wall was found */
{
/* Use the Y intercept to determine the wall column */
BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
/* Keep the orientation the same no matter which side we're on */
if ((int)iLastX < xPlayer)
BitmapColumn = 63 - BitmapColumn;
/* Did we strike a door? */
if (BitmapNumber == DOOR_XCODE)
{
index = FindDoor(xMapPosn);
if (index >= 0) /* This is a valid door */
{
j = Door[index].ColOffset; /* Get its current pos */
if ((int)iLastX > xPlayer) /* Handle orientation */
j = -j;
BitmapColumn += j; /* Adjust column to show */
if (BitmapColumn > 63) /* Door is opening */
{
/* Get the grid coordinates for this door */
OldMapPosn = Door[index].mPos;
OldMapPosn1 = Door[index].mPos1;
/* Fake the engine into thinking no door is there */
xGrid[OldMapPosn] = 0;
xGrid[OldMapPosn1] = 0;
/* Cast the ray to get walls beyond the door */
BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle);
/* Put back the door codes if not fully open */
if (Door[index].ColOffset < 63)
{
xGrid[OldMapPosn] = Door[index].mCode;
xGrid[OldMapPosn1] = Door[index].mCode1;
}
/* Calc the new bitmap column of wall behind door */
BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
if ((int)iLastX < xPlayer)
BitmapColumn = 63 - BitmapColumn;
}
}
}
/* Calculate the distance to the wall. Since the X position was */
/* fixed to move 64 or -64 we can use it to determine the actual */
/* wall distance. The InvCosTable values were stored with a fixed */
/* point of 20 decimal places. At this time we'll knock off 14 of */
/* them so we can later multiple with a fixed point value of 16 */
xd = iLastX - xPlayer;
WallDistance = (xd * InvCosTable[ViewAngle]) >> 14;
/* Still looking for the reason this may occur. But this check */
/* will force the distance to a ridiculous value so no wall is */
/* seen later on when the X and Y walls are compared. */
if (WallDistance < 0)
WallDistance = 120000L;
/* Walls that are not doors will have shadowing */
if (BitmapNumber < DOOR_XCODE)
WallCode = 1;
}
txRay += CLOCK_PTR - yd;
}
/* Don't cast a Y ray if its impossible to intercept any Y walls */
if (ViewAngle != 0 && ViewAngle != INT_ANGLE_180)
{
xd = CLOCK_PTR;
yBitmap = yRay(xPlayer,yPlayer,ViewAngle);
if (yBitmap) /* A wall was found */
{
/* Use the X intercept to determine the column of the bitmap */
yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
/* Handle orientation from either side of the wall */
if ((int)iLastY > yPlayer)
yBitmapColumn = 63 - yBitmapColumn;
/* Did we strike a door? */
if (yBitmap == DOOR_YCODE)
{
index = FindDoor(yMapPosn);
if (index >= 0) /* This is a valid door */
{
/* Get the current door column offset */
j = Door[index].ColOffset;
/* Deal with orientation */
if ((int)iLastY < yPlayer)
j = -j;
yBitmapColumn += j;
/* If beyond width of bitmap than cast again */
if (yBitmapColumn > 63)
{
/* Get the yGrid coordinates for this door */
OldMapPosn = Door[index].mPos;
OldMapPosn1 = Door[index].mPos1;
/* Fool the engine into thinking no door is there */
yGrid[OldMapPosn] = 0;
yGrid[OldMapPosn1] = 0;
/* Cast again for walls beyond the door */
yBitmap = yRay(xPlayer,yPlayer,ViewAngle);
/* Put door code back if not fully open */
if (Door[index].ColOffset < 63)
{
yGrid[OldMapPosn] = Door[index].mCode;
yGrid[OldMapPosn1] = Door[index].mCode1;
}
/* Get the bitmap column of wall beyond door */
yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
if ((int)iLastY > yPlayer)
yBitmapColumn = 63 - yBitmapColumn;
}
}
}
/* Calculate the distance to the wall. Since the Y position was */
/* fixed to move 64 or -64 we can use it to determine the actual */
/* wall distance. The InvSinTable values were stored with a fixed */
/* point of 20 decimal places. At this time we'll knock off 14 of */
/* them so we can later multiple with a fixed point value of 16 */
yd = iLastY - yPlayer;
yDistance = (yd * InvSinTable[ViewAngle]) >> 14;
/* Don't know the reason but change negative value into ridiculous */
if (yDistance < 0)
yDistance = 120000L;
/* At this point check the distance to the Y wall against the X */
/* wall to see which one is closer. The closer one is the one */
/* we'll draw at this column of the screen. */
if (yDistance < WallDistance)
{
WallCode = 0; /* Turn off shadowing if on */
WallDistance = yDistance;
BitmapNumber = yBitmap;
BitmapColumn = yBitmapColumn;
}
}
tyRay += CLOCK_PTR - xd;
}
if (BitmapColumn < 64) /* A wall was found (either X or Y) */
{
/* To avoid a fishbowl affect we need to adjust the distance so */
/* it appears perpendicular to the center point of the display */
/* which is relative angle 0 from the players current angle. We */
/* started at -30 degrees for the first screen column and will */
/* cycle from -30 down to 0 then back up to +30 degrees. This */
/* cosine value was pre-calculated and placed in ViewCosTable. */
WallDistance *= ViewCosTable[i];
/* Now we strip off somemore decimal points and check round-up */
xd = WallDistance >> 14;
if (WallDistance - (xd << 14) >= 8096)
xd++;
/* The last decimal points from the multiplication after the X and */
/* Y rays is stripped off and checked for round-up. */
WallDistance = xd >> 6;
if (xd - (WallDistance << 6) >= 32)
WallDistance++;
/* Don't really need to, but put it into an integer for fast compare */
distance = WallDistance;
/* This is an arbitrary minimum distance to look for */
if (distance < 10)
distance = 10;
/* Don't want it to go outside our table boundaries */
if (distance >= MAX_DISTANCE)
distance = MAX_DISTANCE - 1;
/* Save the wall data to display when done with entire screen */
Walls[i].Distance = distance;
Walls[i].Number = (BitmapNumber & 0x3F) + WallCode;
Walls[i].Column = BitmapColumn;
if (distance > MaxDistance)
MaxDistance = distance;
}
ViewAngle++;
if (ViewAngle >= INT_ANGLE_360)
ViewAngle -= INT_ANGLE_360;
}
xd = CLOCK_PTR;
/* This routine gets the Walls structure and draws all of the walls */
DrawWalls();
tDOW += CLOCK_PTR - xd;
/* Now we look at any objects that may be closer than the walls */
FindObject(xPlayer,yPlayer,PlayerAngle);
xd = CLOCK_PTR;
/* Reset mask to allow all planes then flip to the page we just drew to */
outp(0x3c5,255);
flippage();
PageNum ^= 1;
usepage(PageNum);
tFlip += CLOCK_PTR - xd;
}
/****************************************************************************
** This routine is used when the player moves location as well as by the **
** moveable objects. Its purpose is to determine if a valid obstacle is **
** in front of the player or object. **
** **
****************************************************************************/
int CheckHit(int xPlayer,int yPlayer,int ViewAngle)
{
int BitmapColumn,BitmapNumber,yBitmap,distance;
int i,WallCode;
long WallDistance,xd,yd,yDistance;
long CheckDist;
WallDistance = 3000000; /* Set to a ridiculous value */
WallCode = 3; /* Initialize to strike an object */
CheckDist = 48L; /* Initial minimum distance to look for */
BitmapNumber = 0; /* Initialize to no bitmap found */
/* Clear out any objects seen from previous passes */
memset(ObjFlags,0,MaxObjects);
/* Set number of objects seen on this pass */
TotalObjects = 0;
/* Don't allow one of these angles, causes either the X or Y ray to not be */
/* cast which gives a false reading about an obstacle. */
if (ViewAngle == INT_ANGLE_45 ||
ViewAngle == INT_ANGLE_135 ||
ViewAngle == INT_ANGLE_225 ||
ViewAngle == INT_ANGLE_315)
ViewAngle++;
/* Don't cast an X ray if no chance of striking a X wall */
if (ViewAngle != INT_ANGLE_90 && ViewAngle != INT_ANGLE_270)
{
BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle);
if (BitmapNumber)
{
xd = iLastX - xPlayer;
/* Use the delta X to determine the distance to the wall */
WallDistance = (xd * InvCosTable[ViewAngle]) >> 14;
if (WallDistance < 0)
WallDistance = 120000L;
/* Set the wall struck code to an X wall */
WallCode = 1;
}
}
/* Don't cast a Y ray if impossible to strike a Y wall */
if (ViewAngle != 0 && ViewAngle != INT_ANGLE_180)
{
yBitmap = yRay(xPlayer,yPlayer,ViewAngle);
if (yBitmap)
{
yd = iLastY - yPlayer;
/* Use the delta Y to determine distance to the wall */
yDistance = (yd * InvSinTable[ViewAngle]) >> 14;
if (yDistance < 0)
yDistance = 120000L;
/* If Y wall closer than X wall then use Y wall data */
if (yDistance < WallDistance)
{
WallDistance = yDistance;
/* Indicate the wall struck was a Y wall */
WallCode = 2;
BitmapNumber = yBitmap;
}
}
}
/* Since doors appear in the middle of the wall, adjust the minimum distance */
/* to it. This handles walking up close to a door. */
if (BitmapNumber >= DOOR_XCODE)
CheckDist += 34L;
if (WallCode)
{
/* Adjust the distance based on the center of the screen */
WallDistance *= ViewCosTable[160];
/* Remove fixed point and round-up */
xd = WallDistance >> 14;
if (WallDistance - (xd << 14) >= 8096)
xd++;
/* Remove initial fixed point and round-up */
WallDistance = xd >> 6;
if (xd - (WallDistance << 6) >= 32)
WallDistance++;
/* Get minimum distance to any objects between player and wall */
yDistance = CheckObjects(xPlayer,yPlayer,ViewAngle);
/* An object was found, if closer than use object as obstacle */
if (yDistance > 0L && yDistance < WallDistance)
{
/* Return code for an object struck */
WallCode = 3;
/* Adjust minimum distance to keep object from getting too close */
CheckDist += 32L;
WallDistance = yDistance;
}
/* If the wall or object is further than the minimum distance, we can */
/* continue moving in this direction. */
if (WallDistance > CheckDist)
WallCode = 0;
}
return(WallCode);
}