home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
dostank.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
89KB
|
3,816 lines
/**********************************************************************
*
* File : dostank.c
*
* Abstract : A very simple, sample RenderWare application for
* MS-Dos / PC-Dos. This application has very little
* functionality, but is simply intended as a demonstration
* of how to use the RenderWare API.
*
* This application had been written to be compatible with
* both the fixed and floating-point versions of the
* RenderWare library, i.e., it uses the macros CREAL,
* INT2REAL, RAdd, RDiv, RSub etc. If your application is
* intended for the floating-point version of the library
* only these macros are not necessary.
*
* Please note that this application is intended for
* demonstration purposes only. No support will be
* provided for this code and it comes with no warranty.
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. and Canon Inc. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1991, 1992, 1993. Canon Inc.
* All Rights Reserved.
*
**********************************************************************/
/****************************************************************************
Includes
*/
#include <stdlib.h>
#include <string.h>
#include <i86.h>
#include <math.h> /* Required for floating point */
#include "rwlib.h"
#include "rwdos.h"
#include "doswrap.h"
/****************************************************************************
Types
*/
/**********************************************************************
*
* Application constants.
*
**********************************************************************/
#define M_2PI 6.28318
#define EXPLOSION_VEL CREAL(0.01)
#define FORCE_OF_GRAVITY 0.0005
/*
* Bullet Defines
*/
#define BULLET_SCALE CREAL(0.03)
#define BULLET_SPEED CREAL(0.1)
#define BULLET_LIFE 100
/* When bullets hits another bullet */
#define BULLET_BITS 5
#define BULLET_STILL_BITS 6
#define NON_EXPLOSION_BITS 5
/*
* And the rest
*/
#define DELETE 8
#define BOOL int
/*
* MS Windows compatible defines
*/
#define MK_CONTROL 0x4
#define MK_SHIFT 0x2
/*
* Default distance of the camera from the origin.
*/
#define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
/* PI !*/
#define PI 3.141592654
/* */
#define MAX_GROUND_TEXTURES 26
#define MAX_GROUND_THINGS 20
#define GROUND_WIDTH 16
#define GROUND_HEIGHT 16
#define GROUND_SPLIT 2
#define GROUND_DISP_WIDTH 11
#define GROUND_DISP_HEIGHT 11
#define GROUND_SIZE CREAL(10.0)
#define MAX_BULLETS 20
/* Tank mode types - computer control modes */
/* General operations */
#define TANK_CONTROL_FORWARD 0
#define TANK_CONTROL_ROTATE 1
#define TANK_CONTROL_WAIT 2
#define TANK_CONTROL_FOLLOW 3
/* Other characteristics */
#define TANK_CONTROL_AIM 8
#define TANK_CONTROL_ATTACK 16
/* Objects */
#define MAX_MOVE_OBJECTS 20
#define MAX_TANKS 7
#define TANK_CLOSE_FLIP CREAL(1.0)
/* MINIMUM TANKS in scene */
#define MIN_TANKS 6
/* Tank defines */
#define TANK_SCALE CREAL(0.07)
#define TANK_HITS 4
#define TANK_EXPLOSION_BITS 15
#define TANK_FIRE_RATE 60
/* Still Objects */
#define MAX_STILL_OBJECTS 30
/* Tank control defines */
#define OP_ROT_BASE 1
#define OP_MOVE 2
#define OP_ROT_TURRET 3
#define OP_MOVE_GUN 4
#define OP_SET_TURRET 5
#define OP_FIRE 6
/* Display Modes */
#define DISPLAY_OUTSIDE 1
#define DISPLAY_FIRST 2
#define DISPLAY_FLOAT 3
#define DISPLAY_BEHIND 4
#define DISPLAY_TIME 64
/* Object types */
#define TYPE_TANK 1
#define TYPE_BULLET 2
#define TYPE_BIT 3
/* Amount of frames for tank firing */
#define FIRE_TIME 10
#define TANK_BACK_FORCE CREAL(0.1)
/* Bits defines */
#define MAX_BITS 30
#define BIT_SIZE CREAL(0.03)
#define BIT_LIFE 50
/**********************************************************************
*
* Type definitions.
*
**********************************************************************/
/****************************************************************************
Stack Class
*/
typedef struct StackTag {
int nElementSize;
char *pData;
char *pCurPtr;
int nAmoElements;
int nCurElement;
} Stack;
/***************************************************************************/
/*
* StillObject
*/
typedef struct StillObjectTag {
RwClump *cpGeo;
RwV3d vPos;
RwReal nSize;
struct StillObjectTag *sopNext;
} StillObject;
/*
* The ground plane element type
*/
typedef struct GroundEleTag {
RwTexture *tpTex;
RwUV uvPos;
StillObject *sopObj;
} GroundEle;
/*
* The entire ground plane
*/
typedef struct GroundTag {
RwReal nXPos;
RwReal nZPos;
int nWidth;
int nHeight;
int nX;
int nY;
int nDispWidth;
int nDispHeight;
int nSplit;
/* Ground */
RwReal nSize;
RwReal nStepSize;
GroundEle *pGround;
RwTexture *tpaTex[MAX_GROUND_TEXTURES];
int nAmoTextures;
/* Things */
RwClump *cpaGeo[MAX_GROUND_THINGS];
int nAmoThings;
RwReal naScale[MAX_GROUND_THINGS];
/* The polygon array */
RwPolygon3d **paPolyData;
/* The Grounds geometry */
RwClump *cpGeo;
/* Pos of the ground */
RwMatrix4d *mpPos;
/* The width of a texture element */
RwReal nTexStep;
/* World coord size */
RwReal nWorldWidth;
RwReal nWorldHeight;
} Ground;
/*
* MoveObject
*/
typedef struct MoveObjectTag {
int nType;
void *pObject;
RwClump *cpGeo;
RwV3d vPos;
RwReal nSize;
RwV3d vVel;
RwMatrix4d *mpRot,*mpPos;
} MoveObject;
/*
* Tank
*/
typedef struct TankTag {
int nMode; /* When computer controlled */
int nParam1; /* Some control parameter */
RwReal nParam2;
int nHit;
int nFireCount;
MoveObject moBase;
RwClump *cpTurret;
RwMatrix4d *mpTurretRotPos;
RwClump *cpGun;
RwReal nTurretAngle;
RwMatrix4d *mpGunRotPos;
} Tank;
/*
* All Move Objects
*/
typedef struct AllMoveObjTag {
Stack sDisplay;
Stack sDisplayed;
Stack sToDisplay;
Stack sDestroy;
} AllMoveObj;
/*
* All Still Objects
*/
typedef struct AllStillObjTag {
Stack sStillDisplayed;
Stack sStillToDisplay;
} AllStillObj;
/*
* All Tanks
*/
typedef struct AllTanksTag {
Stack sFree;
Stack sUsed;
Tank *tpTanks;
} AllTanks;
/*
* Bit
*/
typedef struct BitTag {
int nLife;
MoveObject moBase;
} Bit;
/*
* All Non interacting 'Bits'
*/
typedef struct AllBitsTag {
Stack sFree;
Stack sUsed;
Bit *bpBits;
} AllBits;
/*
* Display Class
*/
typedef struct DisplayTag {
RwReal nBehindDist;
RwReal nBehindTilt;
RwReal nBehindPan;
RwV3d vFloatPos;
int nDisplayMode;
RwReal nMinHeight;
RwReal nMaxX;
RwReal nMaxZ;
} Display;
/*
* Bullet
*/
typedef struct BulletTag {
int nLife;
Tank *tpTank;
MoveObject moBase;
} Bullet;
/*
* All Bullets
*/
typedef struct AllBulletsTag {
Stack sFree;
Stack sUsed;
Bullet *bpBullets;
} AllBullets;
/**********************************************************************
*
* Application global variables.
*
**********************************************************************/
/* Current button status */
static int bButtonDown = 0;
static int LastX;
static int LastY;
/*
* Ground plane texture map
*/
static char sGGroundMap[]="\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaccccc\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
cccccdcccccccccc\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
aaaaabaaaaaaaaaa\
";
/* Globals */
static Ground gGGround;
static AllMoveObj amoGObjects;
static AllTanks atGTanks;
static Display dGDisplay;
static AllBullets abGBullets;
static AllStillObj asoGObjects;
static AllMoveObj amoGBits;
static AllBits abGBits;
static int nGDemoMode; /* Non zero => demo mode */
static int nGDisplayTime; /* Counter for view point flip */
static int nGDisplay; /* Current view point counter */
/*
* Texts colour
*/
static int nGTextColour;
/*
* Global RenderWare object pointers. In this simple application we
* make use of only a single scene, camera and light.
*/
static RwScene *Scene = NULL;
static RwCamera *Camera = NULL;
static RwLight *Light = NULL;
/*
* This variable tells us what kind of action to take on a mouse move.
* The action depends on the object that was picked when the mouse button
* went down, and on the selection of virtual keys that were depressed at
* that time. By default no action is taken on mouse move.
*/
/*
* Current distance the camera is from the origin. This is stored to
* help us pan and zoom the camera.
*/
static RwReal CameraDistance = DEFAULT_CAMERA_DISTANCE;
/*
* Current animation frame number. This is incremented each time a
* frame is drawn on timer expiry. The purpose of this variable is
* to enable us to periodically (based on the number of frames) call
* RwOrthoNormalizeMatrix() to correct any errors which have crept
* into the clump's joint matrix because of the inevitable
* restrictions on the accuracy of fixed-point numbers. See
* HandleTimer for more details.
*/
static int nGFrameNumber = 0;
/* The size of the screen
*/
static int nGScrWidth;
static int nGScrHeight;
/* Fire Counter */
static int nGFireCount;
/****************************************************************************
Proto types
*/
/* Other prototypes */
void TankControl(Tank *tpTank,
int nOperation,
RwReal nParam1);
void MoveObjectCreate(MoveObject *mopObj,
RwReal nScale,
RwClump *cpGeo,
int nType,
void *pObject);
int AllTanksAddTank(AllTanks *atpTanks,
RwReal nXPos,
RwReal nZPos);
/* Stack Prototypes */
int StackCreate(Stack *spStack,int nEleSize,int nAmoEle);
void StackClear(Stack *spStack);
void *StackData(Stack *spStack);
int StackElements(Stack *spStack);
void *StackFront(Stack *spStack,void *pData);
int StackDestroy(Stack *spStack);
void *StackPush(Stack *spStack,void *pData);
int StackPop(Stack *spStack,void *pData);
void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
void *pUser);
int StackRemove(Stack *spStack,void *pEle);
void *StackFind(Stack *spStack,void *pEle);
int StackTop(Stack *spStack,void *pData);
/****************************************************************************
BitCreate
On entry : Bit
: Scale
: Clump
On exit :
*/
void BitCreate(Bit *bpBit,RwReal nScale,RwClump *cpGeo)
{
MoveObjectCreate(&bpBit->moBase,nScale,cpGeo,TYPE_BIT,(void *)bpBit);
}
/*************************************************************************
BitColour - Sets polygon to a random colour
(called from RwForAllPolygonsInClump)
On entry : Polygon
On exit :
*/
static void BitColour(RwPolygon3d *p)
{
static int zippy = 0;
switch ((rand()>>4) % 7)
{
case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
case 1: RwSetPolygonColor(p, CREAL(0.8), CREAL(0.1), CREAL(0.2)); break;
case 2: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.6), CREAL(0.3)); break;
case 3: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.0), CREAL(0.2)); break;
case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
case 5: RwSetPolygonColor(p, CREAL(0.6), CREAL(0.5), CREAL(0.0)); break;
case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.2)); break;
}
zippy++;
}
/****************************************************************************
AllBitsCreate
On entry : AllBits
On exit :
*/
void AllBitsCreate(AllBits *abpBits)
{
Bit *bpBit;
int nCount;
RwClump *cpBit;
RwClump *cpClump;
RwModelBegin();
RwClumpBegin();
RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
RwSetSurfaceColor(CREAL(1.0),CREAL(1.0),CREAL(1.0));
RwSetHints(0);
RwVertex(CREAL(0.866),CREAL(0.5),CREAL(0));
RwVertex(CREAL(-0.866),CREAL(0.5),CREAL(0));
RwVertex(CREAL(0),CREAL(1.0),CREAL(0));
RwTriangle(1,2,3);
RwTriangle(3,2,1);
RwClumpEnd(&cpClump);
RwModelEnd();
abpBits->bpBits = (Bit *) malloc(sizeof(Bit) *MAX_BITS);
StackCreate(&abpBits->sFree,sizeof(Bit *),MAX_BITS);
StackCreate(&abpBits->sUsed,sizeof(Bit *),MAX_BITS);
bpBit = abpBits->bpBits;
for (nCount =0;nCount<MAX_BITS;nCount++) {
cpBit = RwDuplicateClump(cpClump);
RwForAllPolygonsInClump(cpBit,BitColour);
BitCreate(bpBit,BIT_SIZE,cpBit);
StackPush(&abpBits->sFree,&bpBit);
bpBit++;
};
RwDestroyClump(cpClump);
}
/*****************************************************************************
AllBitsAddBit
On entry : All bits structure
: position
: velocity
On exit :
*/
int AllBitsAddBit(AllBits *abpBits,
RwV3d *vpPos,
RwV3d *vpDir,
int nLife)
{
Bit *bpBit;
MoveObject *mopBit;
if (!StackPop(&abpBits->sFree,&bpBit)) {
StackPush(&abpBits->sUsed,&bpBit);
bpBit->moBase.vPos = (*vpPos);
bpBit->moBase.vVel = (*vpDir);
bpBit->nLife = nLife;
/* Place on the display stack */
mopBit = &bpBit->moBase;
StackPush(&amoGBits.sDisplay,(void *)&mopBit);
return 0;
} else {
return 1;
};
}
/****************************************************************************
AllBitsRemoveBit
On entry : AllBullets
: Bullet to remove
On exit :
*/
void AllBitsRemoveBit(AllBits *abpBits,
Bit *bpBit)
{
MoveObject *mopTmp = &bpBit->moBase;
/* Stop the warnings */
abpBits = abpBits;
/* Remove from display */
StackPush(&amoGBits.sDestroy,&mopTmp);
}
/****************************************************************************
AllBitsHandle
On entry : All Bits
On exit :
*/
void AllBitsHandle(AllBits *abpBits)
{
Bit **bppBit;
Bit *bpBit;
int nAmoBits;
int nCount;
RwReal nHitHeight;
bppBit = (Bit **)StackData(&abpBits->sUsed);
nAmoBits = StackElements(&abpBits->sUsed);
nHitHeight = RMul(BIT_SIZE,CREAL(1.5));
for (nCount=0;nCount<nAmoBits;nCount++) {
bpBit = (*bppBit);
RwTransformMatrix(bpBit->moBase.mpPos,bpBit->moBase.mpRot,rwPOSTCONCAT);
/* Handle it */
bpBit->nLife--;
if ((bpBit->nLife<0)) {
/* Destroy the bullet */
AllBitsRemoveBit(abpBits,bpBit);
} else {
RwAddVector(&bpBit->moBase.vPos,&bpBit->moBase.vVel,
&bpBit->moBase.vPos);
bpBit->moBase.vVel.y -= CREAL(FORCE_OF_GRAVITY);
if ((bpBit->moBase.vPos.y < nHitHeight) &&
(bpBit->moBase.vVel.y<CREAL(0)) ) {
bpBit->moBase.vPos.y = nHitHeight;
bpBit->moBase.vVel.y = -RMul(bpBit->moBase.vVel.y,CREAL(0.5));
};
};
bppBit++;
};
AllMoveObjClean(&amoGBits);
}
/****************************************************************************
AllBitsExplosion
On entry : All Bits
: Position
: Velocity
: Amount of Bits
On exit :
*/
void AllBitsExplosion(AllBits *abpBits,
RwV3d *vpPos,
RwV3d *vpVel,
int nAmoBits)
{
int nCount;
int nLife=0;
RwReal nRand;
Bit *bpBit;
RwV3d vTmp;
for (nCount=0;nCount<nAmoBits;nCount++) {
if (AllBitsAddBit(abpBits,vpPos,vpVel,BIT_LIFE+(nLife&7))) {
break;
};
StackTop(&abpBits->sUsed,&bpBit);
nLife++;
RandomVec(&vTmp);
RwRotateMatrix(bpBit->moBase.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(15.0)),
rwREPLACE);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
bpBit->moBase.vVel.x += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
bpBit->moBase.vVel.y += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
bpBit->moBase.vVel.z += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
};
}
/****************************************************************************
DisplayModeSet
On entry : Display Structure
Display Mode required
On exit :
*/
void DisplayModeSet(Display *dpDisp,
int nMode)
{
dpDisp->nDisplayMode = nMode;
switch(nMode) {
case DISPLAY_OUTSIDE: {
RwSetCameraLookUp(Camera,CREAL(1.0),CREAL(0.0),CREAL(0.0));
RwSetCameraPosition(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
break;
};
case DISPLAY_FIRST: {
RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
break;
};
case DISPLAY_FLOAT: {
RwSetCameraLookUp(Camera,CREAL(1.0),CREAL(0.0),CREAL(0.0));
RwSetCameraPosition(Camera,CREAL(2.0),CREAL(1.0),CREAL(0.0));
RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
break;
};
case DISPLAY_BEHIND: {
RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
break;
};
};
}
/****************************************************************************
DisplayCreate
On entry : Display
On exit :
*/
void DisplayModeCreate(Display *dpDisp)
{
dpDisp->nBehindDist = CREAL(-0.5);
dpDisp->nBehindPan = CREAL(0.0);
dpDisp->nBehindTilt = CREAL(15.0);
dpDisp->vFloatPos.x = CREAL(0.0);
dpDisp->vFloatPos.y = CREAL(1.0);
dpDisp->vFloatPos.z = CREAL(0.0);
dpDisp->nMinHeight = CREAL(0.3);
dpDisp->nMaxX = RMul(GROUND_SIZE,CREAL(0.25));
dpDisp->nMaxZ = RMul(GROUND_SIZE,CREAL(0.25));
}
/****************************************************************************
AllMoveObjCreate
On entry : AllMoveObj
On exit :
*/
void AllMoveObjCreate(AllMoveObj *amopObj,int nMax)
{
StackCreate(&amopObj->sDisplay,sizeof(MoveObject *),nMax);
StackCreate(&amopObj->sDisplayed,sizeof(MoveObject *),nMax);
StackCreate(&amopObj->sToDisplay,sizeof(MoveObject *),nMax);
StackCreate(&amopObj->sDestroy,sizeof(MoveObject *),nMax);
}
/****************************************************************************
AllMoveObjClean
On entry : AllMoveObj
On exit :
*/
void AllMoveObjClean(AllMoveObj *amopObj)
{
MoveObject *mopObj;
void *pFind;
while(!StackPop(&amopObj->sDestroy,&mopObj)) {
pFind = StackFind(&amopObj->sDisplay,&mopObj);
if (pFind) {
StackRemove(&amopObj->sDisplay,pFind);
switch (mopObj->nType) {
case TYPE_BULLET: {
/* Remove from active bullets */
StackRemove(&abGBullets.sUsed,StackFind(&abGBullets.sUsed,&mopObj->pObject));
/* Add to free bullets */
StackPush(&abGBullets.sFree,&mopObj->pObject);
break;
};
case TYPE_TANK: {
/* Remove from active bullets */
StackRemove(&atGTanks.sUsed,StackFind(&atGTanks.sUsed,&mopObj->pObject));
/* Add to free bullets */
StackPush(&atGTanks.sFree,&mopObj->pObject);
break;
};
case TYPE_BIT: {
/* Remove from active bullets */
StackRemove(&abGBits.sUsed,StackFind(&abGBits.sUsed,&mopObj->pObject));
/* Add to free bullets */
StackPush(&abGBits.sFree,&mopObj->pObject);
break;
};
};
};
};
}
/****************************************************************************
AllStillObjCreate
On entry : AllMoveObj
On exit :
*/
void AllStillObjCreate(AllStillObj *asopObj)
{
StackCreate(&asopObj->sStillDisplayed,sizeof(StillObject *),MAX_STILL_OBJECTS);
StackCreate(&asopObj->sStillToDisplay,sizeof(StillObject *),MAX_STILL_OBJECTS);
}
/****************************************************************************
AddObjectToScene
On entry : Position
: Rotation
: Clump
On exit :
*/
void PosObjectInScene(RwV3d *vpPos,
RwMatrix4d *mpPos,
RwClump *cpClump)
{
RwPushScratchMatrix();
RwCopyMatrix(mpPos,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),
(vpPos->x-gGGround.nXPos),
vpPos->y,
(vpPos->z-gGGround.nZPos), rwPOSTCONCAT);
RwTransformClump(cpClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
}
/****************************************************************************
AllMoveObjDisplay
On entry : AllMoveObj
On exit :
*/
int _AllMoveObjDisplay(void *pA,void *pB)
{
return (((*(int *)pA))-((*(int *)pB)));
}
void AllMoveObjDisplay(AllMoveObj *amopObj,Ground *gpGrou)
{
MoveObject *mopObj;
RwReal nMinX,nMaxX,nMinZ,nMaxZ;
Stack sTmp;
int nDisp;
int nToDisp;
MoveObject **mopDisp;
MoveObject **mopToDisp;
Tank *tpTank;
tpTank = *((Tank **)StackData(&atGTanks.sUsed));
nMinX = RSub(gpGrou->nXPos,RDiv(gpGrou->nSize,CREAL(2)));
nMinZ = RSub(gpGrou->nZPos,RDiv(gpGrou->nSize,CREAL(2)));
nMaxX = nMinX + gpGrou->nSize;
nMaxZ = nMinZ + gpGrou->nSize;
StackClear(&amopObj->sToDisplay);
mopDisp = (MoveObject **)StackData(&amopObj->sDisplay);
nDisp = StackElements(&amopObj->sDisplay);
for (;nDisp;nDisp--) {
mopObj = (*mopDisp);
mopDisp++;
if ((mopObj->vPos.x<nMinX) ||
(mopObj->vPos.x>nMaxX) ||
(mopObj->vPos.z<nMinZ) ||
(mopObj->vPos.z>nMaxZ)) {
continue;
};
if ((dGDisplay.nDisplayMode==DISPLAY_FIRST)&&
(mopObj==(&tpTank->moBase))) {
/* If first person, then dont display your tank */
continue;
};
StackPush(&amopObj->sToDisplay,(void *) &mopObj);
};
/* Sort the stacks for later comparison */
qsort(StackData(&amopObj->sToDisplay),
StackElements(&amopObj->sToDisplay),
sizeof(MoveObject *),_AllMoveObjDisplay);
/* Find what needs to be added and removed from scene */
mopToDisp = (MoveObject **) StackData(&amopObj->sToDisplay);
nToDisp = StackElements(&amopObj->sToDisplay);
mopDisp = (MoveObject **)StackData(&amopObj->sDisplayed);
nDisp = StackElements(&amopObj->sDisplayed);
while (nToDisp&&nDisp) {
if ((*mopDisp)==(*mopToDisp)) {
PosObjectInScene(&((*mopToDisp)->vPos),
(*mopToDisp)->mpPos,
(*mopToDisp)->cpGeo);
mopDisp++;
mopToDisp++;
nToDisp--;
nDisp--;
} else {
if ((*mopDisp)<(*mopToDisp)) {
RwRemoveClumpFromScene((*mopDisp)->cpGeo);
nDisp--;
mopDisp++;
} else {
RwAddClumpToScene(Scene,(*mopToDisp)->cpGeo);
PosObjectInScene(&(*mopToDisp)->vPos,
(*mopToDisp)->mpPos,
(*mopToDisp)->cpGeo);
nToDisp--;
mopToDisp++;
};
};
};
if (nDisp) {
for (;nDisp;nDisp--) {
RwRemoveClumpFromScene((*mopDisp)->cpGeo);
mopDisp++;
};
};
if (nToDisp) {
for (;nToDisp;nToDisp--) {
RwAddClumpToScene(Scene,(*mopToDisp)->cpGeo);
PosObjectInScene(&(*mopToDisp)->vPos,
(*mopToDisp)->mpPos,
(*mopToDisp)->cpGeo);
mopToDisp++;
};
};
/* Switch stacks - to remove a qsort!*/
sTmp = amopObj->sDisplayed;
amopObj->sDisplayed = amopObj->sToDisplay;
amopObj->sToDisplay = sTmp;
}
/****************************************************************************
AllMoveObjBound
On entry : All move objects
Ground
On exit :
*/
void AllMoveObjBound(AllMoveObj *amopObj,
Ground *gpGrou)
{
MoveObject **moppCur;
int nAmoObj;
RwReal nMinX,nMaxX,nMinZ,nMaxZ;
moppCur = (MoveObject **)StackData(&amopObj->sDisplay);
nAmoObj = StackElements(&amopObj->sDisplay);
nMinX = CREAL(0);
nMinZ = CREAL(0);
nMaxX = RSub(gpGrou->nWorldWidth,CREAL(0.001));
nMaxZ = RSub(gpGrou->nWorldHeight,CREAL(0.001));
for (;nAmoObj;nAmoObj--) {
if ((*moppCur)->nType==TYPE_TANK) {
if ((*moppCur)->vPos.x<nMinX) {
(*moppCur)->vPos.x = nMinX;
};
if ((*moppCur)->vPos.x>nMaxX) {
(*moppCur)->vPos.x = nMaxX;
};
if ((*moppCur)->vPos.z<nMinZ) {
(*moppCur)->vPos.z = nMinZ;
};
if ((*moppCur)->vPos.z>nMaxZ) {
(*moppCur)->vPos.z = nMaxZ;
};
};
moppCur++;
};
}
/****************************************************************************
AllMoveObjCollision
On entry : All move objects
On exit :
*/
void AllMoveObjCollision(AllMoveObj *amopObj)
{
MoveObject **moppCur;
MoveObject **moppCheck;
int nCount,nCount2;
int nAmoObj;
RwReal nCurSize,nMinSize;
RwV3d vCur;
RwV3d vTmp,vVel;
RwReal nDist;
Tank *tpTank;
Bullet *bpBull;
RwV3d vExpDir,vExpPos;
vVel.x = CREAL(0);
vVel.y = CREAL(0);
vVel.z = CREAL(0);
moppCur = (MoveObject **)StackData(&amopObj->sDisplay);
nAmoObj = StackElements(&amopObj->sDisplay);
for (nCount=nAmoObj-1;nCount>0;nCount--) {
moppCheck = moppCur+1;
vCur = (*moppCur)->vPos;
nCurSize = (*moppCur)->nSize;
for (nCount2=0;nCount2<nCount;nCount2++) {
RwSubtractVector(&vCur,&(*moppCheck)->vPos,&vTmp);
nMinSize = nCurSize + (*moppCheck)->nSize;
if ((vTmp.x>nMinSize)||
(vTmp.x<-nMinSize)||
(vTmp.z>nMinSize)||
(vTmp.z<-nMinSize)) {
moppCheck++;
continue;
};
nDist = RSqrt( RAdd(RMul(vTmp.x,vTmp.x),
RMul(vTmp.z,vTmp.z)) );
if (nDist<nMinSize) {
if ((*moppCur)->nType==(*moppCheck)->nType) {
if (((*moppCur)->nType == TYPE_TANK)) {
/* Two tanks */
nDist= RMul(RSub(nDist,nMinSize),CREAL(0.5));
RwNormalize(&vTmp);
vTmp.x = RMul(vTmp.x,nDist);
vTmp.z = RMul(vTmp.z,nDist);
RwAddVector(&(*moppCheck)->vPos,&vTmp,&(*moppCheck)->vPos);
RwSubtractVector(&(*moppCur)->vPos,&vTmp,&(*moppCur)->vPos);
} else {
/* Two bullets */
AllBitsExplosion(&abGBits,&(*moppCur)->vPos,&vVel,BULLET_BITS);
AllBulletsRemoveBullet(&abGBullets,(*moppCur)->pObject);
AllBulletsRemoveBullet(&abGBullets,(*moppCheck)->pObject);
};
} else {
/* a tank is destroyed */
if ((*moppCur)->nType==TYPE_TANK) {
tpTank = (Tank *)((*moppCur)->pObject);
bpBull = (Bullet *)((*moppCheck)->pObject);
} else {
tpTank = (Tank *)((*moppCheck)->pObject);
bpBull = (Bullet *)((*moppCur)->pObject);
};
if ( (bpBull->tpTank == tpTank) || (nDist<RMul(nMinSize,CREAL(0.5))) ) {
/* A firing tank cannot hit itself */
/* Make it tricky to hit */
moppCheck++;
continue;
};
if (tpTank == *((Tank **)StackData(&atGTanks.sUsed))) {
/* You've been hit */
/* Make sure you dont die */
tpTank->nHit = TANK_HITS;
};
if (tpTank->nHit) {
tpTank->nHit--;
/* Blast back effect */
vExpDir = bpBull->moBase.vVel;
vExpDir.x = RMul(vExpDir.x,CREAL(-0.1));
vExpDir.y = RMul(vExpDir.y,CREAL(-0.1));
vExpDir.z = RMul(vExpDir.z,CREAL(-0.1));
AllBitsExplosion(&abGBits,&bpBull->moBase.vPos,
&vExpDir,
NON_EXPLOSION_BITS);
vExpDir = bpBull->moBase.vVel;
RwNormalize(&vExpDir);
vExpDir.x = RMul(vExpDir.x,TANK_BACK_FORCE);
vExpDir.y = RMul(vExpDir.y,TANK_BACK_FORCE);
vExpDir.z = RMul(vExpDir.z,TANK_BACK_FORCE);
RwAddVector(&tpTank->moBase.vPos,&vExpDir,&tpTank->moBase.vPos);
AllBulletsRemoveBullet(&abGBullets,bpBull);
} else {
/* Tank is destroyed */
vExpDir.x = CREAL(0);
vExpDir.y = CREAL(0.01); /* Make it go up !*/
vExpDir.z = CREAL(0);
vExpPos = tpTank->moBase.vPos;
vExpPos.y += RDiv(tpTank->moBase.nSize,CREAL(2));
AllBitsExplosion(&abGBits,&vExpPos,
&vExpDir,
TANK_EXPLOSION_BITS);
AllBulletsRemoveBullet(&abGBullets,bpBull);
AllTanksRemoveTank(&atGTanks,tpTank);
};
};
};
moppCheck++;
};
moppCur++;
};
/* Delete unwanted entries */
AllMoveObjClean(amopObj);
}
/****************************************************************************
AllMoveObjCollisionStill
On entry : All move objects
: Ground structure
On exit :
*/
void AllMoveObjCollisionStill(AllMoveObj *amopObj,
Ground *gpGrou)
{
MoveObject **moppObj;
MoveObject *mopObj;
int nAmoObj;
GroundEle *gepGrou,*gepCur;
int nStride;
int nXPos;
int nZPos;
StillObject *sopObj;
RwReal nWX,nWZ;
RwReal nDist;
RwV3d vTmp,vExpDir;
gepGrou = gpGrou->pGround;
nStride = gpGrou->nWidth*gpGrou->nSplit;
moppObj = (MoveObject **)StackData(&amopObj->sDisplay);
nAmoObj = StackElements(&amopObj->sDisplay);
for(;nAmoObj;nAmoObj--) {
mopObj = (*moppObj);
if ((mopObj->vPos.x<CREAL(0))||
(mopObj->vPos.z<CREAL(0))||
(mopObj->vPos.x>gpGrou->nWorldWidth)||
(mopObj->vPos.z>gpGrou->nWorldHeight)) {
/* Object not in world */
moppObj++;
continue;
};
nXPos = REAL2INT(RDiv(mopObj->vPos.x,gpGrou->nStepSize));
nZPos = REAL2INT(RDiv(mopObj->vPos.z,gpGrou->nStepSize));
nWX = RMul(INT2REAL(nXPos),gpGrou->nStepSize);
nWZ = RMul(INT2REAL(nZPos),gpGrou->nStepSize);
gepCur = gepGrou+((nStride*nZPos)+(nXPos));
sopObj = gepCur->sopObj;
while (sopObj) {
vTmp = sopObj->vPos;
vTmp.x += nWX;
vTmp.z += nWZ;
vTmp.x -= mopObj->vPos.x;
vTmp.z -= mopObj->vPos.z;
nDist = RSqrt(RAdd(RMul(vTmp.x,vTmp.x),RMul(vTmp.z,vTmp.z)));
if (nDist<RAdd(mopObj->nSize,sopObj->nSize)) {
switch (mopObj->nType) {
case TYPE_TANK: {
RwNormalize(&vTmp);
vTmp.x = RMul(vTmp.x,nDist-(mopObj->nSize+sopObj->nSize));
vTmp.z = RMul(vTmp.z,nDist-(mopObj->nSize+sopObj->nSize));
RwAddVector(&mopObj->vPos,&vTmp,&mopObj->vPos);
break;
};
case TYPE_BULLET: {
vExpDir = mopObj->vVel;
vExpDir.x = RMul(vExpDir.x,CREAL(-0.1));
vExpDir.y = RMul(vExpDir.y,CREAL(-0.1));
vExpDir.z = RMul(vExpDir.z,CREAL(-0.1));
AllBitsExplosion(&abGBits,&mopObj->vPos,&vExpDir,BULLET_STILL_BITS);
AllBulletsRemoveBullet(&abGBullets,mopObj->pObject);
break;
};
default: {
};
};
};
sopObj = sopObj->sopNext;
};
moppObj++;
};
AllMoveObjClean(amopObj);
}
/****************************************************************************
StillObjectCreate
On entry : StillObject
: Scale
: Clump
*/
/*
* StillObject
*/
void StillObjectCreate(StillObject *sopObj,RwReal nScale,RwClump *cpGeo)
{
RwPushScratchMatrix();
sopObj->nSize = RMul(nScale,CREAL(0.8));
RwScaleMatrix(RwScratchMatrix(),nScale,nScale,nScale,rwREPLACE);
RwTransformClumpJoint(cpGeo,RwScratchMatrix(),rwREPLACE);
sopObj->vPos.x = CREAL(0.0);
sopObj->vPos.y = CREAL(0.0);
sopObj->vPos.z = CREAL(0.0);
sopObj->cpGeo = cpGeo;
sopObj->sopNext = NULL;
RwPopScratchMatrix();
}
/****************************************************************************
MoveObjectCreate
On entry : MoveObject
: Objects Scale
: Object in Question
: Data
On exit :
*/
void MoveObjectCreate(MoveObject *mopObj,
RwReal nScale,
RwClump *cpGeo,
int nType,
void *pObject)
{
RwPushScratchMatrix();
mopObj->nSize = RMul(nScale,CREAL(1.0));
RwIdentityMatrix(mopObj->mpRot=RwCreateMatrix());
RwIdentityMatrix(mopObj->mpPos=RwCreateMatrix());
RwScaleMatrix(RwScratchMatrix(),nScale,nScale,nScale,rwREPLACE);
RwTransformClumpJoint(cpGeo,RwScratchMatrix(),rwREPLACE);
mopObj->vPos.x = CREAL(0.0);
mopObj->vPos.y = CREAL(0.0);
mopObj->vPos.z = CREAL(0.0);
mopObj->vVel.x = CREAL(0.0);
mopObj->vVel.y = CREAL(0.0);
mopObj->vVel.z = CREAL(0.0);
mopObj->cpGeo = cpGeo;
mopObj->pObject = pObject;
mopObj->nType = nType;
RwPopScratchMatrix();
}
/****************************************************************************
TankAim
On entry : Tank
: Vector to look at
On exit : Direction to aim
*/
RwReal TankAim(Tank *tpTank,RwV3d *vpDir)
{
RwV3d vDirNeed;
RwV3d vDirTank;
RwV3d vOut;
RwReal nCosDir;
RwReal nAngle;
vDirNeed = (*vpDir);
RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
RwNormalize(&vDirNeed);
vDirTank.x = CREAL(1.0);
vDirTank.y = CREAL(0.0);
vDirTank.z = CREAL(0.0);
RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
nCosDir = RwDotProduct(&vDirTank,&vDirNeed);
if (nCosDir>CREAL(0.999)) {
nCosDir=CREAL(0.999);
};
if (nCosDir<CREAL(-0.999)) {
nCosDir = CREAL(-0.999);
};
RwCrossProduct(&vDirTank,&vDirNeed,&vOut);
nAngle = RMul(RDiv(CREAL(180),CREAL(PI)),FL2REAL(acos(REAL2FL(nCosDir))) );
if (vOut.y<CREAL(0.0)) {
nAngle=-nAngle;
};
return nAngle;
}
/****************************************************************************
TankGivePurpose
On entry : Tank
On exit :
*/
void TankGivePurpose(Tank *tpTank)
{
int nRand;
int nRand2;
int nValue;
nRand = rand();
nRand2= rand();
nValue = nRand&255;
if (nValue<90) {
tpTank->nMode = TANK_CONTROL_FORWARD;
tpTank->nParam1 = nRand2&63;
tpTank->nParam2 = RDiv(INT2REAL(((nRand2>>8)&31)-15),CREAL(1000));
} else if (nValue<130) {
tpTank->nMode = TANK_CONTROL_ROTATE;
tpTank->nParam1 = nRand2&7;
tpTank->nParam2 = RDiv(INT2REAL(((nRand2>>8)&511)-255),CREAL(64));
} else if (nValue<170) {
tpTank->nMode = TANK_CONTROL_WAIT;
tpTank->nParam1 = nRand2&31;
} else {
tpTank->nMode = TANK_CONTROL_FOLLOW;
tpTank->nParam1 = nRand2&63;
};
nValue = (nRand>>8)&15;
if (((nRand>>8)&15)<5) {
tpTank->nMode|=TANK_CONTROL_AIM;
};
if (((nRand>>12)&15)<5) {
tpTank->nMode|=TANK_CONTROL_ATTACK;
};
}
/****************************************************************************
TankAct
On entry : Tank Structure
On exit :
*/
void TankAct(Tank *tpTank)
{
Tank *tpTarget;
RwV3d vDirNeed;
RwV3d vDirTank;
RwReal nValue;
if (tpTank->nParam1--<0) {
TankGivePurpose(tpTank);
};
if (tpTank->nFireCount) {
tpTank->nFireCount--;
};
tpTarget = *((Tank **)StackData(&atGTanks.sUsed));
switch(tpTank->nMode&3) {
case TANK_CONTROL_FORWARD: {
TankControl(tpTank,OP_MOVE,tpTank->nParam2);
break;
};
case TANK_CONTROL_ROTATE: {
TankControl(tpTank,OP_ROT_BASE,tpTank->nParam2);
break;
};
case TANK_CONTROL_WAIT: {
break;
};
case TANK_CONTROL_FOLLOW: {
vDirNeed = tpTarget->moBase.vPos;
RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
RwNormalize(&vDirNeed);
vDirTank.x = CREAL(0.0);
vDirTank.y = CREAL(0.0);
vDirTank.z = CREAL(1.0);
RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
if (RwDotProduct(&vDirTank,&vDirNeed)<CREAL(0.0)) {
TankControl(tpTank,OP_ROT_BASE,CREAL(2));
} else {
TankControl(tpTank,OP_ROT_BASE,CREAL(-2));
};
TankControl(tpTank,OP_MOVE,CREAL(0.01));
if ( ((RAbs(tpTarget->moBase.vPos.x-tpTank->moBase.vPos.x))<TANK_CLOSE_FLIP)&&
((RAbs(tpTarget->moBase.vPos.x-tpTank->moBase.vPos.x))<TANK_CLOSE_FLIP) ) {
/* Its very close so time to back off - probably */
if (rand()&255<20) {
TankGivePurpose(tpTank);
};
};
break;
};
};
if (tpTank->nMode&TANK_CONTROL_AIM) {
vDirNeed = tpTarget->moBase.vPos;
RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
RwNormalize(&vDirNeed);
vDirTank.x = CREAL(0.0);
vDirTank.y = CREAL(0.0);
vDirTank.z = CREAL(1.0);
RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
RwPushScratchMatrix();
RwGetClumpJointMatrix(tpTank->cpTurret,RwScratchMatrix());
RwTransformVector(&vDirTank,RwScratchMatrix());
vDirTank.y = CREAL(0);
RwPopScratchMatrix();
if ((nValue = RwDotProduct(&vDirTank,&vDirNeed))<CREAL(0.0)) {
TankControl(tpTank,OP_ROT_TURRET,CREAL(2));
} else {
TankControl(tpTank,OP_ROT_TURRET,CREAL(-2));
};
if (tpTank->nMode&TANK_CONTROL_ATTACK) {
if ( (RAbs(tpTank->moBase.vPos.x-tpTarget->moBase.vPos.x)<
RDiv(gGGround.nSize,CREAL(2)) ) &&
(RAbs(tpTank->moBase.vPos.z-tpTarget->moBase.vPos.z)<
RDiv(gGGround.nSize,CREAL(2)) ) && (!tpTank->nFireCount)) {
if (nValue<CREAL(0.2)) {
TankControl(tpTank,OP_FIRE,CREAL(0));
tpTank->nFireCount = TANK_FIRE_RATE;
};
};
};
};
}
/****************************************************************************
TankCreate
On entry : Tank
: Scale
: Clump
*/
RwClump *_TankCreate(RwClump *cpClump,void *pData)
{
Tank *tpTank = (Tank *)pData;
if (!tpTank->cpGun) {
tpTank->cpGun = cpClump;
} else {
if (!tpTank->cpTurret) {
tpTank->cpTurret = cpClump;
};
};
return NULL;
}
void TankCreate(Tank *tpTank,RwReal nScale,RwClump *cpGeo)
{
MoveObjectCreate(&tpTank->moBase,nScale,cpGeo,TYPE_TANK,(void *)tpTank);
RwIdentityMatrix(tpTank->mpTurretRotPos=RwCreateMatrix());
RwIdentityMatrix(tpTank->mpGunRotPos=RwCreateMatrix());
tpTank->nTurretAngle = CREAL(0.0);
tpTank->cpGun = NULL; /* Mark as unused */
tpTank->cpTurret = NULL; /* Mark as unused */
RwForAllClumpsInHierarchyPointer(cpGeo,_TankCreate,(void *)tpTank);
tpTank->nHit = TANK_HITS;
tpTank->nFireCount = 0;
TankGivePurpose(tpTank);
}
/****************************************************************************
TankGunEndDirection
On entry : Tank
: (OUT) direction vector
On exit :
*/
void TankGunEndDirection(Tank *tpTank,
RwV3d *vpEnd,
RwV3d *vpDir)
{
RwV3d vTmp;
RwPushScratchMatrix();
vpEnd->x = CREAL(1.0);
vpEnd->y = CREAL(0.0);
vpEnd->z = CREAL(0.0);
RwGetClumpLTM(tpTank->cpGun,RwScratchMatrix());
RwTransformPoint(vpEnd,RwScratchMatrix());
vTmp.x = CREAL(0.5);
vTmp.y = CREAL(0.0);
vTmp.z = CREAL(0.0);
RwTransformPoint(&vTmp,RwScratchMatrix());
RwSubtractVector(vpEnd,&vTmp,vpDir);
RwNormalize(vpDir);
RwPopScratchMatrix();
}
/****************************************************************************
AllTanksLaunch
On entry : AllTanks
On exit :
*/
void AllTanksLaunch(AllTanks *atpTanks)
{
int nAmoTanks;
Tank *tpTank;
RwReal nX,nZ,nXDist,nZDist;
int nValue;
tpTank = *(Tank **)StackData(&atpTanks->sUsed);
nAmoTanks = StackElements(&atpTanks->sUsed);
if (nAmoTanks<MIN_TANKS) {
nValue = rand()&0xff;
if (nValue<4) {
nX = RMul(RDiv(INT2REAL(rand()&255),INT2REAL(255) ),
gGGround.nWorldWidth);
nZ = RMul(RDiv(INT2REAL(rand()&255),INT2REAL(255) ),
gGGround.nWorldHeight);
nXDist = tpTank->moBase.vPos.x-nX;
nZDist = tpTank->moBase.vPos.z-nZ;
if ((nXDist>RMul(INT2REAL(gGGround.nDispWidth/2),gGGround.nStepSize))||
(nXDist<-RMul(INT2REAL(gGGround.nDispWidth/2),gGGround.nStepSize))||
(nZDist>RMul(INT2REAL(gGGround.nDispHeight/2),gGGround.nStepSize))||
(nZDist<-RMul(INT2REAL(gGGround.nDispHeight/2),gGGround.nStepSize))) {
AllTanksAddTank(atpTanks,nX,nZ);
};
};
};
}
/****************************************************************************
AllTanksCreate
On entry : AllTanks
On exit :
*/
void AllTanksCreate(AllTanks *atpTanks)
{
Tank *tpTanks;
int nCount;
char saFileNames[][10]={"tank.rwx",
"tank.rwx"};
int nNames = 2;
RwClump *cpaClumps[MAX_TANKS];
for (nCount = 0;nCount<nNames;nCount++) {
cpaClumps[nCount] = RwReadShape(saFileNames[nCount]);
};
atpTanks->tpTanks = (Tank *) malloc(sizeof(Tank) *MAX_TANKS);
StackCreate(&atpTanks->sFree,sizeof(Tank *),MAX_TANKS);
StackCreate(&atpTanks->sUsed,sizeof(Tank *),MAX_TANKS);
tpTanks = atpTanks->tpTanks;
for (nCount =0;nCount<MAX_TANKS;nCount++) {
TankCreate(tpTanks,TANK_SCALE,RwDuplicateClump(cpaClumps[nCount%nNames]));
StackPush(&atpTanks->sFree,&tpTanks);
tpTanks++;
};
for (nCount = 0;nCount<nNames;nCount++) {
RwDestroyClump(cpaClumps[nCount]);
};
}
/****************************************************************************
AllTanksHandle
On entry : AllTanks
On exit :
*/
void AllTanksHandle(AllTanks *atpTanks)
{
int nCount;
Tank **tppTank;
int nAmoTanks;
tppTank = ((Tank **)StackData(&atpTanks->sUsed));
nAmoTanks = StackElements(&atpTanks->sUsed);
if (nGDemoMode) {
nCount=0;
} else {
nCount=1;
tppTank++;
};
for (nCount=1;nCount<nAmoTanks;nCount++) {
TankAct((*tppTank));
tppTank++;
};
}
/****************************************************************************
Tank Control
On entry : TanksStructure
: Operation
: Param1
On exit :
*/
void TankControl(Tank *tpTank,
int nOperation,
RwReal nParam1)
{
RwV3d vTmp;
RwV3d vPos,vDir;
RwPushScratchMatrix();
switch(nOperation) {
case OP_ROT_BASE: {
RwCopyMatrix(tpTank->moBase.mpPos,RwScratchMatrix());
RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(1),CREAL(0),nParam1,
rwPOSTCONCAT);
RwCopyMatrix(RwScratchMatrix(),tpTank->moBase.mpPos);
break;
};
case OP_MOVE: {
vTmp.x = nParam1;
vTmp.y = CREAL(0.0);
vTmp.z = CREAL(0.0);
RwTransformVector(&vTmp,tpTank->moBase.mpPos);
tpTank->moBase.vPos.x+=vTmp.x;
tpTank->moBase.vPos.z+=vTmp.z;
break;
};
case OP_SET_TURRET: {
tpTank->nTurretAngle=CREAL(0);
/* Fall through !*/
};
case OP_ROT_TURRET: {
tpTank->nTurretAngle+=nParam1;
RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(1),CREAL(0),
tpTank->nTurretAngle,rwREPLACE);
RwTransformClumpJoint(tpTank->cpTurret,RwScratchMatrix(),rwREPLACE);
break;
};
case OP_MOVE_GUN: {
RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(0),CREAL(1),nParam1,
rwREPLACE);
RwTransformClumpJoint(tpTank->cpGun,RwScratchMatrix(),rwREPLACE);
break;
};
case OP_FIRE: {
TankGunEndDirection(tpTank,&vPos,&vDir);
vPos.x = RAdd(vPos.x,gGGround.nXPos);
vPos.z = RAdd(vPos.z,gGGround.nZPos);
AllBulletsAddBullet(&abGBullets,&vPos,&vDir,tpTank);
break;
};
default: {
break;
};
};
RwPopScratchMatrix();
}
/****************************************************************************
AllTanksAddTank
On entry : TanksStructure
: Tank file name
: Start x pos
: start z pos
On exit : 0 if all ok
*/
int AllTanksAddTank(AllTanks *atpTanks,
RwReal nXPos,
RwReal nZPos)
{
MoveObject *mopTank;
Tank *tpTank;
if (!StackPop(&atpTanks->sFree,&tpTank)) {
StackPush(&atpTanks->sUsed,&tpTank);
tpTank->moBase.vPos.x = nXPos;
tpTank->moBase.vPos.z = nZPos;
tpTank->nHit = TANK_HITS;
mopTank = &tpTank->moBase;
StackPush(&amoGObjects.sDisplay,(void *)&mopTank);
return 0;
} else {
return 1;
};
}
/****************************************************************************
AllTanksRemoveTank
On entry : All Tanks
: Tank to destroy
On exit :
*/
void AllTanksRemoveTank(AllTanks *atpTanks,
Tank *tpTank)
{
MoveObject *mopTmp;
/* Stop warnings */
atpTanks = atpTanks;
mopTmp = &tpTank->moBase;
/* Remove from Display */
StackPush(&amoGObjects.sDestroy,&mopTmp);
}
/****************************************************************************
BulletCreate
On entry : Bullet
On exit :
*/
void BulletCreate(Bullet *bpBull,RwReal nScale,RwClump *cpGeo)
{
MoveObjectCreate(&bpBull->moBase,nScale,cpGeo,TYPE_BULLET,(void *)bpBull);
}
/****************************************************************************
AllBulletsCreate
On entry : all bullets
On exit :
*/
void AllBulletsCreate(AllBullets *abpBull)
{
int nCount;
Bullet *bpBull;
RwClump *cpBullet,*cpClump;
cpBullet = RwReadShape("shell.rwx");
abpBull->bpBullets = malloc(sizeof(Bullet)*MAX_BULLETS);
StackCreate(&abpBull->sUsed,sizeof(Bullet *),MAX_BULLETS);
StackCreate(&abpBull->sFree,sizeof(Bullet *),MAX_BULLETS);
bpBull = abpBull->bpBullets;
for (nCount=0;nCount<MAX_BULLETS;nCount++) {
cpClump = RwDuplicateClump(cpBullet);
BulletCreate(bpBull,BULLET_SCALE,cpClump);
StackPush(&abpBull->sFree,&bpBull);
bpBull++;
};
RwDestroyClump(cpBullet);
}
/****************************************************************************
AllBulletsAddBullet
On entry : All bullets
: Starting position
: Direction of motion
On exit :
*/
int AllBulletsAddBullet(AllBullets *abpBull,
RwV3d *vpPos,
RwV3d *vpDir,
Tank *tpTank)
{
Bullet *bpBull;
MoveObject *mopBullet;
RwReal naEle[4][4];
if (!StackPop(&abpBull->sFree,&bpBull)) {
StackPush(&abpBull->sUsed,&bpBull);
bpBull->moBase.vPos = (*vpPos);
bpBull->moBase.vVel = (*vpDir);
bpBull->tpTank = tpTank;
bpBull->nLife = BULLET_LIFE;
/* Make the bullets clump face in the correct direction */
RwIdentityMatrix(bpBull->moBase.mpPos);
RwGetMatrixElements(bpBull->moBase.mpPos,naEle);
*(RwV3d *)naEle[0] = (*vpDir);
RwCrossProduct((RwV3d *)naEle[0],(RwV3d *)naEle[1],(RwV3d *)naEle[2]);
RwSetMatrixElements(bpBull->moBase.mpPos,naEle);
RwOrthoNormalizeMatrix(bpBull->moBase.mpPos,bpBull->moBase.mpPos);
/* Find the Bullets speed */
RwScaleVector(vpDir,BULLET_SPEED,vpDir);
bpBull->moBase.vVel = (*vpDir);
/* Place on the display stack */
mopBullet = &bpBull->moBase;
StackPush(&amoGObjects.sDisplay,(void *)&mopBullet);
return 0;
} else {
return 1;
};
}
/****************************************************************************
AllBulletsRemoveBullet
On entry : AllBullets
: Bullet to remove
On exit :
*/
void AllBulletsRemoveBullet(AllBullets *abpBull,
Bullet *bpBull)
{
MoveObject *mopTmp = &bpBull->moBase;
/* Stop warnings */
abpBull = abpBull;
/* Remove from display */
StackPush(&amoGObjects.sDestroy,&mopTmp);
}
/****************************************************************************
AllBulletsHandle
On entry : All Bullets
On exit :
*/
void AllBulletsHandle(AllBullets *abpBull)
{
Bullet **bppBull;
Bullet *bpBull;
int nAmoBullets;
int nCount;
bppBull = (Bullet **)StackData(&abpBull->sUsed);
nAmoBullets = StackElements(&abpBull->sUsed);
for (nCount=0;nCount<nAmoBullets;nCount++) {
bpBull = (*bppBull);
/* Handle it */
bpBull->nLife--;
if ((bpBull->nLife<0)||
(bpBull->moBase.vPos.x<CREAL(0))||
(bpBull->moBase.vPos.z<CREAL(0))||
(bpBull->moBase.vPos.x>gGGround.nWorldWidth)||
(bpBull->moBase.vPos.z>gGGround.nWorldHeight)) {
/* Destroy the bullet */
AllBulletsRemoveBullet(abpBull,bpBull);
} else {
RwAddVector(&bpBull->moBase.vPos,&bpBull->moBase.vVel,
&bpBull->moBase.vPos);
};
bppBull++;
};
AllMoveObjClean(&amoGObjects);
}
/****************************************************************************
GroundGetTextures
On entry : Ground structure
On exit :
*/
void GroundGetTextures(Ground *gpGrou)
{
char saTextureFiles[][14]={
"rough",
"groad1",
"groad2",
"groad3"};
int nAmoNames=4;
int nCount;
gpGrou->nAmoTextures = nAmoNames;
for (nCount=0;nCount<gpGrou->nAmoTextures;nCount++) {
gpGrou->tpaTex[nCount] = RwReadNamedTexture(saTextureFiles[nCount]);
};
}
/****************************************************************************
GroundGetThings
( It is assumed that all 'things' are normalised to 1.0 size )
On entry : Ground structure
On exit :
*/
void GroundGetThings(Ground *gpGrou)
{
char saThingFiles[][14]={
"tree.rwx",
"tankhous.rwx",
"tankhou2.rwx",
"tree2.rwx"};
RwReal naThingScale[]={
CREAL(0.2),
CREAL(0.3),
CREAL(0.3),
CREAL(0.25)};
int nAmoThings=4;
int nCount;
gpGrou->nAmoThings = nAmoThings;
for (nCount=0;nCount<nAmoThings;nCount++) {
gpGrou->cpaGeo[nCount] = RwReadShape(saThingFiles[nCount]);
gpGrou->naScale[nCount] = naThingScale[nCount];
};
}
/****************************************************************************
GroundCreateTiles
On entry : Ground Structure
: Ground texture map
: Ground width
: Ground height
: Ground split
*/
void GroundCreateTiles(Ground *gpGrou,
char *cpGroundMap,
char *cpThingMap,
int nWidth,
int nHeight,
int nSplit)
{
RwClump *cpGeo;
int nCount,nCount2;
GroundEle *gepCur;
int nX,nY;
int nTex;
char *cpCur;
char *cpThing;
StillObject *sopThing;
gpGrou->pGround = (GroundEle *)
malloc(sizeof(GroundEle)*nWidth*nHeight*nSplit*nSplit);
gepCur = gpGrou->pGround;
cpCur = cpGroundMap;
cpThing = cpThingMap;
gpGrou->nWidth = nWidth;
gpGrou->nHeight = nHeight;
gpGrou->nSplit = nSplit;
gpGrou->nTexStep = RDiv(CREAL(1),INT2REAL(nSplit));
for (nY=0;nY<nHeight;nY++) {
for (nCount=0;nCount<nSplit;nCount++) {
for (nX = 0; nX<nWidth;nX++) {
for (nCount2=0;nCount2<nSplit;nCount2++) {
nTex = (cpCur[nX])-'a';
gepCur->tpTex = gpGrou->tpaTex[nTex];
gepCur->uvPos.u = RDiv(INT2REAL(nCount2),INT2REAL(nSplit));
gepCur->uvPos.v = RDiv(INT2REAL(nCount),INT2REAL(nSplit));
/* Mark as no object on this square */
if ((*cpThing)>' ') {
sopThing = (StillObject *)malloc(sizeof(StillObject));
gepCur->sopObj = sopThing;
cpGeo = RwDuplicateClump(gpGrou->cpaGeo[(*cpThing)-'a']);
StillObjectCreate(sopThing,gpGrou->naScale[(*cpThing)-'a'],cpGeo);
sopThing->vPos.x += RDiv(gpGrou->nStepSize,CREAL(2));
sopThing->vPos.z += RDiv(gpGrou->nStepSize,CREAL(2));
} else {
gepCur->sopObj= NULL;
};
cpThing++;
gepCur++;
};
};
};
cpCur+=gpGrou->nWidth;
};
}
/****************************************************************************
AddGroundPoly
On entry : Polygon
: pointer to polygon data structure
On exit :
*/
RwPolygon3d *AddGroundPoly(RwPolygon3d *pPoly,void *pData);
RwPolygon3d *AddGroundPoly(RwPolygon3d *pPoly,void *pData)
{
int nX;
int nZ;
Ground *gpGrou = (Ground *)pData;
RwSetPolygonTextureModes(pPoly,rwFORESHORTEN);
nZ = RwGetPolygonTag(pPoly)%(gpGrou->nDispWidth);
nX = RwGetPolygonTag(pPoly)/(gpGrou->nDispWidth);
gpGrou->paPolyData[nX+(nZ*gpGrou->nDispWidth)] = pPoly;
return NULL;
}
/****************************************************************************
GroundCreateClump
On entry : Ground structure
: Display width
: Display height
: Total size of the clump in world coordinates
On exit :
*/
void GroundCreateClump(Ground *gpGrou,
int nDispWidth,
int nDispHeight,
RwReal nSize)
{
RwClump *cpGeo;
int nX,nZ;
RwReal nPosX,nPosZ;
int nNum;
RwMatrix4d *mpTmp;
gpGrou->nDispWidth = nDispWidth;
gpGrou->nDispHeight = nDispHeight;
gpGrou->nSize = nSize;
gpGrou->nStepSize = RDiv(nSize,INT2REAL(nDispWidth));
RwModelBegin();
RwClumpBegin();
RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
RwSetSurfaceLightSampling(rwFACET);
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetHints(rwCONTAINER);
nPosX = -RDiv(nSize,CREAL(2.0));
for (nX = 0;nX <gpGrou->nDispWidth;nX++) {
nPosZ = -RDiv(nSize,CREAL(2.0));
for (nZ = 0;nZ<gpGrou->nDispHeight;nZ++) {
RwVertex(nPosX,CREAL(0.0),nPosZ);
RwVertex(nPosX,CREAL(0.0),RAdd(nPosZ,gpGrou->nStepSize));
RwVertex(RAdd(nPosX,gpGrou->nStepSize),
CREAL(0.0),RAdd(nPosZ,gpGrou->nStepSize));
RwVertex(RAdd(nPosX,gpGrou->nStepSize),CREAL(0.0),nPosZ);
nPosZ = RAdd(nPosZ,gpGrou->nStepSize);
};
nPosX = RAdd(nPosX,gpGrou->nStepSize);
};
/* Give it some depth ! */
RwVertex(CREAL(0.0),CREAL(2.0),CREAL(0.0));
for (nNum=0;nNum<(gpGrou->nDispWidth*gpGrou->nDispHeight);nNum++) {
RwQuadExt((nNum<<2)+1,(nNum<<2)+2,(nNum<<2)+3,(nNum<<2)+4,nNum);
};
RwClumpEnd(&cpGeo);
RwModelEnd();
RwIdentityMatrix(mpTmp = RwCreateMatrix());
RwTransformClump(cpGeo,mpTmp,rwREPLACE);
RwTransformClumpJoint(cpGeo,mpTmp,rwREPLACE);
RwDestroyMatrix(mpTmp);
gpGrou->cpGeo = cpGeo;
gpGrou->paPolyData = (RwPolygon3d **)malloc(sizeof(RwPolygon3d *)*
gpGrou->nDispWidth*
gpGrou->nDispHeight);
RwForAllPolygonsInClumpPointer(cpGeo,AddGroundPoly,
(void*)gpGrou);
}
/****************************************************************************
GroundCreate
On entry : Ground Structure
: Ground map array
: Ground texture array
: Width
: Height
: Split (ie the amount of segments a texture is split to
On exit :
*/
void GroundCreate(Ground *gpGround)
{
char *cpThingMap;
int nSize;
int nCount;
nSize = GROUND_WIDTH*GROUND_HEIGHT*GROUND_SPLIT*GROUND_SPLIT;
cpThingMap = (char *)malloc(nSize);
memset(cpThingMap,' ',nSize);
for (nCount=0;nCount<40;nCount++) {
cpThingMap[rand()&(nSize-1)] = 'a';
};
for (nCount=0;nCount<20;nCount++) {
cpThingMap[rand()&(nSize-1)] = 'b';
};
for (nCount=0;nCount<20;nCount++) {
cpThingMap[rand()&(nSize-1)] = 'c';
};
for (nCount=0;nCount<20;nCount++) {
cpThingMap[rand()&(nSize-1)] = 'd';
};
RwIdentityMatrix(gpGround->mpPos=RwCreateMatrix());
GroundGetTextures(gpGround);
GroundGetThings(gpGround);
GroundCreateClump(gpGround,GROUND_DISP_WIDTH,GROUND_DISP_HEIGHT,
GROUND_SIZE);
GroundCreateTiles(gpGround,sGGroundMap,cpThingMap,GROUND_WIDTH,GROUND_HEIGHT,GROUND_SPLIT);
free(cpThingMap);
gpGround->nWorldWidth =
RMul(INT2REAL(gpGround->nWidth*gpGround->nSplit),gpGround->nStepSize);
gpGround->nWorldHeight =
RMul(INT2REAL(gpGround->nHeight*gpGround->nSplit),gpGround->nStepSize);
}
/****************************************************************************
GroundDisplay
On entry : Ground structure
: Xcoord
: Ycoord
On exit :
*/
void GroundDisplay(Ground *gpGrou,AllStillObj *asopObj,RwReal nX, RwReal nZ)
{
RwReal nXOff;
RwReal nZOff;
int nMapX;
int nMapZ;
int nCount,nCount2;
RwPolygon3d **pPolys;
GroundEle *gepCur;
int nStride;
RwUV uvaPos[4];
RwReal nStepSize;
StillObject **soppDisp;
int nDisp;
StillObject **soppToDisp;
int nToDisp;
RwReal nXStart;
RwReal nZStart;
RwReal nXPos;
RwReal nZPos;
Stack sTmp;
if (nX<RDiv(gpGrou->nSize,CREAL(2)) ) {
nX = RDiv(gpGrou->nSize,CREAL(2));
};
if (nZ<RDiv(gpGrou->nSize,CREAL(2)) ) {
nZ = RDiv(gpGrou->nSize,CREAL(2));
};
if (nX> gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2)) ) {
nX = gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2));
};
if (nZ> gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2)) ) {
nZ = gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2));
};
gpGrou->nXPos = nX;
gpGrou->nZPos = nZ;
nStepSize = (gpGrou->nStepSize);
nXOff = RDiv(RSub(nX,RDiv(gpGrou->nSize,CREAL(2))),nStepSize);
nZOff = RDiv(RSub(nZ,RDiv(gpGrou->nSize,CREAL(2))),nStepSize);
nMapX = REAL2INT(nXOff);
nMapZ = REAL2INT(nZOff);
nXOff = RMul(RSub(nXOff,INT2REAL(nMapX)),nStepSize);
nZOff = RMul(RSub(nZOff,INT2REAL(nMapZ)),nStepSize);
nXStart = -nXOff;
nZStart = -nZOff;
RwTranslateMatrix(gpGrou->mpPos, nXStart,CREAL(0),nZStart,rwREPLACE);
RwTransformClump(gpGrou->cpGeo,gpGrou->mpPos,rwREPLACE);
nXStart = RSub(nXStart,RDiv(gpGrou->nSize,CREAL(2)) );
nZStart = RSub(nZStart,RDiv(gpGrou->nSize,CREAL(2)) );
nStride = gpGrou->nWidth*gpGrou->nSplit;
pPolys = gpGrou->paPolyData;
gepCur = gpGrou->pGround + (nMapX+(nMapZ*nStride));
StackClear(&asopObj->sStillToDisplay);
RwPushScratchMatrix();
RwIdentityMatrix(RwScratchMatrix());
nZPos = nZStart;
for (nCount2=0;nCount2<gpGrou->nDispHeight;nCount2++) {
nXPos = nXStart;
for (nCount=0;nCount<gpGrou->nDispWidth;nCount++) {
RwSetPolygonTexture((*pPolys),gepCur->tpTex);
uvaPos[0] = gepCur->uvPos;
uvaPos[1] = gepCur->uvPos;
uvaPos[1].v= RAdd(uvaPos[1].v,gpGrou->nTexStep);
uvaPos[2] = uvaPos[1];
uvaPos[2].u = RAdd(uvaPos[2].u,gpGrou->nTexStep);
uvaPos[3] = uvaPos[2];
uvaPos[3].v= RSub(uvaPos[3].v,gpGrou->nTexStep);
RwSetPolygonUV((*pPolys),uvaPos);
if (gepCur->sopObj) {
RwTranslateMatrix(RwScratchMatrix(),
RAdd(nXPos,gepCur->sopObj->vPos.x),
gepCur->sopObj->vPos.y,
RAdd(nZPos,gepCur->sopObj->vPos.z),
rwREPLACE);
RwTransformClump(gepCur->sopObj->cpGeo, RwScratchMatrix(), rwREPLACE);
StackPush(&asopObj->sStillToDisplay,&gepCur->sopObj);
};
nXPos += gpGrou->nStepSize;
pPolys++;
gepCur++;
};
nZPos += gpGrou->nStepSize;
gepCur+=nStride-gpGrou->nDispWidth;
};
RwPopScratchMatrix();
/* Do the adding and removing of clumps to the scene */
/* Sort the stacks for later comparison */
qsort(StackData(&asopObj->sStillToDisplay),
StackElements(&asopObj->sStillToDisplay),sizeof(StillObject **),_AllMoveObjDisplay);
/* Find what needs to be added and removed from scene */
soppToDisp = (StillObject **) StackData(&asopObj->sStillToDisplay);
nToDisp = StackElements(&asopObj->sStillToDisplay);
soppDisp = (StillObject **)StackData(&asopObj->sStillDisplayed);
nDisp = StackElements(&asopObj->sStillDisplayed);
while (nToDisp&&nDisp) {
if ((*soppDisp)==(*soppToDisp)) {
soppDisp++;
soppToDisp++;
nToDisp--;
nDisp--;
} else {
if ((*soppDisp)<(*soppToDisp)) {
RwRemoveClumpFromScene((*soppDisp)->cpGeo);
nDisp--;
soppDisp++;
} else {
RwAddClumpToScene(Scene,(*soppToDisp)->cpGeo);
nToDisp--;
soppToDisp++;
};
};
};
if (nDisp) {
for (;nDisp;nDisp--) {
RwRemoveClumpFromScene((*soppDisp)->cpGeo);
soppDisp++;
};
};
if (nToDisp) {
for (;nToDisp;nToDisp--) {
RwAddClumpToScene(Scene,(*soppToDisp)->cpGeo);
soppToDisp++;
};
};
/* Switch stacks - to remove a qsort!*/
sTmp = asopObj->sStillDisplayed;
asopObj->sStillDisplayed = asopObj->sStillToDisplay;
asopObj->sStillToDisplay = sTmp;
}
/****************************************************************************
StackCreate
On entry : Pointer to stack structure
On exit : 0 if all went to plan
*/
int StackCreate(Stack *spStack,int nEleSize,int nAmoEle)
{
if (!(spStack->pData = (char *) malloc (nEleSize*nAmoEle))) {
return 1;
};
spStack->nCurElement = 0;
spStack->pCurPtr = spStack->pData;
spStack->nAmoElements = nAmoEle;
spStack->nElementSize = nEleSize;
return 0;
}
/****************************************************************************
StackClear
emptys the stack
On entry : Stack to clear
*/
void StackClear(Stack *spStack)
{
spStack->nCurElement = 0;
spStack->pCurPtr = spStack->pData;
}
/****************************************************************************
StackData
On entry : Stack
On exit : Stacks contents as an array bottom element first
*/
void *StackData(Stack *spStack)
{
return spStack->pData;
}
/****************************************************************************
StackElements
On entry : Stack
On exit : Amount of entries in the stack
*/
int StackElements(Stack *spStack)
{
return spStack->nCurElement;
}
/****************************************************************************
StackFront
On entry : Stack
: Element too stick on the bottom of the stack
On exit : Pointer to entry on stack,NULL for fail
*/
void *StackFront(Stack *spStack,void *pData)
{
char *pTmp;
int nCount;
if (spStack->nCurElement==spStack->nAmoElements) {
return NULL;
} else {
pTmp = spStack->pCurPtr;
for (nCount=0;nCount<spStack->nCurElement;nCount++) {
memcpy(pTmp,pTmp-spStack->nElementSize,spStack->nElementSize);
pTmp -= spStack->nElementSize;
};
memcpy(spStack->pData,pData,spStack->nElementSize);
spStack->pCurPtr+=spStack->nElementSize;
spStack->nCurElement++;
return spStack->pData;
};
}
/****************************************************************************
StackDestroy
On entry : Stack
On exit : 0 if all went to plan
*/
int StackDestroy(Stack *spStack)
{
free(spStack->pData);
return 0;
}
/****************************************************************************
StackPush
On entry : Stack
: Pointer to element to push
On exit : Pointer to Saved object if all ok else NULL
*/
void *StackPush(Stack *spStack,void *pData)
{
void *pSave;
if (spStack->nCurElement==spStack->nAmoElements) {
return NULL;
} else {
pSave = spStack->pCurPtr;
memcpy(pSave,pData,spStack->nElementSize);
spStack->pCurPtr+=spStack->nElementSize;
spStack->nCurElement++;
return pSave;
};
}
/****************************************************************************
StackPop
On entry : Stack
On exit : 0 if all ok
*/
int StackPop(Stack *spStack,void *pData)
{
if (!spStack->nCurElement) {
return 1;
} else {
spStack->nCurElement--;
spStack->pCurPtr-=spStack->nElementSize;
memcpy(pData,spStack->pCurPtr,spStack->nElementSize);
return 0;
};
}
/****************************************************************************
StackTop
On entry : Stack
On exit : 0 if all ok
*/
int StackTop(Stack *spStack,void *pData)
{
if (!spStack->nCurElement) {
return 1;
} else {
memcpy(pData,
spStack->pCurPtr-spStack->nElementSize,spStack->nElementSize);
return 0;
};
}
/****************************************************************************
StackForAll
Goes from top of stack to bottom
On entry : Stack
: Function to be called
: Pointer to user data
*/
void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
void *pUser)
{
char *pData;
int nCount;
pData = spStack->pCurPtr-spStack->nElementSize;
for (nCount=spStack->nCurElement;nCount--;nCount) {
(*Func)(pData,pUser);
pData-=spStack->nElementSize;
};
}
/****************************************************************************
StackRemove
Removes an entry from the stack
On entry : Stack
: Element to remove
On exit : 0 if all ok
*/
int StackRemove(Stack *spStack,void *pEle)
{
char *pData=(char *)pEle;
while (pData!=(spStack->pCurPtr-spStack->nElementSize)) {
memcpy(pData,pData+spStack->nElementSize,spStack->nElementSize);
pData+=spStack->nElementSize;
};
spStack->pCurPtr-=spStack->nElementSize;
spStack->nCurElement--;
return 0;
}
/****************************************************************************
StackFind
On entry : Stack
: Data entry to find
On exit : Pointer to element (NULL if not found)
*/
void *StackFind(Stack *spStack,void *pEle)
{
int nCount,nCount2;
char *pData,*pData2 = (char *)pEle;
pData = spStack->pData;
for (nCount=0;nCount<spStack->nCurElement;nCount++) {
for (nCount2=0;nCount2<spStack->nElementSize;nCount2++) {
if (pData[nCount2] != pData2[nCount2]) {
break;
};
};
if (nCount2>=spStack->nElementSize) {
return pData;
};
pData+=spStack->nElementSize;
};
return NULL;
}
/***************************************************************************
RandomVec - create a random vector
On entry : Random vector to create
On exit :
*/
static void RandomVec(RwV3d *vec)
{
vec->x = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
vec->y = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
vec->z = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
}
/****************************************************************************
DosShiftCtrl
On entry :
On exit : Bit Meaning
0 Right Shift
1 Left Shift
2 Ctrl
3 Alt
4 Scroll Lock
5 Num Lock
6 Caps Lock
7 Insert on
*/
int DosShiftCtrl(void)
{
union REGPACK rp;
memset(&rp,0,sizeof(rp));
rp.h.ah=0x02;
intr(0x16,&rp);
return ((int)rp.h.al);
}
/****************************************************************************
DosPrintString
On entry : xcord
: ycord
: string
: colour
On exit :
*/
void DosPrintString(int nX,int nY,char *sString,int nCol)
{
RwPrintChar pcPrint;
pcPrint.x = nX;
pcPrint.y = nY;
pcPrint.color = nCol;
for (;(*sString);sString++) {
pcPrint.c = (*sString);
RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
pcPrint.x+=8;
};
}
/****************************************************************************
DosGetKey
Get the ascii key code of any depressed key. (Do not wait for a key press.
-> return 0 if no key is pressed)
On entry :
On exit : Key pressed in ascii (or 0 if no key pressed)
*/
int DosGetKey(void)
{
union REGPACK rp;
memset(&rp,0,sizeof(rp));
rp.h.ah = 0x06;
rp.h.dl = 0xff;
intr(0x21,&rp);
if (!(rp.w.flags & 0x40 )) { /* Check Z flag */
/* Got key */
if (rp.h.al) {
return ((int)rp.h.al);
};
memset(&rp,0,sizeof(rp));
rp.h.ah = 0x06;
rp.h.dl = 0xff;
intr(0x21,&rp);
if (!(rp.w.flags & 0x40)) {
return ((int)rp.h.al);
};
return (rp.h.al|0x80);
};
return 0;
}
/**********************************************************************/
/*
* This function initializes the 3D (i.e. RenderWare) components of the
* application. This function opens the RenderWare library, creates a
* camera, a scene, a light and a matrix for spinning. A user-draw may
* also be created if USERDRAW_LABELS is defined.
*/
static BOOL
Init3D(char *sFilename)
{
char windowText[128];
char version[30];
char buffer[128];
int param;
int i;
RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
long nError;
RwRaster *rpRaster;
/*
* Attempt to open (and initialize) the RenderWare library.
*/
if (!RwOpen("DOSMOUSE", &nError))
{
printf("Unable to access renderware!!\n");
switch (nError) {
case E_RW_DOS_MODE_UNAVAILABLE: {
printf("The installed VESA card is unable to switch to the resolution");
printf(" requested.\n");
printf("Either install a different video adapter or use a ");
printf("supported video mode.");
break;
};
case E_RW_DOS_NO_VESA_BIOS: {
printf("A VESA bios is unavailable on this machine.\n");
printf("Either use a VESA compatible Video Adapter or install a ");
printf("VESA bios emulation TSR.\n");
break;
};
case E_RW_DOS_INCOMPATIBLE_BIOS: {
printf("The VESA bios on this machine is not of high enough version ");
printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
printf(" higher VESA bios or TSR.\n");
break;
};
case E_RW_DOS_NO_MOUSE: {
printf("No Microsoft compatible mouse driver present.\n");
printf("Install a microsoft compatible mouse driver and try again.\n");
break;
};
default: {
printf("Unknown Error !!!!!!!!!!!!!!!\n");
break;
};
};
return FALSE;
}
/* Set up character set */
RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
/*--- Only look for scripts and textures in subdirectories under the current
one. RWSHAPEPATH need not be set then */
RwSetShapePath(".",rwPRECONCAT);
strcpy(buffer,sFilename);
i = strlen(buffer);
while((buffer[i] != '\\')&&(i>=0)) {
i--;
};
if (i>=0) {
buffer[i+1] = 0;
strcat(buffer, "TEXTURES");
RwSetShapePath(buffer, rwPOSTCONCAT);
buffer[i+1] = 0;
strcat(buffer, "SCRIPTS");
RwSetShapePath(buffer, rwPOSTCONCAT);
};
RwSetShapePath("SCRIPTS", rwPRECONCAT);
RwSetShapePath("TEXTURES", rwPRECONCAT);
/*
* Label the display with information about the version of
* RenderWare being used. Its rather unlikely that
* RwGetSystemInfo() will fail so we ignore its return value.
*/
RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
sprintf(windowText, "DosTank V%s %s",
version, (param ? "Fixed" : "Float"));
DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
/*
* Create the camera which will be used for rendering.
*/
Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
if (!Camera)
{
/*
* As with RwOpen(), the most common cause for a failure to create
* a camera is insufficient memory so we will explicitly check for
* this condition and report it. Otherwise a general error is issued.
*/
if (RwGetError() == E_RW_NOMEM)
{
RwClose();
printf("Insufficient memory to create the RenderWare(tm) camera\n");
}
else
{
RwClose();
printf("Error creating the RenderWare(tm) camera\n");
}
exit(-1);
}
RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
/*
* Set the camera's background color to blue.
*/
RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.3));
/*
* By default, the camera lies on the X-Z plane and points down Z
* into the screen. We shall retain the camera's orientation, but move
* the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
*/
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(2.0), CameraDistance);
/*
* Another change from previous versions of RenderWare is the amount of
* prespective generated by the default viewwindow size. When converting
* applications from previous versions of RenderWare the simple rule is
* to divide the viewwindow size by five to get the same prespective effect
* as given under previous versions.
*/
if (nGScrWidth >= nGScrHeight) {
RwSetCameraViewwindow(Camera,
CREAL(1.0),
RMul(CREAL(1.0),
RDiv(INT2REAL(nGScrHeight),
INT2REAL(nGScrWidth))));
} else {
RwSetCameraViewwindow(Camera,
RMul(CREAL(1.0),
RDiv(INT2REAL(nGScrWidth),
INT2REAL(nGScrHeight))),
CREAL(1.0));
};
/*
* Create a scene which will contain the clumps to be rendered and the
* light or lights illuminating those clumps . In this very simple
* application it would be perfectly acceptable to use the default scene
* (as returned by RwDefaultScene()) for rendering. However, it is good
* practice to always create a scene which will be used for your rendering
* and only use the default scene as a bag for currently unused clumps and
* lights.
*/
Scene = RwCreateScene();
if (!Scene)
{
RwDestroyCamera(Camera);
RwClose();
printf("Error creating the RenderWare(tm) scene\n");
exit(-1);
}
/*
* Our scene will be illuminated by a directional light. The illumination
* vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
*/
Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
CREAL(1.0));
if (!Light)
{
RwDestroyScene(Scene);
RwDestroyCamera(Camera);
RwClose();
printf("Error creating the RenderWare(tm) light\n");
exit(-1);
}
/*
* Add the new light to our scene.
*/
RwAddLightToScene(Scene, Light);
/* Add backdrop */
rpRaster = RwReadRaster("mount.bmp",rwGAMMARASTER|rwDITHERRASTER);
if (rpRaster) {
/* Make it the backdrop */
RwSetCameraBackdrop(Camera,rpRaster);
RwSetCameraBackdropViewportRect(Camera,0,0,nGScrWidth,nGScrHeight-24);
};
/*
* All the 3D components are now successfully initialized, so
* work can begin...
*/
return TRUE;
}
/**********************************************************************/
/*
* This function shuts down the 3D (i.e. RenderWare) components of the
* application in a polite fashion.
*/
static void
TidyUp3D()
{
/*
* Destroy the scene. This will destroy the contents of the scene,
* i.e. any clumps and lights in that scene. In this case destroying
* the scene will destroy the light we created in Init3D, and any
* clumps we have loaded and not already destroyed.
*/
RwDestroyScene(Scene);
/*
* Destroy the camera.
*/
RwDestroyCamera(Camera);
/*
* Close the library. This will free up any internal resources and
* textures loaded.
*/
RwClose();
}
/****************************************************************************
DisplayMode
On entry :
On exit :
*/
void DisplayMode(void)
{
if (nGDemoMode) {
DosPrintString(0,nGScrHeight-8,"Demo Mode On ",nGTextColour);
} else {
DosPrintString(0,nGScrHeight-8,"Demo Mode Off",nGTextColour);
};
}
/**********************************************************************/
/*
* This functions handles the left mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves, such as spinning a clump, or panning the camera. This involves
* examining the virtual keys that were depressed when the mouse button
* went down and attempting to pick a clump under the mouse pointer
* position.
*/
static void
HandleLeftButtonDown(int x, int y, int vKeys)
{
/* Stop warnings */
x=x;
vKeys = vKeys;
bButtonDown |=1;
if (y>nGScrHeight-8) {
if (nGDemoMode) {
nGDemoMode = 0;
DisplayMode();
} else {
nGDemoMode = 1;
DisplayMode();
};
};
}
/**********************************************************************/
/*
* This functions handles the right mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves such as panning the camera.
*/
static void
HandleRightButtonDown(int x, int y, int vKeys)
{
/* Stop warnings */
x=x;
y=y;
vKeys = vKeys;
bButtonDown |= 2;
if (!nGFireCount) {
nGFireCount = FIRE_TIME;
};
}
/**********************************************************************/
/*
* Handle the left mouse button comming back up. The basic action is
* to turn off mouse move actions and release mouse capture.
*/
static void
HandleLeftButtonUp(void)
{
bButtonDown &= ~1;
}
/**********************************************************************/
/*
* Handle the right mouse button comming back up. The basic action is
* to turn of mouse move actions and release mouse capture.
*/
static void
HandleRightButtonUp(void)
{
bButtonDown &= ~2;
}
/*************************************************************************
DisplayBound
On entry : Display
On exit :
*/
void DisplayBound(Display *dpDisp)
{
RwV3d vPos;
RwGetCameraPosition(Camera,&vPos);
if (vPos.y<dpDisp->nMinHeight) {
vPos.y = dpDisp->nMinHeight;
};
if (vPos.x>dpDisp->nMaxX) {
vPos.x = dpDisp->nMaxX;
};
if (vPos.x<-dpDisp->nMaxX) {
vPos.x = -dpDisp->nMaxX;
};
if (vPos.z>dpDisp->nMaxZ) {
vPos.z = dpDisp->nMaxZ;
};
if (vPos.z<-dpDisp->nMaxZ) {
vPos.z = -dpDisp->nMaxZ;
};
RwSetCameraPosition(Camera,vPos.x,vPos.y,vPos.z);
}
/****************************************************************************
TrackbackdropToCamera
On entry : CAmera
On exit :
*/
static BOOL
TrackBackdropToCamera(RwCamera *camera)
{
RwRaster *backdrop;
int backdropWidth;
int backdropHeight;
RwV3d at;
RwReal angle;
int xOffset;
int yOffset;
RwInt32 windowWidth;
RwInt32 windowHeight;
backdrop = RwGetCameraBackdrop(camera);
/*
* No-op if the camera has no backdrop.
*/
if (backdrop != NULL)
{
/*
* Get the window and backdrop dimensions.
*/
RwGetCameraViewport(camera, NULL, NULL, &windowWidth, &windowHeight);
backdropWidth = RwGetRasterWidth(backdrop);
backdropHeight = RwGetRasterHeight(backdrop);
/*
* We use the look at vector for determining both
* horizontal and vertical positioning.
*/
RwGetCameraLookAt(camera, &at);
/*
* Compute the horizontal position. This is done
* by compute the camera's angle of rotate about
* the Z axis. The angle is then directly converted
* into a horizontal backdrop offset.
*/
/*
* Compute the angle in the range 0 => PI.
*/
at.y = CREAL(0.0);
RwNormalize(&at);
if (at.z > CREAL(1.0))
at.z = CREAL(1.0);
else if (at.z < CREAL(-1.0))
at.z = CREAL(-1.0);
angle = FL2REAL(acos(REAL2FL(at.z)));
/*
* Get the angle in the range 0 => 2 PI
*/
if (at.x < CREAL(0.0))
angle = RSub(CREAL(M_2PI), angle);
/*
* The backdrop X offset is derived simply from
* the angle computed above.
*/
xOffset = -REAL2INT(RDiv(RMul(angle, INT2REAL(backdropWidth)), CREAL(M_2PI)));
/*
* Compute the vertical position. This is done by getting
* the angle between the look at vector and the Y axis. We
* simply use the dot product (cosine of the angle) multiplied
* by a scale factor to compute the vertical offset.
*/
RwGetCameraLookAt(Camera, &at);
yOffset = REAL2INT(RAdd(INT2REAL(windowHeight / 2), RMul(RMul(at.y, CREAL(1.5)), INT2REAL(windowHeight / 2)))) - (backdropHeight / 2);
yOffset-=30;
RwSetCameraBackdropOffset(Camera, xOffset, 0);
RwSetCameraBackdropViewportRect(Camera, 0, yOffset, windowWidth, backdropHeight);
}
return TRUE;
}
/**********************************************************************/
/*
* Handle MS Window's timer expiry. This function will perform any
* animation actions necessary, including spinning clumps and animating
* textures.
*/
static void
HandleTimer(void) {
Tank *tpTank;
RwV3d vAt,vPos;
RwReal naEle[4][4];
/* Hanle Computer controlled tanks */
AllTanksLaunch(&atGTanks);
AllTanksHandle(&atGTanks);
AllMoveObjCollisionStill(&amoGObjects,&gGGround);
AllMoveObjCollision(&amoGObjects);
AllBulletsHandle(&abGBullets);
AllBitsHandle(&abGBits);
/* Handle the display */
tpTank = *((Tank **)StackData(&atGTanks.sUsed));
switch (dGDisplay.nDisplayMode) {
case DISPLAY_FLOAT: {
RwPushScratchMatrix();
RwRotateMatrix(RwScratchMatrix(),
CREAL(0),CREAL(1),CREAL(0),CREAL(2),rwREPLACE);
RwGetCameraPosition(Camera,&vPos);
RwTransformVector(&vPos,RwScratchMatrix());
RwSetCameraPosition(Camera,vPos.x,vPos.y,vPos.z);
RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
GroundDisplay(&gGGround,&asoGObjects,
tpTank->moBase.vPos.x,
tpTank->moBase.vPos.z );
RwPopScratchMatrix();
break;
};
case DISPLAY_FIRST: {
vAt.x = CREAL(1.0);
vAt.y = CREAL(0.0);
vAt.z = CREAL(0.0);
RwTransformVector(&vAt,tpTank->moBase.mpPos);
RwSetCameraLookAt(Camera,vAt.x,vAt.y,vAt.z);
RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
RwSetCameraPosition(Camera,CREAL(0.0),RDiv(TANK_SCALE,CREAL(2)),CREAL(0.0));
GroundDisplay(&gGGround,&asoGObjects,
tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
break;
};
case DISPLAY_OUTSIDE: {
GroundDisplay(&gGGround,&asoGObjects,
tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
break;
};
case DISPLAY_BEHIND: {
RwPushScratchMatrix();
RwGetClumpMatrix(tpTank->moBase.cpGeo,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),
CREAL(0),
RDiv(tpTank->moBase.nSize,CREAL(2)),
CREAL(0),
rwPOSTCONCAT);
RwRotateMatrix(RwScratchMatrix(),
CREAL(0),CREAL(1),CREAL(0),CREAL(-90),rwPOSTCONCAT);
RwGetMatrixElements(RwScratchMatrix(),naEle);
RwSetCameraPosition(Camera,naEle[3][0],naEle[3][1],naEle[3][2]);
RwSetCameraLookAt(Camera,-naEle[2][0],-naEle[2][1],-naEle[2][2]);
RwSetCameraLookUp(Camera,naEle[1][0],naEle[1][1],naEle[1][2]);
RwPopScratchMatrix();
RwPanCamera(Camera,dGDisplay.nBehindPan);
RwTiltCamera(Camera,dGDisplay.nBehindTilt);
RwVCMoveCamera(Camera,CREAL(0),
CREAL(0),
dGDisplay.nBehindDist);
GroundDisplay(&gGGround,&asoGObjects,
tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
break;
};
default: {
break;
};
};
/* Place in ground plane boundary */
AllMoveObjBound(&amoGObjects,&gGGround);
/* Add to scene as necessary */
AllMoveObjDisplay(&amoGObjects,&gGGround);
AllMoveObjDisplay(&amoGBits,&gGGround);
/*
* Animate textures. Enumerate over all the textures in the texture
* dictionary stack calling RwTextureNextFrame() to bump the
* current frame pointer of each texture. For single frame textures
* this is a no-op.
*/
RwForAllNamedTextures(RwTextureNextFrame);
TrackBackdropToCamera(Camera);
/*
* See the description of HandlePaint() for a description of this common
* RenderWare cliche for rendering a scene and copying it to the display.
*/
RwBeginCameraUpdate(Camera,NULL);
RwClearCameraViewport(Camera);
RwRenderScene(Scene);
RwEndCameraUpdate(Camera);
RwShowCameraImage(Camera, NULL);
nGFrameNumber++;
}
/****************************************************************************
TankMouseControl
On entry : Mouse X
: Mouse Y
On exit :
*/
void TankMouseControl(int nX,int nY)
{
Tank *tpTank;
if (!nGDemoMode) {
tpTank = *((Tank **)StackData(&atGTanks.sUsed));
if (bButtonDown&1) {
TankControl(tpTank,OP_ROT_BASE,
RMul(RDiv(INT2REAL(nX),INT2REAL(nGScrWidth))-CREAL(0.5),CREAL(-5)) );
TankControl(tpTank,OP_MOVE,
RMul(RDiv(INT2REAL(nY),INT2REAL(nGScrHeight))-CREAL(0.5),CREAL(-0.04)) );
};
if (nGFireCount==FIRE_TIME) {
TankControl(tpTank,OP_FIRE,CREAL(0));
};
if (nGFireCount) {
nGFireCount--;
};
};
}
/****************************************************************************
Handle Mouse Move
On entry : Mouse X
: Mouse Y
On exit :
*/
static void
HandleMouseMove(int nX, int nY,int nShiftCtrl)
{
int nDx,nDy;
nDx = nX - LastX;
nDy = nY - LastY;
switch(dGDisplay.nDisplayMode) {
case DISPLAY_OUTSIDE: {
switch (bButtonDown) {
case 1: {
/* Move in X-Z plane */
RwVCMoveCamera(Camera,
RMul(INT2REAL(nDx),CREAL(0.01)),
RMul(INT2REAL(nDy),CREAL(0.01)),CREAL(0.0));
DisplayBound(&dGDisplay);
RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
};
case 2: {
/* Zoom In and Out */
RwVCMoveCamera(Camera,CREAL(0),CREAL(0),RMul(INT2REAL(nDy),CREAL(0.01)));
RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
DisplayBound(&dGDisplay);
break;
};
case 3: {
/* Tilt */
RwRevolveCamera(Camera,RMul(INT2REAL(nDx),CREAL(0.5)) );
DisplayBound(&dGDisplay);
break;
};
};
break;
};
case DISPLAY_BEHIND: {
if (nShiftCtrl&MK_SHIFT) {
switch(bButtonDown) {
case 1: {
dGDisplay.nBehindTilt += RMul(INT2REAL(nDy),CREAL(0.5));
dGDisplay.nBehindPan += RMul(INT2REAL(nDx),CREAL(0.5));
if (dGDisplay.nBehindTilt<CREAL(10)) {
dGDisplay.nBehindTilt = CREAL(10);
};
if (dGDisplay.nBehindTilt>CREAL(90)) {
dGDisplay.nBehindTilt = CREAL(90);
};
break;
};
case 2: {
dGDisplay.nBehindDist += RMul(INT2REAL(nDy),CREAL(0.01));
if (dGDisplay.nBehindDist>CREAL(-0.2)) {
dGDisplay.nBehindDist = CREAL(-0.2);
};
if (dGDisplay.nBehindDist<CREAL(-1.0)) {
dGDisplay.nBehindDist = CREAL(-1.0);
};
break;
};
};
} else {
TankMouseControl(nX,nY);
};
break;
};
case DISPLAY_FIRST: {
if (bButtonDown&1) {
TankMouseControl(nX,nY);
};
break;
};
case DISPLAY_FLOAT: {
if (bButtonDown&1) {
/* Zoom In and Out */
RwVCMoveCamera(Camera,CREAL(0),CREAL(0),RMul(INT2REAL(nDy),CREAL(0.01)));
DisplayBound(&dGDisplay);
};
break;
}
};
}
/****************************************************************************
Main
*/
void main(int nArgc,char *saArgv[])
{
int nKey;
int nMouseX,nMouseY,nMouseBut,nOldMouseBut;
int nChange;
int nShiftCtrl=0;
/* Stop warnings */
nArgc = nArgc;
if (!Init3D(saArgv[0]))
{
exit(-1);
};
/* Put in demo Mode */
nGDemoMode = 1;
nGDisplayTime = DISPLAY_TIME;
nGDisplay = 0;
DisplayMode();
/* Create the ground */
DisplayModeCreate(&dGDisplay);
DisplayModeSet(&dGDisplay,DISPLAY_BEHIND);
GroundCreate(&gGGround);
RwAddClumpToScene(Scene,gGGround.cpGeo);
AllStillObjCreate(&asoGObjects);
AllMoveObjCreate(&amoGObjects,MAX_MOVE_OBJECTS);
AllTanksCreate(&atGTanks);
AllMoveObjCreate(&amoGBits,MAX_BITS);
/* The first created tank is always the user operated one */
AllTanksAddTank(&atGTanks,CREAL(8.0),CREAL(8.0));
/* Create the bullets */
AllBulletsCreate(&abGBullets);
AllBitsCreate(&abGBits);
/* Create pointer */
RwDPointerDisplay(&LastX,&LastY,&nOldMouseBut);
nKey = DosGetKey();
while (nKey!=27) { /* ESC quits */
RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
/* The other bits */
/* nDX =(nMouseX-LastX);
nDY =(nMouseY-LastY);
*/
nKey = DosGetKey();
nShiftCtrl = DosShiftCtrl();
if ((nKey>='1')&&(nKey<='4')) {
DisplayModeSet(&dGDisplay,(nKey-'1')+1);
};
if (nGDemoMode) {
nGDisplayTime--;
if (nGDisplayTime<0) {
DisplayModeSet(&dGDisplay,(nGDisplay&3)+1);
nGDisplayTime = DISPLAY_TIME;
nGDisplay++;
};
};
nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
switch (nChange) {
case 0+0:
case 2+1:
case 8+4:
case 8+2+4+1: {
/* No change */
break;
};
case 2:
case 8+2+4: {
/* Left Button Down */
HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 8:
case 8+2+1: {
/* Right Button Down */
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 8+1: {
/* Right down left Up */
HandleLeftButtonUp();
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 2+4: {
/* Right up left Down */
HandleRightButtonUp();
HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 8+2: {
/* Left down RIght Down */
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 1+4: {
/* Left up Right Up */
HandleRightButtonUp();
HandleLeftButtonUp();
break;
};
case 1:
case 8+4+1: {
/* Left up */
HandleLeftButtonUp();
break;
};
case 4:
case 2+4+1: {
/* Right up */
HandleRightButtonUp();
break;
};
};
HandleMouseMove(nMouseX,nMouseY,nShiftCtrl);
HandleTimer();
LastX = nMouseX;
LastY = nMouseY;
nOldMouseBut = nMouseBut;
};
/*
* Tidy up the 3D (RenderWare) components of the application.
*/
TidyUp3D();
exit(0);
}