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 >
C/C++ Source or Header  |  1995-02-15  |  89KB  |  3,816 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     dostank.c
  4.  *
  5.  * Abstract : A very simple, sample RenderWare application for
  6.  *            MS-Dos / PC-Dos. This application has very little
  7.  *            functionality, but is simply intended as a demonstration
  8.  *            of how to use the RenderWare API.
  9.  *
  10.  *            This application had been written to be compatible with
  11.  *            both the fixed and floating-point versions of the
  12.  *            RenderWare library, i.e., it uses the macros CREAL,
  13.  *            INT2REAL, RAdd, RDiv, RSub etc. If your application is
  14.  *            intended for the floating-point version of the library
  15.  *            only these macros are not necessary.
  16.  *
  17.  *            Please note that this application is intended for
  18.  *            demonstration purposes only. No support will be
  19.  *            provided for this code and it comes with no warranty.
  20.  *
  21.  * This file is a product of Criterion Software Ltd.
  22.  *
  23.  * This file is provided as is with no warranties of any kind and is
  24.  * provided without any obligation on Criterion Software Ltd. or
  25.  * Canon Inc. to assist in its use or modification.
  26.  *
  27.  * Criterion Software Ltd. and Canon Inc. will not, under any
  28.  * circumstances, be liable for any lost revenue or other damages arising
  29.  * from the use of this file.
  30.  *
  31.  * Copyright (c) 1991, 1992, 1993. Canon Inc.
  32.  * All Rights Reserved.
  33.  *
  34.  **********************************************************************/
  35.  
  36. /****************************************************************************
  37.  Includes
  38.  */
  39.  
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <i86.h>
  43. #include <math.h>    /* Required for floating point */
  44.  
  45. #include "rwlib.h"
  46. #include "rwdos.h"
  47. #include "doswrap.h"
  48.  
  49. /****************************************************************************
  50.  Types
  51.  */
  52.  
  53. /**********************************************************************
  54.  *
  55.  * Application constants.
  56.  *
  57.  **********************************************************************/
  58.  
  59. #define M_2PI 6.28318
  60.  
  61. #define EXPLOSION_VEL CREAL(0.01)
  62. #define FORCE_OF_GRAVITY 0.0005
  63.  
  64.  
  65. /*
  66.  * Bullet Defines
  67.  */
  68.  
  69. #define BULLET_SCALE CREAL(0.03)
  70. #define BULLET_SPEED CREAL(0.1)
  71. #define BULLET_LIFE 100
  72.  
  73. /* When bullets hits another bullet */
  74.  
  75. #define BULLET_BITS 5
  76. #define BULLET_STILL_BITS 6
  77. #define NON_EXPLOSION_BITS 5
  78.  
  79. /*
  80.  * And the rest
  81.  */
  82.  
  83. #define DELETE 8
  84. #define BOOL int
  85.  
  86. /*
  87.  * MS Windows compatible defines
  88.  */
  89.  
  90. #define MK_CONTROL 0x4
  91. #define MK_SHIFT 0x2
  92.  
  93. /*
  94.  * Default distance of the camera from the origin.
  95.  */
  96.  
  97. #define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
  98.  
  99. /* PI !*/
  100.  
  101. #define PI 3.141592654
  102.  
  103. /* */
  104.  
  105. #define MAX_GROUND_TEXTURES 26
  106. #define MAX_GROUND_THINGS 20
  107.  
  108. #define GROUND_WIDTH 16
  109. #define GROUND_HEIGHT 16
  110. #define GROUND_SPLIT 2
  111.  
  112. #define GROUND_DISP_WIDTH 11
  113. #define GROUND_DISP_HEIGHT 11
  114. #define GROUND_SIZE CREAL(10.0)
  115.  
  116. #define MAX_BULLETS 20
  117.  
  118. /* Tank mode types - computer control modes */
  119. /* General operations */
  120.  
  121. #define TANK_CONTROL_FORWARD 0
  122. #define TANK_CONTROL_ROTATE  1
  123. #define TANK_CONTROL_WAIT    2
  124. #define TANK_CONTROL_FOLLOW  3
  125.  
  126. /* Other characteristics */
  127.  
  128. #define TANK_CONTROL_AIM     8
  129. #define TANK_CONTROL_ATTACK  16
  130.  
  131. /* Objects */
  132.  
  133. #define MAX_MOVE_OBJECTS 20
  134. #define MAX_TANKS 7
  135.  
  136. #define TANK_CLOSE_FLIP CREAL(1.0)
  137.  
  138. /* MINIMUM TANKS in scene */
  139.  
  140. #define MIN_TANKS 6
  141.  
  142. /* Tank defines */
  143.  
  144. #define TANK_SCALE CREAL(0.07)
  145. #define TANK_HITS 4
  146. #define TANK_EXPLOSION_BITS 15
  147. #define TANK_FIRE_RATE 60
  148.  
  149. /* Still Objects */
  150.  
  151. #define MAX_STILL_OBJECTS 30
  152.  
  153. /* Tank control defines */
  154.  
  155. #define OP_ROT_BASE 1
  156. #define OP_MOVE 2
  157. #define OP_ROT_TURRET 3
  158. #define OP_MOVE_GUN 4
  159. #define OP_SET_TURRET 5
  160. #define OP_FIRE 6
  161.  
  162. /* Display Modes */
  163.  
  164. #define DISPLAY_OUTSIDE 1
  165. #define DISPLAY_FIRST 2
  166. #define DISPLAY_FLOAT 3
  167. #define DISPLAY_BEHIND 4
  168.  
  169. #define DISPLAY_TIME 64
  170.  
  171. /* Object types */
  172.  
  173. #define TYPE_TANK 1
  174. #define TYPE_BULLET 2
  175. #define TYPE_BIT 3
  176.  
  177. /* Amount of frames for tank firing */
  178.  
  179. #define FIRE_TIME 10
  180.  
  181. #define TANK_BACK_FORCE CREAL(0.1)
  182.  
  183. /* Bits defines */
  184.  
  185. #define MAX_BITS 30
  186. #define BIT_SIZE CREAL(0.03)
  187. #define BIT_LIFE 50
  188.  
  189. /**********************************************************************
  190.  *
  191.  * Type definitions.
  192.  *
  193.  **********************************************************************/
  194.  
  195. /****************************************************************************
  196.  Stack Class
  197.  */
  198.  
  199. typedef struct StackTag {
  200.     int nElementSize;
  201.     char *pData;
  202.     char *pCurPtr;
  203.     int nAmoElements;
  204.     int nCurElement;
  205. } Stack;
  206.  
  207.  
  208. /***************************************************************************/
  209.  
  210. /*
  211.  * StillObject
  212.  */
  213.  
  214. typedef struct StillObjectTag {
  215.     RwClump *cpGeo;
  216.     RwV3d vPos;
  217.     RwReal nSize;
  218.     struct StillObjectTag *sopNext;
  219. } StillObject;
  220.  
  221.  
  222. /*
  223.  * The ground plane element type
  224.  */
  225.  
  226. typedef struct GroundEleTag {
  227.     RwTexture *tpTex;
  228.     RwUV uvPos;
  229.     StillObject *sopObj;
  230. } GroundEle;
  231.  
  232. /*
  233.  * The entire ground plane
  234.  */
  235.  
  236. typedef struct GroundTag {
  237.     RwReal nXPos;
  238.     RwReal nZPos;
  239.     int nWidth;
  240.     int nHeight;
  241.     int nX;
  242.     int nY;
  243.     int nDispWidth;
  244.     int nDispHeight;
  245.     int nSplit;
  246.     /* Ground */
  247.     RwReal nSize;
  248.     RwReal nStepSize;
  249.     GroundEle *pGround;
  250.     RwTexture *tpaTex[MAX_GROUND_TEXTURES];
  251.     int nAmoTextures;
  252.     /* Things */
  253.     RwClump *cpaGeo[MAX_GROUND_THINGS];
  254.     int nAmoThings;
  255.     RwReal naScale[MAX_GROUND_THINGS];
  256.     /* The polygon array */
  257.     RwPolygon3d **paPolyData;
  258.     /* The Grounds geometry */
  259.     RwClump *cpGeo;
  260.     /* Pos of the ground */
  261.     RwMatrix4d *mpPos;
  262.     /* The width of a texture element */
  263.     RwReal nTexStep;
  264.     /* World coord size */
  265.     RwReal nWorldWidth;
  266.     RwReal nWorldHeight;
  267. } Ground;
  268.  
  269.  
  270. /*
  271.  * MoveObject
  272.  */
  273.  
  274. typedef struct MoveObjectTag {
  275.     int nType;
  276.     void *pObject;
  277.     RwClump *cpGeo;
  278.     RwV3d vPos;
  279.     RwReal nSize;
  280.     RwV3d vVel;
  281.     RwMatrix4d *mpRot,*mpPos;
  282. } MoveObject;
  283.  
  284. /*
  285.  * Tank
  286.  */
  287.  
  288. typedef struct TankTag {
  289.     int nMode;                    /* When computer controlled */
  290.     int nParam1;                /* Some control parameter */
  291.     RwReal nParam2;
  292.     int nHit;
  293.     int nFireCount;
  294.     MoveObject moBase;
  295.     RwClump *cpTurret;
  296.     RwMatrix4d *mpTurretRotPos;
  297.     RwClump *cpGun;
  298.     RwReal nTurretAngle;
  299.     RwMatrix4d *mpGunRotPos;
  300. } Tank;
  301.  
  302. /*
  303.  * All Move Objects
  304.  */
  305.  
  306. typedef struct AllMoveObjTag {
  307.     Stack sDisplay;
  308.     Stack sDisplayed;
  309.     Stack sToDisplay;
  310.     Stack sDestroy;
  311. } AllMoveObj;
  312.  
  313. /*
  314.  * All Still Objects
  315.  */
  316.  
  317. typedef struct AllStillObjTag {
  318.     Stack sStillDisplayed;
  319.     Stack sStillToDisplay;
  320. } AllStillObj;
  321.  
  322.  
  323. /*
  324.  * All Tanks
  325.  */
  326.  
  327. typedef struct AllTanksTag {
  328.     Stack sFree;
  329.     Stack sUsed;
  330.     Tank *tpTanks;
  331. } AllTanks;
  332.  
  333. /*
  334.  * Bit
  335.  */
  336.  
  337. typedef struct BitTag {
  338.     int nLife;
  339.     MoveObject moBase;
  340. } Bit;
  341.  
  342. /*
  343.  * All Non interacting 'Bits'
  344.  */
  345.  
  346. typedef struct AllBitsTag {
  347.     Stack sFree;
  348.     Stack sUsed;
  349.     Bit *bpBits;
  350. } AllBits;
  351.  
  352.  
  353. /*
  354.  * Display Class
  355.  */
  356.  
  357. typedef struct DisplayTag {
  358.     RwReal nBehindDist;
  359.     RwReal nBehindTilt;
  360.     RwReal nBehindPan;
  361.     RwV3d vFloatPos;
  362.     int nDisplayMode;
  363.     RwReal nMinHeight;
  364.     RwReal nMaxX;
  365.     RwReal nMaxZ;
  366. } Display;
  367.  
  368. /*
  369.  * Bullet
  370.  */
  371.  
  372. typedef struct BulletTag {
  373.     int nLife;
  374.     Tank *tpTank;
  375.     MoveObject moBase;
  376. } Bullet;
  377.  
  378. /*
  379.  * All Bullets
  380.  */
  381.  
  382. typedef struct AllBulletsTag {
  383.     Stack sFree;
  384.     Stack sUsed;
  385.     Bullet *bpBullets;
  386. } AllBullets;
  387.  
  388. /**********************************************************************
  389.  *
  390.  * Application global variables.
  391.  *
  392.  **********************************************************************/
  393.  
  394. /* Current button status */
  395.  
  396. static int bButtonDown = 0;
  397. static int         LastX;
  398. static int         LastY;
  399.  
  400. /*
  401.  * Ground plane texture map
  402.  */
  403.  
  404. static char sGGroundMap[]="\
  405. aaaaabaaaaaaaaaa\
  406. aaaaabaaaaaaaaaa\
  407. aaaaabaaaaaaaaaa\
  408. aaaaabaaaaaccccc\
  409. aaaaabaaaaaaaaaa\
  410. aaaaabaaaaaaaaaa\
  411. aaaaabaaaaaaaaaa\
  412. aaaaabaaaaaaaaaa\
  413. aaaaabaaaaaaaaaa\
  414. aaaaabaaaaaaaaaa\
  415. cccccdcccccccccc\
  416. aaaaabaaaaaaaaaa\
  417. aaaaabaaaaaaaaaa\
  418. aaaaabaaaaaaaaaa\
  419. aaaaabaaaaaaaaaa\
  420. aaaaabaaaaaaaaaa\
  421. ";
  422.  
  423. /* Globals */
  424.  
  425. static Ground gGGround;
  426. static AllMoveObj amoGObjects;
  427. static AllTanks atGTanks;
  428. static Display dGDisplay;
  429. static AllBullets abGBullets;
  430. static AllStillObj asoGObjects;
  431. static AllMoveObj amoGBits;
  432. static AllBits abGBits;
  433.  
  434. static int nGDemoMode;             /* Non zero => demo mode */
  435. static int nGDisplayTime;     /* Counter for view point flip */
  436. static int nGDisplay;         /* Current view point counter */
  437.  
  438. /*
  439.  * Texts colour
  440.  */
  441.  
  442. static int nGTextColour;
  443.  
  444.  
  445. /*
  446.  * Global RenderWare object pointers. In this simple application we
  447.  * make use of only a single scene, camera and light.
  448.  */
  449. static RwScene    *Scene  = NULL;
  450. static RwCamera   *Camera = NULL;
  451. static RwLight    *Light  = NULL;
  452.  
  453. /*
  454.  * This variable tells us what kind of action to take on a mouse move.
  455.  * The action depends on the object that was picked when the mouse button
  456.  * went down, and on the selection of virtual keys that were depressed at
  457.  * that time. By default no action is taken on mouse move.
  458.  */
  459.  
  460. /*
  461.  * Current distance the camera is from the origin. This is stored to
  462.  * help us pan and zoom the camera.
  463.  */
  464. static RwReal      CameraDistance = DEFAULT_CAMERA_DISTANCE;
  465.  
  466. /*
  467.  * Current animation frame number. This is incremented each time a
  468.  * frame is drawn on timer expiry. The purpose of this variable is
  469.  * to enable us to periodically (based on the number of frames) call
  470.  * RwOrthoNormalizeMatrix() to correct any errors which have crept
  471.  * into the clump's joint matrix because of the inevitable
  472.  * restrictions on the accuracy of fixed-point numbers. See
  473.  * HandleTimer for more details.
  474.  */
  475. static int         nGFrameNumber = 0;
  476.  
  477. /* The size of the screen
  478.  */
  479.  
  480. static int nGScrWidth;
  481. static int nGScrHeight;
  482.  
  483. /* Fire Counter */
  484.  
  485. static int nGFireCount;
  486.  
  487. /****************************************************************************
  488.  Proto types
  489.  */
  490.  
  491. /* Other prototypes */
  492.  
  493. void TankControl(Tank *tpTank,
  494.                                  int nOperation,
  495.                  RwReal nParam1);
  496. void MoveObjectCreate(MoveObject *mopObj,
  497.                       RwReal nScale,
  498.                                             RwClump *cpGeo,
  499.                                             int nType,
  500.                       void *pObject);
  501. int AllTanksAddTank(AllTanks *atpTanks,
  502.                     RwReal nXPos,
  503.                     RwReal nZPos);
  504.  
  505. /* Stack Prototypes */
  506. int StackCreate(Stack *spStack,int nEleSize,int nAmoEle);
  507. void StackClear(Stack *spStack);
  508. void *StackData(Stack *spStack);
  509. int StackElements(Stack *spStack);
  510. void *StackFront(Stack *spStack,void *pData);
  511. int StackDestroy(Stack *spStack);
  512. void *StackPush(Stack *spStack,void *pData);
  513. int StackPop(Stack *spStack,void *pData);
  514. void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
  515.                                     void *pUser);
  516. int StackRemove(Stack *spStack,void *pEle);
  517. void *StackFind(Stack *spStack,void *pEle);
  518. int StackTop(Stack *spStack,void *pData);
  519.  
  520. /****************************************************************************
  521.  BitCreate
  522.  
  523.  On entry    : Bit
  524.                     : Scale
  525.                     : Clump
  526.  On exit    :
  527.  */
  528.  
  529. void BitCreate(Bit *bpBit,RwReal nScale,RwClump *cpGeo)
  530. {
  531.     MoveObjectCreate(&bpBit->moBase,nScale,cpGeo,TYPE_BIT,(void *)bpBit);
  532. }
  533.  
  534. /*************************************************************************
  535.  BitColour - Sets polygon to a random colour
  536.              (called from RwForAllPolygonsInClump)
  537.  
  538.  On entry    : Polygon
  539.  On exit    :
  540.  */
  541.  
  542. static void BitColour(RwPolygon3d *p)
  543. {
  544.   static int zippy = 0;
  545.  
  546.   switch ((rand()>>4) % 7)
  547.     {
  548.     case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
  549.     case 1: RwSetPolygonColor(p, CREAL(0.8), CREAL(0.1), CREAL(0.2)); break;
  550.     case 2: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.6), CREAL(0.3)); break;
  551.     case 3: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.0), CREAL(0.2)); break;
  552.     case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
  553.     case 5: RwSetPolygonColor(p, CREAL(0.6), CREAL(0.5), CREAL(0.0)); break;
  554.     case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.2)); break;
  555.     }
  556.   zippy++;
  557. }
  558.  
  559. /****************************************************************************
  560.  AllBitsCreate
  561.  
  562.  On entry    : AllBits
  563.  On exit    :
  564.  */
  565.  
  566. void AllBitsCreate(AllBits *abpBits)
  567. {
  568.     Bit *bpBit;
  569.     int nCount;
  570.     RwClump *cpBit;
  571.     RwClump *cpClump;
  572.  
  573.     RwModelBegin();
  574.   RwClumpBegin();
  575.   RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
  576.   RwSetSurfaceColor(CREAL(1.0),CREAL(1.0),CREAL(1.0));
  577.     RwSetHints(0);
  578.  
  579.     RwVertex(CREAL(0.866),CREAL(0.5),CREAL(0));
  580.     RwVertex(CREAL(-0.866),CREAL(0.5),CREAL(0));
  581.     RwVertex(CREAL(0),CREAL(1.0),CREAL(0));
  582.  
  583.     RwTriangle(1,2,3);
  584.     RwTriangle(3,2,1);
  585.  
  586.     RwClumpEnd(&cpClump);
  587.     RwModelEnd();
  588.  
  589.     abpBits->bpBits = (Bit *) malloc(sizeof(Bit) *MAX_BITS);
  590.  
  591.     StackCreate(&abpBits->sFree,sizeof(Bit *),MAX_BITS);
  592.     StackCreate(&abpBits->sUsed,sizeof(Bit *),MAX_BITS);
  593.  
  594.     bpBit = abpBits->bpBits;
  595.     for (nCount =0;nCount<MAX_BITS;nCount++) {
  596.         cpBit = RwDuplicateClump(cpClump);
  597.         RwForAllPolygonsInClump(cpBit,BitColour);
  598.  
  599.         BitCreate(bpBit,BIT_SIZE,cpBit);
  600.         StackPush(&abpBits->sFree,&bpBit);
  601.         bpBit++;
  602.     };
  603.  
  604.     RwDestroyClump(cpClump);
  605. }
  606.  
  607. /*****************************************************************************
  608.  AllBitsAddBit
  609.  
  610.  On entry    : All bits structure
  611.                     : position
  612.                     : velocity
  613.  On exit    :
  614.  */
  615.  
  616. int AllBitsAddBit(AllBits *abpBits,
  617.                                                 RwV3d *vpPos,
  618.                                                 RwV3d *vpDir,
  619.                                                 int nLife)
  620. {
  621.     Bit *bpBit;
  622.     MoveObject *mopBit;
  623.  
  624.     if (!StackPop(&abpBits->sFree,&bpBit)) {
  625.         StackPush(&abpBits->sUsed,&bpBit);
  626.  
  627.         bpBit->moBase.vPos = (*vpPos);
  628.         bpBit->moBase.vVel = (*vpDir);
  629.  
  630.         bpBit->nLife = nLife;
  631.  
  632.         /* Place on the display stack */
  633.  
  634.         mopBit = &bpBit->moBase;
  635.         StackPush(&amoGBits.sDisplay,(void *)&mopBit);
  636.         return 0;
  637.     } else {
  638.         return 1;
  639.     };
  640. }
  641.  
  642. /****************************************************************************
  643.  AllBitsRemoveBit
  644.  
  645.  On entry    : AllBullets
  646.                     : Bullet to remove
  647.  On exit     :
  648.  */
  649.  
  650. void AllBitsRemoveBit(AllBits *abpBits,
  651.                                                         Bit *bpBit)
  652. {
  653.     MoveObject *mopTmp = &bpBit->moBase;
  654.  
  655.   /* Stop the warnings */
  656.  
  657.   abpBits = abpBits;
  658.  
  659.     /* Remove from display */
  660.  
  661.     StackPush(&amoGBits.sDestroy,&mopTmp);
  662. }
  663.  
  664. /****************************************************************************
  665.  AllBitsHandle
  666.  
  667.  On entry    : All Bits
  668.  On exit    :
  669.  */
  670.  
  671. void AllBitsHandle(AllBits *abpBits)
  672. {
  673.     Bit **bppBit;
  674.     Bit *bpBit;
  675.     int nAmoBits;
  676.     int nCount;
  677.     RwReal nHitHeight;
  678.  
  679.     bppBit = (Bit **)StackData(&abpBits->sUsed);
  680.     nAmoBits = StackElements(&abpBits->sUsed);
  681.  
  682.     nHitHeight = RMul(BIT_SIZE,CREAL(1.5));
  683.  
  684.     for (nCount=0;nCount<nAmoBits;nCount++) {
  685.         bpBit = (*bppBit);
  686.  
  687.         RwTransformMatrix(bpBit->moBase.mpPos,bpBit->moBase.mpRot,rwPOSTCONCAT);
  688.         /* Handle it */
  689.  
  690.         bpBit->nLife--;
  691.         if ((bpBit->nLife<0)) {
  692.             /* Destroy the bullet */
  693.             AllBitsRemoveBit(abpBits,bpBit);
  694.         } else {
  695.             RwAddVector(&bpBit->moBase.vPos,&bpBit->moBase.vVel,
  696.                 &bpBit->moBase.vPos);
  697.             bpBit->moBase.vVel.y -= CREAL(FORCE_OF_GRAVITY);
  698.  
  699.             if ((bpBit->moBase.vPos.y < nHitHeight) &&
  700.                     (bpBit->moBase.vVel.y<CREAL(0)) ) {
  701.                 bpBit->moBase.vPos.y = nHitHeight;
  702.                 bpBit->moBase.vVel.y = -RMul(bpBit->moBase.vVel.y,CREAL(0.5));
  703.             };
  704.         };
  705.  
  706.         bppBit++;
  707.     };
  708.  
  709.     AllMoveObjClean(&amoGBits);
  710. }
  711.  
  712. /****************************************************************************
  713.  AllBitsExplosion
  714.  
  715.  On entry    : All Bits
  716.                     : Position
  717.                     : Velocity
  718.                     : Amount of Bits
  719.  On exit    :
  720.  */
  721.  
  722. void AllBitsExplosion(AllBits *abpBits,
  723.                       RwV3d *vpPos,
  724.                                             RwV3d *vpVel,
  725.                                             int nAmoBits)
  726. {
  727.     int nCount;
  728.     int nLife=0;
  729.     RwReal nRand;
  730.     Bit *bpBit;
  731.     RwV3d vTmp;
  732.  
  733.     for (nCount=0;nCount<nAmoBits;nCount++) {
  734.         if (AllBitsAddBit(abpBits,vpPos,vpVel,BIT_LIFE+(nLife&7))) {
  735.             break;
  736.         };
  737.  
  738.         StackTop(&abpBits->sUsed,&bpBit);
  739.  
  740.         nLife++;
  741.  
  742.         RandomVec(&vTmp);
  743.  
  744.     RwRotateMatrix(bpBit->moBase.mpRot,vTmp.x,vTmp.y,vTmp.z,
  745.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(15.0)),
  746.                           rwREPLACE);
  747.  
  748.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  749.         bpBit->moBase.vVel.x += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  750.                                                                                 EXPLOSION_VEL);
  751.  
  752.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  753.         bpBit->moBase.vVel.y += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  754.                                                                                 EXPLOSION_VEL);
  755.  
  756.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  757.         bpBit->moBase.vVel.z += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  758.                                                                                 EXPLOSION_VEL);
  759.     };
  760. }
  761.  
  762. /****************************************************************************
  763.  DisplayModeSet
  764.  
  765.  On entry    : Display Structure
  766.                          Display Mode required
  767.  On exit    :
  768.  */
  769.  
  770. void DisplayModeSet(Display *dpDisp,
  771.                                         int nMode)
  772. {
  773.     dpDisp->nDisplayMode = nMode;
  774.  
  775.     switch(nMode) {
  776.         case DISPLAY_OUTSIDE: {
  777.             RwSetCameraLookUp(Camera,CREAL(1.0),CREAL(0.0),CREAL(0.0));
  778.             RwSetCameraPosition(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
  779.             RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
  780.             break;
  781.         };
  782.         case DISPLAY_FIRST: {
  783.             RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
  784.             break;
  785.         };
  786.         case DISPLAY_FLOAT: {
  787.             RwSetCameraLookUp(Camera,CREAL(1.0),CREAL(0.0),CREAL(0.0));
  788.             RwSetCameraPosition(Camera,CREAL(2.0),CREAL(1.0),CREAL(0.0));
  789.             RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
  790.             break;
  791.         };
  792.         case DISPLAY_BEHIND: {
  793.             RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
  794.             break;
  795.         };
  796.     };
  797. }
  798.  
  799. /****************************************************************************
  800.  DisplayCreate
  801.  
  802.  On entry    : Display
  803.  On exit    :
  804.  */
  805.  
  806. void DisplayModeCreate(Display *dpDisp)
  807. {
  808.     dpDisp->nBehindDist = CREAL(-0.5);
  809.     dpDisp->nBehindPan = CREAL(0.0);
  810.     dpDisp->nBehindTilt = CREAL(15.0);
  811.  
  812.     dpDisp->vFloatPos.x = CREAL(0.0);
  813.     dpDisp->vFloatPos.y = CREAL(1.0);
  814.     dpDisp->vFloatPos.z = CREAL(0.0);
  815.  
  816.     dpDisp->nMinHeight = CREAL(0.3);
  817.     dpDisp->nMaxX = RMul(GROUND_SIZE,CREAL(0.25));
  818.     dpDisp->nMaxZ = RMul(GROUND_SIZE,CREAL(0.25));
  819. }
  820.  
  821. /****************************************************************************
  822.  AllMoveObjCreate
  823.  
  824.  On entry    : AllMoveObj
  825.  On exit    :
  826.  */
  827.  
  828. void AllMoveObjCreate(AllMoveObj *amopObj,int nMax)
  829. {
  830.     StackCreate(&amopObj->sDisplay,sizeof(MoveObject *),nMax);
  831.     StackCreate(&amopObj->sDisplayed,sizeof(MoveObject *),nMax);
  832.     StackCreate(&amopObj->sToDisplay,sizeof(MoveObject *),nMax);
  833.     StackCreate(&amopObj->sDestroy,sizeof(MoveObject *),nMax);
  834. }
  835.  
  836. /****************************************************************************
  837.  AllMoveObjClean
  838.  
  839.  On entry    : AllMoveObj
  840.  On exit    :
  841.  */
  842.  
  843. void AllMoveObjClean(AllMoveObj *amopObj)
  844. {
  845.     MoveObject *mopObj;
  846.     void *pFind;
  847.  
  848.     while(!StackPop(&amopObj->sDestroy,&mopObj)) {
  849.         pFind = StackFind(&amopObj->sDisplay,&mopObj);
  850.  
  851.         if (pFind) {
  852.             StackRemove(&amopObj->sDisplay,pFind);
  853.  
  854.             switch (mopObj->nType) {
  855.                 case TYPE_BULLET: {
  856.                     /* Remove from active bullets */
  857.                     StackRemove(&abGBullets.sUsed,StackFind(&abGBullets.sUsed,&mopObj->pObject));
  858.                     /* Add to free bullets */
  859.                     StackPush(&abGBullets.sFree,&mopObj->pObject);
  860.                     break;
  861.                 };
  862.                 case TYPE_TANK: {
  863.                     /* Remove from active bullets */
  864.                     StackRemove(&atGTanks.sUsed,StackFind(&atGTanks.sUsed,&mopObj->pObject));
  865.                     /* Add to free bullets */
  866.                     StackPush(&atGTanks.sFree,&mopObj->pObject);
  867.                     break;
  868.                 };
  869.                 case TYPE_BIT: {
  870.                     /* Remove from active bullets */
  871.                     StackRemove(&abGBits.sUsed,StackFind(&abGBits.sUsed,&mopObj->pObject));
  872.                     /* Add to free bullets */
  873.                     StackPush(&abGBits.sFree,&mopObj->pObject);
  874.                     break;
  875.                 };
  876.             };
  877.         };
  878.     };
  879. }
  880.  
  881. /****************************************************************************
  882.  AllStillObjCreate
  883.  
  884.  On entry    : AllMoveObj
  885.  On exit    :
  886.  */
  887.  
  888. void AllStillObjCreate(AllStillObj *asopObj)
  889. {
  890.     StackCreate(&asopObj->sStillDisplayed,sizeof(StillObject *),MAX_STILL_OBJECTS);
  891.     StackCreate(&asopObj->sStillToDisplay,sizeof(StillObject *),MAX_STILL_OBJECTS);
  892. }
  893.  
  894.  
  895. /****************************************************************************
  896.  AddObjectToScene
  897.  
  898.  On entry    : Position
  899.                     : Rotation
  900.                     : Clump
  901.  On exit    :
  902.  */
  903.  
  904. void PosObjectInScene(RwV3d *vpPos,
  905.                                             RwMatrix4d *mpPos,
  906.                                             RwClump *cpClump)
  907. {
  908.     RwPushScratchMatrix();
  909.     RwCopyMatrix(mpPos,RwScratchMatrix());
  910.     RwTranslateMatrix(RwScratchMatrix(),
  911.         (vpPos->x-gGGround.nXPos),
  912.         vpPos->y,
  913.         (vpPos->z-gGGround.nZPos), rwPOSTCONCAT);
  914.     RwTransformClump(cpClump, RwScratchMatrix(), rwREPLACE);
  915.     RwPopScratchMatrix();
  916. }
  917.  
  918. /****************************************************************************
  919.  AllMoveObjDisplay
  920.  
  921.  On entry    : AllMoveObj
  922.  On exit     :
  923.  */
  924.  
  925. int _AllMoveObjDisplay(void *pA,void *pB)
  926. {
  927.     return (((*(int *)pA))-((*(int *)pB)));
  928. }
  929.  
  930. void AllMoveObjDisplay(AllMoveObj *amopObj,Ground *gpGrou)
  931. {
  932.     MoveObject *mopObj;
  933.     RwReal nMinX,nMaxX,nMinZ,nMaxZ;
  934.     Stack sTmp;
  935.     int nDisp;
  936.     int nToDisp;
  937.     MoveObject **mopDisp;
  938.     MoveObject **mopToDisp;
  939.     Tank *tpTank;
  940.  
  941.     tpTank = *((Tank **)StackData(&atGTanks.sUsed));
  942.  
  943.     nMinX = RSub(gpGrou->nXPos,RDiv(gpGrou->nSize,CREAL(2)));
  944.     nMinZ = RSub(gpGrou->nZPos,RDiv(gpGrou->nSize,CREAL(2)));
  945.     nMaxX = nMinX + gpGrou->nSize;
  946.     nMaxZ = nMinZ + gpGrou->nSize;
  947.  
  948.     StackClear(&amopObj->sToDisplay);
  949.  
  950.     mopDisp = (MoveObject **)StackData(&amopObj->sDisplay);
  951.     nDisp = StackElements(&amopObj->sDisplay);
  952.  
  953.     for (;nDisp;nDisp--) {
  954.         mopObj = (*mopDisp);
  955.         mopDisp++;
  956.         if ((mopObj->vPos.x<nMinX) ||
  957.                 (mopObj->vPos.x>nMaxX) ||
  958.                 (mopObj->vPos.z<nMinZ) ||
  959.                 (mopObj->vPos.z>nMaxZ)) {
  960.             continue;
  961.         };
  962.  
  963.         if ((dGDisplay.nDisplayMode==DISPLAY_FIRST)&&
  964.                     (mopObj==(&tpTank->moBase))) {
  965.             /* If first person, then dont display your tank */
  966.             continue;
  967.         };
  968.         StackPush(&amopObj->sToDisplay,(void *) &mopObj);
  969.     };
  970.  
  971.     /* Sort the stacks for later comparison */
  972.  
  973.     qsort(StackData(&amopObj->sToDisplay),
  974.         StackElements(&amopObj->sToDisplay),
  975.         sizeof(MoveObject *),_AllMoveObjDisplay);
  976.  
  977.     /* Find what needs to be added and removed from scene */
  978.  
  979.     mopToDisp = (MoveObject **) StackData(&amopObj->sToDisplay);
  980.     nToDisp = StackElements(&amopObj->sToDisplay);
  981.  
  982.     mopDisp = (MoveObject **)StackData(&amopObj->sDisplayed);
  983.     nDisp = StackElements(&amopObj->sDisplayed);
  984.  
  985.     while (nToDisp&&nDisp) {
  986.         if ((*mopDisp)==(*mopToDisp)) {
  987.             PosObjectInScene(&((*mopToDisp)->vPos),
  988.                                              (*mopToDisp)->mpPos,
  989.                                              (*mopToDisp)->cpGeo);
  990.  
  991.             mopDisp++;
  992.             mopToDisp++;
  993.             nToDisp--;
  994.             nDisp--;
  995.         } else {
  996.             if ((*mopDisp)<(*mopToDisp)) {
  997.                 RwRemoveClumpFromScene((*mopDisp)->cpGeo);
  998.  
  999.                 nDisp--;
  1000.                 mopDisp++;
  1001.             } else {
  1002.                 RwAddClumpToScene(Scene,(*mopToDisp)->cpGeo);
  1003.                 PosObjectInScene(&(*mopToDisp)->vPos,
  1004.                                                  (*mopToDisp)->mpPos,
  1005.                                                  (*mopToDisp)->cpGeo);
  1006.  
  1007.                 nToDisp--;
  1008.                 mopToDisp++;
  1009.             };
  1010.         };
  1011.     };
  1012.  
  1013.     if (nDisp) {
  1014.         for (;nDisp;nDisp--) {
  1015.             RwRemoveClumpFromScene((*mopDisp)->cpGeo);
  1016.             mopDisp++;
  1017.         };
  1018.     };
  1019.  
  1020.     if (nToDisp) {
  1021.         for (;nToDisp;nToDisp--) {
  1022.             RwAddClumpToScene(Scene,(*mopToDisp)->cpGeo);
  1023.             PosObjectInScene(&(*mopToDisp)->vPos,
  1024.                                              (*mopToDisp)->mpPos,
  1025.                                              (*mopToDisp)->cpGeo);
  1026.             mopToDisp++;
  1027.         };
  1028.     };
  1029.  
  1030.     /* Switch stacks - to remove a qsort!*/
  1031.  
  1032.     sTmp = amopObj->sDisplayed;
  1033.     amopObj->sDisplayed = amopObj->sToDisplay;
  1034.     amopObj->sToDisplay = sTmp;
  1035. }
  1036.  
  1037. /****************************************************************************
  1038.  AllMoveObjBound
  1039.  
  1040.  On entry    : All move objects
  1041.                         Ground
  1042.  On exit    :
  1043.  */
  1044.  
  1045. void AllMoveObjBound(AllMoveObj *amopObj,
  1046.                                          Ground *gpGrou)
  1047. {
  1048.     MoveObject **moppCur;
  1049.     int nAmoObj;
  1050.     RwReal nMinX,nMaxX,nMinZ,nMaxZ;
  1051.  
  1052.     moppCur = (MoveObject **)StackData(&amopObj->sDisplay);
  1053.     nAmoObj = StackElements(&amopObj->sDisplay);
  1054.  
  1055.     nMinX = CREAL(0);
  1056.     nMinZ = CREAL(0);
  1057.     nMaxX = RSub(gpGrou->nWorldWidth,CREAL(0.001));
  1058.     nMaxZ = RSub(gpGrou->nWorldHeight,CREAL(0.001));
  1059.  
  1060.     for (;nAmoObj;nAmoObj--) {
  1061.         if ((*moppCur)->nType==TYPE_TANK) {
  1062.             if ((*moppCur)->vPos.x<nMinX) {
  1063.                 (*moppCur)->vPos.x = nMinX;
  1064.             };
  1065.             if ((*moppCur)->vPos.x>nMaxX) {
  1066.                 (*moppCur)->vPos.x = nMaxX;
  1067.             };
  1068.             if ((*moppCur)->vPos.z<nMinZ) {
  1069.                 (*moppCur)->vPos.z = nMinZ;
  1070.             };
  1071.             if ((*moppCur)->vPos.z>nMaxZ) {
  1072.                 (*moppCur)->vPos.z = nMaxZ;
  1073.             };
  1074.         };
  1075.  
  1076.         moppCur++;
  1077.     };
  1078. }
  1079.  
  1080. /****************************************************************************
  1081.  AllMoveObjCollision
  1082.  
  1083.  On entry    : All move objects
  1084.  On    exit    :
  1085.  */
  1086.  
  1087. void AllMoveObjCollision(AllMoveObj *amopObj)
  1088. {
  1089.     MoveObject **moppCur;
  1090.     MoveObject **moppCheck;
  1091.     int nCount,nCount2;
  1092.     int nAmoObj;
  1093.     RwReal nCurSize,nMinSize;
  1094.   RwV3d vCur;
  1095.     RwV3d vTmp,vVel;
  1096.     RwReal nDist;
  1097.     Tank *tpTank;
  1098.     Bullet *bpBull;
  1099.     RwV3d vExpDir,vExpPos;
  1100.  
  1101.     vVel.x = CREAL(0);
  1102.     vVel.y = CREAL(0);
  1103.     vVel.z = CREAL(0);
  1104.  
  1105.     moppCur = (MoveObject **)StackData(&amopObj->sDisplay);
  1106.     nAmoObj = StackElements(&amopObj->sDisplay);
  1107.  
  1108.     for (nCount=nAmoObj-1;nCount>0;nCount--) {
  1109.         moppCheck = moppCur+1;
  1110.         vCur = (*moppCur)->vPos;
  1111.         nCurSize = (*moppCur)->nSize;
  1112.         for (nCount2=0;nCount2<nCount;nCount2++) {
  1113.             RwSubtractVector(&vCur,&(*moppCheck)->vPos,&vTmp);
  1114.  
  1115.             nMinSize = nCurSize + (*moppCheck)->nSize;
  1116.  
  1117.             if ((vTmp.x>nMinSize)||
  1118.                     (vTmp.x<-nMinSize)||
  1119.                     (vTmp.z>nMinSize)||
  1120.                     (vTmp.z<-nMinSize)) {
  1121.                 moppCheck++;
  1122.                 continue;
  1123.             };
  1124.  
  1125.             nDist = RSqrt( RAdd(RMul(vTmp.x,vTmp.x),
  1126.                                 RMul(vTmp.z,vTmp.z)) );
  1127.  
  1128.             if (nDist<nMinSize) {
  1129.                 if ((*moppCur)->nType==(*moppCheck)->nType) {
  1130.                     if (((*moppCur)->nType == TYPE_TANK)) {
  1131.                         /* Two tanks */
  1132.                         nDist= RMul(RSub(nDist,nMinSize),CREAL(0.5));
  1133.  
  1134.                         RwNormalize(&vTmp);
  1135.                         vTmp.x = RMul(vTmp.x,nDist);
  1136.                         vTmp.z = RMul(vTmp.z,nDist);
  1137.  
  1138.                         RwAddVector(&(*moppCheck)->vPos,&vTmp,&(*moppCheck)->vPos);
  1139.                         RwSubtractVector(&(*moppCur)->vPos,&vTmp,&(*moppCur)->vPos);
  1140.                     } else {
  1141.                         /* Two bullets */
  1142.                         AllBitsExplosion(&abGBits,&(*moppCur)->vPos,&vVel,BULLET_BITS);
  1143.  
  1144.                         AllBulletsRemoveBullet(&abGBullets,(*moppCur)->pObject);
  1145.                         AllBulletsRemoveBullet(&abGBullets,(*moppCheck)->pObject);
  1146.                     };
  1147.                 } else {
  1148.                     /* a tank is destroyed */
  1149.                     if ((*moppCur)->nType==TYPE_TANK) {
  1150.                         tpTank = (Tank *)((*moppCur)->pObject);
  1151.                         bpBull = (Bullet *)((*moppCheck)->pObject);
  1152.                     } else {
  1153.                         tpTank = (Tank *)((*moppCheck)->pObject);
  1154.                         bpBull = (Bullet *)((*moppCur)->pObject);
  1155.                     };
  1156.  
  1157.                     if ( (bpBull->tpTank == tpTank) || (nDist<RMul(nMinSize,CREAL(0.5))) )  {
  1158.                         /* A firing tank cannot hit itself */
  1159.                         /* Make it tricky to hit */
  1160.                         moppCheck++;
  1161.                         continue;
  1162.                     };
  1163.  
  1164.                     if (tpTank == *((Tank **)StackData(&atGTanks.sUsed))) {
  1165.                         /* You've been hit */
  1166.                         /* Make sure you dont die */
  1167.  
  1168.                         tpTank->nHit = TANK_HITS;
  1169.                     };
  1170.  
  1171.  
  1172.                     if (tpTank->nHit) {
  1173.                         tpTank->nHit--;
  1174.  
  1175.                         /* Blast back effect */
  1176.                         vExpDir = bpBull->moBase.vVel;
  1177.  
  1178.                         vExpDir.x = RMul(vExpDir.x,CREAL(-0.1));
  1179.                         vExpDir.y = RMul(vExpDir.y,CREAL(-0.1));
  1180.                         vExpDir.z = RMul(vExpDir.z,CREAL(-0.1));
  1181.  
  1182.                         AllBitsExplosion(&abGBits,&bpBull->moBase.vPos,
  1183.                                                                             &vExpDir,
  1184.                                                                             NON_EXPLOSION_BITS);
  1185.  
  1186.                         vExpDir = bpBull->moBase.vVel;
  1187.                         RwNormalize(&vExpDir);
  1188.  
  1189.                         vExpDir.x = RMul(vExpDir.x,TANK_BACK_FORCE);
  1190.                         vExpDir.y = RMul(vExpDir.y,TANK_BACK_FORCE);
  1191.                         vExpDir.z = RMul(vExpDir.z,TANK_BACK_FORCE);
  1192.  
  1193.                         RwAddVector(&tpTank->moBase.vPos,&vExpDir,&tpTank->moBase.vPos);
  1194.  
  1195.                         AllBulletsRemoveBullet(&abGBullets,bpBull);
  1196.                     } else {
  1197.                         /* Tank is destroyed */
  1198.                         vExpDir.x = CREAL(0);
  1199.                         vExpDir.y = CREAL(0.01);     /* Make it go up !*/
  1200.                         vExpDir.z = CREAL(0);
  1201.  
  1202.                         vExpPos = tpTank->moBase.vPos;
  1203.                         vExpPos.y += RDiv(tpTank->moBase.nSize,CREAL(2));
  1204.  
  1205.                         AllBitsExplosion(&abGBits,&vExpPos,
  1206.                                                                             &vExpDir,
  1207.                                                                             TANK_EXPLOSION_BITS);
  1208.                         AllBulletsRemoveBullet(&abGBullets,bpBull);
  1209.                         AllTanksRemoveTank(&atGTanks,tpTank);
  1210.                     };
  1211.                 };
  1212.             };
  1213.  
  1214.             moppCheck++;
  1215.         };
  1216.         moppCur++;
  1217.     };
  1218.  
  1219.     /* Delete unwanted entries */
  1220.  
  1221.     AllMoveObjClean(amopObj);
  1222. }
  1223.  
  1224. /****************************************************************************
  1225.  AllMoveObjCollisionStill
  1226.  
  1227.  On entry    : All move objects
  1228.                     : Ground structure
  1229.  On exit    :
  1230.  */
  1231.  
  1232. void AllMoveObjCollisionStill(AllMoveObj *amopObj,
  1233.                                                             Ground *gpGrou)
  1234. {
  1235.     MoveObject **moppObj;
  1236.     MoveObject *mopObj;
  1237.     int nAmoObj;
  1238.     GroundEle *gepGrou,*gepCur;
  1239.     int nStride;
  1240.     int nXPos;
  1241.     int nZPos;
  1242.     StillObject *sopObj;
  1243.     RwReal nWX,nWZ;
  1244.     RwReal nDist;
  1245.   RwV3d vTmp,vExpDir;
  1246.  
  1247.     gepGrou = gpGrou->pGround;
  1248.     nStride = gpGrou->nWidth*gpGrou->nSplit;
  1249.  
  1250.     moppObj = (MoveObject **)StackData(&amopObj->sDisplay);
  1251.     nAmoObj = StackElements(&amopObj->sDisplay);
  1252.  
  1253.     for(;nAmoObj;nAmoObj--) {
  1254.         mopObj = (*moppObj);
  1255.  
  1256.         if ((mopObj->vPos.x<CREAL(0))||
  1257.               (mopObj->vPos.z<CREAL(0))||
  1258.               (mopObj->vPos.x>gpGrou->nWorldWidth)||
  1259.               (mopObj->vPos.z>gpGrou->nWorldHeight)) {
  1260.             /* Object not in world */
  1261.             moppObj++;
  1262.             continue;
  1263.         };
  1264.  
  1265.         nXPos = REAL2INT(RDiv(mopObj->vPos.x,gpGrou->nStepSize));
  1266.         nZPos = REAL2INT(RDiv(mopObj->vPos.z,gpGrou->nStepSize));
  1267.  
  1268.         nWX = RMul(INT2REAL(nXPos),gpGrou->nStepSize);
  1269.         nWZ = RMul(INT2REAL(nZPos),gpGrou->nStepSize);
  1270.  
  1271.         gepCur = gepGrou+((nStride*nZPos)+(nXPos));
  1272.         sopObj = gepCur->sopObj;
  1273.  
  1274.         while (sopObj) {
  1275.  
  1276.             vTmp = sopObj->vPos;
  1277.             vTmp.x += nWX;
  1278.             vTmp.z += nWZ;
  1279.  
  1280.             vTmp.x -= mopObj->vPos.x;
  1281.             vTmp.z -= mopObj->vPos.z;
  1282.  
  1283.             nDist = RSqrt(RAdd(RMul(vTmp.x,vTmp.x),RMul(vTmp.z,vTmp.z)));
  1284.  
  1285.             if (nDist<RAdd(mopObj->nSize,sopObj->nSize)) {
  1286.                 switch (mopObj->nType) {
  1287.                     case TYPE_TANK: {
  1288.                         RwNormalize(&vTmp);
  1289.                         vTmp.x = RMul(vTmp.x,nDist-(mopObj->nSize+sopObj->nSize));
  1290.                         vTmp.z = RMul(vTmp.z,nDist-(mopObj->nSize+sopObj->nSize));
  1291.  
  1292.                         RwAddVector(&mopObj->vPos,&vTmp,&mopObj->vPos);
  1293.                         break;
  1294.                     };
  1295.                     case TYPE_BULLET: {
  1296.                         vExpDir = mopObj->vVel;
  1297.                         vExpDir.x = RMul(vExpDir.x,CREAL(-0.1));
  1298.                         vExpDir.y = RMul(vExpDir.y,CREAL(-0.1));
  1299.                         vExpDir.z = RMul(vExpDir.z,CREAL(-0.1));
  1300.  
  1301.                         AllBitsExplosion(&abGBits,&mopObj->vPos,&vExpDir,BULLET_STILL_BITS);
  1302.                         AllBulletsRemoveBullet(&abGBullets,mopObj->pObject);
  1303.                         break;
  1304.                     };
  1305.                     default: {
  1306.                     };
  1307.                 };
  1308.             };
  1309.             sopObj = sopObj->sopNext;
  1310.         };
  1311.  
  1312.         moppObj++;
  1313.     };
  1314.  
  1315.     AllMoveObjClean(amopObj);
  1316. }
  1317.  
  1318. /****************************************************************************
  1319.  StillObjectCreate
  1320.  
  1321.  On entry    : StillObject
  1322.                     : Scale
  1323.                     : Clump
  1324.  */
  1325.  
  1326. /*
  1327.  * StillObject
  1328.  */
  1329.  
  1330. void StillObjectCreate(StillObject *sopObj,RwReal nScale,RwClump *cpGeo)
  1331. {
  1332.     RwPushScratchMatrix();
  1333.  
  1334.     sopObj->nSize = RMul(nScale,CREAL(0.8));
  1335.  
  1336.     RwScaleMatrix(RwScratchMatrix(),nScale,nScale,nScale,rwREPLACE);
  1337.     RwTransformClumpJoint(cpGeo,RwScratchMatrix(),rwREPLACE);
  1338.  
  1339.     sopObj->vPos.x = CREAL(0.0);
  1340.     sopObj->vPos.y = CREAL(0.0);
  1341.     sopObj->vPos.z = CREAL(0.0);
  1342.  
  1343.     sopObj->cpGeo = cpGeo;
  1344.  
  1345.     sopObj->sopNext = NULL;
  1346.     RwPopScratchMatrix();
  1347. }
  1348.  
  1349. /****************************************************************************
  1350.  MoveObjectCreate
  1351.  
  1352.  On entry    : MoveObject
  1353.                     : Objects Scale
  1354.                     : Object in Question
  1355.                     : Data
  1356.  On exit    :
  1357.  */
  1358.  
  1359. void MoveObjectCreate(MoveObject *mopObj,
  1360.                       RwReal nScale,
  1361.                                             RwClump *cpGeo,
  1362.                                             int nType,
  1363.                                             void *pObject)
  1364. {
  1365.     RwPushScratchMatrix();
  1366.  
  1367.     mopObj->nSize = RMul(nScale,CREAL(1.0));
  1368.  
  1369.     RwIdentityMatrix(mopObj->mpRot=RwCreateMatrix());
  1370.     RwIdentityMatrix(mopObj->mpPos=RwCreateMatrix());
  1371.  
  1372.     RwScaleMatrix(RwScratchMatrix(),nScale,nScale,nScale,rwREPLACE);
  1373.     RwTransformClumpJoint(cpGeo,RwScratchMatrix(),rwREPLACE);
  1374.  
  1375.     mopObj->vPos.x = CREAL(0.0);
  1376.     mopObj->vPos.y = CREAL(0.0);
  1377.     mopObj->vPos.z = CREAL(0.0);
  1378.  
  1379.     mopObj->vVel.x = CREAL(0.0);
  1380.     mopObj->vVel.y = CREAL(0.0);
  1381.     mopObj->vVel.z = CREAL(0.0);
  1382.  
  1383.     mopObj->cpGeo = cpGeo;
  1384.  
  1385.     mopObj->pObject = pObject;
  1386.     mopObj->nType = nType;
  1387.  
  1388.     RwPopScratchMatrix();
  1389. }
  1390.  
  1391. /****************************************************************************
  1392.  TankAim
  1393.  
  1394.  On entry    : Tank
  1395.                     : Vector to look at
  1396.  On exit    : Direction to aim
  1397.  */
  1398.  
  1399. RwReal TankAim(Tank *tpTank,RwV3d *vpDir)
  1400. {
  1401.     RwV3d vDirNeed;
  1402.     RwV3d vDirTank;
  1403.     RwV3d vOut;
  1404.     RwReal nCosDir;
  1405.     RwReal nAngle;
  1406.  
  1407.     vDirNeed = (*vpDir);
  1408.     RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
  1409.     RwNormalize(&vDirNeed);
  1410.  
  1411.     vDirTank.x = CREAL(1.0);
  1412.     vDirTank.y = CREAL(0.0);
  1413.     vDirTank.z = CREAL(0.0);
  1414.  
  1415.     RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
  1416.  
  1417.     nCosDir = RwDotProduct(&vDirTank,&vDirNeed);
  1418.     if (nCosDir>CREAL(0.999)) {
  1419.         nCosDir=CREAL(0.999);
  1420.     };
  1421.     if (nCosDir<CREAL(-0.999)) {
  1422.         nCosDir = CREAL(-0.999);
  1423.     };
  1424.  
  1425.     RwCrossProduct(&vDirTank,&vDirNeed,&vOut);
  1426.  
  1427.     nAngle = RMul(RDiv(CREAL(180),CREAL(PI)),FL2REAL(acos(REAL2FL(nCosDir))) );
  1428.     if (vOut.y<CREAL(0.0)) {
  1429.         nAngle=-nAngle;
  1430.     };
  1431.  
  1432.     return nAngle;
  1433. }
  1434.  
  1435.  
  1436.  
  1437. /****************************************************************************
  1438.  TankGivePurpose
  1439.  
  1440.  On entry    : Tank
  1441.  On exit    :
  1442.  */
  1443.  
  1444. void TankGivePurpose(Tank *tpTank)
  1445. {
  1446.     int nRand;
  1447.     int nRand2;
  1448.     int nValue;
  1449.  
  1450.     nRand = rand();
  1451.     nRand2= rand();
  1452.     nValue = nRand&255;
  1453.  
  1454.     if (nValue<90) {
  1455.         tpTank->nMode = TANK_CONTROL_FORWARD;
  1456.         tpTank->nParam1 = nRand2&63;
  1457.         tpTank->nParam2 = RDiv(INT2REAL(((nRand2>>8)&31)-15),CREAL(1000));
  1458.     } else if (nValue<130) {
  1459.         tpTank->nMode = TANK_CONTROL_ROTATE;
  1460.         tpTank->nParam1 = nRand2&7;
  1461.         tpTank->nParam2 = RDiv(INT2REAL(((nRand2>>8)&511)-255),CREAL(64));
  1462.     } else if (nValue<170) {
  1463.         tpTank->nMode = TANK_CONTROL_WAIT;
  1464.         tpTank->nParam1 = nRand2&31;
  1465.     } else {
  1466.         tpTank->nMode = TANK_CONTROL_FOLLOW;
  1467.         tpTank->nParam1 = nRand2&63;
  1468.     };
  1469.  
  1470.     nValue = (nRand>>8)&15;
  1471.  
  1472.     if (((nRand>>8)&15)<5) {
  1473.         tpTank->nMode|=TANK_CONTROL_AIM;
  1474.     };
  1475.     if (((nRand>>12)&15)<5) {
  1476.         tpTank->nMode|=TANK_CONTROL_ATTACK;
  1477.     };
  1478. }
  1479.  
  1480. /****************************************************************************
  1481.  TankAct
  1482.  
  1483.  On entry    : Tank Structure
  1484.  On exit    :
  1485.  */
  1486.  
  1487. void TankAct(Tank *tpTank)
  1488. {
  1489.     Tank *tpTarget;
  1490.     RwV3d vDirNeed;
  1491.     RwV3d vDirTank;
  1492.     RwReal nValue;
  1493.  
  1494.     if (tpTank->nParam1--<0) {
  1495.         TankGivePurpose(tpTank);
  1496.     };
  1497.  
  1498.     if (tpTank->nFireCount) {
  1499.         tpTank->nFireCount--;
  1500.     };
  1501.  
  1502.     tpTarget = *((Tank **)StackData(&atGTanks.sUsed));
  1503.  
  1504.     switch(tpTank->nMode&3) {
  1505.         case TANK_CONTROL_FORWARD: {
  1506.             TankControl(tpTank,OP_MOVE,tpTank->nParam2);
  1507.             break;
  1508.         };
  1509.         case TANK_CONTROL_ROTATE: {
  1510.             TankControl(tpTank,OP_ROT_BASE,tpTank->nParam2);
  1511.             break;
  1512.         };
  1513.         case TANK_CONTROL_WAIT: {
  1514.             break;
  1515.         };
  1516.         case TANK_CONTROL_FOLLOW: {
  1517.  
  1518.             vDirNeed = tpTarget->moBase.vPos;
  1519.  
  1520.             RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
  1521.             RwNormalize(&vDirNeed);
  1522.  
  1523.             vDirTank.x = CREAL(0.0);
  1524.             vDirTank.y = CREAL(0.0);
  1525.             vDirTank.z = CREAL(1.0);
  1526.  
  1527.             RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
  1528.  
  1529.             if (RwDotProduct(&vDirTank,&vDirNeed)<CREAL(0.0)) {
  1530.                 TankControl(tpTank,OP_ROT_BASE,CREAL(2));
  1531.             } else {
  1532.                 TankControl(tpTank,OP_ROT_BASE,CREAL(-2));
  1533.             };
  1534.  
  1535.             TankControl(tpTank,OP_MOVE,CREAL(0.01));
  1536.  
  1537.             if ( ((RAbs(tpTarget->moBase.vPos.x-tpTank->moBase.vPos.x))<TANK_CLOSE_FLIP)&&
  1538.                      ((RAbs(tpTarget->moBase.vPos.x-tpTank->moBase.vPos.x))<TANK_CLOSE_FLIP) ) {
  1539.                 /* Its very close so time to back off - probably */
  1540.                 if (rand()&255<20) {
  1541.                     TankGivePurpose(tpTank);
  1542.                 };
  1543.             };
  1544.  
  1545.             break;
  1546.         };
  1547.     };
  1548.  
  1549.  
  1550.     if (tpTank->nMode&TANK_CONTROL_AIM) {
  1551.         vDirNeed = tpTarget->moBase.vPos;
  1552.  
  1553.         RwSubtractVector(&vDirNeed,&tpTank->moBase.vPos,&vDirNeed);
  1554.         RwNormalize(&vDirNeed);
  1555.  
  1556.         vDirTank.x = CREAL(0.0);
  1557.         vDirTank.y = CREAL(0.0);
  1558.         vDirTank.z = CREAL(1.0);
  1559.  
  1560.         RwTransformVector(&vDirTank,tpTank->moBase.mpPos);
  1561.  
  1562.         RwPushScratchMatrix();
  1563.         RwGetClumpJointMatrix(tpTank->cpTurret,RwScratchMatrix());
  1564.         RwTransformVector(&vDirTank,RwScratchMatrix());
  1565.         vDirTank.y = CREAL(0);
  1566.         RwPopScratchMatrix();
  1567.  
  1568.         if ((nValue = RwDotProduct(&vDirTank,&vDirNeed))<CREAL(0.0)) {
  1569.             TankControl(tpTank,OP_ROT_TURRET,CREAL(2));
  1570.         } else {
  1571.             TankControl(tpTank,OP_ROT_TURRET,CREAL(-2));
  1572.         };
  1573.  
  1574.         if (tpTank->nMode&TANK_CONTROL_ATTACK) {
  1575.             if ( (RAbs(tpTank->moBase.vPos.x-tpTarget->moBase.vPos.x)<
  1576.                 RDiv(gGGround.nSize,CREAL(2)) ) &&
  1577.              (RAbs(tpTank->moBase.vPos.z-tpTarget->moBase.vPos.z)<
  1578.                 RDiv(gGGround.nSize,CREAL(2)) ) && (!tpTank->nFireCount)) {
  1579.  
  1580.                 if (nValue<CREAL(0.2)) {
  1581.                     TankControl(tpTank,OP_FIRE,CREAL(0));
  1582.  
  1583.                     tpTank->nFireCount = TANK_FIRE_RATE;
  1584.                 };
  1585.             };
  1586.         };
  1587.     };
  1588. }
  1589.  
  1590.  
  1591. /****************************************************************************
  1592.  TankCreate
  1593.  
  1594.  On entry    : Tank
  1595.                     : Scale
  1596.                     : Clump
  1597.  */
  1598.  
  1599. RwClump *_TankCreate(RwClump *cpClump,void *pData)
  1600. {
  1601.     Tank *tpTank = (Tank *)pData;
  1602.  
  1603.     if (!tpTank->cpGun) {
  1604.         tpTank->cpGun = cpClump;
  1605.     } else {
  1606.         if (!tpTank->cpTurret) {
  1607.             tpTank->cpTurret = cpClump;
  1608.         };
  1609.     };
  1610.     return NULL;
  1611. }
  1612.  
  1613. void TankCreate(Tank *tpTank,RwReal nScale,RwClump *cpGeo)
  1614. {
  1615.     MoveObjectCreate(&tpTank->moBase,nScale,cpGeo,TYPE_TANK,(void *)tpTank);
  1616.  
  1617.     RwIdentityMatrix(tpTank->mpTurretRotPos=RwCreateMatrix());
  1618.     RwIdentityMatrix(tpTank->mpGunRotPos=RwCreateMatrix());
  1619.  
  1620.     tpTank->nTurretAngle = CREAL(0.0);
  1621.  
  1622.     tpTank->cpGun = NULL;        /* Mark as unused */
  1623.     tpTank->cpTurret = NULL; /* Mark as unused */
  1624.  
  1625.     RwForAllClumpsInHierarchyPointer(cpGeo,_TankCreate,(void *)tpTank);
  1626.  
  1627.     tpTank->nHit = TANK_HITS;
  1628.     tpTank->nFireCount = 0;
  1629.  
  1630.     TankGivePurpose(tpTank);
  1631. }
  1632.  
  1633. /****************************************************************************
  1634.  TankGunEndDirection
  1635.  
  1636.  On entry    : Tank
  1637.                     : (OUT) direction vector
  1638.  On exit    :
  1639.  */
  1640.  
  1641. void TankGunEndDirection(Tank *tpTank,
  1642.                                             RwV3d *vpEnd,
  1643.                                             RwV3d *vpDir)
  1644. {
  1645.     RwV3d vTmp;
  1646.  
  1647.     RwPushScratchMatrix();
  1648.  
  1649.     vpEnd->x = CREAL(1.0);
  1650.     vpEnd->y = CREAL(0.0);
  1651.     vpEnd->z = CREAL(0.0);
  1652.  
  1653.     RwGetClumpLTM(tpTank->cpGun,RwScratchMatrix());
  1654.     RwTransformPoint(vpEnd,RwScratchMatrix());
  1655.  
  1656.     vTmp.x = CREAL(0.5);
  1657.     vTmp.y = CREAL(0.0);
  1658.     vTmp.z = CREAL(0.0);
  1659.  
  1660.     RwTransformPoint(&vTmp,RwScratchMatrix());
  1661.  
  1662.     RwSubtractVector(vpEnd,&vTmp,vpDir);
  1663.     RwNormalize(vpDir);
  1664.  
  1665.     RwPopScratchMatrix();
  1666. }
  1667.  
  1668. /****************************************************************************
  1669.  AllTanksLaunch
  1670.  
  1671.  On entry    : AllTanks
  1672.  On exit    :
  1673.  */
  1674.  
  1675. void AllTanksLaunch(AllTanks *atpTanks)
  1676. {
  1677.     int nAmoTanks;
  1678.     Tank *tpTank;
  1679.     RwReal nX,nZ,nXDist,nZDist;
  1680.     int nValue;
  1681.  
  1682.     tpTank = *(Tank **)StackData(&atpTanks->sUsed);
  1683.     nAmoTanks = StackElements(&atpTanks->sUsed);
  1684.  
  1685.     if (nAmoTanks<MIN_TANKS) {
  1686.         nValue = rand()&0xff;
  1687.         if (nValue<4) {
  1688.             nX = RMul(RDiv(INT2REAL(rand()&255),INT2REAL(255) ),
  1689.                 gGGround.nWorldWidth);
  1690.             nZ = RMul(RDiv(INT2REAL(rand()&255),INT2REAL(255) ),
  1691.                 gGGround.nWorldHeight);
  1692.  
  1693.             nXDist = tpTank->moBase.vPos.x-nX;
  1694.             nZDist = tpTank->moBase.vPos.z-nZ;
  1695.  
  1696.             if ((nXDist>RMul(INT2REAL(gGGround.nDispWidth/2),gGGround.nStepSize))||
  1697.               (nXDist<-RMul(INT2REAL(gGGround.nDispWidth/2),gGGround.nStepSize))||
  1698.                 (nZDist>RMul(INT2REAL(gGGround.nDispHeight/2),gGGround.nStepSize))||
  1699.                 (nZDist<-RMul(INT2REAL(gGGround.nDispHeight/2),gGGround.nStepSize))) {
  1700.  
  1701.                 AllTanksAddTank(atpTanks,nX,nZ);
  1702.             };
  1703.         };
  1704.     };
  1705. }
  1706.  
  1707. /****************************************************************************
  1708.  AllTanksCreate
  1709.  
  1710.  On entry    : AllTanks
  1711.  On exit    :
  1712.  */
  1713.  
  1714. void AllTanksCreate(AllTanks *atpTanks)
  1715. {
  1716.     Tank *tpTanks;
  1717.     int nCount;
  1718.     char saFileNames[][10]={"tank.rwx",
  1719.                                                     "tank.rwx"};
  1720.     int nNames = 2;
  1721.     RwClump *cpaClumps[MAX_TANKS];
  1722.  
  1723.     for (nCount = 0;nCount<nNames;nCount++) {
  1724.         cpaClumps[nCount] = RwReadShape(saFileNames[nCount]);
  1725.     };
  1726.  
  1727.     atpTanks->tpTanks = (Tank *) malloc(sizeof(Tank) *MAX_TANKS);
  1728.  
  1729.     StackCreate(&atpTanks->sFree,sizeof(Tank *),MAX_TANKS);
  1730.     StackCreate(&atpTanks->sUsed,sizeof(Tank *),MAX_TANKS);
  1731.  
  1732.     tpTanks = atpTanks->tpTanks;
  1733.     for (nCount =0;nCount<MAX_TANKS;nCount++) {
  1734.         TankCreate(tpTanks,TANK_SCALE,RwDuplicateClump(cpaClumps[nCount%nNames]));
  1735.  
  1736.         StackPush(&atpTanks->sFree,&tpTanks);
  1737.         tpTanks++;
  1738.     };
  1739.  
  1740.     for (nCount = 0;nCount<nNames;nCount++) {
  1741.         RwDestroyClump(cpaClumps[nCount]);
  1742.     };
  1743. }
  1744.  
  1745. /****************************************************************************
  1746.  AllTanksHandle
  1747.  
  1748.  On entry    : AllTanks
  1749.  On exit    :
  1750.  */
  1751.  
  1752. void AllTanksHandle(AllTanks *atpTanks)
  1753. {
  1754.     int nCount;
  1755.     Tank **tppTank;
  1756.     int nAmoTanks;
  1757.  
  1758.     tppTank = ((Tank **)StackData(&atpTanks->sUsed));
  1759.  
  1760.     nAmoTanks = StackElements(&atpTanks->sUsed);
  1761.  
  1762.     if (nGDemoMode) {
  1763.         nCount=0;
  1764.     } else {
  1765.         nCount=1;
  1766.         tppTank++;
  1767.     };
  1768.  
  1769.     for (nCount=1;nCount<nAmoTanks;nCount++) {
  1770.         TankAct((*tppTank));
  1771.         tppTank++;
  1772.     };
  1773. }
  1774.  
  1775. /****************************************************************************
  1776.  Tank Control
  1777.  
  1778.  On entry    : TanksStructure
  1779.                     : Operation
  1780.                     : Param1
  1781.  On exit    :
  1782.  */
  1783.  
  1784. void TankControl(Tank *tpTank,
  1785.                                  int nOperation,
  1786.                  RwReal nParam1)
  1787. {
  1788.     RwV3d vTmp;
  1789.     RwV3d vPos,vDir;
  1790.  
  1791.     RwPushScratchMatrix();
  1792.  
  1793.     switch(nOperation) {
  1794.         case OP_ROT_BASE: {
  1795.             RwCopyMatrix(tpTank->moBase.mpPos,RwScratchMatrix());
  1796.             RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(1),CREAL(0),nParam1,
  1797.                 rwPOSTCONCAT);
  1798.             RwCopyMatrix(RwScratchMatrix(),tpTank->moBase.mpPos);
  1799.             break;
  1800.         };
  1801.         case OP_MOVE: {
  1802.             vTmp.x = nParam1;
  1803.             vTmp.y = CREAL(0.0);
  1804.             vTmp.z = CREAL(0.0);
  1805.  
  1806.             RwTransformVector(&vTmp,tpTank->moBase.mpPos);
  1807.  
  1808.             tpTank->moBase.vPos.x+=vTmp.x;
  1809.             tpTank->moBase.vPos.z+=vTmp.z;
  1810.             break;
  1811.         };
  1812.         case OP_SET_TURRET: {
  1813.             tpTank->nTurretAngle=CREAL(0);
  1814.             /* Fall through !*/
  1815.         };
  1816.         case OP_ROT_TURRET: {
  1817.             tpTank->nTurretAngle+=nParam1;
  1818.  
  1819.             RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(1),CREAL(0),
  1820.                 tpTank->nTurretAngle,rwREPLACE);
  1821.             RwTransformClumpJoint(tpTank->cpTurret,RwScratchMatrix(),rwREPLACE);
  1822.             break;
  1823.         };
  1824.         case OP_MOVE_GUN: {
  1825.             RwRotateMatrix(RwScratchMatrix(),CREAL(0),CREAL(0),CREAL(1),nParam1,
  1826.                 rwREPLACE);
  1827.             RwTransformClumpJoint(tpTank->cpGun,RwScratchMatrix(),rwREPLACE);
  1828.             break;
  1829.         };
  1830.         case OP_FIRE: {
  1831.             TankGunEndDirection(tpTank,&vPos,&vDir);
  1832.  
  1833.             vPos.x = RAdd(vPos.x,gGGround.nXPos);
  1834.             vPos.z = RAdd(vPos.z,gGGround.nZPos);
  1835.             AllBulletsAddBullet(&abGBullets,&vPos,&vDir,tpTank);
  1836.             break;
  1837.         };
  1838.         default: {
  1839.             break;
  1840.         };
  1841.     };
  1842.  
  1843.     RwPopScratchMatrix();
  1844. }
  1845.  
  1846. /****************************************************************************
  1847.  AllTanksAddTank
  1848.  
  1849.  On entry    : TanksStructure
  1850.                     : Tank file name
  1851.                     : Start x pos
  1852.                     : start z pos
  1853.  On exit    : 0 if all ok
  1854.  */
  1855.  
  1856. int AllTanksAddTank(AllTanks *atpTanks,
  1857.                     RwReal nXPos,
  1858.                     RwReal nZPos)
  1859. {
  1860.     MoveObject *mopTank;
  1861.     Tank *tpTank;
  1862.  
  1863.     if (!StackPop(&atpTanks->sFree,&tpTank)) {
  1864.         StackPush(&atpTanks->sUsed,&tpTank);
  1865.  
  1866.  
  1867.         tpTank->moBase.vPos.x = nXPos;
  1868.         tpTank->moBase.vPos.z = nZPos;
  1869.  
  1870.         tpTank->nHit = TANK_HITS;
  1871.  
  1872.         mopTank = &tpTank->moBase;
  1873.  
  1874.         StackPush(&amoGObjects.sDisplay,(void *)&mopTank);
  1875.  
  1876.         return 0;
  1877.     } else {
  1878.         return 1;
  1879.     };
  1880. }
  1881.  
  1882. /****************************************************************************
  1883.  AllTanksRemoveTank
  1884.  
  1885.  On entry    : All Tanks
  1886.                     : Tank to destroy
  1887.  On exit    :
  1888.  */
  1889.  
  1890. void AllTanksRemoveTank(AllTanks *atpTanks,
  1891.                                                 Tank *tpTank)
  1892. {
  1893.     MoveObject *mopTmp;
  1894.  
  1895.   /* Stop warnings */
  1896.  
  1897.   atpTanks = atpTanks;
  1898.  
  1899.     mopTmp = &tpTank->moBase;
  1900.  
  1901.     /* Remove from Display */
  1902.     StackPush(&amoGObjects.sDestroy,&mopTmp);
  1903. }
  1904.  
  1905. /****************************************************************************
  1906.  BulletCreate
  1907.  
  1908.  On entry    : Bullet
  1909.  On exit    :
  1910.  */
  1911.  
  1912. void BulletCreate(Bullet *bpBull,RwReal nScale,RwClump *cpGeo)
  1913. {
  1914.     MoveObjectCreate(&bpBull->moBase,nScale,cpGeo,TYPE_BULLET,(void *)bpBull);
  1915. }
  1916.  
  1917. /****************************************************************************
  1918.  AllBulletsCreate
  1919.  
  1920.  On entry    : all bullets
  1921.  On exit    :
  1922.  */
  1923.  
  1924. void AllBulletsCreate(AllBullets *abpBull)
  1925. {
  1926.     int nCount;
  1927.     Bullet *bpBull;
  1928.     RwClump *cpBullet,*cpClump;
  1929.  
  1930.     cpBullet = RwReadShape("shell.rwx");
  1931.  
  1932.     abpBull->bpBullets = malloc(sizeof(Bullet)*MAX_BULLETS);
  1933.  
  1934.     StackCreate(&abpBull->sUsed,sizeof(Bullet *),MAX_BULLETS);
  1935.     StackCreate(&abpBull->sFree,sizeof(Bullet *),MAX_BULLETS);
  1936.  
  1937.     bpBull = abpBull->bpBullets;
  1938.     for (nCount=0;nCount<MAX_BULLETS;nCount++) {
  1939.         cpClump = RwDuplicateClump(cpBullet);
  1940.         BulletCreate(bpBull,BULLET_SCALE,cpClump);
  1941.  
  1942.         StackPush(&abpBull->sFree,&bpBull);
  1943.         bpBull++;
  1944.     };
  1945.  
  1946.     RwDestroyClump(cpBullet);
  1947. }
  1948.  
  1949. /****************************************************************************
  1950.  AllBulletsAddBullet
  1951.  
  1952.  On entry    : All bullets
  1953.                     : Starting position
  1954.                     : Direction of motion
  1955.  On exit    :
  1956.  */
  1957.  
  1958. int AllBulletsAddBullet(AllBullets *abpBull,
  1959.                                                 RwV3d *vpPos,
  1960.                                                 RwV3d *vpDir,
  1961.                                                 Tank *tpTank)
  1962. {
  1963.     Bullet *bpBull;
  1964.     MoveObject *mopBullet;
  1965.     RwReal naEle[4][4];
  1966.  
  1967.     if (!StackPop(&abpBull->sFree,&bpBull)) {
  1968.         StackPush(&abpBull->sUsed,&bpBull);
  1969.  
  1970.         bpBull->moBase.vPos = (*vpPos);
  1971.         bpBull->moBase.vVel = (*vpDir);
  1972.  
  1973.         bpBull->tpTank = tpTank;
  1974.  
  1975.         bpBull->nLife = BULLET_LIFE;
  1976.  
  1977.         /* Make the bullets clump face in the correct direction */
  1978.  
  1979.         RwIdentityMatrix(bpBull->moBase.mpPos);
  1980.         RwGetMatrixElements(bpBull->moBase.mpPos,naEle);
  1981.  
  1982.         *(RwV3d *)naEle[0] = (*vpDir);
  1983.         RwCrossProduct((RwV3d *)naEle[0],(RwV3d *)naEle[1],(RwV3d *)naEle[2]);
  1984.  
  1985.         RwSetMatrixElements(bpBull->moBase.mpPos,naEle);
  1986.         RwOrthoNormalizeMatrix(bpBull->moBase.mpPos,bpBull->moBase.mpPos);
  1987.  
  1988.         /* Find the Bullets speed */
  1989.  
  1990.         RwScaleVector(vpDir,BULLET_SPEED,vpDir);
  1991.         bpBull->moBase.vVel = (*vpDir);
  1992.  
  1993.         /* Place on the display stack */
  1994.  
  1995.         mopBullet = &bpBull->moBase;
  1996.         StackPush(&amoGObjects.sDisplay,(void *)&mopBullet);
  1997.         return 0;
  1998.     } else {
  1999.         return 1;
  2000.     };
  2001. }
  2002.  
  2003. /****************************************************************************
  2004.  AllBulletsRemoveBullet
  2005.  
  2006.  On entry    : AllBullets
  2007.                     : Bullet to remove
  2008.  On exit     :
  2009.  */
  2010.  
  2011. void AllBulletsRemoveBullet(AllBullets *abpBull,
  2012.                                                         Bullet *bpBull)
  2013. {
  2014.     MoveObject *mopTmp = &bpBull->moBase;
  2015.  
  2016.   /* Stop warnings */
  2017.  
  2018.   abpBull = abpBull;
  2019.  
  2020.     /* Remove from display */
  2021.  
  2022.     StackPush(&amoGObjects.sDestroy,&mopTmp);
  2023. }
  2024.  
  2025. /****************************************************************************
  2026.  AllBulletsHandle
  2027.  
  2028.  On entry    : All Bullets
  2029.  On exit    :
  2030.  */
  2031.  
  2032. void AllBulletsHandle(AllBullets *abpBull)
  2033. {
  2034.     Bullet **bppBull;
  2035.     Bullet *bpBull;
  2036.     int nAmoBullets;
  2037.     int nCount;
  2038.  
  2039.     bppBull = (Bullet **)StackData(&abpBull->sUsed);
  2040.     nAmoBullets = StackElements(&abpBull->sUsed);
  2041.  
  2042.     for (nCount=0;nCount<nAmoBullets;nCount++) {
  2043.         bpBull = (*bppBull);
  2044.         /* Handle it */
  2045.  
  2046.         bpBull->nLife--;
  2047.         if ((bpBull->nLife<0)||
  2048.            (bpBull->moBase.vPos.x<CREAL(0))||
  2049.              (bpBull->moBase.vPos.z<CREAL(0))||
  2050.              (bpBull->moBase.vPos.x>gGGround.nWorldWidth)||
  2051.              (bpBull->moBase.vPos.z>gGGround.nWorldHeight)) {
  2052.             /* Destroy the bullet */
  2053.             AllBulletsRemoveBullet(abpBull,bpBull);
  2054.         } else {
  2055.             RwAddVector(&bpBull->moBase.vPos,&bpBull->moBase.vVel,
  2056.                 &bpBull->moBase.vPos);
  2057.         };
  2058.  
  2059.         bppBull++;
  2060.     };
  2061.  
  2062.     AllMoveObjClean(&amoGObjects);
  2063. }
  2064.  
  2065. /****************************************************************************
  2066.  GroundGetTextures
  2067.  
  2068.  On entry    : Ground structure
  2069.  On exit    :
  2070.  */
  2071.  
  2072. void GroundGetTextures(Ground *gpGrou)
  2073. {
  2074.     char saTextureFiles[][14]={
  2075.         "rough",
  2076.         "groad1",
  2077.         "groad2",
  2078.         "groad3"};
  2079.     int nAmoNames=4;
  2080.     int nCount;
  2081.  
  2082.     gpGrou->nAmoTextures = nAmoNames;
  2083.  
  2084.     for (nCount=0;nCount<gpGrou->nAmoTextures;nCount++) {
  2085.         gpGrou->tpaTex[nCount] = RwReadNamedTexture(saTextureFiles[nCount]);
  2086.     };
  2087. }
  2088.  
  2089. /****************************************************************************
  2090.  GroundGetThings
  2091.  
  2092.  ( It is assumed that all 'things' are normalised to 1.0 size )
  2093.  
  2094.  On entry : Ground structure
  2095.  On exit    :
  2096.  */
  2097.  
  2098. void GroundGetThings(Ground *gpGrou)
  2099. {
  2100.     char saThingFiles[][14]={
  2101.         "tree.rwx",
  2102.         "tankhous.rwx",
  2103.         "tankhou2.rwx",
  2104.         "tree2.rwx"};
  2105.     RwReal naThingScale[]={
  2106.             CREAL(0.2),
  2107.             CREAL(0.3),
  2108.             CREAL(0.3),
  2109.             CREAL(0.25)};
  2110.     int nAmoThings=4;
  2111.     int nCount;
  2112.  
  2113.     gpGrou->nAmoThings = nAmoThings;
  2114.  
  2115.     for (nCount=0;nCount<nAmoThings;nCount++) {
  2116.         gpGrou->cpaGeo[nCount] = RwReadShape(saThingFiles[nCount]);
  2117.  
  2118.         gpGrou->naScale[nCount] = naThingScale[nCount];
  2119.     };
  2120. }
  2121.  
  2122. /****************************************************************************
  2123.  GroundCreateTiles
  2124.  
  2125.  On entry    : Ground Structure
  2126.                     : Ground texture map
  2127.                     : Ground width
  2128.                     : Ground height
  2129.                     : Ground split
  2130.  */
  2131.  
  2132. void GroundCreateTiles(Ground *gpGrou,
  2133.                                              char *cpGroundMap,
  2134.                                              char *cpThingMap,
  2135.                                              int nWidth,
  2136.                                              int nHeight,
  2137.                                              int nSplit)
  2138. {
  2139.     RwClump *cpGeo;
  2140.     int nCount,nCount2;
  2141.     GroundEle *gepCur;
  2142.     int nX,nY;
  2143.     int nTex;
  2144.     char *cpCur;
  2145.     char *cpThing;
  2146.     StillObject *sopThing;
  2147.  
  2148.     gpGrou->pGround = (GroundEle *)
  2149.         malloc(sizeof(GroundEle)*nWidth*nHeight*nSplit*nSplit);
  2150.  
  2151.     gepCur = gpGrou->pGround;
  2152.     cpCur = cpGroundMap;
  2153.     cpThing = cpThingMap;
  2154.  
  2155.     gpGrou->nWidth = nWidth;
  2156.     gpGrou->nHeight = nHeight;
  2157.     gpGrou->nSplit = nSplit;
  2158.     gpGrou->nTexStep = RDiv(CREAL(1),INT2REAL(nSplit));
  2159.  
  2160.     for (nY=0;nY<nHeight;nY++) {
  2161.         for (nCount=0;nCount<nSplit;nCount++) {
  2162.             for (nX = 0; nX<nWidth;nX++) {
  2163.                 for (nCount2=0;nCount2<nSplit;nCount2++) {
  2164.                     nTex = (cpCur[nX])-'a';
  2165.  
  2166.                     gepCur->tpTex = gpGrou->tpaTex[nTex];
  2167.                     gepCur->uvPos.u = RDiv(INT2REAL(nCount2),INT2REAL(nSplit));
  2168.                     gepCur->uvPos.v = RDiv(INT2REAL(nCount),INT2REAL(nSplit));
  2169.  
  2170.                     /* Mark as no object on this square */
  2171.  
  2172.                     if ((*cpThing)>' ') {
  2173.                         sopThing = (StillObject *)malloc(sizeof(StillObject));
  2174.                         gepCur->sopObj = sopThing;
  2175.  
  2176.                         cpGeo = RwDuplicateClump(gpGrou->cpaGeo[(*cpThing)-'a']);
  2177.                         StillObjectCreate(sopThing,gpGrou->naScale[(*cpThing)-'a'],cpGeo);
  2178.                          sopThing->vPos.x += RDiv(gpGrou->nStepSize,CREAL(2));
  2179.                         sopThing->vPos.z += RDiv(gpGrou->nStepSize,CREAL(2));
  2180.                     } else {
  2181.                         gepCur->sopObj= NULL;
  2182.                     };
  2183.  
  2184.                     cpThing++;
  2185.                     gepCur++;
  2186.                 };
  2187.             };
  2188.         };
  2189.         cpCur+=gpGrou->nWidth;
  2190.     };
  2191. }
  2192.  
  2193. /****************************************************************************
  2194.  AddGroundPoly
  2195.  
  2196.  On entry    : Polygon
  2197.                     : pointer to polygon data structure
  2198.  On exit    :
  2199.  */
  2200.  
  2201. RwPolygon3d *AddGroundPoly(RwPolygon3d *pPoly,void *pData);
  2202.  
  2203. RwPolygon3d *AddGroundPoly(RwPolygon3d *pPoly,void *pData)
  2204. {
  2205.     int nX;
  2206.     int nZ;
  2207.  
  2208.     Ground *gpGrou = (Ground *)pData;
  2209.     RwSetPolygonTextureModes(pPoly,rwFORESHORTEN);
  2210.  
  2211.     nZ = RwGetPolygonTag(pPoly)%(gpGrou->nDispWidth);
  2212.  
  2213.     nX = RwGetPolygonTag(pPoly)/(gpGrou->nDispWidth);
  2214.  
  2215.     gpGrou->paPolyData[nX+(nZ*gpGrou->nDispWidth)] = pPoly;
  2216.     return NULL;
  2217. }
  2218.  
  2219.  
  2220.  
  2221. /****************************************************************************
  2222.  GroundCreateClump
  2223.  
  2224.  On entry    : Ground structure
  2225.                     : Display width
  2226.                     : Display height
  2227.                     : Total size of the clump in world coordinates
  2228.  On exit    :
  2229.  */
  2230.  
  2231. void GroundCreateClump(Ground *gpGrou,
  2232.                                              int nDispWidth,
  2233.                                              int nDispHeight,
  2234.                        RwReal nSize)
  2235. {
  2236.     RwClump *cpGeo;
  2237.     int nX,nZ;
  2238.     RwReal nPosX,nPosZ;
  2239.     int nNum;
  2240.     RwMatrix4d *mpTmp;
  2241.  
  2242.     gpGrou->nDispWidth = nDispWidth;
  2243.     gpGrou->nDispHeight = nDispHeight;
  2244.     gpGrou->nSize = nSize;
  2245.     gpGrou->nStepSize = RDiv(nSize,INT2REAL(nDispWidth));
  2246.  
  2247.     RwModelBegin();
  2248.     RwClumpBegin();
  2249.   RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
  2250.   RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
  2251.   RwSetSurfaceLightSampling(rwFACET);
  2252.   RwSetSurfaceGeometrySampling(rwSOLID);
  2253.  
  2254.     RwSetHints(rwCONTAINER);
  2255.  
  2256.     nPosX = -RDiv(nSize,CREAL(2.0));
  2257.     for (nX = 0;nX <gpGrou->nDispWidth;nX++) {
  2258.         nPosZ = -RDiv(nSize,CREAL(2.0));
  2259.         for (nZ = 0;nZ<gpGrou->nDispHeight;nZ++) {
  2260.  
  2261.             RwVertex(nPosX,CREAL(0.0),nPosZ);
  2262.             RwVertex(nPosX,CREAL(0.0),RAdd(nPosZ,gpGrou->nStepSize));
  2263.             RwVertex(RAdd(nPosX,gpGrou->nStepSize),
  2264.                           CREAL(0.0),RAdd(nPosZ,gpGrou->nStepSize));
  2265.             RwVertex(RAdd(nPosX,gpGrou->nStepSize),CREAL(0.0),nPosZ);
  2266.  
  2267.             nPosZ = RAdd(nPosZ,gpGrou->nStepSize);
  2268.         };
  2269.         nPosX = RAdd(nPosX,gpGrou->nStepSize);
  2270.     };
  2271.  
  2272.     /* Give it some depth ! */
  2273.  
  2274.     RwVertex(CREAL(0.0),CREAL(2.0),CREAL(0.0));
  2275.  
  2276.     for (nNum=0;nNum<(gpGrou->nDispWidth*gpGrou->nDispHeight);nNum++) {
  2277.         RwQuadExt((nNum<<2)+1,(nNum<<2)+2,(nNum<<2)+3,(nNum<<2)+4,nNum);
  2278.     };
  2279.  
  2280.     RwClumpEnd(&cpGeo);
  2281.     RwModelEnd();
  2282.  
  2283.     RwIdentityMatrix(mpTmp = RwCreateMatrix());
  2284.     RwTransformClump(cpGeo,mpTmp,rwREPLACE);
  2285.     RwTransformClumpJoint(cpGeo,mpTmp,rwREPLACE);
  2286.     RwDestroyMatrix(mpTmp);
  2287.  
  2288.     gpGrou->cpGeo = cpGeo;
  2289.  
  2290.     gpGrou->paPolyData = (RwPolygon3d **)malloc(sizeof(RwPolygon3d *)*
  2291.                                                             gpGrou->nDispWidth*
  2292.                                                             gpGrou->nDispHeight);
  2293.  
  2294.     RwForAllPolygonsInClumpPointer(cpGeo,AddGroundPoly,
  2295.                     (void*)gpGrou);
  2296. }
  2297.  
  2298. /****************************************************************************
  2299.  GroundCreate
  2300.  
  2301.  On entry    : Ground Structure
  2302.                     : Ground map array
  2303.                     : Ground texture array
  2304.                     : Width
  2305.                     : Height
  2306.                     : Split (ie the amount of segments a texture is split to
  2307.  On exit    :
  2308.  */
  2309.  
  2310. void GroundCreate(Ground *gpGround)
  2311. {
  2312.     char *cpThingMap;
  2313.     int nSize;
  2314.     int nCount;
  2315.  
  2316.     nSize = GROUND_WIDTH*GROUND_HEIGHT*GROUND_SPLIT*GROUND_SPLIT;
  2317.  
  2318.     cpThingMap = (char *)malloc(nSize);
  2319.     memset(cpThingMap,' ',nSize);
  2320.  
  2321.     for (nCount=0;nCount<40;nCount++) {
  2322.         cpThingMap[rand()&(nSize-1)] = 'a';
  2323.     };
  2324.  
  2325.     for (nCount=0;nCount<20;nCount++) {
  2326.         cpThingMap[rand()&(nSize-1)] = 'b';
  2327.     };
  2328.  
  2329.     for (nCount=0;nCount<20;nCount++) {
  2330.         cpThingMap[rand()&(nSize-1)] = 'c';
  2331.     };
  2332.  
  2333.     for (nCount=0;nCount<20;nCount++) {
  2334.         cpThingMap[rand()&(nSize-1)] = 'd';
  2335.     };
  2336.  
  2337.     RwIdentityMatrix(gpGround->mpPos=RwCreateMatrix());
  2338.  
  2339.     GroundGetTextures(gpGround);
  2340.     GroundGetThings(gpGround);
  2341.     GroundCreateClump(gpGround,GROUND_DISP_WIDTH,GROUND_DISP_HEIGHT,
  2342.                                         GROUND_SIZE);
  2343.     GroundCreateTiles(gpGround,sGGroundMap,cpThingMap,GROUND_WIDTH,GROUND_HEIGHT,GROUND_SPLIT);
  2344.  
  2345.     free(cpThingMap);
  2346.  
  2347.     gpGround->nWorldWidth =
  2348.         RMul(INT2REAL(gpGround->nWidth*gpGround->nSplit),gpGround->nStepSize);
  2349.     gpGround->nWorldHeight =
  2350.         RMul(INT2REAL(gpGround->nHeight*gpGround->nSplit),gpGround->nStepSize);
  2351. }
  2352.  
  2353. /****************************************************************************
  2354.  GroundDisplay
  2355.  
  2356.  On entry    : Ground structure
  2357.                     : Xcoord
  2358.                     : Ycoord
  2359.  On exit    :
  2360.  */
  2361.  
  2362. void GroundDisplay(Ground *gpGrou,AllStillObj *asopObj,RwReal nX, RwReal nZ)
  2363. {
  2364.     RwReal nXOff;
  2365.     RwReal nZOff;
  2366.     int nMapX;
  2367.     int nMapZ;
  2368.     int nCount,nCount2;
  2369.     RwPolygon3d **pPolys;
  2370.     GroundEle *gepCur;
  2371.     int nStride;
  2372.     RwUV uvaPos[4];
  2373.     RwReal nStepSize;
  2374.     StillObject **soppDisp;
  2375.     int nDisp;
  2376.     StillObject **soppToDisp;
  2377.     int nToDisp;
  2378.     RwReal nXStart;
  2379.     RwReal nZStart;
  2380.     RwReal nXPos;
  2381.     RwReal nZPos;
  2382.     Stack sTmp;
  2383.  
  2384.     if (nX<RDiv(gpGrou->nSize,CREAL(2)) ) {
  2385.         nX = RDiv(gpGrou->nSize,CREAL(2));
  2386.     };
  2387.     if (nZ<RDiv(gpGrou->nSize,CREAL(2)) ) {
  2388.         nZ = RDiv(gpGrou->nSize,CREAL(2));
  2389.     };
  2390.  
  2391.     if (nX> gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2)) ) {
  2392.         nX = gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2));
  2393.     };
  2394.  
  2395.     if (nZ> gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2)) ) {
  2396.         nZ = gpGrou->nWorldWidth-RDiv(gpGrou->nSize,CREAL(2));
  2397.     };
  2398.  
  2399.     gpGrou->nXPos = nX;
  2400.     gpGrou->nZPos = nZ;
  2401.  
  2402.     nStepSize = (gpGrou->nStepSize);
  2403.  
  2404.     nXOff = RDiv(RSub(nX,RDiv(gpGrou->nSize,CREAL(2))),nStepSize);
  2405.     nZOff = RDiv(RSub(nZ,RDiv(gpGrou->nSize,CREAL(2))),nStepSize);
  2406.  
  2407.     nMapX = REAL2INT(nXOff);
  2408.     nMapZ = REAL2INT(nZOff);
  2409.  
  2410.     nXOff = RMul(RSub(nXOff,INT2REAL(nMapX)),nStepSize);
  2411.     nZOff = RMul(RSub(nZOff,INT2REAL(nMapZ)),nStepSize);
  2412.  
  2413.     nXStart = -nXOff;
  2414.     nZStart = -nZOff;
  2415.  
  2416.     RwTranslateMatrix(gpGrou->mpPos, nXStart,CREAL(0),nZStart,rwREPLACE);
  2417.  
  2418.     RwTransformClump(gpGrou->cpGeo,gpGrou->mpPos,rwREPLACE);
  2419.  
  2420.      nXStart = RSub(nXStart,RDiv(gpGrou->nSize,CREAL(2)) );
  2421.     nZStart = RSub(nZStart,RDiv(gpGrou->nSize,CREAL(2)) );
  2422.  
  2423.     nStride = gpGrou->nWidth*gpGrou->nSplit;
  2424.  
  2425.     pPolys = gpGrou->paPolyData;
  2426.     gepCur = gpGrou->pGround + (nMapX+(nMapZ*nStride));
  2427.  
  2428.     StackClear(&asopObj->sStillToDisplay);
  2429.  
  2430.     RwPushScratchMatrix();
  2431.     RwIdentityMatrix(RwScratchMatrix());
  2432.  
  2433.     nZPos = nZStart;
  2434.     for (nCount2=0;nCount2<gpGrou->nDispHeight;nCount2++) {
  2435.         nXPos = nXStart;
  2436.         for (nCount=0;nCount<gpGrou->nDispWidth;nCount++) {
  2437.  
  2438.             RwSetPolygonTexture((*pPolys),gepCur->tpTex);
  2439.             uvaPos[0] = gepCur->uvPos;
  2440.             uvaPos[1] = gepCur->uvPos;
  2441.             uvaPos[1].v= RAdd(uvaPos[1].v,gpGrou->nTexStep);
  2442.             uvaPos[2] = uvaPos[1];
  2443.             uvaPos[2].u = RAdd(uvaPos[2].u,gpGrou->nTexStep);
  2444.             uvaPos[3] = uvaPos[2];
  2445.             uvaPos[3].v= RSub(uvaPos[3].v,gpGrou->nTexStep);
  2446.  
  2447.             RwSetPolygonUV((*pPolys),uvaPos);
  2448.  
  2449.             if (gepCur->sopObj) {
  2450.                 RwTranslateMatrix(RwScratchMatrix(),
  2451.                     RAdd(nXPos,gepCur->sopObj->vPos.x),
  2452.                     gepCur->sopObj->vPos.y,
  2453.                     RAdd(nZPos,gepCur->sopObj->vPos.z),
  2454.                     rwREPLACE);
  2455.                 RwTransformClump(gepCur->sopObj->cpGeo, RwScratchMatrix(), rwREPLACE);
  2456.  
  2457.                 StackPush(&asopObj->sStillToDisplay,&gepCur->sopObj);
  2458.             };
  2459.  
  2460.             nXPos += gpGrou->nStepSize;
  2461.             pPolys++;
  2462.             gepCur++;
  2463.         };
  2464.         nZPos += gpGrou->nStepSize;
  2465.         gepCur+=nStride-gpGrou->nDispWidth;
  2466.     };
  2467.  
  2468.     RwPopScratchMatrix();
  2469.  
  2470.     /* Do the adding and removing of clumps to the scene */
  2471.  
  2472.     /* Sort the stacks for later comparison */
  2473.  
  2474.     qsort(StackData(&asopObj->sStillToDisplay),
  2475.         StackElements(&asopObj->sStillToDisplay),sizeof(StillObject **),_AllMoveObjDisplay);
  2476.  
  2477.     /* Find what needs to be added and removed from scene */
  2478.  
  2479.     soppToDisp = (StillObject **) StackData(&asopObj->sStillToDisplay);
  2480.     nToDisp = StackElements(&asopObj->sStillToDisplay);
  2481.  
  2482.     soppDisp = (StillObject **)StackData(&asopObj->sStillDisplayed);
  2483.     nDisp = StackElements(&asopObj->sStillDisplayed);
  2484.  
  2485.     while (nToDisp&&nDisp) {
  2486.         if ((*soppDisp)==(*soppToDisp)) {
  2487.             soppDisp++;
  2488.             soppToDisp++;
  2489.             nToDisp--;
  2490.             nDisp--;
  2491.         } else {
  2492.             if ((*soppDisp)<(*soppToDisp)) {
  2493.                 RwRemoveClumpFromScene((*soppDisp)->cpGeo);
  2494.  
  2495.                 nDisp--;
  2496.                 soppDisp++;
  2497.             } else {
  2498.                 RwAddClumpToScene(Scene,(*soppToDisp)->cpGeo);
  2499.  
  2500.                 nToDisp--;
  2501.                 soppToDisp++;
  2502.             };
  2503.         };
  2504.     };
  2505.  
  2506.     if (nDisp) {
  2507.         for (;nDisp;nDisp--) {
  2508.             RwRemoveClumpFromScene((*soppDisp)->cpGeo);
  2509.             soppDisp++;
  2510.         };
  2511.     };
  2512.  
  2513.     if (nToDisp) {
  2514.         for (;nToDisp;nToDisp--) {
  2515.             RwAddClumpToScene(Scene,(*soppToDisp)->cpGeo);
  2516.             soppToDisp++;
  2517.         };
  2518.     };
  2519.  
  2520.     /* Switch stacks - to remove a qsort!*/
  2521.  
  2522.     sTmp = asopObj->sStillDisplayed;
  2523.     asopObj->sStillDisplayed = asopObj->sStillToDisplay;
  2524.     asopObj->sStillToDisplay = sTmp;
  2525. }
  2526.  
  2527. /****************************************************************************
  2528.  StackCreate
  2529.  
  2530.  On entry    : Pointer to stack structure
  2531.  On exit    : 0 if all went to plan
  2532.  */
  2533.  
  2534. int StackCreate(Stack *spStack,int nEleSize,int nAmoEle)
  2535. {
  2536.     if (!(spStack->pData = (char *) malloc (nEleSize*nAmoEle))) {
  2537.         return 1;
  2538.     };
  2539.     spStack->nCurElement = 0;
  2540.     spStack->pCurPtr = spStack->pData;
  2541.     spStack->nAmoElements = nAmoEle;
  2542.     spStack->nElementSize = nEleSize;
  2543.  
  2544.     return 0;
  2545. }
  2546.  
  2547. /****************************************************************************
  2548.  StackClear
  2549.  
  2550.  emptys the stack
  2551.  
  2552.  On entry    : Stack to clear
  2553.  */
  2554.  
  2555. void StackClear(Stack *spStack)
  2556. {
  2557.     spStack->nCurElement = 0;
  2558.     spStack->pCurPtr = spStack->pData;
  2559. }
  2560.  
  2561. /****************************************************************************
  2562.  StackData
  2563.  
  2564.  On entry    : Stack
  2565.  On exit    : Stacks contents as an array bottom element first
  2566.  */
  2567.  
  2568. void *StackData(Stack *spStack)
  2569. {
  2570.     return spStack->pData;
  2571. }
  2572.  
  2573.  
  2574. /****************************************************************************
  2575.  StackElements
  2576.  
  2577.  On entry    : Stack
  2578.  On exit    : Amount of entries in the stack
  2579.  */
  2580.  
  2581. int StackElements(Stack *spStack)
  2582. {
  2583.     return spStack->nCurElement;
  2584. }
  2585.  
  2586. /****************************************************************************
  2587.  StackFront
  2588.  
  2589.  On entry    : Stack
  2590.                      : Element too stick on the bottom of the stack
  2591.  On exit    : Pointer to entry on stack,NULL for fail
  2592.  */
  2593.  
  2594. void *StackFront(Stack *spStack,void *pData)
  2595. {
  2596.     char *pTmp;
  2597.     int nCount;
  2598.  
  2599.     if (spStack->nCurElement==spStack->nAmoElements) {
  2600.         return NULL;
  2601.     } else {
  2602.         pTmp = spStack->pCurPtr;
  2603.  
  2604.         for (nCount=0;nCount<spStack->nCurElement;nCount++) {
  2605.             memcpy(pTmp,pTmp-spStack->nElementSize,spStack->nElementSize);
  2606.             pTmp -= spStack->nElementSize;
  2607.         };
  2608.  
  2609.         memcpy(spStack->pData,pData,spStack->nElementSize);
  2610.  
  2611.         spStack->pCurPtr+=spStack->nElementSize;
  2612.         spStack->nCurElement++;
  2613.  
  2614.         return spStack->pData;
  2615.     };
  2616. }
  2617.  
  2618. /****************************************************************************
  2619.  StackDestroy
  2620.  
  2621.  On entry    : Stack
  2622.  On exit    : 0 if all went to plan
  2623.  */
  2624.  
  2625. int StackDestroy(Stack *spStack)
  2626. {
  2627.     free(spStack->pData);
  2628.  
  2629.     return 0;
  2630. }
  2631.  
  2632. /****************************************************************************
  2633.  StackPush
  2634.  
  2635.  On entry    : Stack
  2636.                     : Pointer to element to push
  2637.  On exit    : Pointer to Saved object if all ok else NULL
  2638.  */
  2639.  
  2640. void *StackPush(Stack *spStack,void *pData)
  2641. {
  2642.     void *pSave;
  2643.  
  2644.     if (spStack->nCurElement==spStack->nAmoElements) {
  2645.         return NULL;
  2646.     } else {
  2647.         pSave = spStack->pCurPtr;
  2648.         memcpy(pSave,pData,spStack->nElementSize);
  2649.  
  2650.         spStack->pCurPtr+=spStack->nElementSize;
  2651.         spStack->nCurElement++;
  2652.  
  2653.         return pSave;
  2654.     };
  2655. }
  2656.  
  2657. /****************************************************************************
  2658.  StackPop
  2659.  
  2660.  On entry    : Stack
  2661.  On exit    : 0 if all ok
  2662.  */
  2663.  
  2664. int StackPop(Stack *spStack,void *pData)
  2665. {
  2666.     if (!spStack->nCurElement) {
  2667.         return 1;
  2668.     } else {
  2669.         spStack->nCurElement--;
  2670.         spStack->pCurPtr-=spStack->nElementSize;
  2671.  
  2672.         memcpy(pData,spStack->pCurPtr,spStack->nElementSize);
  2673.         return 0;
  2674.     };
  2675. }
  2676.  
  2677. /****************************************************************************
  2678.  StackTop
  2679.  
  2680.  On entry    : Stack
  2681.  On exit    : 0 if all ok
  2682.  */
  2683.  
  2684. int StackTop(Stack *spStack,void *pData)
  2685. {
  2686.     if (!spStack->nCurElement) {
  2687.         return 1;
  2688.     } else {
  2689.         memcpy(pData,
  2690.             spStack->pCurPtr-spStack->nElementSize,spStack->nElementSize);
  2691.         return 0;
  2692.     };
  2693. }
  2694.  
  2695. /****************************************************************************
  2696.  StackForAll
  2697.  
  2698.  Goes from top of stack to bottom
  2699.  
  2700.  On entry    : Stack
  2701.                     : Function to be called
  2702.                     : Pointer to user data
  2703.  */
  2704.  
  2705. void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
  2706.                                     void *pUser)
  2707. {
  2708.     char *pData;
  2709.     int nCount;
  2710.  
  2711.     pData = spStack->pCurPtr-spStack->nElementSize;
  2712.     for (nCount=spStack->nCurElement;nCount--;nCount) {
  2713.         (*Func)(pData,pUser);
  2714.         pData-=spStack->nElementSize;
  2715.     };
  2716. }
  2717.  
  2718. /****************************************************************************
  2719.  StackRemove
  2720.  
  2721.  Removes an entry from the stack
  2722.  
  2723.  On entry    : Stack
  2724.                     : Element to remove
  2725.  On exit    : 0 if all ok
  2726.  */
  2727.  
  2728. int StackRemove(Stack *spStack,void *pEle)
  2729. {
  2730.     char *pData=(char *)pEle;
  2731.  
  2732.     while (pData!=(spStack->pCurPtr-spStack->nElementSize)) {
  2733.         memcpy(pData,pData+spStack->nElementSize,spStack->nElementSize);
  2734.         pData+=spStack->nElementSize;
  2735.     };
  2736.  
  2737.     spStack->pCurPtr-=spStack->nElementSize;
  2738.     spStack->nCurElement--;
  2739.  
  2740.     return 0;
  2741. }
  2742.  
  2743. /****************************************************************************
  2744.  StackFind
  2745.  
  2746.  On entry    : Stack
  2747.                     : Data entry to find
  2748.  On exit    : Pointer to element (NULL if not found)
  2749.  */
  2750.  
  2751. void *StackFind(Stack *spStack,void *pEle)
  2752. {
  2753.     int nCount,nCount2;
  2754.     char *pData,*pData2 = (char *)pEle;
  2755.  
  2756.     pData = spStack->pData;
  2757.  
  2758.     for (nCount=0;nCount<spStack->nCurElement;nCount++) {
  2759.         for (nCount2=0;nCount2<spStack->nElementSize;nCount2++) {
  2760.             if (pData[nCount2] != pData2[nCount2]) {
  2761.                 break;
  2762.             };
  2763.         };
  2764.  
  2765.         if (nCount2>=spStack->nElementSize) {
  2766.             return pData;
  2767.         };
  2768.  
  2769.         pData+=spStack->nElementSize;
  2770.     };
  2771.  
  2772.     return NULL;
  2773. }
  2774.  
  2775. /***************************************************************************
  2776.  RandomVec - create a random vector
  2777.  
  2778.  On entry    : Random vector to create
  2779.  On exit    :
  2780.  */
  2781.  
  2782. static void RandomVec(RwV3d *vec)
  2783. {
  2784.   vec->x = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  2785.   vec->y = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  2786.   vec->z = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  2787. }
  2788.  
  2789. /****************************************************************************
  2790.  DosShiftCtrl
  2791.  
  2792.  On entry    :
  2793.  On exit    : Bit         Meaning
  2794.                         0                Right Shift
  2795.                         1                Left Shift
  2796.                         2                Ctrl
  2797.                         3                Alt
  2798.                         4       Scroll Lock
  2799.                         5                Num Lock
  2800.                         6             Caps Lock
  2801.                         7                Insert on
  2802.  */
  2803.  
  2804. int DosShiftCtrl(void)
  2805. {
  2806.     union REGPACK rp;
  2807.  
  2808.     memset(&rp,0,sizeof(rp));
  2809.  
  2810.     rp.h.ah=0x02;
  2811.     intr(0x16,&rp);
  2812.  
  2813.     return ((int)rp.h.al);
  2814. }
  2815.  
  2816.  
  2817. /****************************************************************************
  2818.  DosPrintString
  2819.  
  2820.  On entry     : xcord
  2821.                         : ycord
  2822.                         : string
  2823.                         : colour
  2824.  On exit        :
  2825.  */
  2826.  
  2827. void DosPrintString(int nX,int nY,char *sString,int nCol)
  2828. {
  2829.     RwPrintChar pcPrint;
  2830.  
  2831.     pcPrint.x = nX;
  2832.     pcPrint.y = nY;
  2833.     pcPrint.color = nCol;
  2834.  
  2835.     for (;(*sString);sString++)  {
  2836.         pcPrint.c = (*sString);
  2837.     RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
  2838.         pcPrint.x+=8;
  2839.     };
  2840. }
  2841.  
  2842.  
  2843. /****************************************************************************
  2844.  DosGetKey
  2845.  
  2846.  Get the ascii key code of any depressed key. (Do not wait for a key press.
  2847.  -> return 0 if no key is pressed)
  2848.  
  2849.  On entry    :
  2850.  On exit     : Key pressed in ascii (or 0 if no key pressed)
  2851.  */
  2852.  
  2853. int DosGetKey(void)
  2854. {
  2855.     union REGPACK rp;
  2856.  
  2857.     memset(&rp,0,sizeof(rp));
  2858.     rp.h.ah = 0x06;
  2859.     rp.h.dl = 0xff;
  2860.  
  2861.     intr(0x21,&rp);
  2862.  
  2863.     if (!(rp.w.flags & 0x40 )) {       /* Check Z flag */
  2864.         /* Got key */
  2865.  
  2866.         if (rp.h.al) {
  2867.             return ((int)rp.h.al);
  2868.         };
  2869.  
  2870.         memset(&rp,0,sizeof(rp));
  2871.         rp.h.ah = 0x06;
  2872.         rp.h.dl = 0xff;
  2873.         intr(0x21,&rp);
  2874.  
  2875.         if (!(rp.w.flags & 0x40)) {
  2876.             return ((int)rp.h.al);
  2877.         };
  2878.  
  2879.         return (rp.h.al|0x80);
  2880.     };
  2881.  
  2882.     return 0;
  2883. }
  2884.  
  2885.  
  2886. /**********************************************************************/
  2887.  
  2888. /*
  2889.  * This function initializes the 3D (i.e. RenderWare) components of the
  2890.  * application. This function opens the RenderWare library, creates a
  2891.  * camera, a scene, a light and a matrix for spinning. A user-draw may
  2892.  * also be created if USERDRAW_LABELS is defined.
  2893.  */
  2894. static BOOL
  2895. Init3D(char *sFilename)
  2896. {
  2897.     char     windowText[128];
  2898.     char     version[30];
  2899.     char     buffer[128];
  2900.     int      param;
  2901.     int i;
  2902.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  2903.     long nError;
  2904.     RwRaster *rpRaster;
  2905.  
  2906.     /*
  2907.     * Attempt to open (and initialize) the RenderWare library.
  2908.     */
  2909.     if (!RwOpen("DOSMOUSE", &nError))
  2910.     {
  2911.         printf("Unable to access renderware!!\n");
  2912.         switch (nError) {
  2913.             case E_RW_DOS_MODE_UNAVAILABLE: {
  2914.                printf("The installed VESA card is unable to switch to the resolution");
  2915.                 printf(" requested.\n");
  2916.                 printf("Either install a different video adapter or use a ");
  2917.                 printf("supported video mode.");
  2918.                 break;
  2919.             };
  2920.             case E_RW_DOS_NO_VESA_BIOS: {
  2921.                 printf("A VESA bios is unavailable on this machine.\n");
  2922.                 printf("Either use a VESA compatible Video Adapter or install a ");
  2923.                 printf("VESA bios emulation TSR.\n");
  2924.                 break;
  2925.             };
  2926.             case E_RW_DOS_INCOMPATIBLE_BIOS: {
  2927.                 printf("The VESA bios on this machine is not of high enough version ");
  2928.                 printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
  2929.                 printf(" higher VESA bios or TSR.\n");
  2930.                 break;
  2931.             };
  2932.             case E_RW_DOS_NO_MOUSE: {
  2933.                 printf("No Microsoft compatible mouse driver present.\n");
  2934.                 printf("Install a microsoft compatible mouse driver and try again.\n");
  2935.                 break;
  2936.             };
  2937.             default: {
  2938.                 printf("Unknown Error !!!!!!!!!!!!!!!\n");
  2939.                 break;
  2940.             };
  2941.         };
  2942.         return FALSE;
  2943.     }
  2944.  
  2945.     /* Set up character set */
  2946.  
  2947.   RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
  2948.   RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
  2949.   nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  2950.  
  2951.     /*--- Only look for scripts and textures in subdirectories under the current
  2952.     one. RWSHAPEPATH need not be set then */
  2953.  
  2954.     RwSetShapePath(".",rwPRECONCAT);
  2955.  
  2956.     strcpy(buffer,sFilename);
  2957.  
  2958.     i = strlen(buffer);
  2959.     while((buffer[i] != '\\')&&(i>=0)) {
  2960.         i--;
  2961.     };
  2962.  
  2963.  
  2964.     if (i>=0) {
  2965.         buffer[i+1] = 0;
  2966.         strcat(buffer, "TEXTURES");
  2967.         RwSetShapePath(buffer, rwPOSTCONCAT);
  2968.  
  2969.         buffer[i+1] = 0;
  2970.         strcat(buffer, "SCRIPTS");
  2971.         RwSetShapePath(buffer, rwPOSTCONCAT);
  2972.     };
  2973.  
  2974.     RwSetShapePath("SCRIPTS", rwPRECONCAT);
  2975.     RwSetShapePath("TEXTURES", rwPRECONCAT);
  2976.  
  2977.  
  2978.     /*
  2979.     * Label the display with information about the version of
  2980.     * RenderWare being used. Its rather unlikely that
  2981.     * RwGetSystemInfo() will fail so we ignore its return value.
  2982.     */
  2983.   RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
  2984.   RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
  2985.     sprintf(windowText, "DosTank V%s %s",
  2986.         version, (param ? "Fixed" : "Float"));
  2987.     DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
  2988.  
  2989.     /*
  2990.     * Create the camera which will be used for rendering.
  2991.     */
  2992.  
  2993.     Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
  2994.     if (!Camera)
  2995.     {
  2996.         /*
  2997.           * As with RwOpen(), the most common cause for a failure to create
  2998.           * a camera is insufficient memory so we will explicitly check for
  2999.           * this condition and report it. Otherwise a general error is issued.
  3000.           */
  3001.         if (RwGetError() == E_RW_NOMEM)
  3002.         {
  3003.             RwClose();
  3004.             printf("Insufficient memory to create the RenderWare(tm) camera\n");
  3005.         }
  3006.         else
  3007.         {
  3008.             RwClose();
  3009.             printf("Error creating the RenderWare(tm) camera\n");
  3010.         }
  3011.         exit(-1);
  3012.     }
  3013.  
  3014.   RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
  3015.  
  3016.  
  3017.  
  3018.     /*
  3019.     * Set the camera's background color to blue.
  3020.     */
  3021.     RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.3));
  3022.  
  3023.     /*
  3024.     * By default, the camera lies on the X-Z plane and points down Z
  3025.     * into the screen. We shall retain the camera's orientation, but move
  3026.     * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
  3027.     */
  3028.  
  3029.     RwVCMoveCamera(Camera, CREAL(0.0), CREAL(2.0), CameraDistance);
  3030.  
  3031.     /*
  3032.     * Another change from previous versions of RenderWare is the amount of
  3033.     * prespective generated by the default viewwindow size. When converting
  3034.     * applications from previous versions of RenderWare the simple rule is
  3035.     * to divide the viewwindow size by five to get the same prespective effect
  3036.     * as given under previous versions.
  3037.     */
  3038.     if (nGScrWidth >= nGScrHeight) {
  3039.         RwSetCameraViewwindow(Camera,
  3040.                               CREAL(1.0),
  3041.                               RMul(CREAL(1.0),
  3042.                                                     RDiv(INT2REAL(nGScrHeight),
  3043.                                                     INT2REAL(nGScrWidth))));
  3044.     } else {
  3045.         RwSetCameraViewwindow(Camera,
  3046.                               RMul(CREAL(1.0),
  3047.                                                     RDiv(INT2REAL(nGScrWidth),
  3048.                                                     INT2REAL(nGScrHeight))),
  3049.                               CREAL(1.0));
  3050.     };
  3051.  
  3052.     /*
  3053.     * Create a scene which will contain the clumps to be rendered and the
  3054.     * light or lights illuminating those clumps . In this very simple
  3055.     * application it would be perfectly acceptable to use the default scene
  3056.     * (as returned by RwDefaultScene()) for rendering. However, it is good
  3057.     * practice to always create a scene which will be used for your rendering
  3058.     * and only use the default scene as a bag for currently unused clumps and
  3059.     * lights.
  3060.     */
  3061.  
  3062.     Scene = RwCreateScene();
  3063.     if (!Scene)
  3064.     {
  3065.         RwDestroyCamera(Camera);
  3066.         RwClose();
  3067.         printf("Error creating the RenderWare(tm) scene\n");
  3068.         exit(-1);
  3069.     }
  3070.  
  3071.     /*
  3072.     * Our scene will be illuminated by a directional light. The illumination
  3073.     * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  3074.     */
  3075.  
  3076.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  3077.                       CREAL(1.0));
  3078.     if (!Light)
  3079.     {
  3080.         RwDestroyScene(Scene);
  3081.         RwDestroyCamera(Camera);
  3082.         RwClose();
  3083.         printf("Error creating the RenderWare(tm) light\n");
  3084.         exit(-1);
  3085.     }
  3086.  
  3087.     /*
  3088.     * Add the new light to our scene.
  3089.     */
  3090.     RwAddLightToScene(Scene, Light);
  3091.  
  3092.     /* Add backdrop */
  3093.  
  3094.     rpRaster = RwReadRaster("mount.bmp",rwGAMMARASTER|rwDITHERRASTER);
  3095.  
  3096.     if (rpRaster) {
  3097.         /* Make it the backdrop */
  3098.         RwSetCameraBackdrop(Camera,rpRaster);
  3099.         RwSetCameraBackdropViewportRect(Camera,0,0,nGScrWidth,nGScrHeight-24);
  3100.     };
  3101.  
  3102.     /*
  3103.     * All the 3D components are now successfully initialized, so
  3104.     * work can begin...
  3105.     */
  3106.  
  3107.     return TRUE;
  3108. }
  3109.  
  3110. /**********************************************************************/
  3111.  
  3112. /*
  3113.  * This function shuts down the 3D (i.e. RenderWare) components of the
  3114.  * application in a polite fashion.
  3115.  */
  3116.  
  3117. static void
  3118. TidyUp3D()
  3119. {
  3120.  
  3121.     /*
  3122.     * Destroy the scene. This will destroy the contents of the scene,
  3123.     * i.e. any clumps and lights in that scene. In this case destroying
  3124.     * the scene will destroy the light we created in Init3D, and any
  3125.     * clumps we have loaded and not already destroyed.
  3126.     */
  3127.     RwDestroyScene(Scene);
  3128.  
  3129.     /*
  3130.     * Destroy the camera.
  3131.     */
  3132.     RwDestroyCamera(Camera);
  3133.  
  3134.     /*
  3135.     * Close the library. This will free up any internal resources and
  3136.     * textures loaded.
  3137.     */
  3138.     RwClose();
  3139. }
  3140.  
  3141. /****************************************************************************
  3142.  DisplayMode
  3143.  
  3144.  On entry    :
  3145.  On exit     :
  3146.  */
  3147.  
  3148. void DisplayMode(void)
  3149. {
  3150.     if (nGDemoMode) {
  3151.         DosPrintString(0,nGScrHeight-8,"Demo Mode On ",nGTextColour);
  3152.     } else {
  3153.         DosPrintString(0,nGScrHeight-8,"Demo Mode Off",nGTextColour);
  3154.     };
  3155. }
  3156.  
  3157. /**********************************************************************/
  3158.  
  3159. /*
  3160.  * This functions handles the left mouse button going down. Its main
  3161.  * job is to determine the kind of action to be taken when the mouse
  3162.  * moves, such as spinning a clump, or panning the camera. This involves
  3163.  * examining the virtual keys that were depressed when the mouse button
  3164.  * went down and attempting to pick a clump under the mouse pointer
  3165.  * position.
  3166.  */
  3167. static void
  3168. HandleLeftButtonDown(int x, int y, int vKeys)
  3169. {
  3170.   /* Stop warnings */
  3171.  
  3172.   x=x;
  3173.   vKeys = vKeys;
  3174.  
  3175.     bButtonDown |=1;
  3176.  
  3177.     if (y>nGScrHeight-8) {
  3178.         if (nGDemoMode) {
  3179.             nGDemoMode = 0;
  3180.             DisplayMode();
  3181.         } else {
  3182.             nGDemoMode = 1;
  3183.             DisplayMode();
  3184.         };
  3185.     };
  3186. }
  3187.  
  3188. /**********************************************************************/
  3189.  
  3190. /*
  3191.  * This functions handles the right mouse button going down. Its main
  3192.  * job is to determine the kind of action to be taken when the mouse
  3193.  * moves such as panning the camera.
  3194.  */
  3195. static void
  3196. HandleRightButtonDown(int x, int y, int vKeys)
  3197. {
  3198.   /* Stop warnings */
  3199.  
  3200.   x=x;
  3201.   y=y;
  3202.   vKeys = vKeys;
  3203.  
  3204.     bButtonDown |= 2;
  3205.     if (!nGFireCount) {
  3206.         nGFireCount = FIRE_TIME;
  3207.     };
  3208. }
  3209.  
  3210.  
  3211. /**********************************************************************/
  3212.  
  3213. /*
  3214.  * Handle the left mouse button comming back up. The basic action is
  3215.  * to turn off mouse move actions and release mouse capture.
  3216.  */
  3217.  
  3218. static void
  3219. HandleLeftButtonUp(void)
  3220. {
  3221.   bButtonDown &= ~1;
  3222. }
  3223.  
  3224. /**********************************************************************/
  3225.  
  3226. /*
  3227.  * Handle the right mouse button comming back up. The basic action is
  3228.  * to turn of mouse move actions and release mouse capture.
  3229.  */
  3230. static void
  3231. HandleRightButtonUp(void)
  3232. {
  3233.     bButtonDown &= ~2;
  3234. }
  3235.  
  3236. /*************************************************************************
  3237.  DisplayBound
  3238.  
  3239.  On entry    : Display
  3240.  On exit  :
  3241.  */
  3242.  
  3243. void DisplayBound(Display *dpDisp)
  3244. {
  3245.     RwV3d vPos;
  3246.  
  3247.     RwGetCameraPosition(Camera,&vPos);
  3248.  
  3249.     if (vPos.y<dpDisp->nMinHeight) {
  3250.         vPos.y = dpDisp->nMinHeight;
  3251.     };
  3252.  
  3253.     if (vPos.x>dpDisp->nMaxX) {
  3254.         vPos.x = dpDisp->nMaxX;
  3255.     };
  3256.     if (vPos.x<-dpDisp->nMaxX) {
  3257.         vPos.x = -dpDisp->nMaxX;
  3258.     };
  3259.  
  3260.     if (vPos.z>dpDisp->nMaxZ) {
  3261.         vPos.z = dpDisp->nMaxZ;
  3262.     };
  3263.     if (vPos.z<-dpDisp->nMaxZ) {
  3264.         vPos.z = -dpDisp->nMaxZ;
  3265.     };
  3266.  
  3267.     RwSetCameraPosition(Camera,vPos.x,vPos.y,vPos.z);
  3268. }
  3269.  
  3270. /****************************************************************************
  3271.  TrackbackdropToCamera
  3272.  
  3273.  On entry    : CAmera
  3274.  On exit    :
  3275.  */
  3276.  
  3277. static BOOL
  3278. TrackBackdropToCamera(RwCamera *camera)
  3279. {
  3280.     RwRaster *backdrop;
  3281.     int       backdropWidth;
  3282.     int       backdropHeight;
  3283.     RwV3d     at;
  3284.     RwReal    angle;
  3285.     int       xOffset;
  3286.     int       yOffset;
  3287.   RwInt32       windowWidth;
  3288.   RwInt32       windowHeight;
  3289.  
  3290.     backdrop = RwGetCameraBackdrop(camera);
  3291.  
  3292.     /*
  3293.      * No-op if the camera has no backdrop.
  3294.      */
  3295.     if (backdrop != NULL)
  3296.     {
  3297.         /*
  3298.          * Get the window and backdrop dimensions.
  3299.          */
  3300.         RwGetCameraViewport(camera, NULL, NULL, &windowWidth, &windowHeight);
  3301.  
  3302.         backdropWidth  = RwGetRasterWidth(backdrop);
  3303.         backdropHeight = RwGetRasterHeight(backdrop);
  3304.  
  3305.         /*
  3306.          * We use the look at vector for determining both
  3307.          * horizontal and vertical positioning.
  3308.          */
  3309.         RwGetCameraLookAt(camera, &at);
  3310.  
  3311.         /*
  3312.          * Compute the horizontal position. This is done
  3313.          * by compute the camera's angle of rotate about
  3314.          * the Z axis. The angle is then directly converted
  3315.          * into a horizontal backdrop offset.
  3316.          */
  3317.  
  3318.         /*
  3319.          * Compute the angle in the range 0 => PI.
  3320.          */
  3321.         at.y = CREAL(0.0);
  3322.         RwNormalize(&at);
  3323.         if (at.z > CREAL(1.0))
  3324.             at.z = CREAL(1.0);
  3325.         else if (at.z < CREAL(-1.0))
  3326.             at.z = CREAL(-1.0);
  3327.         angle = FL2REAL(acos(REAL2FL(at.z)));
  3328.  
  3329.         /*
  3330.          * Get the angle in the range 0 => 2 PI
  3331.          */
  3332.         if (at.x < CREAL(0.0))
  3333.             angle = RSub(CREAL(M_2PI), angle);
  3334.  
  3335.         /*
  3336.          * The backdrop X offset is derived simply from
  3337.          * the angle computed above.
  3338.          */
  3339.         xOffset = -REAL2INT(RDiv(RMul(angle, INT2REAL(backdropWidth)), CREAL(M_2PI)));
  3340.  
  3341.         /*
  3342.          * Compute the vertical position. This is done by getting
  3343.          * the angle between the look at vector and the Y axis. We
  3344.          * simply use the dot product (cosine of the angle) multiplied
  3345.          * by a scale factor to compute the vertical offset.
  3346.          */
  3347.         RwGetCameraLookAt(Camera, &at);
  3348.          yOffset = REAL2INT(RAdd(INT2REAL(windowHeight / 2), RMul(RMul(at.y, CREAL(1.5)), INT2REAL(windowHeight / 2)))) - (backdropHeight / 2);
  3349.  
  3350.         yOffset-=30;
  3351.  
  3352.         RwSetCameraBackdropOffset(Camera, xOffset, 0);
  3353.         RwSetCameraBackdropViewportRect(Camera, 0, yOffset, windowWidth, backdropHeight);
  3354.     }
  3355.     return TRUE;
  3356. }
  3357.  
  3358.  
  3359. /**********************************************************************/
  3360.  
  3361. /*
  3362.  * Handle MS Window's timer expiry. This function will perform any
  3363.  * animation actions necessary, including spinning clumps and animating
  3364.  * textures.
  3365.  */
  3366. static void
  3367. HandleTimer(void) {
  3368.     Tank *tpTank;
  3369.     RwV3d vAt,vPos;
  3370.     RwReal naEle[4][4];
  3371.  
  3372.     /* Hanle Computer controlled tanks */
  3373.  
  3374.     AllTanksLaunch(&atGTanks);
  3375.  
  3376.     AllTanksHandle(&atGTanks);
  3377.  
  3378.      AllMoveObjCollisionStill(&amoGObjects,&gGGround);
  3379.  
  3380.     AllMoveObjCollision(&amoGObjects);
  3381.     AllBulletsHandle(&abGBullets);
  3382.     AllBitsHandle(&abGBits);
  3383.  
  3384.  
  3385.     /* Handle the display */
  3386.  
  3387.     tpTank = *((Tank **)StackData(&atGTanks.sUsed));
  3388.  
  3389.     switch (dGDisplay.nDisplayMode) {
  3390.         case DISPLAY_FLOAT: {
  3391.             RwPushScratchMatrix();
  3392.  
  3393.             RwRotateMatrix(RwScratchMatrix(),
  3394.                 CREAL(0),CREAL(1),CREAL(0),CREAL(2),rwREPLACE);
  3395.             RwGetCameraPosition(Camera,&vPos);
  3396.             RwTransformVector(&vPos,RwScratchMatrix());
  3397.             RwSetCameraPosition(Camera,vPos.x,vPos.y,vPos.z);
  3398.  
  3399.             RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
  3400.             RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
  3401.  
  3402.             GroundDisplay(&gGGround,&asoGObjects,
  3403.                                         tpTank->moBase.vPos.x,
  3404.                                         tpTank->moBase.vPos.z );
  3405.             RwPopScratchMatrix();
  3406.             break;
  3407.         };
  3408.         case DISPLAY_FIRST: {
  3409.             vAt.x = CREAL(1.0);
  3410.             vAt.y = CREAL(0.0);
  3411.             vAt.z = CREAL(0.0);
  3412.  
  3413.             RwTransformVector(&vAt,tpTank->moBase.mpPos);
  3414.  
  3415.             RwSetCameraLookAt(Camera,vAt.x,vAt.y,vAt.z);
  3416.             RwSetCameraLookUp(Camera,CREAL(0.0),CREAL(1.0),CREAL(0.0));
  3417.             RwSetCameraPosition(Camera,CREAL(0.0),RDiv(TANK_SCALE,CREAL(2)),CREAL(0.0));
  3418.  
  3419.             GroundDisplay(&gGGround,&asoGObjects,
  3420.                                         tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
  3421.             break;
  3422.         };
  3423.         case DISPLAY_OUTSIDE: {
  3424.             GroundDisplay(&gGGround,&asoGObjects,
  3425.                                         tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
  3426.             break;
  3427.         };
  3428.         case DISPLAY_BEHIND: {
  3429.             RwPushScratchMatrix();
  3430.             RwGetClumpMatrix(tpTank->moBase.cpGeo,RwScratchMatrix());
  3431.             RwTranslateMatrix(RwScratchMatrix(),
  3432.                                                 CREAL(0),
  3433.                                                 RDiv(tpTank->moBase.nSize,CREAL(2)),
  3434.                                                 CREAL(0),
  3435.                                                 rwPOSTCONCAT);
  3436.             RwRotateMatrix(RwScratchMatrix(),
  3437.                 CREAL(0),CREAL(1),CREAL(0),CREAL(-90),rwPOSTCONCAT);
  3438.  
  3439.             RwGetMatrixElements(RwScratchMatrix(),naEle);
  3440.  
  3441.  
  3442.             RwSetCameraPosition(Camera,naEle[3][0],naEle[3][1],naEle[3][2]);
  3443.             RwSetCameraLookAt(Camera,-naEle[2][0],-naEle[2][1],-naEle[2][2]);
  3444.             RwSetCameraLookUp(Camera,naEle[1][0],naEle[1][1],naEle[1][2]);
  3445.  
  3446.             RwPopScratchMatrix();
  3447.             RwPanCamera(Camera,dGDisplay.nBehindPan);
  3448.             RwTiltCamera(Camera,dGDisplay.nBehindTilt);
  3449.  
  3450.             RwVCMoveCamera(Camera,CREAL(0),
  3451.                                                         CREAL(0),
  3452.                                                         dGDisplay.nBehindDist);
  3453.  
  3454.             GroundDisplay(&gGGround,&asoGObjects,
  3455.                                         tpTank->moBase.vPos.x,tpTank->moBase.vPos.z);
  3456.             break;
  3457.         };
  3458.         default: {
  3459.             break;
  3460.         };
  3461.     };
  3462.  
  3463.     /* Place in ground plane boundary */
  3464.  
  3465.     AllMoveObjBound(&amoGObjects,&gGGround);
  3466.  
  3467.     /* Add to scene as necessary */
  3468.  
  3469.     AllMoveObjDisplay(&amoGObjects,&gGGround);
  3470.     AllMoveObjDisplay(&amoGBits,&gGGround);
  3471.  
  3472.     /*
  3473.     * Animate textures. Enumerate over all the textures in the texture
  3474.     * dictionary stack calling RwTextureNextFrame() to bump the
  3475.     * current frame pointer of each texture. For single frame textures
  3476.     * this is a no-op.
  3477.     */
  3478.  
  3479.     RwForAllNamedTextures(RwTextureNextFrame);
  3480.  
  3481.     TrackBackdropToCamera(Camera);
  3482.  
  3483.     /*
  3484.     * See the description of HandlePaint() for a description of this common
  3485.     * RenderWare cliche for rendering a scene and copying it to the display.
  3486.     */
  3487.   RwBeginCameraUpdate(Camera,NULL);
  3488.     RwClearCameraViewport(Camera);
  3489.     RwRenderScene(Scene);
  3490.     RwEndCameraUpdate(Camera);
  3491.     RwShowCameraImage(Camera, NULL);
  3492.  
  3493.     nGFrameNumber++;
  3494. }
  3495.  
  3496. /****************************************************************************
  3497.  TankMouseControl
  3498.  
  3499.  On entry    : Mouse X
  3500.                     : Mouse Y
  3501.  On exit    :
  3502.  */
  3503.  
  3504. void TankMouseControl(int nX,int nY)
  3505. {
  3506.     Tank *tpTank;
  3507.  
  3508.     if (!nGDemoMode) {
  3509.         tpTank = *((Tank **)StackData(&atGTanks.sUsed));
  3510.  
  3511.         if (bButtonDown&1) {
  3512.             TankControl(tpTank,OP_ROT_BASE,
  3513.             RMul(RDiv(INT2REAL(nX),INT2REAL(nGScrWidth))-CREAL(0.5),CREAL(-5)) );
  3514.  
  3515.             TankControl(tpTank,OP_MOVE,
  3516.             RMul(RDiv(INT2REAL(nY),INT2REAL(nGScrHeight))-CREAL(0.5),CREAL(-0.04)) );
  3517.         };
  3518.  
  3519.         if (nGFireCount==FIRE_TIME) {
  3520.             TankControl(tpTank,OP_FIRE,CREAL(0));
  3521.         };
  3522.  
  3523.         if (nGFireCount) {
  3524.             nGFireCount--;
  3525.         };
  3526.     };
  3527. }
  3528.  
  3529. /****************************************************************************
  3530.  Handle Mouse Move
  3531.  
  3532.  On entry    : Mouse X
  3533.                     : Mouse Y
  3534.  On exit     :
  3535.  */
  3536.  
  3537. static void
  3538. HandleMouseMove(int nX, int nY,int nShiftCtrl)
  3539. {
  3540.     int nDx,nDy;
  3541.  
  3542.     nDx = nX - LastX;
  3543.     nDy = nY - LastY;
  3544.  
  3545.     switch(dGDisplay.nDisplayMode) {
  3546.         case DISPLAY_OUTSIDE: {
  3547.             switch (bButtonDown) {
  3548.                 case 1: {
  3549.                     /* Move in X-Z plane */
  3550.                     RwVCMoveCamera(Camera,
  3551.                     RMul(INT2REAL(nDx),CREAL(0.01)),
  3552.                     RMul(INT2REAL(nDy),CREAL(0.01)),CREAL(0.0));
  3553.  
  3554.                     DisplayBound(&dGDisplay);
  3555.  
  3556.                     RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
  3557.                 };
  3558.                 case 2: {
  3559.                     /* Zoom In and Out */
  3560.                     RwVCMoveCamera(Camera,CREAL(0),CREAL(0),RMul(INT2REAL(nDy),CREAL(0.01)));
  3561.                     RwPointCamera(Camera,CREAL(0.0),CREAL(0.0),CREAL(0.0));
  3562.                     DisplayBound(&dGDisplay);
  3563.                     break;
  3564.                 };
  3565.                 case 3: {
  3566.                     /* Tilt */
  3567.                     RwRevolveCamera(Camera,RMul(INT2REAL(nDx),CREAL(0.5)) );
  3568.                     DisplayBound(&dGDisplay);
  3569.                     break;
  3570.                 };
  3571.             };
  3572.  
  3573.             break;
  3574.         };
  3575.         case DISPLAY_BEHIND: {
  3576.             if (nShiftCtrl&MK_SHIFT) {
  3577.                 switch(bButtonDown) {
  3578.                     case 1: {
  3579.                         dGDisplay.nBehindTilt += RMul(INT2REAL(nDy),CREAL(0.5));
  3580.                         dGDisplay.nBehindPan += RMul(INT2REAL(nDx),CREAL(0.5));
  3581.  
  3582.                         if (dGDisplay.nBehindTilt<CREAL(10)) {
  3583.                             dGDisplay.nBehindTilt = CREAL(10);
  3584.                         };
  3585.                         if (dGDisplay.nBehindTilt>CREAL(90)) {
  3586.                             dGDisplay.nBehindTilt = CREAL(90);
  3587.                         };
  3588.                         break;
  3589.                     };
  3590.                     case 2: {
  3591.                         dGDisplay.nBehindDist += RMul(INT2REAL(nDy),CREAL(0.01));
  3592.  
  3593.                         if (dGDisplay.nBehindDist>CREAL(-0.2)) {
  3594.                             dGDisplay.nBehindDist = CREAL(-0.2);
  3595.                         };
  3596.                         if (dGDisplay.nBehindDist<CREAL(-1.0)) {
  3597.                             dGDisplay.nBehindDist = CREAL(-1.0);
  3598.                         };
  3599.  
  3600.                         break;
  3601.                     };
  3602.                 };
  3603.             } else {
  3604.                 TankMouseControl(nX,nY);
  3605.             };
  3606.  
  3607.             break;
  3608.         };
  3609.         case DISPLAY_FIRST: {
  3610.             if (bButtonDown&1) {
  3611.                 TankMouseControl(nX,nY);
  3612.             };
  3613.             break;
  3614.         };
  3615.         case DISPLAY_FLOAT: {
  3616.             if (bButtonDown&1) {
  3617.                 /* Zoom In and Out */
  3618.                 RwVCMoveCamera(Camera,CREAL(0),CREAL(0),RMul(INT2REAL(nDy),CREAL(0.01)));
  3619.                 DisplayBound(&dGDisplay);
  3620.        };
  3621.  
  3622.             break;
  3623.         }
  3624.     };
  3625. }
  3626.  
  3627.  
  3628. /****************************************************************************
  3629.  Main
  3630.  */
  3631.  
  3632. void main(int nArgc,char *saArgv[])
  3633. {
  3634.     int nKey;
  3635.     int nMouseX,nMouseY,nMouseBut,nOldMouseBut;
  3636.     int nChange;
  3637.     int nShiftCtrl=0;
  3638.  
  3639.   /* Stop warnings */
  3640.  
  3641.   nArgc = nArgc;
  3642.  
  3643.     if (!Init3D(saArgv[0]))
  3644.     {
  3645.         exit(-1);
  3646.     };
  3647.  
  3648.     /* Put in demo Mode */
  3649.  
  3650.     nGDemoMode = 1;
  3651.     nGDisplayTime = DISPLAY_TIME;
  3652.     nGDisplay = 0;
  3653.     DisplayMode();
  3654.  
  3655.     /* Create the ground */
  3656.  
  3657.     DisplayModeCreate(&dGDisplay);
  3658.     DisplayModeSet(&dGDisplay,DISPLAY_BEHIND);
  3659.  
  3660.     GroundCreate(&gGGround);
  3661.  
  3662.     RwAddClumpToScene(Scene,gGGround.cpGeo);
  3663.  
  3664.     AllStillObjCreate(&asoGObjects);
  3665.     AllMoveObjCreate(&amoGObjects,MAX_MOVE_OBJECTS);
  3666.     AllTanksCreate(&atGTanks);
  3667.     AllMoveObjCreate(&amoGBits,MAX_BITS);
  3668.  
  3669.     /* The first created tank is always the user operated one  */
  3670.     AllTanksAddTank(&atGTanks,CREAL(8.0),CREAL(8.0));
  3671.  
  3672.     /* Create the bullets */
  3673.  
  3674.     AllBulletsCreate(&abGBullets);
  3675.     AllBitsCreate(&abGBits);
  3676.  
  3677.     /* Create pointer */
  3678.  
  3679.     RwDPointerDisplay(&LastX,&LastY,&nOldMouseBut);
  3680.  
  3681.     nKey = DosGetKey();
  3682.  
  3683.     while (nKey!=27) {        /* ESC quits */
  3684.         RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
  3685.  
  3686.         /* The other bits */
  3687.  
  3688. /*        nDX =(nMouseX-LastX);
  3689.         nDY =(nMouseY-LastY);
  3690. */
  3691.         nKey = DosGetKey();
  3692.         nShiftCtrl = DosShiftCtrl();
  3693.  
  3694.         if ((nKey>='1')&&(nKey<='4')) {
  3695.             DisplayModeSet(&dGDisplay,(nKey-'1')+1);
  3696.         };
  3697.  
  3698.         if (nGDemoMode) {
  3699.             nGDisplayTime--;
  3700.  
  3701.             if (nGDisplayTime<0) {
  3702.                 DisplayModeSet(&dGDisplay,(nGDisplay&3)+1);
  3703.  
  3704.                 nGDisplayTime = DISPLAY_TIME;
  3705.                 nGDisplay++;
  3706.             };
  3707.         };
  3708.  
  3709.         nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
  3710.  
  3711.         switch (nChange) {
  3712.             case 0+0:
  3713.             case 2+1:
  3714.             case 8+4:
  3715.             case 8+2+4+1: {
  3716.                 /* No change */
  3717.                 break;
  3718.             };
  3719.             case 2:
  3720.             case 8+2+4: {
  3721.  
  3722.                 /* Left Button Down */
  3723.  
  3724.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3725.  
  3726.  
  3727.                 break;
  3728.             };
  3729.             case 8:
  3730.             case 8+2+1: {
  3731.                 /* Right Button Down */
  3732.  
  3733.  
  3734.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3735.  
  3736.  
  3737.                 break;
  3738.             };
  3739.             case 8+1: {
  3740.                 /* Right down left Up */
  3741.  
  3742.  
  3743.                 HandleLeftButtonUp();
  3744.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3745.  
  3746.  
  3747.                 break;
  3748.             };
  3749.             case 2+4: {
  3750.                 /* Right up left Down */
  3751.  
  3752.  
  3753.                 HandleRightButtonUp();
  3754.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3755.  
  3756.  
  3757.                 break;
  3758.             };
  3759.             case 8+2: {
  3760.                 /* Left down RIght Down */
  3761.  
  3762.  
  3763.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3764.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  3765.  
  3766.  
  3767.                 break;
  3768.             };
  3769.             case 1+4: {
  3770.                 /* Left up Right Up */
  3771.  
  3772.  
  3773.                 HandleRightButtonUp();
  3774.                 HandleLeftButtonUp();
  3775.  
  3776.  
  3777.                 break;
  3778.             };
  3779.             case 1:
  3780.             case 8+4+1: {
  3781.                 /* Left up */
  3782.  
  3783.  
  3784.                 HandleLeftButtonUp();
  3785.  
  3786.  
  3787.                 break;
  3788.             };
  3789.             case 4:
  3790.             case 2+4+1: {
  3791.                 /* Right up */
  3792.                 HandleRightButtonUp();
  3793.                 break;
  3794.             };
  3795.         };
  3796.  
  3797.         HandleMouseMove(nMouseX,nMouseY,nShiftCtrl);
  3798.  
  3799.         HandleTimer();
  3800.  
  3801.         LastX = nMouseX;
  3802.         LastY = nMouseY;
  3803.  
  3804.         nOldMouseBut = nMouseBut;
  3805.     };
  3806.  
  3807.     /*
  3808.     * Tidy up the 3D (RenderWare) components of the application.
  3809.     */
  3810.  
  3811.     TidyUp3D();
  3812.  
  3813.     exit(0);
  3814. }
  3815.  
  3816.