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

  1. /**********************************************************************
  2.  *
  3.  * File :     dosmaze.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.  *
  38.  * Header files.
  39.  *
  40.  **********************************************************************/
  41.  
  42. #include <i86.h>
  43.  
  44. #include <stdlib.h>
  45. #include <stdio.h>
  46.  
  47. #include <string.h>
  48. #include <math.h>    /* Required for floating point */
  49.  
  50.  
  51. #include "rwlib.h"
  52. #include "rwtypes.h"
  53.  
  54. #include "rwdos.h"
  55. #include "doswrap.h"
  56.  
  57. #include "palette.h"
  58.  
  59. /**********************************************************************
  60.  *
  61.  * Application constants.
  62.  *
  63.  **********************************************************************/
  64.  
  65. /* Key code for delete key */
  66.  
  67. #define DELETE 8
  68. #define BOOL int
  69.  
  70. /*
  71.  * MS Windows compatible defines
  72.  */
  73.  
  74. #define MK_CONTROL 0x4
  75. #define MK_SHIFT 0x2
  76.  
  77.  
  78. /**********************************************************************
  79.  *
  80.  * Type definitions.
  81.  *
  82.  **********************************************************************/
  83.  
  84. /*
  85.  * This enumerated type tells us what kind of action should be taken
  86.  * on mouse events.
  87.  */
  88. typedef enum
  89. {
  90.     MMNoAction,
  91.     MMPanAndZoomCamera,
  92.     MMTiltCamera,
  93.     MMPanLight
  94. } MMMode;
  95.  
  96. /**********************************************************************
  97.  *
  98.  * Application global variables.
  99.  *
  100.  **********************************************************************/
  101.  
  102. /*
  103.  Screen size
  104.  */
  105.  
  106. static int nGScrWidth;
  107. static int nGScrHeight;
  108.  
  109. /*
  110.  Colour Codes
  111.  */
  112.  
  113. static int nGTextCol;
  114. static int nGMapCol;
  115. static int nGCrossCol;
  116.  
  117. /*
  118.  * The Menu option state
  119.  */
  120. static int         DrawHUD;
  121.  
  122. /*
  123.  * Global RenderWare object pointers. In this simple application we
  124.  * make use of only a single scene, camera and light.
  125.  */
  126. static RwScene    *Scene  = NULL;
  127. static RwCamera   *Camera = NULL;
  128. static RwLight    *Light  = NULL;
  129.  
  130. /*
  131.  * This matrix is used when spinning a clump, it is stored globally
  132.  * so that it is not necessary to re-build the matrix for each frame of
  133.  * animation.
  134.  */
  135. static RwReal    forward,pan;
  136.  
  137.  
  138. /*
  139.  * This variable tells us what kind of action to take on a mouse move.
  140.  * The action depends on the object that was picked when the mouse button
  141.  * went down, and on the selection of virtual keys that were depressed at
  142.  * that time. By default no action is taken on mouse move.
  143.  */
  144. static MMMode      MouseMoveMode = MMNoAction;
  145.  
  146. /* These are stored in the ClumpData field and specify what animation
  147.  * to perform at each tick.
  148.  */
  149. #define DONOTHING    0
  150. #define SPINFADE     1
  151. #define SPIN         2
  152. #define TUMBLE       3
  153.  
  154. /*
  155.  * Global variables used to remember the last mouse X and Y coordinates
  156.  * when involved in a pan, zoom, drag or spin.
  157.  */
  158. static int         LastX;
  159. static int         LastY;
  160.  
  161. /*
  162.  * This flag indicates whether the 3D components of the application
  163.  * have been successfully initialized as yet. It is used to guard
  164.  * the message loop handler functions from being invoked before the
  165.  * 3D components of the application are successfully initialized.
  166.  */
  167. static BOOL        ThreeDInitialized = FALSE;
  168.  
  169.  
  170. #define DUNWIDTH    34
  171. #define DUNHEIGHT   29
  172. char map[DUNHEIGHT][DUNWIDTH] =
  173. {
  174.     {".................................."},
  175.     {"...................1@4*..........."},
  176.     {"...................*..*..........."},
  177.     {"...................3..2..........."},
  178.     {"..............a*****..**d***......"},
  179.     {"..............****......****......"},
  180.     {"..............****......****......"},
  181.     {"..............***C......****......"},
  182.     {"..............3............3......"},
  183.     {".........e*****.......a*****......"},
  184.     {".........****.........****........"},
  185.     {".........****.........****........"},
  186.     {".........***B.........***A........"},
  187.     {".........3............3..........."},
  188.     {"......1***.........1***..........."},
  189.     {"......*............*.............."},
  190.     {"......b***.........b***..........."},
  191.     {"......****.........****..........."},
  192.     {"......****.........****..........."},
  193.     {"......****4*.......***B4*........."},
  194.     {"...........*............*........."},
  195.     {"...........2.........c***........."},
  196.     {"...........**d***....****........."},
  197.     {".............****....****........."},
  198.     {".............****..1*****........."},
  199.     {".............****..*.............."},
  200.     {"................2..3.............."},
  201.     {"................****.............."},
  202.     {".................................."}
  203. };
  204.  
  205. #define CLOSEST    CREAL(0.1)
  206. #define NORTH    1
  207. #define EAST     2
  208. #define SOUTH    4
  209. #define WEST     8
  210. typedef struct _dcell
  211. {
  212.     int    tag;
  213.     RwClump     *geometry,*hgeometry,*vgeometry;
  214.     RwMatrix4d  *mat;
  215.     struct _dcell *horizontal,*vertical;
  216.     int    walls;
  217.     RwScene    *contents;
  218.     int    dobacking;
  219. } Dcell;
  220.  
  221. Dcell dungeon[DUNHEIGHT][DUNWIDTH];
  222.  
  223. /**********************************************************************
  224.  *
  225.  * Functions.
  226.  *
  227.  **********************************************************************/
  228.  
  229. /****************************************************************************
  230.  DosDrawLine
  231.  
  232.  Draws a line from (xcord,ycord) to (xcord2,ycord2) on a cameras image raster.
  233.  
  234.  On entry    : Camera to write to
  235.                     : xcord1
  236.                     : ycord1
  237.                     : xcord2
  238.                     : ycord2
  239.                     : colour
  240.  */
  241.  
  242. void DosDrawLine(RwCamera *pCamera,
  243.                                  int xcord,
  244.                                  int ycord,
  245.                                  int xcord2,
  246.                                  int ycord2,
  247.                                  unsigned int colour)
  248. {
  249.     RwReal x1,y1,x2,y2;
  250.     RwReal dx, dy, tmp;
  251.     int count;
  252.     int p, q;
  253.     unsigned char *cpScreen;
  254.     RwReal vpr,vpb;
  255.     RwRaster *rpRaster;
  256.     int nWidth,nHeight,nDepth,nStride;
  257.  
  258.     rpRaster = (RwRaster *) RwGetCameraImage(pCamera);
  259.  
  260.     nWidth = RwGetRasterWidth(rpRaster);
  261.     nHeight = RwGetRasterHeight(rpRaster);
  262.  
  263.     if ((xcord<0)||(xcord>=nWidth) ||
  264.           (ycord<0)||(ycord>=nHeight)) {
  265.         return;
  266.     };
  267.  
  268.     nDepth = RwGetRasterDepth(rpRaster);
  269.     nStride = RwGetRasterStride(rpRaster);
  270.  
  271.     vpr = INT2REAL(nWidth);
  272.     vpb = INT2REAL(nHeight);
  273.  
  274.     x1 = INT2REAL(xcord);
  275.     y1 = INT2REAL(ycord);
  276.     x2 = INT2REAL(xcord2);
  277.     y2 = INT2REAL(ycord2);
  278.  
  279.     if (x2 < x1)
  280.     {
  281.         tmp = x1;
  282.         x1 = x2;
  283.         x2 = tmp;
  284.         tmp = y1;
  285.         y1 = y2;
  286.         y2 = tmp;
  287.     }
  288.  
  289.     if (x2 == vpr)
  290.     {
  291.         if (x1 == vpr){
  292.             return;
  293.         };
  294.         dx = RSub(x2,x1);
  295.         dy = RSub(y2,y1);
  296.         dy = (dy < 0)? -dy : dy;
  297.         if (dy > dx) {
  298.             x2 = RSub(x2,CREAL( 1));
  299.         };
  300.     }
  301.     if ((y1 == vpb)||(y2 == vpb))
  302.     {
  303.         if (y1==y2) {
  304.             return;
  305.         };
  306.         if (y1 == vpb) {
  307.             y1 = RSub(y1,CREAL(1));
  308.         } else {
  309.             dx = RSub(x2,x1);
  310.             dy = RSub(y2,y1);
  311.             if (dy < dx) {
  312.                 y2 = RSub(y2,CREAL(1));
  313.             };
  314.         }
  315.     }
  316.  
  317.     dx = RSub(x2,x1);
  318.     dy = RSub(y2,y1);
  319.  
  320.     p = REAL2INT(dx);
  321.     q = REAL2INT(dy);
  322.  
  323.     if (q < 0) {
  324.         q = -q;
  325.     };
  326.     count = p;
  327.     if (count < q) {
  328.         count = q;
  329.     };
  330.  
  331.     /* We can get x's and y's that fall on the first pixel outside the image
  332.     buffer. So we do some shortening here */
  333.  
  334.     if (count)
  335.     {
  336.         dx = RDiv(dx,INT2REAL(count));
  337.         dy = RDiv(dy,INT2REAL(count));
  338.     };
  339.  
  340.     count++;
  341.  
  342.     /* Draw the line at the correct depth */
  343.  
  344.     cpScreen = RwGetRasterPixels(rpRaster);
  345.  
  346.     if (nDepth==8) {
  347.         while (count--)
  348.         {
  349.             cpScreen[nStride*(REAL2INT(y1))+(REAL2INT(x1))] = colour;
  350.             x1 = RAdd(x1,dx);
  351.             y1 = RAdd(y1,dy);
  352.         }
  353.     } else {
  354.         /* Assume 16 bit */
  355.         while (count--)
  356.         {
  357.             cpScreen[nStride*(REAL2INT(y1))+((REAL2INT(x1))<<1)] = colour;
  358.             cpScreen[nStride*(REAL2INT(y1))+((REAL2INT(x1))<<1) +1] = (colour>>8);
  359.             x1 = RAdd(x1,dx);
  360.             y1 = RAdd(y1,dy);
  361.         }
  362.     };
  363. }
  364.  
  365. /****************************************************************************
  366.  DosPrintString
  367.  
  368.  Print a string using the DOS character printing DeviceControl.
  369.  
  370.  On entry     : xcord
  371.                         : ycord
  372.                         : string
  373.                         : colour
  374.  On exit        :
  375.  */
  376.  
  377. void DosPrintString(int nX,int nY,char *sString,int nCol)
  378. {
  379.     for (;(*sString);sString++)  {
  380.         RwDPrintChar(nX,nY,(*sString),nCol);
  381.         nX+=8;
  382.     };
  383. }
  384.  
  385.  
  386. /****************************************************************************
  387.  DosTimer
  388.  
  389.  Uses the DOS 18 per sec timer to find time in millisecs.
  390.  
  391.  On entry    :
  392.  On exit    : Timer (in milliseconds)
  393.  */
  394.  
  395. int DosTimer(void)
  396. {
  397.     union REGS r;
  398.     int nTime;
  399.  
  400.     r.h.ah=0;
  401.  
  402.     int386(0x1a,&r,&r);
  403.  
  404.     nTime = ((r.w.cx)<<16)|(r.w.dx);
  405.  
  406.     return (nTime*55);
  407. }
  408.  
  409. /****************************************************************************
  410.  DosGetKey
  411.  
  412.  Get the key pressed (ascii), 0 if no key pressed.
  413.  
  414.  On entry    :
  415.  On exit     : Key pressed in ascii (or 0 if no key pressed)
  416.  */
  417.  
  418. int DosGetKey(void)
  419. {
  420.     union REGPACK rp;
  421.  
  422.     memset(&rp,0,sizeof(rp));
  423.     rp.h.ah = 0x06;
  424.     rp.h.dl = 0xff;
  425.  
  426.     intr(0x21,&rp);
  427.  
  428.     if (!(rp.w.flags & 0x40 )) {       /* Check Z flag */
  429.         /* Got key */
  430.  
  431.         if (rp.h.al) {
  432.             return ((int)rp.h.al);
  433.         };
  434.  
  435.         memset(&rp,0,sizeof(rp));
  436.         rp.h.ah = 0x06;
  437.         rp.h.dl = 0xff;
  438.         intr(0x21,&rp);
  439.  
  440.         if (!(rp.w.flags & 0x40)) {
  441.             return ((int)rp.h.al);
  442.         };
  443.  
  444.         return (rp.h.al|0x80);
  445.     };
  446.  
  447.     return 0;
  448. }
  449.  
  450. /****************************************************************************
  451.  DosShiftCtrl
  452.  
  453.  Find the status of the Shift,Ctrl etc keys.
  454.  
  455.  On entry    :
  456.  On exit    : Bit         Meaning
  457.                         0                Right Shift
  458.                         1                Left Shift
  459.                         2                Ctrl
  460.                         3                Alt
  461.                         4       Scroll Lock
  462.                         5                Num Lock
  463.                         6             Caps Lock
  464.                         7                Insert on
  465.  */
  466.  
  467. int DosShiftCtrl(void)
  468. {
  469.     union REGPACK rp;
  470.  
  471.     memset(&rp,0,sizeof(rp));
  472.  
  473.     rp.h.ah=0x02;
  474.     intr(0x16,&rp);
  475.  
  476.     return ((int)rp.h.al);
  477. }
  478.  
  479. /**********************************************************************/
  480.  
  481. /*
  482.  * This function initializes the 3D (i.e. RenderWare) components of the
  483.  * application. This function opens the RenderWare library, creates a
  484.  * camera, a scene, a light and a matrix for spinning. A user-draw may
  485.  * also be created if USERDRAW_LABELS is defined.
  486.  */
  487.  
  488. static BOOL
  489. Init3D(char *sFilename)
  490. {
  491.     RwClump *Room,*RoomSky,*Turn,*TurnF,*TurnB,*clump;
  492.     RwMatrix4d *mat;
  493.     int      x,y,dx,dy,i;
  494.     char     windowText[128];
  495.     char     version[30];
  496.     char     buffer[128];
  497.     int      param;
  498.         RwReal naTextCol[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  499.         RwReal naMapCol[]={CREAL(0.0),CREAL(1.0),CREAL(0.0)};
  500.         RwReal naCrossCol[]={CREAL(1.0),CREAL(0.0),CREAL(1.0)};
  501.         long nError;
  502.     RwReal naBlack[] = {CREAL(0.0),CREAL(0.0),CREAL(0.0)};
  503.     int nBlack;
  504.     RwPointerImage piImage;
  505.  
  506.  
  507.     /*
  508.      * Attempt to open (and initialize) the RenderWare library.
  509.      * Explicitly specifying the MS Windows driver. The MS Windows
  510.      * device driver requires the application's instance handle so
  511.      * this is passed in as the device specific parameter to RwOpen().
  512.      */
  513.  
  514.     if (!RwOpen("DOSMOUSE", &nError))
  515.     {
  516.         printf("Unable to access renderware!!\n");
  517.         switch (nError) {
  518.             case E_RW_DOS_MODE_UNAVAILABLE: {
  519.                printf("The installed VESA card is unable to switch to the resolution");
  520.                 printf(" requested.\n");
  521.                 printf("Either install a different video adapter or use a ");
  522.                 printf("supported video mode.");
  523.                 break;
  524.             };
  525.             case E_RW_DOS_NO_VESA_BIOS: {
  526.                 printf("A VESA bios is unavailable on this machine.\n");
  527.                 printf("Either use a VESA compatible Video Adapter or install a ");
  528.                 printf("VESA bios emulation TSR.\n");
  529.                 break;
  530.             };
  531.             case E_RW_DOS_INCOMPATIBLE_BIOS: {
  532.                 printf("The VESA bios on this machine is not of high enough version ");
  533.                 printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
  534.                 printf(" higher VESA bios or TSR.\n");
  535.                 break;
  536.             };
  537.             case E_RW_DOS_NO_MOUSE: {
  538.                 printf("No Microsoft compatible mouse driver present.\n");
  539.                 printf("Install a microsoft compatible mouse driver and try again.\n");
  540.                 break;
  541.             };
  542.             default: {
  543.                 printf("Unknown Error !!!!!!!!!!!!!!!\n");
  544.                 break;
  545.             };
  546.         };
  547.         return FALSE;
  548.     }
  549.  
  550.   /* Load in the palette */
  551.  
  552.   CheckAndReadPalette("rwmaze.pal");
  553.  
  554.   nGTextCol = RwDeviceControl(rwSCRGETCOLOR,0,naTextCol,sizeof(naTextCol));
  555.   nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack));
  556.  
  557.   /* Rematch the pointer image */
  558.  
  559.   piImage.image = NULL;
  560.   piImage.hotx=0;
  561.   piImage.hoty=0;
  562.   piImage.w = nBlack;
  563.   piImage.h = nGTextCol;
  564.  
  565.   RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
  566.  
  567.     /* Set up the DOS Character Set */
  568.  
  569.   RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
  570.   RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrHeight));
  571.  
  572.   nGMapCol = RwDeviceControl(rwSCRGETCOLOR,0,naMapCol,sizeof(naMapCol));
  573.   nGCrossCol = RwDeviceControl(rwSCRGETCOLOR,0,naCrossCol,sizeof(naCrossCol));
  574.  
  575.     RwSetShapePath(".",rwPRECONCAT);
  576.  
  577.     strcpy(buffer,sFilename);
  578.  
  579.     i = strlen(buffer);
  580.     while((buffer[i] != '\\')&&(i>=0)) {
  581.         i--;
  582.     };
  583.  
  584.  
  585.     if (i>=0) {
  586.         buffer[i+1] = 0;
  587.         strcat(buffer, "TEXTURES");
  588.         RwSetShapePath(buffer, rwPOSTCONCAT);
  589.  
  590.         buffer[i+1] = 0;
  591.         strcat(buffer, "SCRIPTS");
  592.         RwSetShapePath(buffer, rwPOSTCONCAT);
  593.     };
  594.  
  595.     RwSetShapePath("SCRIPTS", rwPRECONCAT);
  596.     RwSetShapePath("TEXTURES", rwPRECONCAT);
  597.  
  598.  
  599.     /*    RwOpenDebugStream("DEBUG:");    */
  600.  
  601.     /*
  602.     * Label the window with information about the version of
  603.     * RenderWare being used. Its rather unlikely that
  604.     * RwGetSystemInfo() will fail so we ignore its return value.
  605.     */
  606.  
  607.   RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
  608.   RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
  609.     sprintf(windowText, "DosMaze V%s %s",
  610.         version, (param ? "Fixed" : "Float"));
  611.     DosPrintString(0,nGScrHeight-16,windowText,nGTextCol);
  612.  
  613.  
  614.     /*
  615.     * Create the camera which will be used for rendering. The initial window
  616.     * size the application will create is given by nGScrWidth and
  617.     * nGScrHeight-17 which depends on the screen res used.
  618.     */
  619.  
  620.     Camera = RwCreateCamera(nGScrWidth,nGScrHeight-17, NULL);
  621.     if (!Camera)
  622.     {
  623.     /*
  624.     * As with RwOpen(), the most common cause for a failure to create
  625.     * a camera is insufficient memory so we will explicitly check for
  626.     * this condition and report it. Otherwise a general error is issued.
  627.     */
  628.         if (RwGetError() == E_RW_NOMEM)
  629.         {
  630.             RwClose();
  631.             printf("Insufficient memory to create the RenderWare(tm) camera\n");
  632.         }
  633.         else
  634.         {
  635.             RwClose();
  636.             printf("Error creating the RenderWare(tm) camera\n");
  637.         }
  638.         exit(-1);
  639.     }
  640.  
  641.  
  642.     /*
  643.      * The window has been resized. Therefore, it is necessary to
  644.      * to modify the camera's viewport to be the same size as the
  645.      * client area of the window.
  646.      */
  647.     RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
  648.  
  649.     RwSetCameraBackdropViewportRect(Camera, 0,0,nGScrWidth,nGScrHeight-24);
  650.  
  651.     /* aspect ratio of 1:1 */
  652.  
  653.         if (nGScrWidth >= (nGScrHeight-24)) {
  654.         RwSetCameraViewwindow(Camera,
  655.             CREAL(1.0),
  656.             RMul(CREAL(1.0), RDiv(INT2REAL(nGScrHeight-24), INT2REAL(nGScrWidth))));
  657.         } else {
  658.             RwSetCameraViewwindow(Camera,
  659.             RMul(CREAL(1.0), RDiv(INT2REAL(nGScrWidth), INT2REAL(nGScrHeight-24))),
  660.             CREAL(1.0));
  661.         };
  662.  
  663.     /*
  664.      * Set the camera's background color to cyan.
  665.      */
  666.     RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.8), CREAL(0.8));
  667.  
  668.     RwSetCameraBackdrop(Camera, RwReadRaster("backgrou", rwDITHERRASTER) );
  669.     RwSetCameraBackdropOffset(Camera, 0,0);
  670.  
  671.     /*
  672.      * Create a scene which will contain the clumps to be rendered and the
  673.      * light or lights illuminating those clumps . In this very simple
  674.      * application it would be perfectly acceptable to use the default scene
  675.      * (as returned by RwDefaultScene()) for rendering. However, it is good
  676.      * practice to always create a scene which will be used for your rendering
  677.      * and only use the default scene as a bag for currently unused clumps and
  678.      * lights.
  679.      */
  680.  
  681.     Scene = RwCreateScene();
  682.     if (!Scene)
  683.     {
  684.         RwDestroyCamera(Camera);
  685.         RwClose();
  686.         printf("Error creating the RenderWare(tm) scene\n");
  687.         exit(-1);
  688.     }
  689.  
  690.     /*
  691.      * Our scene will be illuminated by a directional light. The illumination
  692.      * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  693.      */
  694.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-0.5), CREAL(-1.0), CREAL(0.5),
  695.                           CREAL(1.0));
  696.     if (!Light)
  697.     {
  698.         RwDestroyScene(Scene);
  699.         RwDestroyCamera(Camera);
  700.         RwClose();
  701.         printf("Error creating the RenderWare(tm) light\n");
  702.         exit(-1);
  703.     }
  704.  
  705.  
  706.     /*
  707.      * Add the new light to our scene.
  708.      */
  709.     RwAddLightToScene(Scene, Light);
  710.  
  711.  
  712.     /* Create the maze components */
  713.     Turn = RwReadShape("turn.rwx");
  714.         if (!Turn) {
  715.             RwClose();
  716.             printf("Cant find turn.rwx\n");
  717.             exit(-1);
  718.         };
  719.         RwAddClumpToScene(Scene, Turn);
  720.  
  721.     TurnF = RwReadShape("turnf.rwx");
  722.         if (!TurnF) {
  723.             RwClose();
  724.             printf("Cant find turnf.rwx\n");
  725.             exit(-1);
  726.         };
  727.     RwAddClumpToScene(Scene, TurnF);
  728.  
  729.     TurnB = RwReadShape("turnb.rwx");
  730.         if (!TurnB) {
  731.             RwClose();
  732.             printf("Cant find turnb.rwx\n");
  733.             exit(-1);
  734.         };
  735.     RwAddClumpToScene(Scene, TurnB);
  736.  
  737.     Room = RwReadShape("mazeroom.rwx");
  738.         if (!Room) {
  739.             RwClose();
  740.             printf("Cant find mazeroom.rwx\n");
  741.             exit(-1);
  742.         };
  743.     RwAddClumpToScene(Scene, Room);
  744.  
  745.       RoomSky = RwReadShape("roomsky.rwx");
  746.         if (!RoomSky) {
  747.             RwClose();
  748.             printf("Cant find roomsky.rwx\n");
  749.             exit(-1);
  750.         };
  751.     RwAddClumpToScene(Scene, RoomSky);
  752.  
  753.         /*
  754.      * We now scan the array map[][] and for each cell we initialise
  755.      * the corresponding dungeon[][] entry with the appropriate
  756.      * geometry for this cell.  Since the room and corridor objects
  757.      * are larger than a single grid square, we arrange that the
  758.      * map[][] array specifies a tag in the top left corner of the
  759.      * room or corridor and the switch statement below ensures the
  760.      * related grids are initialised appropriately.
  761.      */
  762.  
  763.     for (y = 0; y<DUNHEIGHT; y++)
  764.     {
  765.         for (x = 0; x<DUNWIDTH; x++)
  766.         {
  767.             switch(map[y][x])
  768.             {
  769.             default:
  770.                 break;
  771.             case '@':
  772.                 RwSetCameraPosition(Camera, RAdd(CREAL(0.5),INT2REAL(x)),
  773.                                             CREAL(0.3),
  774.                                             RAdd(CREAL(0.5),INT2REAL(y)));
  775.                 RwSetCameraLookAt(Camera, CREAL(1.0),CREAL(0),CREAL(0));
  776.                 break;
  777.             case '1':
  778.                 dungeon[y][x].tag = '1';
  779.                 dungeon[y][x].geometry = Turn;
  780.                 dungeon[y][x].hgeometry = TurnB;
  781.                 dungeon[y][x].vgeometry = TurnF;
  782.                 mat = RwCreateMatrix();
  783.                 RwTranslateMatrix(mat,INT2REAL(x),CREAL(0),INT2REAL(y),rwREPLACE);
  784.                 dungeon[y][x].mat = mat;
  785.                 dungeon[y][x].vertical = &dungeon[y+2][x];
  786.                 dungeon[y][x].horizontal = &dungeon[y][x+2];
  787.                 dungeon[y][x].walls = WEST | NORTH;
  788.  
  789.                 dungeon[y][x+1] = dungeon[y][x];
  790.                 dungeon[y][x+1].walls = NORTH | SOUTH;
  791.                 dungeon[y+1][x] = dungeon[y][x];
  792.                 dungeon[y+1][x].walls = WEST | EAST;
  793.                 break;
  794.             case '2':
  795.                 dungeon[y][x].tag = '2';
  796.                 dungeon[y][x].geometry = Turn;
  797.                 dungeon[y][x].hgeometry = TurnF;
  798.                 dungeon[y][x].vgeometry = TurnB;
  799.                 mat = RwCreateMatrix();
  800.                 RwTranslateMatrix(mat,INT2REAL(x),CREAL(0),INT2REAL(y+2),rwREPLACE);
  801.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(90),rwPRECONCAT);
  802.                 dungeon[y][x].mat = mat;
  803.                 dungeon[y][x].vertical = &dungeon[y-1][x];
  804.                 dungeon[y][x].horizontal = &dungeon[y+1][x+2];
  805.                 dungeon[y][x].walls = WEST | EAST;
  806.  
  807.                 dungeon[y+1][x] = dungeon[y][x];
  808.                 dungeon[y+1][x].walls = WEST | SOUTH;
  809.                 dungeon[y+1][x+1] = dungeon[y][x];
  810.                 dungeon[y+1][x+1].walls = NORTH | SOUTH;
  811.                 break;
  812.             case '3':
  813.                 dungeon[y][x].tag = '3';
  814.                 dungeon[y][x].geometry = Turn;
  815.                 dungeon[y][x].hgeometry = TurnB;
  816.                 dungeon[y][x].vgeometry = TurnF;
  817.                 mat = RwCreateMatrix();
  818.                 RwTranslateMatrix(mat,INT2REAL(x+1),CREAL(0),INT2REAL(y+2),rwREPLACE);
  819.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(180),rwPRECONCAT);
  820.                 dungeon[y][x].mat = mat;
  821.                 dungeon[y][x].vertical = &dungeon[y-1][x];
  822.                 dungeon[y][x].horizontal = &dungeon[y+1][x-2];
  823.                 dungeon[y][x].walls = WEST | EAST;
  824.  
  825.                 dungeon[y+1][x-1] = dungeon[y][x];
  826.                 dungeon[y+1][x-1].walls = NORTH | SOUTH;
  827.                 dungeon[y+1][x] = dungeon[y][x];
  828.                 dungeon[y+1][x].walls = SOUTH | EAST;
  829.                 break;
  830.             case '4':
  831.                 dungeon[y][x].tag = '4';
  832.                 dungeon[y][x].geometry = Turn;
  833.                 dungeon[y][x].hgeometry = TurnF;
  834.                 dungeon[y][x].vgeometry = TurnB;
  835.                 mat = RwCreateMatrix();
  836.                 RwTranslateMatrix(mat,INT2REAL(x+2),CREAL(0),INT2REAL(y),rwREPLACE);
  837.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(-90),rwPRECONCAT);
  838.                 dungeon[y][x].mat = mat;
  839.                 dungeon[y][x].vertical = &dungeon[y+2][x+1];
  840.                 dungeon[y][x].horizontal = &dungeon[y][x-1];
  841.                 dungeon[y][x].walls = NORTH | SOUTH;
  842.  
  843.                 dungeon[y][x+1] = dungeon[y][x];
  844.                 dungeon[y][x+1].walls = NORTH | EAST;
  845.                 dungeon[y+1][x+1] = dungeon[y][x];
  846.                 dungeon[y+1][x+1].walls = WEST | EAST;
  847.                 break;
  848.             case 'a':
  849.                 dungeon[y][x].tag = 'a';
  850.                 dungeon[y][x].geometry = Room;
  851.                 dungeon[y][x].hgeometry = Room;
  852.                 dungeon[y][x].vgeometry = Room;
  853.                 mat = RwCreateMatrix();
  854.                 RwTranslateMatrix(mat,INT2REAL(x),CREAL(0),INT2REAL(y), rwREPLACE);
  855.                 dungeon[y][x].mat = mat;
  856.                 dungeon[y][x].vertical = &dungeon[y+4][x];
  857.                 dungeon[y][x].horizontal = &dungeon[y][x+4];
  858.  
  859.                 dungeon[y][x].walls = 0;
  860.                 for (dy=0; dy<4; dy++)
  861.                     for (dx=0; dx<4; dx++)
  862.                         dungeon[y+dy][x+dx] = dungeon[y][x];
  863.                 for (dy=0; dy<4; dy++)
  864.                 {
  865.                     for (dx=0; dx<4; dx++)
  866.                     {
  867.                         if (dx == 0)
  868.                             dungeon[y+dy][x+dx].walls |= WEST;
  869.                         if (dx == 3)
  870.                             dungeon[y+dy][x+dx].walls |= EAST;
  871.                         if (dy == 0)
  872.                             dungeon[y+dy][x+dx].walls |= NORTH;
  873.                         if (dy == 3)
  874.                             dungeon[y+dy][x+dx].walls |= SOUTH;
  875.                     }
  876.                 }
  877.                 /* punch holes for the two doors */
  878.                 dungeon[y][x+3].walls &= ~EAST;
  879.                 dungeon[y+3][x].walls &= ~SOUTH;
  880.                 break;
  881.             case 'b':
  882.                 dungeon[y][x].tag = 'b';
  883.                 dungeon[y][x].geometry = Room;
  884.                 dungeon[y][x].hgeometry = Room;
  885.                 dungeon[y][x].vgeometry = Room;
  886.                 mat = RwCreateMatrix();
  887.                 RwTranslateMatrix(mat,INT2REAL(x),CREAL(0),INT2REAL(y+4), rwREPLACE);
  888.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(90), rwPRECONCAT);
  889.                 dungeon[y][x].mat = mat;
  890.                 dungeon[y][x].vertical = &dungeon[y-1][x];
  891.                 dungeon[y][x].horizontal = &dungeon[y+3][x+4];
  892.  
  893.                 dungeon[y][x].walls = 0;
  894.                 for (dy=0; dy<4; dy++)
  895.                     for (dx=0; dx<4; dx++)
  896.                         dungeon[y+dy][x+dx] = dungeon[y][x];
  897.                 for (dy=0; dy<4; dy++)
  898.                 {
  899.                     for (dx=0; dx<4; dx++)
  900.                     {
  901.                         if (dx == 0)
  902.                             dungeon[y+dy][x+dx].walls |= WEST;
  903.                         if (dx == 3)
  904.                             dungeon[y+dy][x+dx].walls |= EAST;
  905.                         if (dy == 0)
  906.                             dungeon[y+dy][x+dx].walls |= NORTH;
  907.                         if (dy == 3)
  908.                             dungeon[y+dy][x+dx].walls |= SOUTH;
  909.                     }
  910.                 }
  911.                 /* punch holes for the two doors */
  912.                 dungeon[y][x].walls &= ~NORTH;
  913.                 dungeon[y+3][x+3].walls &= ~EAST;
  914.  
  915.                 break;
  916.             case 'c':
  917.                 dungeon[y][x].tag = 'c';
  918.                 dungeon[y][x].geometry = Room;
  919.                 dungeon[y][x].hgeometry = Room;
  920.                 dungeon[y][x].vgeometry = Room;
  921.                 mat = RwCreateMatrix();
  922.                 RwTranslateMatrix(mat,INT2REAL(x+4),CREAL(0),INT2REAL(y+4), rwREPLACE);
  923.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(180), rwPRECONCAT);
  924.                 dungeon[y][x].mat = mat;
  925.                 dungeon[y][x].vertical = &dungeon[y-1][x+3];
  926.                 dungeon[y][x].horizontal = &dungeon[y+3][x-1];
  927.  
  928.                 dungeon[y][x].walls = 0;
  929.                 for (dy=0; dy<4; dy++)
  930.                     for (dx=0; dx<4; dx++)
  931.                         dungeon[y+dy][x+dx] = dungeon[y][x];
  932.                 for (dy=0; dy<4; dy++)
  933.                 {
  934.                     for (dx=0; dx<4; dx++)
  935.                     {
  936.                         if (dx == 0)
  937.                             dungeon[y+dy][x+dx].walls |= WEST;
  938.                         if (dx == 3)
  939.                             dungeon[y+dy][x+dx].walls |= EAST;
  940.                         if (dy == 0)
  941.                             dungeon[y+dy][x+dx].walls |= NORTH;
  942.                         if (dy == 3)
  943.                             dungeon[y+dy][x+dx].walls |= SOUTH;
  944.                     }
  945.                 }
  946.                 /* punch holes for the two doors */
  947.                 dungeon[y+3][x].walls &= ~WEST;
  948.                 dungeon[y][x+3].walls &= ~NORTH;
  949.  
  950.                 break;
  951.             case 'd':
  952.                 dungeon[y][x].tag = 'd';
  953.                 dungeon[y][x].geometry = Room;
  954.                 dungeon[y][x].hgeometry = Room;
  955.                 dungeon[y][x].vgeometry = Room;
  956.                 mat = RwCreateMatrix();
  957.                 RwTranslateMatrix(mat,INT2REAL(x+4),CREAL(0),INT2REAL(y), rwREPLACE);
  958.                 RwRotateMatrix(mat, CREAL(0),CREAL(1),CREAL(0),CREAL(-90), rwPRECONCAT);
  959.                 dungeon[y][x].mat = mat;
  960.                 dungeon[y][x].vertical = &dungeon[y+4][x+3];
  961.                 dungeon[y][x].horizontal = &dungeon[y][x-1];
  962.  
  963.                 dungeon[y][x].walls = 0;
  964.                 for (dy=0; dy<4; dy++)
  965.                     for (dx=0; dx<4; dx++)
  966.                         dungeon[y+dy][x+dx] = dungeon[y][x];
  967.                 for (dy=0; dy<4; dy++)
  968.                 {
  969.                     for (dx=0; dx<4; dx++)
  970.                     {
  971.                         if (dx == 0)
  972.                             dungeon[y+dy][x+dx].walls |= WEST;
  973.                         if (dx == 3)
  974.                             dungeon[y+dy][x+dx].walls |= EAST;
  975.                         if (dy == 0)
  976.                             dungeon[y+dy][x+dx].walls |= NORTH;
  977.                         if (dy == 3)
  978.                             dungeon[y+dy][x+dx].walls |= SOUTH;
  979.                     }
  980.                 }
  981.                 /* punch holes for the two doors */
  982.                 dungeon[y][x].walls &= ~WEST;
  983.                 dungeon[y+3][x+3].walls &= ~SOUTH;
  984.  
  985.                 break;
  986.             case 'e':
  987.                 dungeon[y][x].tag = 'e';
  988.                 dungeon[y][x].geometry = RoomSky;
  989.                 dungeon[y][x].hgeometry = RoomSky;
  990.                 dungeon[y][x].vgeometry = RoomSky;
  991.                 mat = RwCreateMatrix();
  992.                 RwTranslateMatrix(mat,INT2REAL(x),CREAL(0),INT2REAL(y), rwREPLACE);
  993.                 dungeon[y][x].mat = mat;
  994.                 dungeon[y][x].vertical = &dungeon[y+4][x];
  995.                 dungeon[y][x].horizontal = &dungeon[y][x+4];
  996.                 dungeon[y][x].dobacking = 1;
  997.                 dungeon[y][x].walls = 0;
  998.                 for (dy=0; dy<4; dy++)
  999.                     for (dx=0; dx<4; dx++)
  1000.                         dungeon[y+dy][x+dx] = dungeon[y][x];
  1001.                 for (dy=0; dy<4; dy++)
  1002.                 {
  1003.                     for (dx=0; dx<4; dx++)
  1004.                     {
  1005.                         if (dx == 0)
  1006.                             dungeon[y+dy][x+dx].walls |= WEST;
  1007.                         if (dx == 3)
  1008.                             dungeon[y+dy][x+dx].walls |= EAST;
  1009.                         if (dy == 0)
  1010.                             dungeon[y+dy][x+dx].walls |= NORTH;
  1011.                         if (dy == 3)
  1012.                             dungeon[y+dy][x+dx].walls |= SOUTH;
  1013.                     }
  1014.                 }
  1015.                 /* punch holes for the two doors */
  1016.                 dungeon[y][x+3].walls &= ~EAST;
  1017.                 dungeon[y+3][x].walls &= ~SOUTH;
  1018.                 break;
  1019.             case 'A':
  1020.                 dungeon[y][x].contents = RwCreateScene();
  1021.                 for (dy=0; dy<4; dy++)
  1022.                     for (dx=0; dx<4; dx++)
  1023.                         dungeon[y-dy][x-dx].contents = dungeon[y][x].contents;
  1024.                 RwAddLightToScene(dungeon[y][x].contents, RwDuplicateLight(Light));
  1025.                 clump = RwReadShape("c.rwx");
  1026.                 RwTranslateMatrix(RwScratchMatrix(),CREAL(x-2),CREAL(0),CREAL(y-2), rwREPLACE);
  1027.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1028.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1029.                 RwSetClumpData(clump, SPINFADE);
  1030.  
  1031.                 clump = RwReadShape("cube.rwx");
  1032.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1033.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x),CREAL(0),CREAL(y), rwPRECONCAT);
  1034.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1035.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1036.                 RwSetClumpData(clump, TUMBLE);
  1037.                 break;
  1038.  
  1039.             case 'B':
  1040.                 dungeon[y][x].contents = RwCreateScene();
  1041.                 for (dy=0; dy<4; dy++)
  1042.                     for (dx=0; dx<4; dx++)
  1043.                         dungeon[y-dy][x-dx].contents = dungeon[y][x].contents;
  1044.                 RwAddLightToScene(dungeon[y][x].contents, RwDuplicateLight(Light));
  1045.                 clump = RwReadShape("cone.rwx");
  1046.                 RwTranslateMatrix(RwScratchMatrix(),CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1047.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x),CREAL(0),CREAL(y), rwPOSTCONCAT);
  1048.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1049.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1050.                 RwSetClumpData(clump, TUMBLE);
  1051.  
  1052.                 clump = RwReadShape("flames.rwx");
  1053.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1054.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x),CREAL(0),CREAL(y-3), rwPOSTCONCAT);
  1055.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1056.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1057.                 RwSetClumpData(clump, DONOTHING);
  1058.  
  1059.                 clump = RwReadShape("flames.rwx");
  1060.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1061.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x-2),CREAL(0),CREAL(y-3), rwPOSTCONCAT);
  1062.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1063.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1064.                 RwSetClumpData(clump, DONOTHING);
  1065.  
  1066.                 clump = RwReadShape("flames.rwx");
  1067.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1068.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x-1),CREAL(0),CREAL(y-1), rwPOSTCONCAT);
  1069.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1070.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1071.                 RwSetClumpData(clump, DONOTHING);
  1072.                 RwForAllPolygonsInClumpReal(clump, RwSetPolygonOpacity, CREAL(0.5));
  1073.                 break;
  1074.             case 'C':
  1075.                 dungeon[y][x].contents = RwCreateScene();
  1076.                 for (dy=0; dy<4; dy++)
  1077.                     for (dx=0; dx<4; dx++)
  1078.                         dungeon[y-dy][x-dx].contents = dungeon[y][x].contents;
  1079.                 RwAddLightToScene(dungeon[y][x].contents,
  1080.                   RwCreateLight(rwDIRECTIONAL,CREAL(0.5),CREAL(1),CREAL(0.5),CREAL(1)));
  1081.                 clump = RwReadShape("lampshade.rwx");
  1082.                 RwTranslateMatrix(RwScratchMatrix(),CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1083.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x-1),CREAL(1.5),CREAL(y-1), rwPOSTCONCAT);
  1084.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1085.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1086.                 RwSetClumpData(clump, TUMBLE);
  1087.                 clump = RwReadShape("slab.rwx");
  1088.                 RwTranslateMatrix(RwScratchMatrix(),CREAL(0.5),CREAL(0),CREAL(0.5), rwREPLACE);
  1089.                 RwTranslateMatrix(RwScratchMatrix(), CREAL(x-1),CREAL(1.5),CREAL(y-1), rwPOSTCONCAT);
  1090.                 RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  1091.                 RwAddClumpToScene(dungeon[y][x].contents, clump);
  1092.                 RwSetClumpData(clump, DONOTHING);
  1093.                 break;
  1094.             }
  1095.         }
  1096.     }
  1097.  
  1098.     /*
  1099.      * All the 3D components are now successfully initialized, so
  1100.      * work can begin...
  1101.      */
  1102.     ThreeDInitialized = TRUE;
  1103.  
  1104.     return TRUE;
  1105. }
  1106.  
  1107. /**********************************************************************/
  1108.  
  1109. /*
  1110.  * This function shuts down the 3D (i.e. RenderWare) components of the
  1111.  * application in a polite fashion.
  1112.  */
  1113. static void
  1114. TidyUp3D()
  1115. {
  1116. int x,y;
  1117.  
  1118.     /*
  1119.      * Re-parse the map[][] array and destroy any RenderWare objects we
  1120.      * we created in Init3D().  The geometry is all cleaned up by just
  1121.      * doing a RwDestroyScene() which will automatically destroy all
  1122.      * geometry in the scene along with any light sources.
  1123.      */
  1124.     for (y=0; y<DUNHEIGHT; y++)
  1125.     {
  1126.         for (x=0; x<DUNWIDTH; x++)
  1127.         {
  1128.             switch(map[y][x])
  1129.             {
  1130.             default:
  1131.             case '.':
  1132.             case '*':
  1133.                 break;
  1134.             case '1':
  1135.             case '2':
  1136.             case '3':
  1137.             case '4':
  1138.                 RwDestroyMatrix(dungeon[y][x].mat);
  1139.                 break;
  1140.             case 'a':
  1141.             case 'b':
  1142.             case 'c':
  1143.             case 'd':
  1144.                 if (dungeon[y][x].contents)
  1145.                     RwDestroyScene(dungeon[y][x].contents);
  1146.                 RwDestroyMatrix(dungeon[y][x].mat);
  1147.                 break;
  1148.             case 'R':
  1149.                 if (dungeon[y][x].contents)
  1150.                     RwDestroyScene(dungeon[y][x].contents);
  1151.                 RwDestroyMatrix(dungeon[y][x].mat);
  1152.                 break;
  1153.             }
  1154.         }
  1155.     }
  1156.  
  1157.  
  1158.     /*
  1159.      * Destroy the scene. This will destroy the contents of the scene,
  1160.      * i.e. any clumps and lights in that scene. In this case destroying
  1161.      * the scene will destroy the light we created in Init3D, and any
  1162.      * clumps we have loaded and not already destroyed.
  1163.      */
  1164.     RwDestroyScene(Scene);
  1165.  
  1166.     /*
  1167.      * Destroy the camera.
  1168.      */
  1169.  
  1170.   RwDestroyCamera(Camera);
  1171.  
  1172.     /*
  1173.      * Close the library. This will free up any internal resources and
  1174.      * textures loaded.
  1175.      */
  1176.   RwClose();
  1177. }
  1178.  
  1179. /**********************************************************************/
  1180.  
  1181. void
  1182. render(void)
  1183. {
  1184.   RwV3d at;
  1185.   Dcell *currcell;
  1186.   int x,y;
  1187.  
  1188.     /*
  1189.      * Get the camera position and floor() so as to find the cell
  1190.      * the camera is currently inside.  We use this to limit
  1191.      * the amount of geometry we draw just to the immediate
  1192.      * vicinity of the camera to get the most performance.
  1193.      */
  1194.     RwGetCameraPosition(Camera, &at);
  1195.     x = REAL2INT(at.x);
  1196.     y = REAL2INT(at.z);
  1197.     if (x < 0 && x >= DUNWIDTH && y < 0 && y >= DUNHEIGHT)
  1198.         return;
  1199.     currcell = &dungeon[y][x];
  1200.     if (currcell == NULL)
  1201.         return;
  1202.  
  1203.     RwBeginCameraUpdate(Camera,NULL);
  1204.  
  1205.     /* if any of the cells we'll be drawing require the viewport to be cleared
  1206.      * we better do it now.
  1207.      */
  1208.     if (currcell->vertical->dobacking ||
  1209.         currcell->horizontal->dobacking ||
  1210.         currcell->dobacking)
  1211.         RwClearCameraViewport(Camera);
  1212.  
  1213.     /*
  1214.      * Here we draw the two adjoining rooms/corridors followed by the
  1215.      * the room we're currently inside.  We do this by transforming the
  1216.      * referenced geometry by the previously computed matrix stored with
  1217.      * the cell, and drawing the geometry with RenderClump. Each room optionally
  1218.      * has a RwScene associated with it which contains the contents of the
  1219.      * room.  Since we gaurantee that the contents is always completely inside
  1220.      * the room, we can draw the contents using RwRenderScene to
  1221.      * overpaint the walls of the room we draw using RwRenderClump().
  1222.      */
  1223.         RwTransformClump(currcell->vertical->vgeometry,currcell->vertical->mat, rwREPLACE);
  1224.         RwRenderClump(currcell->vertical->vgeometry);
  1225.         if (currcell->vertical->contents)
  1226.             RwRenderScene(currcell->vertical->contents);
  1227.  
  1228.         RwTransformClump(currcell->horizontal->hgeometry,currcell->horizontal->mat, rwREPLACE);
  1229.         RwRenderClump(currcell->horizontal->hgeometry);
  1230.         if (currcell->horizontal->contents)
  1231.             RwRenderScene(currcell->horizontal->contents);
  1232.  
  1233.  
  1234.         RwTransformClump(currcell->geometry,currcell->mat, rwREPLACE);
  1235.         RwRenderClump(currcell->geometry);
  1236.         if (currcell->contents)
  1237.             RwRenderScene(currcell->contents);
  1238.  
  1239.     RwEndCameraUpdate(Camera);
  1240.  
  1241.  
  1242.  
  1243.     /* overlay text onto RW image */
  1244.     /* draw crosshair */
  1245.     if (MouseMoveMode == MMPanAndZoomCamera)
  1246.   {
  1247.       DosDrawLine(Camera,(nGScrWidth>>1)-8,(nGScrHeight-24)>>1,
  1248.                                 (nGScrWidth>>1)+8,(nGScrHeight-24)>>1,nGCrossCol);
  1249.       DosDrawLine(Camera,nGScrWidth>>1,((nGScrHeight-24)>>1)-8,
  1250.                                 nGScrWidth>>1,((nGScrHeight-24)>>1)+8,nGCrossCol);
  1251.   }
  1252.  
  1253.     if (DrawHUD)
  1254.   {
  1255.     int dx,dy;
  1256.     int xc,yc;
  1257.  
  1258.         for (dy=-4; dy<=4; dy++)
  1259.     {
  1260.       for (dx=-4; dx<=4; dx++)
  1261.       {
  1262.         if (((x+dx) >= 0) && ((x+dx) < DUNWIDTH) &&
  1263.             ((y+dy) >= 0) && ((y+dy) < DUNHEIGHT))
  1264.         {
  1265.           xc = 100 - ((4+1+4)*10) + (dx + 4) * 10;
  1266.           yc = + (dy + 4) * 10;
  1267.           if (dungeon[y+dy][x+dx].walls & NORTH)
  1268.           {
  1269.                         DosDrawLine(Camera,xc,yc,xc+10,yc,nGMapCol);
  1270.           }
  1271.           if (dungeon[y+dy][x+dx].walls & WEST)
  1272.           {
  1273.                         DosDrawLine(Camera,xc,yc,xc,yc+10,nGMapCol);
  1274.           }
  1275.           if (dungeon[y+dy][x+dx].walls & SOUTH)
  1276.           {
  1277.                         DosDrawLine(Camera,xc,yc+10,xc+10,yc+10,nGMapCol);
  1278.           }
  1279.           if (dungeon[y+dy][x+dx].walls & EAST)
  1280.           {
  1281.                         DosDrawLine(Camera,xc+10,yc,xc+10,yc+10,nGMapCol);
  1282.           }
  1283.           /* mark spot where we are */
  1284.           if ((dx == 0) && (dy == 0)) {
  1285.                         DosDrawLine(Camera,xc+1,yc+1,xc+9,yc+1,nGTextCol);
  1286.                         DosDrawLine(Camera,xc+9,yc+1,xc+9,yc+9,nGTextCol);
  1287.                         DosDrawLine(Camera,xc+9,yc+9,xc+1,yc+9,nGTextCol);
  1288.                         DosDrawLine(Camera,xc+1,yc+9,xc+1,yc+1,nGTextCol);
  1289.                     };
  1290.         }
  1291.       }
  1292.     }
  1293.   }
  1294.  
  1295.   RwShowCameraImage(Camera, NULL);
  1296. }
  1297.  
  1298. /**********************************************************************/
  1299.  
  1300. /*
  1301.  * Move the camera forward.  We cannot use RwVCMoveCamera() since the
  1302.  * camera is potentially tilted up or down - we want to move forward
  1303.  * only in the XZ plane.  In addition we have some simple periodic
  1304.  * movement in the Y direction to give a feeling of walking.
  1305.  * We constrain the camera movement by examining the "walls" field
  1306.  * of the current cell to determine whether the camera (aka player)
  1307.  * is able to move in that direction.
  1308.  */
  1309. void
  1310. moveforward(RwReal forward)
  1311. {
  1312. RwV3d pos1,pos2;
  1313. RwV3d at;
  1314. int x1,y1,x2,y2;
  1315. static int dbounce;
  1316.  
  1317.     RwGetCameraPosition(Camera, &pos1);
  1318.     x1 = REAL2INT(pos1.x);
  1319.     y1 = REAL2INT(pos1.z);
  1320.     RwGetCameraLookAt(Camera, &at);
  1321.  
  1322.     if (forward)
  1323.     {
  1324.         if (dbounce >= 8)
  1325.             dbounce = 0;
  1326.  
  1327.         RwWCMoveCamera(Camera, RMul(at.x,forward),
  1328.                                dbounce >= 4 ? CREAL(0.025) : CREAL(-0.025),
  1329.                                RMul(at.z,forward));
  1330.         dbounce++;
  1331.     }
  1332.  
  1333.     RwGetCameraPosition(Camera, &pos2);
  1334.     x2 = REAL2INT(pos2.x);
  1335.     y2 = REAL2INT(pos2.z);
  1336.  
  1337.  
  1338.     /* constrain movement based upon cell walls */
  1339.     if (REAL2INT(pos2.x - CLOSEST) < x1 && (dungeon[y1][x1].walls & WEST))
  1340.     {
  1341.         pos2.x = INT2REAL(REAL2INT(pos1.x));
  1342.         pos2.x += CLOSEST;
  1343.     }
  1344.     if (REAL2INT(pos2.x + CLOSEST) > x1 && (dungeon[y1][x1].walls & EAST))
  1345.     {
  1346.         pos2.x = INT2REAL(REAL2INT(pos1.x) + 1);
  1347.         pos2.x -= CLOSEST;
  1348.     }
  1349.     if (REAL2INT(pos2.z - CLOSEST) < y1 && (dungeon[y1][x1].walls & NORTH))
  1350.     {
  1351.         pos2.z = INT2REAL(REAL2INT(pos1.z));
  1352.         pos2.z += CLOSEST;
  1353.     }
  1354.     if (REAL2INT(pos2.z + CLOSEST) > y1 && (dungeon[y1][x1].walls & SOUTH))
  1355.     {
  1356.         pos2.z = INT2REAL(REAL2INT(pos1.z) + 1);
  1357.         pos2.z -= CLOSEST;
  1358.     }
  1359.  
  1360.     /* special case diagonal move which causes problems */
  1361.     if ((x1 != x2) && (y1 != y2))
  1362.     {
  1363.         if (y2 > y1)
  1364.         {
  1365.             if (dungeon[y2-1][x2].walls & SOUTH)
  1366.             {
  1367.                 pos2.z = INT2REAL(REAL2INT(pos1.z) + 1);
  1368.                 pos2.z -= CLOSEST;
  1369.             }
  1370.         }
  1371.         else
  1372.         {
  1373.             if (dungeon[y2+1][x2].walls & NORTH)
  1374.             {
  1375.                 pos2.z = INT2REAL(REAL2INT(pos1.z));
  1376.                 pos2.z += CLOSEST;
  1377.             }
  1378.         }
  1379.     }
  1380.  
  1381.     RwSetCameraPosition(Camera, pos2.x, pos2.y, pos2.z);
  1382. }
  1383.  
  1384.  
  1385. /**********************************************************************/
  1386.  
  1387. /*
  1388.  * This functions handles the left mouse button going down. Its main
  1389.  * job is to determine the kind of action to be taken when the mouse
  1390.  * moves, such as spinning a clump, or panning the camera. This involves
  1391.  * examining the virtual keys that were depressed when the mouse button
  1392.  * went down and attempting to pick a clump under the mouse pointer
  1393.  * position.
  1394.  */
  1395. static void
  1396. HandleLeftButtonDown(int x, int y, int vKeys)
  1397. {
  1398.  
  1399.  
  1400.   if (vKeys & MK_CONTROL)
  1401.   {
  1402.     MouseMoveMode = MMPanLight;
  1403.   }
  1404.   else if (vKeys & MK_SHIFT)
  1405.   {
  1406.     MouseMoveMode = MMTiltCamera;
  1407.   }
  1408.   else
  1409.   {
  1410.     MouseMoveMode = MMPanAndZoomCamera;
  1411.     forward = CREAL(0.0);
  1412.     pan = CREAL(0.0);
  1413.   }
  1414.  
  1415.  
  1416.   /*
  1417.     * If any form of action is to be taken on mouse move, remember the
  1418.     * the current x and y position of the mouse and capture future
  1419.     * mouse movement.
  1420.     */
  1421.  
  1422.     if (MouseMoveMode != MMNoAction)
  1423.     {
  1424.         LastX = x;
  1425.         LastY = y;
  1426.     }
  1427. }
  1428.  
  1429. /**********************************************************************/
  1430.  
  1431. /*
  1432.  * This functions handles the right mouse button going down. Its main
  1433.  * job is to determine the kind of action to be taken when the mouse
  1434.  * moves such as panning the camera.
  1435.  */
  1436. static void
  1437. HandleRightButtonDown( int x, int y, int vKeys)
  1438. {
  1439.  
  1440.  
  1441.   if (vKeys & MK_CONTROL)
  1442.   {
  1443.     MouseMoveMode = MMPanLight;
  1444.   }
  1445.   else if (vKeys & MK_SHIFT)
  1446.   {
  1447.     MouseMoveMode = MMTiltCamera;
  1448.   }
  1449.   else
  1450.   {
  1451.     MouseMoveMode = MMPanAndZoomCamera;
  1452.     forward = CREAL(0.0);
  1453.     pan = CREAL(0.0);
  1454.   }
  1455.  
  1456.  
  1457.   /*
  1458.     * If any form of action is to be taken on mouse move, remember the
  1459.     * the current x and y position of the mouse and capture future
  1460.     * mouse movement.
  1461.     */
  1462.     if (MouseMoveMode != MMNoAction)
  1463.     {
  1464.         LastX = x;
  1465.         LastY = y;
  1466.     }
  1467. }
  1468.  
  1469. /**********************************************************************/
  1470.  
  1471. /*
  1472.  * Handle a movement of the mouse. If a previous left or right mouse
  1473.  * button down event has set a mouse move mode then this function will
  1474.  * take the necessary actions. For example, pan and zooming the camera,
  1475.  * panning the light, dragging or spinning a clump etc.
  1476.  */
  1477. static void
  1478. HandleMouseMove(int x, int y)
  1479. {
  1480.     int nXCentre,nYCentre;
  1481.   RwInt32 offx,offy;
  1482.  
  1483.     nXCentre = nGScrWidth >>1;
  1484.   nYCentre = nGScrHeight >>1;
  1485.  
  1486.   /*
  1487.     * MouseMoveMode tells us what kind of action to perform.
  1488.     */
  1489.   switch (MouseMoveMode) {
  1490.     case MMNoAction:
  1491.       break;
  1492.  
  1493.     case MMPanAndZoomCamera:
  1494.       /*
  1495.         * We are panning and zooming the camera. Movement of the
  1496.         * mouse in the X direction will pan the camera about the
  1497.         * origin of world coordinate space, and movement of the mouse
  1498.         * in the Y direction will zoom the camera into and out of the
  1499.         * the scene.
  1500.         */
  1501.       /*
  1502.         * Pan the camera by mouse X delta degrees.
  1503.         */
  1504.       pan = RDiv(INT2REAL(nXCentre - x), CREAL(10.0));
  1505.  
  1506.       /*
  1507.         * Zoom the camera by changing the distance the camera
  1508.         * is from the origin of the world by mouse Y delta divided
  1509.         * by 100 units.
  1510.         */
  1511.       forward = RDiv(INT2REAL(nYCentre - y), CREAL(400.0));
  1512.       break;
  1513.  
  1514.     case MMTiltCamera:
  1515.       /*
  1516.         * Move the camera back to the origin, as we wish to tilt about
  1517.         * the origin of the world and not about the origin of the
  1518.         * camera.
  1519.         */
  1520.       /*
  1521.         * Pan the camera by mouse X delta degrees.
  1522.         */
  1523.       RwRotateMatrix(RwScratchMatrix(), CREAL(0.0),CREAL(1.0),CREAL(0.0),
  1524.                       INT2REAL(LastX - x),rwREPLACE);
  1525.       RwTransformCameraOrientation(Camera, RwScratchMatrix());
  1526.       RwTiltCamera(Camera, INT2REAL(y - LastY));
  1527.  
  1528.       RwGetCameraBackdropOffset(Camera, &offx,&offy);
  1529.       RwSetCameraBackdropOffset(Camera, offx - (LastX - x)*2, offy);
  1530.  
  1531.       break;
  1532.  
  1533.     case MMPanLight:
  1534.             /*
  1535.             * We are panning the light about the origin. We will rotate
  1536.             * the light about the Y axis for movements of the mouse in
  1537.             * X and rotate the light about the X axis for movements of
  1538.             * the mouse in Y. In this case we will ignore the effects
  1539.             * of camera orientation changes.
  1540.             */
  1541.       RwPushScratchMatrix();
  1542.             /*
  1543.             * Replace the CTM with a rotation matrix about Y. The number
  1544.             * of degrees of rotation is given by the mouse X delta.
  1545.             */
  1546.       RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  1547.                       INT2REAL(LastX - x), rwREPLACE);
  1548.  
  1549.             /*
  1550.             * Postconcat another rotation onto the CTM. The new rotation
  1551.             * is a rotation about X, the angle being given by the mouse
  1552.             * Y delta.
  1553.             */
  1554.       RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
  1555.                       INT2REAL(LastY - y), rwPOSTCONCAT);
  1556.  
  1557.       /*
  1558.       * Transform the light by the resultant rotations.
  1559.       */
  1560.       RwTransformLight(Light, RwScratchMatrix(),rwPOSTCONCAT);
  1561.       RwPopScratchMatrix();
  1562.   }
  1563.  
  1564.   /*
  1565.     * Remember the current X and Y for next time.
  1566.     */
  1567.   LastX = x;
  1568.   LastY = y;
  1569. }
  1570.  
  1571. /**********************************************************************/
  1572.  
  1573. /*
  1574.  * Handle the left mouse button comming back up. The basic action is
  1575.  * to turn off mouse move actions and release mouse capture.
  1576.  */
  1577. static void
  1578. HandleLeftButtonUp()
  1579. {
  1580.     /*
  1581.       * If we were engaged in a mouse move action and the button has come
  1582.       * back up, then terminate the action and release mouse capture.
  1583.       */
  1584.     if (MouseMoveMode != MMNoAction)
  1585.     {
  1586.       MouseMoveMode = MMNoAction;
  1587.     }
  1588. }
  1589.  
  1590. /**********************************************************************/
  1591.  
  1592. /*
  1593.  * Handle the right mouse button comming back up. The basic action is
  1594.  * to turn of mouse move actions and release mouse capture.
  1595.  */
  1596. static void
  1597. HandleRightButtonUp()
  1598. {
  1599.  
  1600.   RwSetCameraLookUp(Camera, CREAL(0.0),CREAL(1.0),CREAL(0.0));
  1601.  
  1602.   /*
  1603.     * If we were engaged in a mouse move action and the button has come
  1604.     * back up, then terminate the action and release mouse capture.
  1605.     */
  1606.   if (MouseMoveMode != MMNoAction)
  1607.   {
  1608.     MouseMoveMode = MMNoAction;
  1609.   }
  1610. }
  1611.  
  1612.  
  1613. /**********************************************************************/
  1614.  
  1615. /*
  1616.  * Each Scene associated with a room enumerates the Clumps and calls
  1617.  * this function to perform some simple behaviour.  The choice of
  1618.  * behaviour is determined by the low 8 bits of the clump's Data
  1619.  * field.  The bits above the low 8 bits are used as a counter to
  1620.  * trigger when orthonormalisation must occur.
  1621.  */
  1622. RwClump *
  1623. dispatchbehav(RwClump *obj)
  1624. {
  1625. long val;
  1626. int ortho;
  1627. static RwV3d axis = {CREAL(1),CREAL(1),CREAL(1)};
  1628. static RwReal theta = CREAL(0);
  1629. static RwReal dtheta = CREAL(0.5);
  1630. RwReal opacity;
  1631.  
  1632.     ortho = 0;
  1633.     val = (long)RwGetClumpData(obj);
  1634.     switch (val & 255)
  1635.     {
  1636.         case DONOTHING:
  1637.             break;
  1638.         case SPINFADE:
  1639.             if ((val >> 8) & 32)
  1640.             {
  1641.                 opacity = RDiv(INT2REAL((val >> 8) & 15), CREAL(16));
  1642.                 if (((val >> 8) & 31) >= 16)
  1643.                     opacity = RSub(CREAL(1),opacity);
  1644.             }
  1645.             else
  1646.                 opacity = 0;
  1647.  
  1648.             opacity = RSub(CREAL(1),opacity);
  1649.             RwForAllPolygonsInClumpReal(obj, RwSetPolygonOpacity, opacity);
  1650.             /* fall-thru */
  1651.         case SPIN:
  1652.             RwRotateMatrix(RwScratchMatrix(), CREAL(0.0),CREAL(1.0),CREAL(0.0),
  1653.                                               CREAL(10), rwREPLACE);
  1654.             RwTransformClumpJoint(obj, RwScratchMatrix(), rwPRECONCAT);
  1655.             ortho = 1;
  1656.             break;
  1657.         case TUMBLE:
  1658.             theta = RAdd(theta, dtheta);
  1659.             if ((theta <= CREAL(-30)) || (theta >= CREAL(30)))
  1660.                 dtheta = -dtheta;
  1661.             if (theta == CREAL(0))
  1662.             {
  1663.                 axis.x = rand();
  1664.                 axis.y = rand();
  1665.                 axis.z = rand();
  1666.             }
  1667.             RwRotateMatrix(RwScratchMatrix(), axis.x, axis.y,axis.z,
  1668.                                             theta, rwREPLACE);
  1669.             RwTransformClumpJoint(obj, RwScratchMatrix(), rwPRECONCAT);
  1670.             ortho = 1;
  1671.             break;
  1672.     }
  1673.  
  1674.     /* Do periodic orthonormalisation if we're using rotation */
  1675.     if (ortho)
  1676.     {
  1677.         val += 256;
  1678.         RwSetClumpData(obj, val);
  1679.         if (((val>>8) & 127) == 0)
  1680.         {
  1681.             RwGetClumpJointMatrix(obj, RwScratchMatrix());
  1682.             RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
  1683.             RwTransformClumpJoint(obj, RwScratchMatrix(), rwREPLACE);
  1684.         }
  1685.     }
  1686.     return(obj);
  1687. }
  1688.  
  1689. /**********************************************************************/
  1690.  
  1691. /*
  1692.  * Handle MS Window's timer expiry. This function will perform any
  1693.  * animation actions necessary, including spinning clumps and animating
  1694.  * textures.
  1695.  */
  1696. static void
  1697. HandleTimer(void)
  1698. {
  1699.     static int FrameNumber = 0;
  1700.   RwInt32 dx,dy;
  1701.     RwV3d at;
  1702.     Dcell *currcell;
  1703.  
  1704.   FrameNumber++;
  1705.  
  1706.   /*
  1707.     * Animate textures. Enumerate over all the textures in the texture
  1708.     * dictionary stack calling RwTextureNextFrame() to bump the
  1709.     * current frame pointer of each texture. For single frame textures
  1710.     * this is a no-op.
  1711.     */
  1712.   RwForAllNamedTextures(RwTextureNextFrame);
  1713.  
  1714.   /*
  1715.     * Perform any behaviour for each scene associated with visible
  1716.     * clumps.
  1717.     */
  1718.   RwGetCameraPosition(Camera, &at);
  1719.   dx = REAL2INT(at.x);
  1720.   dy = REAL2INT(at.z);
  1721.   currcell = &dungeon[dy][dx];
  1722.   if (currcell->vertical->contents)
  1723.       RwForAllClumpsInScene(currcell->vertical->contents, dispatchbehav);
  1724.   if (currcell->horizontal->contents)
  1725.       RwForAllClumpsInScene(currcell->horizontal->contents, dispatchbehav);
  1726.   if (currcell->contents)
  1727.       RwForAllClumpsInScene(currcell->contents, dispatchbehav);
  1728.  
  1729.  
  1730.   if (pan || forward)
  1731.   {
  1732.     RwRotateMatrix(RwScratchMatrix(), CREAL(0.0),CREAL(1.0),CREAL(0.0),pan,rwREPLACE);
  1733.     RwTransformCameraOrientation(Camera, RwScratchMatrix());
  1734.     moveforward(forward);
  1735.     RwGetCameraBackdropOffset(Camera, &dx,&dy);
  1736.     RwSetCameraBackdropOffset(Camera, dx-REAL2INT(pan)*2, dy);
  1737.   }
  1738.  
  1739.   render();
  1740. }
  1741.  
  1742.  
  1743. /****************************************************************************
  1744.  Main
  1745.  */
  1746.  
  1747. void main(int nArgc,char *saArgv[])
  1748. {
  1749.     int nKey;
  1750.     int nMouseX,nMouseY,nMouseBut,nOldMouseBut,nOldMouseX,nOldMouseY;
  1751.     int nDX,nDY;
  1752.     int nChange;
  1753.     int nCtrlShift;
  1754.  
  1755.   /* Stop warnings */
  1756.  
  1757.   nArgc = nArgc;
  1758.  
  1759.     if (!Init3D(saArgv[0]))
  1760.     {
  1761.         exit(-1);
  1762.     };
  1763.  
  1764.  
  1765.     DrawHUD=1;
  1766.  
  1767.     /*
  1768.     * Parse any command line parameters.
  1769.     */
  1770.  
  1771.     RwDPointerDisplay(&nOldMouseX,&nOldMouseY,&nOldMouseBut);
  1772.  
  1773.     nKey = DosGetKey();
  1774.  
  1775.     while (nKey!=27) {        /* ESC quits */
  1776.  
  1777.         RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
  1778.  
  1779.         nKey = DosGetKey();
  1780.  
  1781.         nCtrlShift = DosShiftCtrl();
  1782.  
  1783.         nDX =(nMouseX-nOldMouseX);
  1784.         nDY =(nMouseY-nOldMouseY);
  1785.  
  1786.         nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
  1787.  
  1788.         switch (nChange) {
  1789.             case 0+0:
  1790.             case 2+1:
  1791.             case 8+4:
  1792.             case 8+2+4+1: {
  1793.                 /* No change */
  1794.                 break;
  1795.             };
  1796.             case 2:
  1797.             case 8+2+4: {
  1798.  
  1799.                 /* Left Button Down */
  1800.  
  1801.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  1802.  
  1803.                 break;
  1804.             };
  1805.             case 8:
  1806.             case 8+2+1: {
  1807.                 /* Right Button Down */
  1808.  
  1809.  
  1810.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  1811.  
  1812.                 break;
  1813.             };
  1814.             case 8+1: {
  1815.                 /* Right down left Up */
  1816.  
  1817.                 HandleLeftButtonUp();
  1818.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  1819.  
  1820.                 break;
  1821.             };
  1822.             case 2+4: {
  1823.                 /* Right up left Down */
  1824.  
  1825.  
  1826.                 HandleRightButtonUp();
  1827.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  1828.  
  1829.  
  1830.                 break;
  1831.             };
  1832.             case 8+2: {
  1833.                 /* Left down RIght Down */
  1834.  
  1835.  
  1836.                 HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
  1837.                 HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
  1838.  
  1839.  
  1840.                 break;
  1841.             };
  1842.             case 1+4: {
  1843.                 /* Left up Right Up */
  1844.  
  1845.  
  1846.                 HandleRightButtonUp();
  1847.                 HandleLeftButtonUp();
  1848.  
  1849.  
  1850.                 break;
  1851.             };
  1852.             case 1:
  1853.             case 8+4+1: {
  1854.                 /* Left up */
  1855.  
  1856.  
  1857.                 HandleLeftButtonUp();
  1858.  
  1859.  
  1860.                 break;
  1861.             };
  1862.             case 4:
  1863.             case 2+4+1: {
  1864.                 /* Right up */
  1865.  
  1866.  
  1867.                 HandleRightButtonUp();
  1868.  
  1869.  
  1870.                 break;
  1871.             };
  1872.         };
  1873.  
  1874.  
  1875.  
  1876.         if (nDX||nDY) {
  1877.             /* Mouse Move  */
  1878.             HandleMouseMove(nMouseX,nMouseY);
  1879.         };
  1880.  
  1881.  
  1882.  
  1883.         HandleTimer();
  1884.  
  1885.         nOldMouseX = nMouseX;
  1886.         nOldMouseY = nMouseY;
  1887.         nOldMouseBut = nMouseBut;
  1888.  
  1889.     };
  1890.  
  1891.     /*
  1892.     * Tidy up the 3D (RenderWare) components of the application.
  1893.     */
  1894.  
  1895.     TidyUp3D();
  1896.  
  1897.     exit(0);
  1898. }
  1899.  
  1900.  
  1901. /**********************************************************************/
  1902.