home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwdos / dostunne.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  61KB  |  2,474 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     dostunne.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 application can be built using the Watcom v9.5 compiler and the
  22.  * fixed-point RenderWare v1.3 library as follows:
  23.  * wcc386p /I=\rw\include /zW /4r /zp4 /mf /fpc /s /j /ei /oxtail
  24.  *         /DRWFIXED /fo=dostunne.obj dostunne.c
  25.  * wlink option caseexact option stack=32768 name dostunne
  26.  *         file dostunne.obj,\rw\lib\rwdrxp.lib
  27.  *
  28.  * This application can be built using the Watcom v9.5 compiler and the
  29.  * floating-point RenderWare v1.3 library as follows:
  30.  * wcc386p /I=\rw\include /zW /4r /zp4 /mf /7 /s /j /ei /oxtailm
  31.  *         /DRWFLOAT /fo=dostunne.obj dostunne.c
  32.  * wlink option caseexact option stack=32768 name dostunne
  33.  *         file dostunne.obj,\rw\lib\rwdrlp.lib
  34.  *
  35.  * This file is a product of Criterion Software Ltd.
  36.  *
  37.  * This file is provided as is with no warranties of any kind and is
  38.  * provided without any obligation on Criterion Software Ltd. or
  39.  * Canon Inc. to assist in its use or modification.
  40.  *
  41.  * Criterion Software Ltd. and Canon Inc. will not, under any
  42.  * circumstances, be liable for any lost revenue or other damages arising
  43.  * from the use of this file.
  44.  *
  45.  * Copyright (c) 1991, 1992, 1993. Canon Inc.
  46.  * All Rights Reserved.
  47.  *
  48.  **********************************************************************/
  49.  
  50. /****************************************************************************
  51.  Includes
  52.  */
  53.  
  54. #include <i86.h>
  55. #include <stdlib.h>
  56. #include <stdio.h>
  57. #include <math.h>    /* Required for floating point */
  58. #include <string.h>
  59.  
  60. #include "rwlib.h"
  61. #include "rwdos.h"
  62. #include "doswrap.h"
  63.  
  64. /****************************************************************************
  65.  Types
  66.  */
  67.  
  68. /**********************************************************************
  69.  *
  70.  * Application constants.
  71.  *
  72.  **********************************************************************/
  73.  
  74. #define FIRE_FRAMES 4
  75.  
  76. #define HOLE_RADIUS 15
  77. #define MAX_TEXTURES 20
  78. #define MAX_RINGS 20
  79.  
  80. #define FORESHORT_RING 10
  81.  
  82. #define MAX_OBJECTS 10
  83. #define MAX_EXPLOSION 40
  84.  
  85. #define EXPLOSION_VEL CREAL(0.02)
  86. #define EXPLOSION_BITS 15
  87.  
  88. #define FORCE_OF_GRAVITY 0.002
  89.  
  90. #define BIT_REDUCE CREAL(0.003)
  91. #define BIT_MINIMUM CREAL(0.002)
  92.  
  93. /*
  94.  * Ring Types
  95.  */
  96.  
  97. #define RING_COLOR 0
  98. #define RING_ROTATE 1
  99.  
  100. #define TYPE_BIT 1
  101. #define TYPE_OBJECT 2
  102.  
  103. #define SIZE_OBJECT CREAL(0.5)
  104. #define SIZE_BIT CREAL(0.1)
  105.  
  106. #define OBJECT_ACCEL CREAL(0.01)
  107.  
  108. /*
  109.  * And the rest
  110.  */
  111.  
  112. #define DELETE 8
  113.  
  114. #define BOOL int
  115.  
  116. /*
  117.  * MS Windows compatible defines
  118.  */
  119.  
  120. #define MK_CONTROL 0x4
  121. #define MK_SHIFT 0x2
  122.  
  123. /*
  124.  * Depending which video mode is being used the colur used will change
  125.  */
  126.  
  127. /*
  128.  * Default distance of the camera from the origin.
  129.  */
  130. #define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
  131.  
  132. /* PI !*/
  133.  
  134. #define PI 3.141592654
  135.  
  136. /**********************************************************************
  137.  *
  138.  * Type definitions.
  139.  *
  140.  **********************************************************************/
  141.  
  142. typedef struct {
  143.     RwTexture *taTextures[MAX_TEXTURES];
  144.     int nAmoTextures;
  145.  
  146.     int nCount;
  147.     int nDisp;
  148.     int nTexWidth;
  149.     int nTexHeight;
  150.     int nX;
  151.     int nY;
  152.     int nTexture;
  153. } Textures;
  154.  
  155.  
  156. typedef struct {
  157.     int nWidth;
  158.     int nDepth;
  159.     RwPolygon3d ***ppaPoly;
  160.     RwPolygon3d **paPolyData;
  161.     RwReal nSegLength;
  162.     RwReal nSize;
  163.     RwReal nOffAngle;
  164.  
  165.     RwClump *cpTube;
  166.     RwMatrix4d *mpTubeRot;
  167.     RwMatrix4d *mpTubeFlip;
  168.     RwMatrix4d *mpTubePos;
  169.     RwV3d vTubePos;
  170.  
  171.     RwReal nStepSize;
  172.     int nSteps;
  173.     int nCurStep;
  174.     RwReal nStepPos;
  175.  
  176.     Textures DispTextures;
  177. } Tube;
  178.  
  179. typedef struct {
  180.     int nType;
  181.     RwRGBColor cColA;
  182.     RwRGBColor cColB;
  183.     int nParam1;
  184.     int nParam2;
  185.     int nParam3;
  186. } RingData;
  187.  
  188. typedef struct {
  189.     RingData raRings[MAX_RINGS];
  190. } Ring;
  191.  
  192. typedef struct ObjectTag
  193. {
  194.     int nType;
  195.     RwClump *cpGeo;
  196.     RwV3d vPos,vVel;
  197.     RwMatrix4d *mpRot,*mpPos;
  198.     int nParam1;
  199.     RwReal nParam2;
  200. } Object;
  201.  
  202. /****************************************************************************
  203.  Stack Class
  204.  */
  205.  
  206. typedef struct StackTag {
  207.     int nElementSize;
  208.     char *pData;
  209.     char *pCurPtr;
  210.     int nAmoElements;
  211.     int nCurElement;
  212. } Stack;
  213.  
  214. /****************************************************************************
  215.  And the rest
  216.  */
  217.  
  218. typedef struct AllObjectsTag {
  219.     Stack sDisplay;
  220.     Stack sExplosion;
  221.     Stack sObjects;
  222.     int nOrthoCount;
  223. } AllObjects;
  224.  
  225. typedef struct LaunchTag {
  226.     int nTime;
  227.     int nCurSpeed;
  228.     int nSpeed;
  229. } Launch;
  230.  
  231. /**********************************************************************
  232.  *
  233.  * Application global variables.
  234.  *
  235.  **********************************************************************/
  236.  
  237. /*
  238.  *
  239.  */
  240.  
  241. static AllObjects aoGObjects;
  242. static Tube tGTube;
  243. static Ring rGRing;
  244. static Launch lGLaunch;
  245.  
  246. RwRGBColor caGColors[]={{CREAL(1.0),CREAL(0.0),CREAL(0.0)},
  247.                                                 {CREAL(0.0),CREAL(1.0),CREAL(0.0)},
  248.                                                 {CREAL(0.0),CREAL(0.0),CREAL(1.0)},
  249.                                                 {CREAL(0.5),CREAL(1.0),CREAL(0.0)},
  250.                                                 {CREAL(0.0),CREAL(0.5),CREAL(0.5)},
  251.                                                 {CREAL(0.0),CREAL(1.0),CREAL(1.0)},
  252.                                                 {CREAL(0.5),CREAL(1.0),CREAL(0.0)},
  253.                                                 {CREAL(1.0),CREAL(0.5),CREAL(0.1)} };
  254. int nGColorMask=7;
  255.  
  256. /*
  257.  * Texts colour
  258.  */
  259.  
  260. static int nGTextColour;
  261.  
  262.  
  263. /*
  264.  * Global RenderWare object pointers. In this simple application we
  265.  * make use of only a single scene, camera and light.
  266.  */
  267.  
  268. static RwScene    *Scene  = NULL;
  269. static RwCamera   *Camera = NULL;
  270. static RwLight    *Light  = NULL;
  271.  
  272. /*
  273.  * Current distance the camera is from the origin. This is stored to
  274.  * help us pan and zoom the camera.
  275.  */
  276.  
  277. static RwReal      CameraDistance = DEFAULT_CAMERA_DISTANCE;
  278.  
  279. /*
  280.  * Current animation frame number. This is incremented each time a
  281.  * frame is drawn on timer expiry. The purpose of this variable is
  282.  * to enable us to periodically (based on the number of frames) call
  283.  * RwOrthoNormalizeMatrix() to correct any errors which have crept
  284.  * into the clump's joint matrix because of the inevitable
  285.  * restrictions on the accuracy of fixed-point numbers. See
  286.  * HandleTimer for more details.
  287.  */
  288. static int         nGFrameNumber = 0;
  289.  
  290. /*
  291.  * This flag indicates whether the 3D components of the application
  292.  * have been successfully initialized as yet. It is used to guard
  293.  * the message loop handler functions from being invoked before the
  294.  * 3D components of the application are successfully initialized.
  295.  */
  296. static BOOL        ThreeDInitialized = FALSE;
  297.  
  298. /*
  299.  * The size of the screen
  300.  */
  301.  
  302. static int nGScrWidth;
  303. static int nGScrHeight;
  304.  
  305. /****************************************************************************
  306.  Cursor Images
  307.  */
  308.  
  309. /* 16 by 16 image */
  310.  
  311. #define MOUSE_ARROW_X 0
  312. #define MOUSE_ARROW_Y 0
  313.  
  314. #define MOUSE_ARROW_W 16
  315. #define MOUSE_ARROW_H 16
  316.  
  317. static void *pGMouseArrow;
  318. static char sGMouseArrow[]="\
  319. aaaa            \
  320. abbbaaa         \
  321. abbbbbbaaa      \
  322. abbbbbbbbba     \
  323.  abbbbbbba      \
  324.  abbbbbba       \
  325.  abbbbbba       \
  326.   abbbbbba      \
  327.   abbaabbba     \
  328.   aba  abbba    \
  329.    a    abbba   \
  330.          abbba  \
  331.           abbba \
  332.            abba \
  333.             aa  \
  334.                 ";
  335.  
  336. /* 13 x 13 */
  337.  
  338. #define MOUSE_FIRE_X 6
  339. #define MOUSE_FIRE_Y 6
  340.  
  341. #define MOUSE_FIRE_W 13
  342. #define MOUSE_FIRE_H 13
  343.  
  344. static void *pGMouseFire;
  345. static char sGMouseFire[]="\
  346.       a      \
  347.      aba     \
  348.      aba     \
  349.      aba     \
  350.      aba     \
  351.  aaaaabaaaaa \
  352. abbbbbbbbbbba\
  353.  aaaaabaaaaa \
  354.      aba     \
  355.      aba     \
  356.      aba     \
  357.      aba     \
  358.       a      \
  359. ";
  360.  
  361. /* 11 x 10 */
  362.  
  363. #define MOUSE_SIGHT_X 6
  364. #define MOUSE_SIGHT_Y 5
  365.  
  366. #define MOUSE_SIGHT_W 11
  367. #define MOUSE_SIGHT_H 10
  368.  
  369. static void *pGMouseSight;
  370. static char sGMouseSight[]="\
  371.   aaaaaaa  \
  372.  abbbbbbba \
  373. ab       ba\
  374. ab       ba\
  375. ab       ba\
  376. ab       ba\
  377. ab       ba\
  378. ab       ba\
  379.  abbbbbbba \
  380.   aaaaaaa  ";
  381.  
  382.  
  383. /* Pick info */
  384.  
  385. static RwPickRecord pGPick;
  386. static int nGPickStatus;
  387.  
  388. /* Fire Counter */
  389.  
  390. static int nGFireCount;
  391.  
  392.  
  393. /****************************************************************************
  394.  Proto types
  395.  */
  396.  
  397. /* Stack Prototypes */
  398.  
  399. int StackCreate(Stack *spStack,int nEleSize,int nAmoEle);
  400. void *StackData(Stack *spStack);
  401. int StackElements(Stack *spStack);
  402. int StackDestroy(Stack *spStack);
  403. void *StackPush(Stack *spStack,void *pData);
  404. int StackPop(Stack *spStack,void *pData);
  405. void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
  406.                                     void *pUser);
  407. int StackRemove(Stack *spStack,void *pEle);
  408.  
  409. /* AllObjects */
  410.  
  411. void AllObjectsRemove(AllObjects *aopObj,Stack *spObj,Object *opObj);
  412. Object *AllObjectsAdd(AllObjects *aoObj,Stack *spObj);
  413.  
  414. /****************************************************************************
  415.  LaunchCreate
  416.  
  417.  On entry    : Launch Structure
  418.                     : Speed of launch
  419.  On exit    :
  420.  */
  421.  
  422. void LaunchCreate(Launch *lpLaunch,int nSpeed)
  423. {
  424.     lpLaunch->nSpeed = nSpeed;
  425.     lpLaunch->nCurSpeed = nSpeed;
  426.     lpLaunch->nTime = nSpeed;
  427. }
  428.  
  429. /****************************************************************************
  430.  StackCreate
  431.  
  432.  On entry    : Pointer to stack structure
  433.  On exit    : 0 if all went to plan
  434.  */
  435.  
  436. int StackCreate(Stack *spStack,int nEleSize,int nAmoEle)
  437. {
  438.     if (!(spStack->pData = (char *) malloc (nEleSize*nAmoEle))) {
  439.         return 1;
  440.     };
  441.     spStack->nCurElement = 0;
  442.     spStack->pCurPtr = spStack->pData;
  443.     spStack->nAmoElements = nAmoEle;
  444.     spStack->nElementSize = nEleSize;
  445.  
  446.     return 0;
  447. }
  448.  
  449. /****************************************************************************
  450.  StackData
  451.  
  452.  On entry    : Stack
  453.  On exit    : Stacks contents as an array bottom element first
  454.  */
  455.  
  456. void *StackData(Stack *spStack)
  457. {
  458.     return spStack->pData;
  459. }
  460.  
  461.  
  462. /****************************************************************************
  463.  StackElements
  464.  
  465.  On entry    : Stack
  466.  On exit    : Amount of entries in the stack
  467.  */
  468.  
  469. int StackElements(Stack *spStack)
  470. {
  471.     return spStack->nCurElement;
  472. }
  473.  
  474. /****************************************************************************
  475.  StackFront
  476.  
  477.  On entry    : Stack
  478.                      : Element too stick on the bottom of the stack
  479.  On exit    : Pointer to entry on stack,NULL for fail
  480.  */
  481.  
  482. void *StackFront(Stack *spStack,void *pData)
  483. {
  484.     char *pTmp;
  485.     int nCount;
  486.  
  487.     if (spStack->nCurElement==spStack->nAmoElements) {
  488.         return NULL;
  489.     } else {
  490.         pTmp = spStack->pCurPtr;
  491.  
  492.         for (nCount=0;nCount<spStack->nCurElement;nCount++) {
  493.             memcpy(pTmp,pTmp-spStack->nElementSize,spStack->nElementSize);
  494.             pTmp -= spStack->nElementSize;
  495.         };
  496.  
  497.         memcpy(spStack->pData,pData,spStack->nElementSize);
  498.  
  499.         spStack->pCurPtr+=spStack->nElementSize;
  500.         spStack->nCurElement++;
  501.  
  502.         return spStack->pData;
  503.     };
  504. }
  505.  
  506. /****************************************************************************
  507.  StackDestroy
  508.  
  509.  On entry    : Stack
  510.  On exit    : 0 if all went to plan
  511.  */
  512.  
  513. int StackDestroy(Stack *spStack)
  514. {
  515.     free(spStack->pData);
  516.  
  517.     return 0;
  518. }
  519.  
  520. /****************************************************************************
  521.  StackPush
  522.  
  523.  On entry    : Stack
  524.                     : Pointer to element to push
  525.  On exit    : Pointer to Saved object if all ok else NULL
  526.  */
  527.  
  528. void *StackPush(Stack *spStack,void *pData)
  529. {
  530.     void *pSave;
  531.  
  532.     if (spStack->nCurElement==spStack->nAmoElements) {
  533.         return NULL;
  534.     } else {
  535.         pSave = spStack->pCurPtr;
  536.         memcpy(pSave,pData,spStack->nElementSize);
  537.  
  538.         spStack->pCurPtr+=spStack->nElementSize;
  539.         spStack->nCurElement++;
  540.  
  541.         return pSave;
  542.     };
  543. }
  544.  
  545. /****************************************************************************
  546.  StackPop
  547.  
  548.  On entry    : Stack
  549.  On exit    : 0 if all ok
  550.  */
  551.  
  552. int StackPop(Stack *spStack,void *pData)
  553. {
  554.     if (!spStack->nCurElement) {
  555.         return 1;
  556.     } else {
  557.         spStack->nCurElement--;
  558.         spStack->pCurPtr-=spStack->nElementSize;
  559.  
  560.         memcpy(pData,spStack->pCurPtr,spStack->nElementSize);
  561.         return 0;
  562.     };
  563. }
  564.  
  565. /****************************************************************************
  566.  StackForAll
  567.  
  568.  Goes from top of stack to bottom
  569.  
  570.  On entry    : Stack
  571.                     : Function to be called
  572.                     : Pointer to user data
  573.  */
  574.  
  575. void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
  576.                                     void *pUser)
  577. {
  578.     char *pData;
  579.     int nCount;
  580.  
  581.     pData = spStack->pCurPtr-spStack->nElementSize;
  582.     for (nCount=spStack->nCurElement;nCount--;nCount) {
  583.         (*Func)(pData,pUser);
  584.         pData-=spStack->nElementSize;
  585.     };
  586. }
  587.  
  588. /****************************************************************************
  589.  StackRemove
  590.  
  591.  Removes an entry from the stack
  592.  
  593.  On entry    : Stack
  594.                     : Element to remove
  595.  On exit    : 0 if all ok
  596.  */
  597.  
  598. int StackRemove(Stack *spStack,void *pEle)
  599. {
  600.     char *pData=(char *)pEle;
  601.  
  602.     while (pData!=(spStack->pCurPtr-spStack->nElementSize)) {
  603.         memcpy(pData,pData+spStack->nElementSize,spStack->nElementSize);
  604.         pData+=spStack->nElementSize;
  605.     };
  606.  
  607.     spStack->pCurPtr-=spStack->nElementSize;
  608.     spStack->nCurElement--;
  609.  
  610.     return 0;
  611. }
  612.  
  613. /****************************************************************************
  614.  CreateExplosion
  615.  
  616.  On entry    : Vector position of explosion
  617.                     : Amount of Bits
  618.  On exit    :
  619.  */
  620.  
  621. void CreateExplosion(AllObjects *aopObj,RwV3d *vpPos,RwV3d *vpVel,int nAmo)
  622. {
  623.     Object *opObj;
  624.     RwReal nRand;
  625.  
  626.   RwPushScratchMatrix();
  627.  
  628.     while (((opObj = AllObjectsAdd(aopObj,&aopObj->sExplosion))!=NULL)
  629.             &&(nAmo-->0)) {
  630.  
  631.         opObj->vPos = (*vpPos);
  632.         opObj->vVel = (*vpVel);
  633.  
  634.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  635.         opObj->vVel.x += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  636.                                                                                 EXPLOSION_VEL);
  637.  
  638.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  639.         opObj->vVel.y += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  640.                                                                                 EXPLOSION_VEL);
  641.  
  642.         nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
  643.         opObj->vVel.z += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
  644.                                                                                 EXPLOSION_VEL);
  645.         opObj->nParam1=14+((nRand>>2)&15);
  646.  
  647.         RwCopyMatrix(opObj->mpPos, RwScratchMatrix());
  648.  
  649.       RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
  650.                                                 opObj->vPos.y,
  651.                                                                                     opObj->vPos.z, rwPOSTCONCAT);
  652.       RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
  653.  
  654.         opObj->nParam2 = SIZE_BIT;
  655.  
  656.         RwScaleMatrix(RwScratchMatrix(),opObj->nParam2,
  657.                                                                         opObj->nParam2,
  658.                                                                         opObj->nParam2,
  659.                                                                         rwREPLACE);
  660.         RwTransformClumpJoint(opObj->cpGeo,RwScratchMatrix(),rwREPLACE);
  661.  
  662.     };
  663.  
  664.   RwPopScratchMatrix();
  665. }
  666.  
  667.  
  668. /*****************************************************************************
  669.  AllObjectsCreate
  670.  
  671.  On entry    : AllObjects
  672.  On exit    : 0 if all ok
  673.  */
  674.  
  675. int AllObjectsCreate(AllObjects *aopObj)
  676. {
  677.     int nStatus;
  678.  
  679.     nStatus = StackCreate(&aopObj->sDisplay,sizeof(Object),MAX_EXPLOSION+MAX_OBJECTS);
  680.     nStatus |= StackCreate(&aopObj->sExplosion,sizeof(Object),MAX_EXPLOSION);
  681.     nStatus |= StackCreate(&aopObj->sObjects,sizeof(Object),MAX_OBJECTS);
  682.  
  683.     return nStatus;
  684. }
  685.  
  686. /*************************************************************************
  687.  MakeZippy - Sets polygon to a random colour
  688.              (called from RwForAllPolygonsInClump)
  689.  
  690.  On entry    : Polygon
  691.  On exit    :
  692.  */
  693.  
  694. static void MakeZippy(RwPolygon3d *p)
  695. {
  696.   static int zippy = 0;
  697.  
  698.   switch (zippy % 7)
  699.     {
  700.     case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
  701.     case 1: RwSetPolygonColor(p, CREAL(0.8), CREAL(0.1), CREAL(0.2)); break;
  702.     case 2: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.6), CREAL(0.3)); break;
  703.     case 3: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.0), CREAL(0.2)); break;
  704.     case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
  705.     case 5: RwSetPolygonColor(p, CREAL(0.6), CREAL(0.5), CREAL(0.0)); break;
  706.     case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.2)); break;
  707.     }
  708.   zippy++;
  709. }
  710.  
  711. /*************************************************************************
  712.  MakeColour - Sets polygon to a random colour
  713.              (called from RwForAllPolygonsInClump)
  714.  
  715.  On entry    : Polygon
  716.  On exit    :
  717.  */
  718.  
  719. static void MakeColour(RwPolygon3d *p)
  720. {
  721.   static int zippy = 0;
  722.  
  723.   switch (zippy % 7)
  724.     {
  725.     case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
  726.     case 1: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.7), CREAL(0.0)); break;
  727.     case 2: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.0), CREAL(0.7)); break;
  728.     case 3: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
  729.     case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.7)); break;
  730.     case 5: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.7), CREAL(0.7)); break;
  731.     case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.7)); break;
  732.     }
  733.   zippy++;
  734. }
  735.  
  736.  
  737. /***************************************************************************
  738.  RandomVec - create a random vector
  739.  
  740.  On entry    : Random vector to create
  741.  On exit    :
  742.  */
  743.  
  744. static void RandomVec(RwV3d *vec)
  745. {
  746.   vec->x = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  747.   vec->y = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  748.   vec->z = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
  749. }
  750.  
  751.  
  752. /****************************************************************************
  753.  StackExplosionCreate
  754.  
  755.  On entry    : Stack To set up with explosions
  756.  On exit    : 0 if all ok
  757.  */
  758.  
  759. int StackExplosionCreate(Stack *spExp)
  760. {
  761.     int nCount;
  762.     RwClump *cpBit;
  763.     RwClump *cpGeo;
  764.     RwV3d vTmp;
  765.     Object oBit;
  766.  
  767.     /* Create the clump which is an explosion bit */
  768.  
  769.     RwModelBegin();
  770.   RwClumpBegin();
  771.   RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
  772.   RwSetSurfaceColor(CREAL(1.0),CREAL(1.0),CREAL(1.0));
  773.     RwSetHints(0);
  774.  
  775.     RwVertex(CREAL(0.866),CREAL(0.5),CREAL(0));
  776.     RwVertex(CREAL(-0.866),CREAL(0.5),CREAL(0));
  777.     RwVertex(CREAL(0),CREAL(1.0),CREAL(0));
  778.  
  779.     RwTriangle(1,2,3);
  780.     RwTriangle(3,2,1);
  781.  
  782.     RwClumpEnd(&cpBit);
  783.     RwModelEnd();
  784.  
  785.     /* For all explosion bits */
  786.  
  787.     for (nCount=0;nCount<MAX_EXPLOSION;nCount++) {
  788.         /* Make a copy of the bit clump */
  789.  
  790.         cpGeo = RwDuplicateClump(cpBit);
  791.  
  792.         /* Zippify the bit */
  793.  
  794.         RwForAllPolygonsInClump(cpGeo, MakeZippy);
  795.  
  796.         /* Mark as bit and unused */
  797.  
  798.         RwSetClumpData(cpGeo,NULL);        /* Mark with Null pointer */
  799.  
  800.         oBit.nType = TYPE_BIT;
  801.         oBit.cpGeo = cpGeo;
  802.  
  803.         RwIdentityMatrix(oBit.mpRot = RwCreateMatrix());
  804.     RwIdentityMatrix(oBit.mpPos = RwCreateMatrix());
  805.  
  806.         /* Give it a random rotation */
  807.  
  808.         RandomVec(&vTmp);
  809.  
  810.     RwRotateMatrix(oBit.mpRot,vTmp.x,vTmp.y,vTmp.z,
  811.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(15.0)),
  812.                           rwREPLACE);
  813.  
  814.         RwPushScratchMatrix();
  815.         RwScaleMatrix(RwScratchMatrix(),SIZE_BIT,SIZE_BIT,SIZE_BIT,rwREPLACE);
  816.         RwTransformClumpJoint(oBit.cpGeo,RwScratchMatrix(),rwREPLACE);
  817.         RwPopScratchMatrix();
  818.  
  819.         StackPush(spExp,&oBit);
  820.     };
  821.  
  822.     /* Destroy the default clump */
  823.  
  824.     RwDestroyClump(cpBit);
  825.  
  826.     return 0;
  827. }
  828.  
  829. /****************************************************************************
  830.  StackObjectsCreate
  831.  
  832.  On entry    : Stack
  833.  On exit     : 0 if all went to plan
  834.  */
  835.  
  836. int StackObjectsCreate(Stack *spObj,int nGeo)
  837. {
  838.     RwClump *cpDefault,*cpLoad;
  839.     RwV3d vTmp;
  840.     int nCount;
  841.     char saFiles[][14]={"z.rwx",
  842.                                         "ball.rwx",
  843.                                         "c.rwx",
  844.                                         "table.rwx",
  845.                                         "slab.rwx",
  846.                                         "torus.rwx",
  847.                                         "banana.rwx",
  848.                                         "lampshad.rwx",
  849.                                         "dummy.rwx"};
  850.     int nFiles=8;
  851.     Object oObj;
  852.     Object *opObj;
  853.  
  854.     if (nGeo) {
  855.  
  856.         RwModelBegin();
  857.       RwClumpBegin();
  858.       RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
  859.       RwSetSurfaceColor(RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))),
  860.                 RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))),
  861.                 RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))));
  862.  
  863.       RwSphere(CREAL(0.1),3);
  864.         RwClumpEnd(&cpDefault);
  865.         RwModelEnd();
  866.  
  867.         for (nCount=0;nCount<nFiles;nCount++) {
  868.             oObj.nType = TYPE_OBJECT;
  869.  
  870.             oObj.vVel.x = CREAL(0.0);
  871.             oObj.vVel.y = CREAL(0.0);
  872.             oObj.vVel.z = CREAL(0.0);
  873.  
  874.             RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
  875.         RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
  876.  
  877.             RandomVec(&vTmp);
  878.  
  879.         RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
  880.           RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
  881.                               rwREPLACE);
  882.  
  883.             cpLoad = RwReadShape(saFiles[nCount]);
  884.             if (!cpLoad)  {
  885.                 cpLoad = RwDuplicateClump(cpDefault);
  886.             };
  887.  
  888.             RwPushScratchMatrix();
  889.             RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
  890.             RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
  891.             RwPopScratchMatrix();
  892.  
  893.             oObj.cpGeo = cpLoad;
  894.  
  895.             opObj = (Object *)StackPush(spObj,&oObj);
  896.  
  897.         };
  898.  
  899.         RwDestroyClump(cpDefault);
  900.     } else {
  901.         /* geometry */
  902.  
  903.         oObj.nType = TYPE_OBJECT;
  904.  
  905.         oObj.vVel.x = CREAL(0.0);
  906.         oObj.vVel.y = CREAL(0.0);
  907.         oObj.vVel.z = CREAL(0.0);
  908.  
  909.         RwModelBegin();
  910.  
  911.       RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
  912.       RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
  913.       RwSetSurfaceLightSampling(rwFACET);
  914.       RwSetSurfaceGeometrySampling(rwSOLID);
  915.  
  916.         /* ! */
  917.  
  918.         RwClumpBegin();
  919.     RwSphere(CREAL(1.0),3);
  920.         RwClumpEnd(&cpLoad);
  921.  
  922.         RwForAllPolygonsInClump(cpLoad, MakeColour);
  923.         RwPushScratchMatrix();
  924.         RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
  925.         RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
  926.         RwPopScratchMatrix();
  927.  
  928.         RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
  929.       RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
  930.         RandomVec(&vTmp);
  931.         RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
  932.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
  933.                             rwREPLACE);
  934.         oObj.cpGeo = cpLoad;
  935.         StackPush(spObj,&oObj);
  936.  
  937.         /* ! */
  938.  
  939.         RwClumpBegin();
  940.     RwTranslateCTM(CREAL(0.0), CREAL(-0.15/2), CREAL(0.0));
  941.     RwCone(CREAL(0.15), CREAL(0.1), 12);
  942.     RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
  943.     RwDisc(CREAL(0.0), CREAL(0.1), 12);
  944.         RwClumpEnd(&cpLoad);
  945.  
  946.         RwForAllPolygonsInClump(cpLoad, MakeColour);
  947.         RwPushScratchMatrix();
  948.         RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
  949.         RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
  950.         RwPopScratchMatrix();
  951.  
  952.         RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
  953.       RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
  954.         RandomVec(&vTmp);
  955.       RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
  956.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
  957.                             rwREPLACE);
  958.         oObj.cpGeo = cpLoad;
  959.         StackPush(spObj,&oObj);
  960.  
  961.         /* !*/
  962.  
  963.         RwClumpBegin();
  964.     RwBlock(CREAL(0.1), CREAL(0.4), CREAL(0.9));
  965.         RwClumpEnd(&cpLoad);
  966.  
  967.         RwForAllPolygonsInClump(cpLoad, MakeColour);
  968.         RwPushScratchMatrix();
  969.         RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
  970.         RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
  971.         RwPopScratchMatrix();
  972.  
  973.         RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
  974.       RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
  975.         RandomVec(&vTmp);
  976.       RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
  977.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
  978.                             rwREPLACE);
  979.         oObj.cpGeo = cpLoad;
  980.         StackPush(spObj,&oObj);
  981.  
  982.         /* !*/
  983.  
  984.         RwClumpBegin();
  985.     RwTranslateCTM(CREAL(0.0), CREAL(-0.15/2), CREAL(0.0));
  986.     RwCylinder(CREAL(0.15), CREAL(0.1), CREAL(0.1), 12);
  987.     RwDisc(CREAL(0.15), CREAL(0.1), 12);
  988.     RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
  989.     RwDisc(CREAL(0.0), CREAL(0.1), 12);
  990.  
  991.         RwClumpEnd(&cpLoad);
  992.  
  993.         RwForAllPolygonsInClump(cpLoad, MakeColour);
  994.         RwPushScratchMatrix();
  995.         RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
  996.         RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
  997.         RwPopScratchMatrix();
  998.  
  999.         RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
  1000.       RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
  1001.         RandomVec(&vTmp);
  1002.       RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
  1003.       RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
  1004.                             rwREPLACE);
  1005.         oObj.cpGeo = cpLoad;
  1006.         StackPush(spObj,&oObj);
  1007.  
  1008.  
  1009.  
  1010.         RwModelEnd();
  1011.     };
  1012.  
  1013.     return 0;
  1014. }
  1015.  
  1016. /****************************************************************************
  1017.  AllObjectsFixPtrs
  1018.  
  1019.  On entry    : All Objects
  1020.  On exit    :
  1021.  */
  1022.  
  1023. void _AllObjectsFixPtrs(void *pData,void *pUser)
  1024. {
  1025.     Object *opObj=(Object *)pData;
  1026.  
  1027.   /* Stop warnings */
  1028.   pUser=pUser;
  1029.  
  1030.     switch (opObj->nType) {
  1031.         case TYPE_BIT: {
  1032.             RwSetClumpData(opObj->cpGeo,NULL);
  1033.             break;
  1034.         };
  1035.         case TYPE_OBJECT: {
  1036.             RwSetClumpData(opObj->cpGeo,opObj);
  1037.             break;
  1038.         };
  1039.     };
  1040. }
  1041.  
  1042. void AllObjectsFixPtrs(AllObjects *aopObj)
  1043. {
  1044.     StackForAll(&aopObj->sDisplay,_AllObjectsFixPtrs,aopObj);
  1045. }
  1046.  
  1047. /****************************************************************************
  1048.  AllObjectsUpdate
  1049.  
  1050.  On entry    : All Objects
  1051.  On exit    :
  1052.  */
  1053.  
  1054. void _AllObjectsUpdate(void *pData,void *pUser)
  1055. {
  1056.     Object *opObj=(Object *)pData;
  1057.     AllObjects *aopObj = (AllObjects *)pUser;
  1058.  
  1059.  
  1060.     aopObj->nOrthoCount++;
  1061.  
  1062.     switch (opObj->nType) {
  1063.         case TYPE_BIT: {
  1064.         RwMultiplyMatrix(opObj->mpPos,opObj->mpRot,RwScratchMatrix());
  1065.             if (!(nGFrameNumber+aopObj->nOrthoCount)&127) {
  1066.                 RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
  1067.             };
  1068.             RwCopyMatrix(RwScratchMatrix(), opObj->mpPos);
  1069.  
  1070.             RwAddVector(&opObj->vPos,&opObj->vVel,&opObj->vPos);
  1071.             opObj->vVel.y -= CREAL(FORCE_OF_GRAVITY);
  1072.  
  1073.         RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
  1074.                                                  opObj->vPos.y,
  1075.                                                                                      opObj->vPos.z, rwPOSTCONCAT);
  1076.         RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
  1077.  
  1078.             opObj->nParam2-=BIT_REDUCE;
  1079.             if (opObj->nParam2<BIT_MINIMUM) {
  1080.                 opObj->nParam2 = BIT_MINIMUM;
  1081.             };
  1082.  
  1083.             RwScaleMatrix(RwScratchMatrix(),opObj->nParam2,
  1084.                                                                             opObj->nParam2,
  1085.                                                                             opObj->nParam2,
  1086.                                                                             rwREPLACE);
  1087.             RwTransformClumpJoint(opObj->cpGeo,RwScratchMatrix(),rwREPLACE);
  1088.  
  1089.             if (!(opObj->nParam1--)) {
  1090.                 AllObjectsRemove(aopObj,&aopObj->sExplosion,opObj);
  1091.             };
  1092.             break;
  1093.         };
  1094.         case TYPE_OBJECT: {
  1095.         RwMultiplyMatrix(opObj->mpPos,opObj->mpRot,RwScratchMatrix());
  1096.             if (!(nGFrameNumber+aopObj->nOrthoCount)&127) {
  1097.                 RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
  1098.             };
  1099.             RwCopyMatrix(RwScratchMatrix(), opObj->mpPos);
  1100.  
  1101.         RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
  1102.                                                  opObj->vPos.y,
  1103.                                                                                      opObj->vPos.z, rwPOSTCONCAT);
  1104.         RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
  1105.  
  1106.  
  1107.             opObj->vVel.x -= RMul(opObj->vPos.x,OBJECT_ACCEL);
  1108.             opObj->vVel.y -= RMul(opObj->vPos.y,OBJECT_ACCEL);
  1109.  
  1110.             opObj->vPos.x += opObj->vVel.x;
  1111.             opObj->vPos.y += opObj->vVel.y;
  1112.  
  1113.             if (opObj->vPos.z>(-DEFAULT_CAMERA_DISTANCE-RDiv(SIZE_OBJECT,CREAL(2))) ) {
  1114.                 AllObjectsRemove(aopObj,&aopObj->sObjects,opObj);
  1115.             };
  1116.  
  1117.             break;
  1118.         };
  1119.     };
  1120.  
  1121.     opObj->vPos.z+= tGTube.nStepSize;
  1122.  
  1123. }
  1124.  
  1125. void AllObjectsUpdate(AllObjects *aopObj)
  1126. {
  1127.     /* Do the display Update */
  1128.  
  1129.     aopObj->nOrthoCount=0;
  1130.  
  1131.     RwPushScratchMatrix();
  1132.     StackForAll(&aopObj->sDisplay,_AllObjectsUpdate,aopObj);
  1133.     RwPopScratchMatrix();
  1134. }
  1135.  
  1136. /****************************************************************************
  1137.  AllObjectsAdd
  1138.  
  1139.  On entry    : All Objects
  1140.                     : Stack to add from
  1141.  On exit    : Pointer to object (NULL if not found)
  1142.  */
  1143.  
  1144. Object *AllObjectsAdd(AllObjects *aoObj,Stack *spObj)
  1145. {
  1146.     Object oObj;
  1147.     Object *pObj;
  1148.  
  1149.     if (!StackPop(spObj,&oObj)) {
  1150.         pObj = StackPush(&aoObj->sDisplay,&oObj);
  1151.         RwAddClumpToScene(Scene,oObj.cpGeo);
  1152.  
  1153.         if (pObj->nType==TYPE_OBJECT) {
  1154.             RwSetClumpData(oObj.cpGeo,(void *)pObj);        /* Mark with data pointer */
  1155.         } else {
  1156.             RwSetClumpData(oObj.cpGeo,NULL);
  1157.         };
  1158.  
  1159.         AllObjectsFixPtrs(aoObj);
  1160.         return pObj;
  1161.     };
  1162.  
  1163.     return (Object *)NULL;
  1164. }
  1165.  
  1166. /****************************************************************************
  1167.  AllObjectsRemove
  1168.  
  1169.  On entry    : All objects
  1170.                     : Object to remove
  1171.  */
  1172.  
  1173. void AllObjectsRemove(AllObjects *aopObj,Stack *spObj,Object *opObj)
  1174. {
  1175.     RwRemoveClumpFromScene(opObj->cpGeo);
  1176.     RwSetClumpData(opObj->cpGeo,NULL);
  1177.  
  1178.     switch (opObj->nType) {
  1179.         case TYPE_BIT: {
  1180.             StackPush(spObj,opObj);
  1181.             break;
  1182.         };
  1183.         case TYPE_OBJECT: {
  1184.             StackFront(spObj,opObj);
  1185.             break;
  1186.         };
  1187.         default: {
  1188.             break;
  1189.         };
  1190.     };
  1191.  
  1192.     StackRemove(&aopObj->sDisplay,opObj);
  1193.  
  1194.     AllObjectsFixPtrs(aopObj);
  1195. }
  1196.  
  1197. /****************************************************************************
  1198.  EnemyLaunchHandler
  1199.  
  1200.  On entry    : AllObjects
  1201.  On exit    :
  1202.  */
  1203.  
  1204. void EnemyLaunchHandler(Launch *lpLau,AllObjects *aopObj)
  1205. {
  1206.     Object *opObj;
  1207.  
  1208.     if (!lpLau->nTime) {
  1209.         opObj = AllObjectsAdd(aopObj,&aopObj->sObjects);
  1210.         if (opObj) {
  1211.             opObj->vPos.x = RDiv(INT2REAL((rand()&511)-256),CREAL(512));
  1212.             opObj->vPos.y = RDiv(INT2REAL((rand()&511)-256),CREAL(512));
  1213.             opObj->vPos.z = DEFAULT_CAMERA_DISTANCE;
  1214.  
  1215.             opObj->vVel.x = CREAL(0.0);
  1216.             opObj->vVel.y = CREAL(0.0);
  1217.             opObj->vVel.z = CREAL(0.0);
  1218.         };
  1219.  
  1220.         lpLau->nTime=lpLau->nSpeed;
  1221.     } else {
  1222.         lpLau->nTime--;
  1223.     };
  1224. }
  1225.  
  1226. /****************************************************************************
  1227.  DosPrintString
  1228.  
  1229.  On entry     : xcord
  1230.                         : ycord
  1231.                         : string
  1232.                         : colour
  1233.  On exit        :
  1234.  */
  1235.  
  1236. void DosPrintString(int nX,int nY,char *sString,int nCol)
  1237. {
  1238.     RwPrintChar pcPrint;
  1239.  
  1240.     pcPrint.x = nX;
  1241.     pcPrint.y = nY;
  1242.     pcPrint.color = nCol;
  1243.  
  1244.     for (;(*sString);sString++)  {
  1245.         pcPrint.c = (*sString);
  1246.     RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
  1247.         pcPrint.x+=8;
  1248.     };
  1249. }
  1250.  
  1251.  
  1252. /****************************************************************************
  1253.  DosGetKey
  1254.  
  1255.  Get the ascii key code of any depressed key. (Do not wait for a key press.
  1256.  -> return 0 if no key is pressed)
  1257.  
  1258.  On entry    :
  1259.  On exit     : Key pressed in ascii (or 0 if no key pressed)
  1260.  */
  1261.  
  1262. int DosGetKey(void)
  1263. {
  1264.     union REGPACK rp;
  1265.  
  1266.     memset(&rp,0,sizeof(rp));
  1267.     rp.h.ah = 0x06;
  1268.     rp.h.dl = 0xff;
  1269.  
  1270.     intr(0x21,&rp);
  1271.  
  1272.     if (!(rp.w.flags & 0x40 )) {       /* Check Z flag */
  1273.         /* Got key */
  1274.  
  1275.         if (rp.h.al) {
  1276.             return ((int)rp.h.al);
  1277.         };
  1278.  
  1279.         memset(&rp,0,sizeof(rp));
  1280.         rp.h.ah = 0x06;
  1281.         rp.h.dl = 0xff;
  1282.         intr(0x21,&rp);
  1283.  
  1284.         if (!(rp.w.flags & 0x40)) {
  1285.             return ((int)rp.h.al);
  1286.         };
  1287.  
  1288.         return (rp.h.al|0x80);
  1289.     };
  1290.  
  1291.     return 0;
  1292. }
  1293.  
  1294.  
  1295. /**********************************************************************/
  1296.  
  1297. /*
  1298.  * This function initializes the 3D (i.e. RenderWare) components of the
  1299.  * application. This function opens the RenderWare library, creates a
  1300.  * camera, a scene, a light and a matrix for spinning. A user-draw may
  1301.  * also be created if USERDRAW_LABELS is defined.
  1302.  */
  1303. static BOOL
  1304. Init3D(char *sFilename)
  1305. {
  1306.     char     windowText[128];
  1307.     char     version[30];
  1308.     char     buffer[128];
  1309.     int      param;
  1310.     int i;
  1311.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  1312.     long nError;
  1313.  
  1314.     /*
  1315.     * Attempt to open (and initialize) the RenderWare library.
  1316.     */
  1317.     if (!RwOpen("DOSMOUSE", &nError))
  1318.     {
  1319.         printf("Unable to access renderware!!\n");
  1320.         switch (nError) {
  1321.             case E_RW_DOS_MODE_UNAVAILABLE: {
  1322.                printf("The installed VESA card is unable to switch to the resolution");
  1323.                 printf(" requested.\n");
  1324.                 printf("Either install a different video adapter or use a ");
  1325.                 printf("supported video mode.");
  1326.                 break;
  1327.             };
  1328.             case E_RW_DOS_NO_VESA_BIOS: {
  1329.                 printf("A VESA bios is unavailable on this machine.\n");
  1330.                 printf("Either use a VESA compatible Video Adapter or install a ");
  1331.                 printf("VESA bios emulation TSR.\n");
  1332.                 break;
  1333.             };
  1334.             case E_RW_DOS_INCOMPATIBLE_BIOS: {
  1335.                 printf("The VESA bios on this machine is not of high enough version ");
  1336.                 printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
  1337.                 printf(" higher VESA bios or TSR.\n");
  1338.                 break;
  1339.             };
  1340.             case E_RW_DOS_NO_MOUSE: {
  1341.                 printf("No Microsoft compatible mouse driver present.\n");
  1342.                 printf("Install a microsoft compatible mouse driver and try again.\n");
  1343.                 break;
  1344.             };
  1345.             default: {
  1346.                 printf("Unknown Error !!!!!!!!!!!!!!!\n");
  1347.                 break;
  1348.             };
  1349.         };
  1350.         return FALSE;
  1351.     }
  1352.  
  1353.     /* Set up character set */
  1354.  
  1355.   RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
  1356.   RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
  1357.   nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  1358.  
  1359.     /*--- Only look for scripts and textures in subdirectories under the current
  1360.     one. RWSHAPEPATH need not be set then */
  1361.  
  1362.     RwSetShapePath(".",rwPRECONCAT);
  1363.  
  1364.     strcpy(buffer,sFilename);
  1365.  
  1366.     i = strlen(buffer);
  1367.     while((buffer[i] != '\\')&&(i>=0)) {
  1368.         i--;
  1369.     };
  1370.  
  1371.  
  1372.     if (i>=0) {
  1373.         buffer[i+1] = 0;
  1374.         strcat(buffer, "TEXTURES");
  1375.         RwSetShapePath(buffer, rwPOSTCONCAT);
  1376.  
  1377.         buffer[i+1] = 0;
  1378.         strcat(buffer, "SCRIPTS");
  1379.         RwSetShapePath(buffer, rwPOSTCONCAT);
  1380.     };
  1381.  
  1382.     RwSetShapePath("SCRIPTS", rwPRECONCAT);
  1383.     RwSetShapePath("TEXTURES", rwPRECONCAT);
  1384.  
  1385.  
  1386.     /*
  1387.     * Label the display with information about the version of
  1388.     * RenderWare being used. Its rather unlikely that
  1389.     * RwGetSystemInfo() will fail so we ignore its return value.
  1390.     */
  1391.   RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
  1392.   RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
  1393.     sprintf(windowText, "DosTunnel V%s %s",
  1394.         version, (param ? "Fixed" : "Float"));
  1395.     DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
  1396.  
  1397.     /*
  1398.     * Create the camera which will be used for rendering.
  1399.     */
  1400.  
  1401.     Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
  1402.     if (!Camera)
  1403.     {
  1404.         /*
  1405.           * As with RwOpen(), the most common cause for a failure to create
  1406.           * a camera is insufficient memory so we will explicitly check for
  1407.           * this condition and report it. Otherwise a general error is issued.
  1408.           */
  1409.         if (RwGetError() == E_RW_NOMEM)
  1410.         {
  1411.             RwClose();
  1412.             printf("Insufficient memory to create the RenderWare(tm) camera\n");
  1413.         }
  1414.         else
  1415.         {
  1416.             RwClose();
  1417.             printf("Error creating the RenderWare(tm) camera\n");
  1418.         }
  1419.         exit(-1);
  1420.     }
  1421.  
  1422.   RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
  1423.  
  1424.  
  1425.  
  1426.     /*
  1427.     * Set the camera's background color to blue.
  1428.     */
  1429.     RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.3));
  1430.  
  1431.     /*
  1432.     * By default, the camera lies on the X-Z plane and points down Z
  1433.     * into the screen. We shall retain the camera's orientation, but move
  1434.     * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
  1435.     */
  1436.  
  1437.     RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
  1438.  
  1439.     /*
  1440.     * Another change from previous versions of RenderWare is the amount of
  1441.     * prespective generated by the default viewwindow size. When converting
  1442.     * applications from previous versions of RenderWare the simple rule is
  1443.     * to divide the viewwindow size by five to get the same prespective effect
  1444.     * as given under previous versions.
  1445.     */
  1446.     if (nGScrWidth >= nGScrHeight) {
  1447.         RwSetCameraViewwindow(Camera,
  1448.                               CREAL(1.0),
  1449.                               RMul(CREAL(1.0),
  1450.                                                     RDiv(INT2REAL(nGScrHeight),
  1451.                                                     INT2REAL(nGScrWidth))));
  1452.     } else {
  1453.         RwSetCameraViewwindow(Camera,
  1454.                               RMul(CREAL(1.0),
  1455.                                                     RDiv(INT2REAL(nGScrWidth),
  1456.                                                     INT2REAL(nGScrHeight))),
  1457.                               CREAL(1.0));
  1458.     };
  1459.  
  1460.     /*
  1461.     * Create a scene which will contain the clumps to be rendered and the
  1462.     * light or lights illuminating those clumps . In this very simple
  1463.     * application it would be perfectly acceptable to use the default scene
  1464.     * (as returned by RwDefaultScene()) for rendering. However, it is good
  1465.     * practice to always create a scene which will be used for your rendering
  1466.     * and only use the default scene as a bag for currently unused clumps and
  1467.     * lights.
  1468.     */
  1469.  
  1470.     Scene = RwCreateScene();
  1471.     if (!Scene)
  1472.     {
  1473.         RwDestroyCamera(Camera);
  1474.         RwClose();
  1475.         printf("Error creating the RenderWare(tm) scene\n");
  1476.         exit(-1);
  1477.     }
  1478.  
  1479.     /*
  1480.     * Our scene will be illuminated by a directional light. The illumination
  1481.     * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  1482.     */
  1483.  
  1484.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  1485.                       CREAL(1.0));
  1486.     if (!Light)
  1487.     {
  1488.         RwDestroyScene(Scene);
  1489.         RwDestroyCamera(Camera);
  1490.         RwClose();
  1491.         printf("Error creating the RenderWare(tm) light\n");
  1492.         exit(-1);
  1493.     }
  1494.  
  1495.     /*
  1496.     * Add the new light to our scene.
  1497.     */
  1498.     RwAddLightToScene(Scene, Light);
  1499.  
  1500.  
  1501.     /*
  1502.     * All the 3D components are now successfully initialized, so
  1503.     * work can begin...
  1504.     */
  1505.     ThreeDInitialized = TRUE;
  1506.  
  1507.     return TRUE;
  1508. }
  1509.  
  1510. /**********************************************************************/
  1511.  
  1512. /*
  1513.  * This function shuts down the 3D (i.e. RenderWare) components of the
  1514.  * application in a polite fashion.
  1515.  */
  1516.  
  1517. static void
  1518. TidyUp3D()
  1519. {
  1520.  
  1521.     /*
  1522.     * Destroy the scene. This will destroy the contents of the scene,
  1523.     * i.e. any clumps and lights in that scene. In this case destroying
  1524.     * the scene will destroy the light we created in Init3D, and any
  1525.     * clumps we have loaded and not already destroyed.
  1526.     */
  1527.     RwDestroyScene(Scene);
  1528.  
  1529.     /*
  1530.     * Destroy the camera.
  1531.     */
  1532.     RwDestroyCamera(Camera);
  1533.  
  1534.     /*
  1535.     * Close the library. This will free up any internal resources and
  1536.     * textures loaded.
  1537.     */
  1538.     RwClose();
  1539. }
  1540.  
  1541. /**********************************************************************/
  1542.  
  1543. /*
  1544.  * This functions handles the left mouse button going down. Its main
  1545.  * job is to determine the kind of action to be taken when the mouse
  1546.  * moves, such as spinning a clump, or panning the camera. This involves
  1547.  * examining the virtual keys that were depressed when the mouse button
  1548.  * went down and attempting to pick a clump under the mouse pointer
  1549.  * position.
  1550.  */
  1551. static void
  1552. HandleLeftButtonDown(int x, int y, int vKeys)
  1553. {
  1554.   /* Stop warnings */
  1555.   vKeys = vKeys;
  1556.   x=x;
  1557.   y=y;
  1558.  
  1559.     nGFireCount=FIRE_FRAMES;
  1560. }
  1561.  
  1562. /**********************************************************************/
  1563.  
  1564. /*
  1565.  * This functions handles the right mouse button going down. Its main
  1566.  * job is to determine the kind of action to be taken when the mouse
  1567.  * moves such as panning the camera.
  1568.  */
  1569. static void
  1570. HandleRightButtonDown(int x, int y, int vKeys)
  1571. {
  1572.   /* Stop warnings */
  1573.  
  1574.   x=x;
  1575.   y=y;
  1576.   vKeys=vKeys;
  1577. }
  1578.  
  1579.  
  1580. /**********************************************************************/
  1581.  
  1582. /*
  1583.  * Handle the left mouse button comming back up. The basic action is
  1584.  * to turn off mouse move actions and release mouse capture.
  1585.  */
  1586.  
  1587. static void
  1588. HandleLeftButtonUp(void)
  1589. {
  1590. }
  1591.  
  1592. /**********************************************************************/
  1593.  
  1594. /*
  1595.  * Handle the right mouse button comming back up. The basic action is
  1596.  * to turn of mouse move actions and release mouse capture.
  1597.  */
  1598. static void
  1599. HandleRightButtonUp(void)
  1600. {
  1601. }
  1602.  
  1603. /**********************************************************************/
  1604.  
  1605. /*
  1606.  * Handle MS Window's timer expiry. This function will perform any
  1607.  * animation actions necessary, including spinning clumps and animating
  1608.  * textures.
  1609.  */
  1610. static void
  1611. HandleTimer(void) {
  1612.  
  1613.     /*
  1614.     * Animate textures. Enumerate over all the textures in the texture
  1615.     * dictionary stack calling RwTextureNextFrame() to bump the
  1616.     * current frame pointer of each texture. For single frame textures
  1617.     * this is a no-op.
  1618.     */
  1619.  
  1620.     RwForAllNamedTextures(RwTextureNextFrame);
  1621.  
  1622.     /*
  1623.     * See the description of HandlePaint() for a description of this common
  1624.     * RenderWare cliche for rendering a scene and copying it to the display.
  1625.     */
  1626.  
  1627.   RwBeginCameraUpdate(Camera,NULL);
  1628.     RwUndamageCameraViewport(Camera,0,0,nGScrWidth,nGScrHeight-24);
  1629.     RwDamageCameraViewport(Camera,(nGScrWidth>>1)-HOLE_RADIUS,
  1630.     ((nGScrHeight-24)>>1)-HOLE_RADIUS,
  1631.     (nGScrWidth>>1)+HOLE_RADIUS,
  1632.     ((nGScrHeight-24)>>1)+HOLE_RADIUS);
  1633.     RwClearCameraViewport(Camera);
  1634.     RwRenderScene(Scene);
  1635.     RwEndCameraUpdate(Camera);
  1636.     RwShowCameraImage(Camera, NULL);
  1637.  
  1638.     nGFrameNumber++;
  1639. }
  1640.  
  1641. /****************************************************************************
  1642.  AddPolyStruct
  1643.  
  1644.  On entry    : Polygon
  1645.                     : pointer to polygon data structure
  1646.  On exit    :
  1647.  */
  1648.  
  1649. RwPolygon3d *AddPolyStruct(RwPolygon3d *pPoly,void *pData);
  1650.  
  1651. RwPolygon3d *AddPolyStruct(RwPolygon3d *pPoly,void *pData)
  1652. {
  1653.     int nRow,nCol;
  1654.     Tube *tpTube = (Tube *)pData;
  1655.  
  1656.     nCol = RwGetPolygonTag(pPoly)%tpTube->nWidth;
  1657.     nRow = RwGetPolygonTag(pPoly)-nCol;
  1658.  
  1659.     tpTube->paPolyData[nRow*2+nCol] = pPoly;
  1660.     tpTube->paPolyData[nRow*2+tpTube->nWidth+nCol] = pPoly;
  1661.  
  1662.     return NULL;
  1663. }
  1664.  
  1665. /****************************************************************************
  1666.  CreatePolyStruct
  1667.  
  1668.  On entry    : Clump to extract
  1669.  On exit    :
  1670.  */
  1671.  
  1672. void CreatePolyStruct(Tube *tpTube)
  1673. {
  1674.     int nCount;
  1675.  
  1676.     tpTube->ppaPoly =
  1677.       (RwPolygon3d ***)malloc(sizeof(RwPolygon3d *)*(tpTube->nDepth-1));
  1678.     tpTube->paPolyData = (RwPolygon3d **)
  1679.        malloc(sizeof(RwPolygon3d *)*(tpTube->nWidth*2)*(tpTube->nDepth-1));
  1680.  
  1681.     for(nCount=0;nCount<tpTube->nDepth-1;nCount++) {
  1682.         tpTube->ppaPoly[nCount] = &(tpTube->paPolyData[nCount*tpTube->nWidth*2]);
  1683.     };
  1684.  
  1685.     RwForAllPolygonsInClumpPointer(tpTube->cpTube,AddPolyStruct,(void*)tpTube);
  1686. }
  1687.  
  1688. /****************************************************************************
  1689.  Create Tube
  1690.  
  1691.  On entry    : Amount of sides
  1692.                     : Size
  1693.                     : Angle change
  1694.  
  1695.  On exit    :
  1696.  */
  1697.  
  1698. void CreateTube(Tube *tpTube)
  1699. {
  1700.     int nCount,nCount2,nPolyNo;
  1701.     RwReal nOffAngPos;
  1702.     short int nStart;
  1703.     RwClump *cpClump;
  1704.  
  1705.     nPolyNo=0;
  1706.  
  1707.     RwModelBegin();
  1708.     RwClumpBegin();
  1709.  
  1710.   RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
  1711.   RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
  1712.   RwSetSurfaceLightSampling(rwFACET);
  1713.   RwSetSurfaceGeometrySampling(rwSOLID);
  1714.  
  1715.     RwSetHints(rwCONTAINER);
  1716.  
  1717.     nOffAngPos=CREAL(0.0);
  1718.  
  1719.     RwTransformBegin();
  1720.     RwIdentityCTM();
  1721.     RwTranslateCTM(CREAL(0),CREAL(0),
  1722.      -RDiv(RMul(tpTube->nSegLength,INT2REAL(tpTube->nDepth-1)),INT2REAL(2)) );
  1723.  
  1724.     for (nCount=0;nCount<tpTube->nDepth;nCount++) {
  1725.         RwTransformBegin();
  1726.         for (nCount2=0;nCount2<tpTube->nWidth-1;nCount2++) {
  1727.  
  1728.             RwTransformBegin();
  1729.             RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1730.               RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
  1731.  
  1732.             RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
  1733.             RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1734.             RwTransformEnd();
  1735.  
  1736.             RwTransformBegin();
  1737.             RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1738.               RDiv(RMul(CREAL(360.0),INT2REAL(nCount2+1)),INT2REAL(tpTube->nWidth)));
  1739.             RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
  1740.             RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1741.             RwTransformEnd();
  1742.  
  1743.             RwTransformBegin();
  1744.             RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1745.               RDiv(RMul(CREAL(360.0),INT2REAL(nCount2+1)),INT2REAL(tpTube->nWidth)));
  1746.             RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
  1747.             RwTranslateCTM(0,0,tpTube->nSegLength);
  1748.             RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1749.             RwTransformEnd();
  1750.  
  1751.             RwTransformBegin();
  1752.             RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1753.               RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
  1754.             RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
  1755.             RwTranslateCTM(0,0,tpTube->nSegLength);
  1756.             RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1757.             RwTransformEnd();
  1758.         };
  1759.         RwTransformBegin();
  1760.         RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1761.             RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
  1762.         RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
  1763.         RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1764.         RwTransformEnd();
  1765.  
  1766.         RwTransformBegin();
  1767.         RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
  1768.         RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1769.         RwTransformEnd();
  1770.  
  1771.         RwTransformBegin();
  1772.         RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
  1773.         RwTranslateCTM(0,0,tpTube->nSegLength);
  1774.         RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1775.         RwTransformEnd();
  1776.  
  1777.         RwTransformBegin();
  1778.         RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
  1779.             RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
  1780.         RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
  1781.         RwTranslateCTM(0,0,tpTube->nSegLength);
  1782.         RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
  1783.         RwTransformEnd();
  1784.  
  1785.  
  1786.         RwTransformEnd();
  1787.         RwTranslateCTM(CREAL(0),CREAL(0),tpTube->nSegLength);
  1788.         nOffAngPos=RAdd(nOffAngPos,tpTube->nOffAngle);
  1789.     };
  1790.     RwTransformEnd();
  1791.  
  1792.  
  1793.     nStart =1;
  1794.  
  1795.     for (nCount=0;nCount<tpTube->nDepth-1;nCount++) {
  1796.         for (nCount2=0;nCount2<tpTube->nWidth;nCount2++) {
  1797.             RwQuadExt(nStart+3,nStart+2,nStart+1,nStart,nPolyNo);
  1798.             nPolyNo++;
  1799.             nStart+=4;
  1800.         };
  1801.     };
  1802.  
  1803.     RwClumpEnd(&cpClump);
  1804.     RwModelEnd();
  1805.  
  1806.     RwSetClumpData(cpClump,NULL);        /* Mark as NULL */
  1807.  
  1808.     tpTube->cpTube = cpClump;
  1809.  
  1810.     tpTube->mpTubeRot = RwCreateMatrix();
  1811.     RwRotateMatrix(tpTube->mpTubeRot,CREAL(0),CREAL(0),CREAL(1.0),
  1812.        CREAL(-2.0),rwREPLACE);
  1813.     RwIdentityMatrix(tpTube->mpTubePos = RwCreateMatrix());
  1814.     tpTube->mpTubeFlip = RwCreateMatrix();
  1815.     RwRotateMatrix(tpTube->mpTubeFlip,CREAL(0),CREAL(0),CREAL(1.0),
  1816.        -tpTube->nOffAngle,rwREPLACE);
  1817.     RwPushScratchMatrix();
  1818.     RwMultiplyMatrix(tpTube->mpTubeFlip,tpTube->mpTubeRot,RwScratchMatrix());
  1819.     RwCopyMatrix(RwScratchMatrix(),tpTube->mpTubeFlip);
  1820.     RwPopScratchMatrix();
  1821.  
  1822.     tpTube->vTubePos.x=CREAL(0.0);
  1823.     tpTube->vTubePos.y=CREAL(0.0);
  1824.     tpTube->vTubePos.z=CREAL(0.0);
  1825.  
  1826.     tpTube->nStepSize = RDiv(tpTube->nSegLength,INT2REAL(tpTube->nSteps));
  1827.     tpTube->nCurStep=0;
  1828.     tpTube->nStepPos = CREAL(0.0);
  1829.  
  1830.     CreatePolyStruct(tpTube);
  1831.  
  1832.     tpTube->DispTextures.nDisp = 5;
  1833.     SetTexture(tpTube);
  1834. }
  1835.  
  1836. /****************************************************************************
  1837.  ScrollPolys
  1838.  
  1839.  On entry    :
  1840.  On exit    :
  1841.  */
  1842.  
  1843. void ScrollPolys(Tube *tpTube)
  1844. {
  1845.     int nCount;
  1846.     int nCount2;
  1847.     RwUV uvaVertex[4];
  1848.  
  1849.     for (nCount=tpTube->nDepth-3;nCount>=0;nCount--) {
  1850.         for (nCount2=0;nCount2<tpTube->nWidth;nCount2++) {
  1851.                 RwSetPolygonMaterial(tpTube->ppaPoly[nCount+1][nCount2],
  1852.                 RwGetPolygonMaterial(tpTube->ppaPoly[nCount][nCount2]));
  1853.  
  1854.                 RwGetPolygonUV(tpTube->ppaPoly[nCount][nCount2],uvaVertex);
  1855.                 RwSetPolygonUV(tpTube->ppaPoly[nCount+1][nCount2],uvaVertex);
  1856.         };
  1857.     };
  1858. }
  1859.  
  1860.  
  1861. /****************************************************************************
  1862.  SetTexture
  1863.  
  1864.  On entry
  1865.  On exit    :
  1866.  */
  1867.  
  1868. void SetTexture(Tube *tpTube)
  1869. {
  1870.     Textures *tpTex = &tpTube->DispTextures;
  1871.     int nValue;
  1872.  
  1873.     nValue = rand();
  1874.  
  1875.     tpTex->nCount=(nValue&3)+2;
  1876.     tpTex->nTexWidth=((nValue>>2)&3)+1;
  1877.     tpTex->nTexHeight=((nValue>>4)&3)+1;
  1878.     tpTex->nX = (nValue>>8)&7;
  1879.     tpTex->nY = 0;
  1880.     tpTex->nTexture++;
  1881.  
  1882.     if (tpTex->nTexture>tpTex->nAmoTextures) {
  1883.         tpTex->nTexture=0;
  1884.     };
  1885. }
  1886.  
  1887. /****************************************************************************
  1888.  RingForeshorten
  1889.  */
  1890.  
  1891. void RingForeshorten(Tube *tpTube)
  1892. {
  1893.     int nCount;
  1894.  
  1895.     for (nCount=0;nCount<tpTube->nWidth;nCount++) {
  1896.             RwSetPolygonTextureModes(tpTube->ppaPoly[FORESHORT_RING][nCount],
  1897.             rwFORESHORTEN);
  1898.     };
  1899. };
  1900.  
  1901.  
  1902. /****************************************************************************
  1903.  AddTexture
  1904.  
  1905.  On entry    : Tube Structure
  1906.  On exit     :
  1907.  */
  1908.  
  1909.  
  1910. void AddTexture(Tube *tpTube)
  1911. {
  1912.     Textures *tpTex;
  1913.     RwUV uvaVertex[4];
  1914.     int nCount;
  1915.  
  1916.     tpTex = &tpTube->DispTextures;
  1917.  
  1918.     if (!tpTex->nCount) {
  1919.         /* Have to do some displaying stuff */
  1920.         for (nCount=0;nCount<(tpTex->nTexWidth);nCount++) {
  1921.             RwSetPolygonTextureModes(tpTube->ppaPoly[0][nCount+tpTex->nX],0);
  1922.             RwSetPolygonTexture(tpTube->ppaPoly[0][nCount+tpTex->nX],
  1923.                 tpTex->taTextures[tpTex->nTexture]);
  1924.  
  1925.             uvaVertex[0].u=RDiv(INT2REAL(nCount),INT2REAL(tpTex->nTexWidth));
  1926.             uvaVertex[0].v=RDiv(INT2REAL(tpTex->nY),INT2REAL(tpTex->nTexHeight));
  1927.  
  1928.             uvaVertex[1].u=RDiv(INT2REAL(nCount+1),INT2REAL(tpTex->nTexWidth));
  1929.             uvaVertex[1].v=RDiv(INT2REAL(tpTex->nY),INT2REAL(tpTex->nTexHeight));
  1930.  
  1931.             uvaVertex[2].u=RDiv(INT2REAL(nCount+1),INT2REAL(tpTex->nTexWidth));
  1932.             uvaVertex[2].v=RDiv(INT2REAL(tpTex->nY+1),INT2REAL(tpTex->nTexHeight));
  1933.  
  1934.             uvaVertex[3].u=RDiv(INT2REAL(nCount),INT2REAL(tpTex->nTexWidth));
  1935.             uvaVertex[3].v=RDiv(INT2REAL(tpTex->nY+1),INT2REAL(tpTex->nTexHeight));
  1936.  
  1937.             RwSetPolygonUV(tpTube->ppaPoly[0][nCount+tpTex->nX],uvaVertex);
  1938.  
  1939.         };
  1940.         tpTex->nY++;
  1941.         if (tpTex->nY>=tpTex->nTexHeight) {
  1942.             SetTexture(tpTube);
  1943.         };
  1944.  
  1945.     } else {
  1946.         tpTex->nCount--;
  1947.     };
  1948. }
  1949.  
  1950. /****************************************************************************
  1951.  UpdateTube
  1952.  
  1953.  On entry    : Tube to be updated
  1954.  On exit    :
  1955.  */
  1956.  
  1957. void UpdateTube(Tube *tpTube,Ring *rpRing)
  1958. {
  1959.     int nValue;
  1960.  
  1961.     HandleRings(tpTube,rpRing);
  1962.  
  1963.   RwPushScratchMatrix();
  1964.  
  1965.     if (tpTube->nCurStep<tpTube->nSteps) {
  1966.         RwMultiplyMatrix(tpTube->mpTubePos,tpTube->mpTubeRot,RwScratchMatrix());
  1967.         if (!(nGFrameNumber&127)) {
  1968.             RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
  1969.         };
  1970.         RwCopyMatrix(RwScratchMatrix(),tpTube->mpTubePos);
  1971.     } else {
  1972.         tpTube->nCurStep=0;
  1973.         tpTube->nStepPos=CREAL(0.0);
  1974.  
  1975.         RwMultiplyMatrix(tpTube->mpTubePos,tpTube->mpTubeFlip,RwScratchMatrix());
  1976.         if (!(nGFrameNumber&127)) {
  1977.             RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
  1978.         };
  1979.         RwCopyMatrix(RwScratchMatrix(), tpTube->mpTubePos);
  1980.  
  1981.         ScrollPolys(tpTube);
  1982.         ScrollRings(tpTube,rpRing);
  1983.  
  1984.         nValue=rand();
  1985.  
  1986.         switch (nValue&7) {
  1987.             case 0:
  1988.             case 3:
  1989.             case 5: {
  1990.                 CreateRingCheck(tpTube,rpRing,caGColors[(nValue>>8)&nGColorMask]);
  1991.                 break;
  1992.             };
  1993.             case 2: {
  1994.                 CreateRingRotate(tpTube,rpRing,
  1995.                 caGColors[(nValue>>8)&nGColorMask],
  1996.                 caGColors[(3+(nValue>>8))&nGColorMask],((nValue>>5)&2)-1) ;
  1997.                 break;
  1998.             };
  1999.             default: {
  2000.                 CreateRingColor(tpTube,rpRing,
  2001.                     caGColors[(nValue>>8)&nGColorMask]);
  2002.                 break;
  2003.             };
  2004.         };
  2005.  
  2006.         AddTexture(tpTube);
  2007.     };
  2008.  
  2009.     RingForeshorten(tpTube);
  2010.  
  2011.     RwTranslateMatrix(RwScratchMatrix(),
  2012.                         tpTube->vTubePos.x,
  2013.                                         tpTube->vTubePos.y,
  2014.                                         RAdd(tpTube->vTubePos.z,tpTube->nStepPos)
  2015.                                         , rwPOSTCONCAT);
  2016.  
  2017.     RwTransformClump(tpTube->cpTube, RwScratchMatrix(), rwREPLACE);
  2018.  
  2019.     RwPopScratchMatrix();
  2020.     tpTube->nCurStep++;
  2021.     tpTube->nStepPos+=tpTube->nStepSize;
  2022. }
  2023.  
  2024. /****************************************************************************
  2025.  SetTubeColor
  2026.  */
  2027.  
  2028. void SetTubeColor(Tube *tpTube,RwRGBColor cCol)
  2029. {
  2030.     int nCount;
  2031.     for (nCount=0;nCount<tpTube->nWidth;nCount++) {
  2032.         RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
  2033.             cCol.r,cCol.g,cCol.b);
  2034.         RwSetPolygonTexture(tpTube->ppaPoly[0][nCount],NULL);
  2035.     };
  2036. }
  2037.  
  2038. /****************************************************************************
  2039.  CreateRingColor
  2040.  
  2041.  On entry    : Color
  2042.  */
  2043.  
  2044. void CreateRingColor(Tube *tpTube,Ring *rpRing,RwRGBColor cColA)
  2045. {
  2046.     SetTubeColor(tpTube,cColA);
  2047.  
  2048.     rpRing->raRings[0].nType = RING_COLOR;
  2049. }
  2050.  
  2051. /****************************************************************************
  2052.  CreateRingCheck
  2053.  
  2054.  On entry    : Color
  2055.  */
  2056.  
  2057. void CreateRingCheck(Tube *tpTube,Ring *rpRing,RwRGBColor cColA)
  2058. {
  2059.     RwRGBColor cColB;
  2060.     int nCount;
  2061.  
  2062.     cColB.r = RDiv(cColA.r,CREAL(4.0));
  2063.     cColB.g = RDiv(cColA.g,CREAL(4.0));
  2064.     cColB.b = RDiv(cColA.b,CREAL(4.0));
  2065.  
  2066.     for (nCount=0;nCount<tpTube->nWidth;nCount++) {
  2067.         if (nCount&1) {
  2068.             RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
  2069.             cColA.r,cColA.g,cColA.b);
  2070.         } else {
  2071.             RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
  2072.             cColB.r,cColB.g,cColB.b);
  2073.         };
  2074.  
  2075.         RwSetPolygonTexture(tpTube->ppaPoly[0][nCount],NULL);
  2076.     };
  2077.  
  2078.     rpRing->raRings[0].nType = RING_COLOR;
  2079. }
  2080.  
  2081. /****************************************************************************
  2082.  CreateRingRotate
  2083.  
  2084.  On entry    : Colour A
  2085.                     : Colour B
  2086.                     : Direction
  2087.  On exit    :
  2088.  */
  2089.  
  2090. void CreateRingRotate(Tube *tpTube,Ring *rpRing,
  2091.                                             RwRGBColor cColA,RwRGBColor cColB,int nDir)
  2092. {
  2093.     RingData *rdpR;
  2094.     rdpR = &rpRing->raRings[0];
  2095.  
  2096.     rdpR->nType = RING_ROTATE;
  2097.     rdpR->cColA = cColA;
  2098.     rdpR->cColB = cColB;
  2099.     rdpR->nParam1 = 0;
  2100.     rdpR->nParam2 = nDir;
  2101.  
  2102.     SetTubeColor(tpTube,cColA);
  2103. }
  2104.  
  2105. /****************************************************************************
  2106.  HandleRings
  2107.  */
  2108.  
  2109. void HandleRings(Tube *tpTube,Ring *rpRing)
  2110. {
  2111.     int nCount;
  2112.     RingData *rdpR;
  2113.  
  2114.     for (nCount=0;nCount<tpTube->nDepth-1;nCount++) {
  2115.         rdpR = &rpRing->raRings[nCount];
  2116.         switch (rdpR->nType) {
  2117.             case RING_COLOR: {
  2118.                 break;
  2119.             };
  2120.             case RING_ROTATE: {
  2121.                 RwSetPolygonColor(tpTube->ppaPoly[nCount][rdpR->nParam1],
  2122.                     rdpR->cColA.r,rdpR->cColA.g,rdpR->cColA.b);
  2123.                 rdpR->nParam1+=rdpR->nParam2;
  2124.                 if (rdpR->nParam1>tpTube->nWidth-1) {
  2125.                     rdpR->nParam1=0;
  2126.                 };
  2127.                 if (rdpR->nParam1<0) {
  2128.                     rdpR->nParam1 = tpTube->nWidth-1;
  2129.                 };
  2130.                 RwSetPolygonColor(tpTube->ppaPoly[nCount][rdpR->nParam1],
  2131.                     rdpR->cColB.r,rdpR->cColB.g,rdpR->cColB.b);
  2132.                 break;
  2133.             };
  2134.         };
  2135.     };
  2136. }
  2137.  
  2138. /****************************************************************************
  2139.  ScrollRings
  2140.  
  2141.  On entry    :
  2142.  On exit    :
  2143.  */
  2144.  
  2145. void ScrollRings(Tube *tpTube,Ring *rpRing)
  2146. {
  2147.     int nCount;
  2148.  
  2149.     for (nCount=tpTube->nDepth-3;nCount>=0;nCount--) {
  2150.         rpRing->raRings[nCount+1] = rpRing->raRings[nCount];
  2151.     };
  2152. }
  2153.  
  2154. /****************************************************************************
  2155.  CreateTextures
  2156.  
  2157.  On entry    : Texture structure
  2158.  On exit    :
  2159.  */
  2160.  
  2161. void CreateTextures(Textures *tpTextures)
  2162. {
  2163.     char saTextureFiles[][14]={
  2164.         "mandel",
  2165.         "bird",
  2166.         "face",
  2167.         "marble",
  2168.         "marble",
  2169.         "wood",
  2170.         "rust"};
  2171.     int nCount;
  2172.  
  2173.     tpTextures->nAmoTextures = 7;
  2174.     for (nCount=0;nCount<tpTextures->nAmoTextures;nCount++) {
  2175.         tpTextures->taTextures[nCount] = RwReadNamedTexture(saTextureFiles[nCount]);
  2176.     };
  2177. }
  2178.  
  2179. /****************************************************************************
  2180.  Main
  2181.  */
  2182.  
  2183. void main(int nArgc,char *saArgv[])
  2184. {
  2185.     int nKey;
  2186.     int nMouseX,nMouseY,nMouseBut,nOldMouseBut,nOldMouseX,nOldMouseY;
  2187.     int nChange;
  2188.     int nStatus;
  2189.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  2190.     RwReal naBlack[]={CREAL(0.0),CREAL(0.0),CREAL(0.0)};
  2191.     int nWhite;
  2192.     int nBlack;
  2193.     RwReal nPointX;
  2194.     RwReal nPointY;
  2195.     RwImageConvert ciConvert;
  2196.     RwPointerImage piImage;
  2197.     RwClump *cpHit;
  2198.     Object *opHit;
  2199.     int nSpeed;
  2200.     char *cpTmp;
  2201.     int nCtrlShift=0;
  2202.     int nGeo = FALSE;
  2203.     int nCount;
  2204.  
  2205.     /* Default speed */
  2206.  
  2207.     nSpeed = 8;
  2208.  
  2209.     /* Parse the command line */
  2210.  
  2211.     for (nCount=1;nCount<nArgc;nCount++) {
  2212.         if (!strcmp("-o",saArgv[nCount])) {
  2213.             nGeo = TRUE;
  2214.         } else {
  2215.             cpTmp = saArgv[nCount];
  2216.             while ((*cpTmp>='0')&&(*cpTmp<='9')) {
  2217.                 cpTmp++;
  2218.             };
  2219.             if (!*cpTmp) {
  2220.                 nSpeed = atoi(saArgv[nCount]);
  2221.             } else {
  2222.                 nArgc = 4;
  2223.                 break;
  2224.             };
  2225.         };
  2226.     };
  2227.  
  2228.     if (nArgc>=4) {
  2229.         printf("Usage : %s [-o] [Speed]\n",saArgv[1]);
  2230.         printf("Smaller is faster (1 fastest) 8 default\n");
  2231.         printf("-o uses objects instead of simple geomety\n");
  2232.         exit(1);
  2233.     };
  2234.  
  2235.     if (!Init3D(saArgv[0]))
  2236.     {
  2237.         exit(-1);
  2238.     };
  2239.  
  2240.   nWhite = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  2241.   nBlack =  RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack)),
  2242.  
  2243.     /* Create the tube */
  2244.  
  2245.     tGTube.nWidth = 8;
  2246.     tGTube.nDepth = 18;
  2247.     tGTube.nSegLength = CREAL(1.3);
  2248.     tGTube.nSize = CREAL(1.0);
  2249.     tGTube.nOffAngle = CREAL(10.0);
  2250.     tGTube.nSteps=nSpeed;
  2251.  
  2252.     CreateTube(&tGTube);
  2253.     RwAddClumpToScene(Scene, tGTube.cpTube);
  2254.     CreateTextures(&tGTube.DispTextures);
  2255.  
  2256.     /* Set up the mouse pointers */
  2257.  
  2258.     ciConvert.inimage = sGMouseArrow;
  2259.     ciConvert.w = MOUSE_ARROW_W;
  2260.     ciConvert.h = MOUSE_ARROW_H;
  2261.     ciConvert.colora = nBlack;
  2262.     ciConvert.colorb = nWhite;
  2263.     ciConvert.outstorage = NULL;
  2264.  
  2265.   RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
  2266.     pGMouseArrow = ciConvert.outstorage;
  2267.  
  2268.     ciConvert.inimage = sGMouseFire;
  2269.     ciConvert.w = MOUSE_FIRE_W;
  2270.     ciConvert.h = MOUSE_FIRE_H;
  2271.     ciConvert.outstorage = NULL;
  2272.  
  2273.   RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
  2274.     pGMouseFire = ciConvert.outstorage;
  2275.  
  2276.     ciConvert.inimage = sGMouseSight;
  2277.     ciConvert.w = MOUSE_SIGHT_W;
  2278.     ciConvert.h = MOUSE_SIGHT_H;
  2279.     ciConvert.outstorage = NULL;
  2280.  
  2281.   RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
  2282.     pGMouseSight = ciConvert.outstorage;
  2283.  
  2284.     /* Creation of objects */
  2285.  
  2286.     AllObjectsCreate(&aoGObjects);
  2287.     StackObjectsCreate(&aoGObjects.sObjects,nGeo);
  2288.     StackExplosionCreate(&aoGObjects.sExplosion);
  2289.     LaunchCreate(&lGLaunch,40);
  2290.  
  2291.     /* Create pointer */
  2292.  
  2293.     RwDPointerDisplay(&nOldMouseX,&nOldMouseY,&nOldMouseBut);
  2294.  
  2295.     nKey = DosGetKey();
  2296.     nStatus =0;
  2297.  
  2298.     while (nKey!=27) {        /* ESC quits */
  2299.         RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
  2300.  
  2301.         if (nGFireCount) {
  2302.             nGFireCount--;
  2303.         };
  2304.         nGPickStatus = 0;
  2305.  
  2306.         if (nMouseY<nGScrHeight-24) {
  2307.             if (RwPickScene(Scene, nMouseX, nMouseY, Camera, &pGPick)) {
  2308.                 if (pGPick.type==rwPICKCLUMP) {
  2309.                     cpHit = pGPick.object.clump.clump;
  2310.                     opHit =(Object *)RwGetClumpData(cpHit);
  2311.  
  2312.                     if (opHit) {
  2313.                         nGPickStatus = 1;
  2314.  
  2315.                     /* Explode the object */
  2316.                         piImage.hotx = MOUSE_FIRE_X;
  2317.                         piImage.hoty = MOUSE_FIRE_Y;
  2318.                         piImage.w = MOUSE_FIRE_W;
  2319.                         piImage.h = MOUSE_FIRE_H;
  2320.                         piImage.image= pGMouseFire;
  2321.  
  2322.             RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
  2323.  
  2324.                         if (nGFireCount) {
  2325.                             /* Explode the object */
  2326.                             CreateExplosion
  2327.                                 (&aoGObjects,&opHit->vPos,&opHit->vVel,EXPLOSION_BITS);
  2328.                             AllObjectsRemove(&aoGObjects,&aoGObjects.sObjects,opHit);
  2329.                         };
  2330.                     };
  2331.                 };
  2332.             };
  2333.         };
  2334.  
  2335.         if (!nGPickStatus) {
  2336.             piImage.hotx = MOUSE_SIGHT_X;
  2337.             piImage.hoty = MOUSE_SIGHT_Y;
  2338.             piImage.w = MOUSE_SIGHT_W;
  2339.             piImage.h = MOUSE_SIGHT_H;
  2340.             piImage.image= pGMouseSight;
  2341.  
  2342.       RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
  2343.         };
  2344.  
  2345.  
  2346.         UpdateTube(&tGTube,&rGRing);
  2347.  
  2348.         /* The other bits */
  2349.  
  2350.  
  2351.         nPointX = RDiv(INT2REAL(nMouseX-(nGScrWidth>>1)),
  2352.            INT2REAL((nGScrWidth>>1)));
  2353.         if (nMouseY<=nGScrHeight-24) {
  2354.              nPointY = RDiv(INT2REAL(nMouseY-((nGScrHeight-24)>>1)),
  2355.                     INT2REAL((nGScrHeight-24)>>1));
  2356.         } else {
  2357.             nPointY = CREAL(1.0);
  2358.         };
  2359.  
  2360.  
  2361.         RwSetCameraPosition(Camera,RMul(nPointX,CREAL(0.58)),
  2362.         -RMul(nPointY,CREAL(0.58)),-DEFAULT_CAMERA_DISTANCE);
  2363.  
  2364.         nKey = DosGetKey();
  2365.  
  2366.         nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
  2367.  
  2368.         switch (nChange) {
  2369.             case 0+0:
  2370.             case 2+1:
  2371.             case 8+4:
  2372.             case 8+2+4+1: {
  2373.                 /* No change */
  2374.                 break;
  2375.             };
  2376.             case 2:
  2377.             case 8+2+4: {
  2378.  
  2379.                 /* Left Button Down */
  2380.  
  2381.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  2382.  
  2383.  
  2384.                 break;
  2385.             };
  2386.             case 8:
  2387.             case 8+2+1: {
  2388.                 /* Right Button Down */
  2389.  
  2390.  
  2391.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  2392.  
  2393.  
  2394.                 break;
  2395.             };
  2396.             case 8+1: {
  2397.                 /* Right down left Up */
  2398.  
  2399.  
  2400.                 HandleLeftButtonUp();
  2401.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  2402.  
  2403.  
  2404.                 break;
  2405.             };
  2406.             case 2+4: {
  2407.                 /* Right up left Down */
  2408.  
  2409.  
  2410.                 HandleRightButtonUp();
  2411.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  2412.  
  2413.  
  2414.                 break;
  2415.             };
  2416.             case 8+2: {
  2417.                 /* Left down RIght Down */
  2418.  
  2419.  
  2420.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  2421.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  2422.  
  2423.  
  2424.                 break;
  2425.             };
  2426.             case 1+4: {
  2427.                 /* Left up Right Up */
  2428.  
  2429.  
  2430.                 HandleRightButtonUp();
  2431.                 HandleLeftButtonUp();
  2432.  
  2433.  
  2434.                 break;
  2435.             };
  2436.             case 1:
  2437.             case 8+4+1: {
  2438.                 /* Left up */
  2439.  
  2440.  
  2441.                 HandleLeftButtonUp();
  2442.  
  2443.  
  2444.                 break;
  2445.             };
  2446.             case 4:
  2447.             case 2+4+1: {
  2448.                 /* Right up */
  2449.                 HandleRightButtonUp();
  2450.                 break;
  2451.             };
  2452.         };
  2453.  
  2454.         EnemyLaunchHandler(&lGLaunch,&aoGObjects);
  2455.         AllObjectsUpdate(&aoGObjects);
  2456.  
  2457.         HandleTimer();
  2458.  
  2459.         nOldMouseX = nMouseX;
  2460.         nOldMouseY = nMouseY;
  2461.         nOldMouseBut = nMouseBut;
  2462.     };
  2463.  
  2464.  
  2465.     /*
  2466.     * Tidy up the 3D (RenderWare) components of the application.
  2467.     */
  2468.  
  2469.     TidyUp3D();
  2470.  
  2471.     exit(0);
  2472. }
  2473.  
  2474.