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

  1. /**********************************************************************
  2.  *
  3.  * File :     rwroller.c
  4.  *
  5.  * Abstract : A very simple, sample RenderWare application for
  6.  *            Microsoft Windows 3.1. 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. 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) 1994 Criterion Software Ltd.
  32.  * All Rights Reserved.
  33.  *
  34.  * RenderWare is a trademark of Canon Inc.
  35.  *
  36.  **********************************************************************/
  37.  
  38. /**********************************************************************
  39.  *
  40.  * Header files.
  41.  *
  42.  **********************************************************************/
  43.  
  44. #include <stdlib.h>
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <i86.h>
  48. #include <math.h>       /* Required for floating point */
  49.  
  50. #include "rwlib.h"
  51. #include "rwdos.h"
  52. #include "doswrap.h"
  53.  
  54. #include "rolltype.h"
  55. #include "palette.h"
  56. #include "pick.h"
  57.  
  58. /**********************************************************************
  59.  *
  60.  * Application constants.
  61.  *
  62.  **********************************************************************/
  63.  /*
  64.  * MS Windows compatible defines
  65.  */
  66.  
  67. #define MK_CONTROL 0x4
  68. #define MK_SHIFT 0x2
  69.  
  70. /*
  71.  * Default distance of the camera from the origin.
  72.  */
  73. #define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
  74.  
  75. /**********************************************************************
  76.  *
  77.  * Forward functions.
  78.  *
  79.  **********************************************************************/
  80.  
  81.  
  82. /**********************************************************************
  83.  *
  84.  * Type definitions.
  85.  *
  86.  **********************************************************************/
  87.  
  88. /*
  89.  * The camera's motion mode.
  90.  */
  91. typedef enum
  92. {
  93.     cmNONE,                 /* No camera motion. */
  94.     cmRIDE,                 /* Camera "rides" the rollercoaster. */
  95.     cmSPOTTER,              /* "Spotter" camera rotates around the rollercoaster car. */
  96.     cmTRAIL,                /* Camera trails the car on the rollercoaster. */
  97.     cmLEAD,                 /* Camera "leads" the car on the rollercoaster. */
  98.     cmELEVATION,    /* Camera pans around and zooms into the rollercoaster elevation. */
  99.     cmPLAN                  /* Camera pans around and zooms into the rollercoaster plan. */
  100. } CMMode;
  101.  
  102. /*
  103.  * This enumerated type tells us what kind of action should be taken
  104.  * on mouse events.
  105.  */
  106. typedef enum
  107. {
  108.     mmNONE,                  /* No mouse move action. */
  109.     mmMOVECAMERA,    /* Move the camera on mouse move. */
  110.     mmALTMOVECAMERA, /* Alternative camera motion on mouse move. */
  111.     mmMOVECONTROL,   /* Move a spline control point on mouse move. */
  112.     mmMOVELIGHT          /* Move the light. */
  113. } MMMode;
  114.  
  115. /*
  116.  * The direction of motion of the viewer on the track.
  117.  */
  118. typedef enum
  119. {
  120.     vmLEVEL,
  121.     vmCLIMBING,
  122.     vmFALLING
  123. } VMMode;
  124.  
  125. /**********************************************************************
  126.  *
  127.  * Application global variables.
  128.  *
  129.  **********************************************************************/
  130.  
  131. /*
  132.  * The global, single camera instance.
  133.  */
  134. static RwCamera   *Camera = NULL;
  135.  
  136. static CMMode      CameraMode = cmRIDE;
  137.  
  138. static RwReal      CameraAngle = CREAL(0.0);
  139.  
  140. /*
  141.  * This variable tells us what kind of action to take on a mouse move.
  142.  * The action depends on the object that was picked when the mouse button
  143.  * went down, and on the selection of virtual keys that were depressed at
  144.  * that time. By default no action is taken on mouse move.
  145.  */
  146. static MMMode      MouseMoveMode = mmNONE;
  147.  
  148. /*
  149.  * Global variables used to remember the last mouse X and Y coordinates
  150.  * when involved in a pan, zoom, drag or spin.
  151.  */
  152. static int         LastX;
  153. static int         LastY;
  154.  
  155. /*
  156.  * Line Clearing string
  157.  */
  158.  
  159. char sGClear[]="                               ";
  160. /*
  161.  * Screen size
  162.  */
  163.  
  164. int nGScrWidth;
  165. int nGScrHeight;
  166.  
  167. /*
  168.  * Default text colour
  169.  */
  170.  
  171. static int nGTextColour;
  172.  
  173. /*
  174.  * View Display Mode
  175.  */
  176.  
  177. static int nGDisplayMode=0;
  178.  
  179. /*
  180.  * Current distance the camera is from the origin. This is stored to
  181.  * help us pan and zoom the camera.
  182.  */
  183. static RwReal      CameraDistance = DEFAULT_CAMERA_DISTANCE;
  184.  
  185. /*
  186.  * Current angle of tilt applied to the camera.
  187.  */
  188. static RwReal      CameraTilt = CREAL(0.0);
  189.  
  190. /*
  191.  * This flag indicates whether the 3D components of the application
  192.  * have been successfully initialized as yet. It is used to guard
  193.  * the message loop handler functions from being invoked before the
  194.  * 3D components of the application are successfully initialized.
  195.  */
  196. static RwBool        ThreeDInitialized = FALSE;
  197.  
  198.  
  199. /*
  200.  * The current rollercoaster.
  201.  */
  202. static RollerCoasterType *CurrentCoaster = NULL;
  203.  
  204. /*
  205.  * The current control point picked (if any).
  206.  */
  207. static int ControlPoint  = 0;
  208.  
  209. /*
  210.  * Whether to show the coaster's car or not.
  211.  */
  212. static RwBool ShowCar = TRUE;
  213.  
  214. static int         DrawFPS;
  215.  
  216. /*
  217.  * Name of the palette and backdrop files to load.
  218.  */
  219. #define PALETTEFILENAME         "rwroller.pal"
  220. #define BACKDROPFILENAME        "mount64.bmp"
  221.  
  222. /**********************************************************************
  223.  *
  224.  * Functions.
  225.  *
  226.  **********************************************************************/
  227.  
  228. /****************************************************************************
  229.  DosTimer
  230.  
  231.  Uses the DOS 18 per sec timer to find time in millisecs.
  232.  
  233.  On entry    :
  234.  On exit    : Timer (in milliseconds)
  235.  */
  236.  
  237. int DosTimer(void)
  238. {
  239.     union REGS r;
  240.     int nTime;
  241.  
  242.     r.h.ah=0;
  243.  
  244.     int386(0x1a,&r,&r);
  245.  
  246.     nTime = ((r.w.cx)<<16)|(r.w.dx);
  247.  
  248.     return (nTime*55);
  249. }
  250.  
  251.  
  252. /****************************************************************************
  253.  DosShiftCtrl
  254.  
  255.  On entry       :
  256.  On exit        : Bit           Meaning
  257.                         0                               Right Shift
  258.                         1                               Left Shift
  259.                         2                               Ctrl
  260.                         3                               Alt
  261.                         4       Scroll Lock
  262.                         5                               Num Lock
  263.                         6                       Caps Lock
  264.                         7                               Insert on
  265.  */
  266.  
  267. int DosShiftCtrl(void)
  268. {
  269.     union REGPACK rp;
  270.  
  271.     memset(&rp,0,sizeof(rp));
  272.  
  273.     rp.h.ah=0x02;
  274.     intr(0x16,&rp);
  275.  
  276.     return ((int)rp.h.al);
  277. }
  278.  
  279.  
  280. /****************************************************************************
  281.  DosPrintString
  282.  
  283.  On entry       : xcord
  284.                         : ycord
  285.                         : string
  286.                         : colour
  287.  On exit                :
  288.  */
  289.  
  290. void DosPrintString(int nX,int nY,char *sString,int nCol)
  291. {
  292.     RwPrintChar pcPrint;
  293.  
  294.     pcPrint.x = nX;
  295.     pcPrint.y = nY;
  296.     pcPrint.color = nCol;
  297.  
  298.     for (;(*sString);sString++)  {
  299.         pcPrint.c = (*sString);
  300.     RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
  301.         pcPrint.x+=8;
  302.     };
  303. }
  304.  
  305.  
  306. /****************************************************************************
  307.  DosGetKey
  308.  
  309.  Get the ascii key code of any depressed key. (Do not wait for a key press.
  310.  -> return 0 if no key is pressed)
  311.  
  312.  On entry       :
  313.  On exit        : Key pressed in ascii (or 0 if no key pressed)
  314.  */
  315.  
  316. int DosGetKey(void)
  317. {
  318.     union REGPACK rp;
  319.  
  320.     memset(&rp,0,sizeof(rp));
  321.     rp.h.ah = 0x06;
  322.     rp.h.dl = 0xff;
  323.  
  324.     intr(0x21,&rp);
  325.  
  326.     if (!(rp.w.flags & 0x40 )) {    /* Check Z flag */
  327.         /* Got key */
  328.  
  329.         if (rp.h.al) {
  330.             return ((int)rp.h.al);
  331.         };
  332.  
  333.         memset(&rp,0,sizeof(rp));
  334.         rp.h.ah = 0x06;
  335.         rp.h.dl = 0xff;
  336.         intr(0x21,&rp);
  337.  
  338.         if (!(rp.w.flags & 0x40)) {
  339.             return ((int)rp.h.al);
  340.         };
  341.  
  342.         return (rp.h.al|0x80);
  343.     };
  344.  
  345.     return 0;
  346. }
  347.  
  348. /**********************************************************************/
  349.  
  350. static RwBool
  351. TrackBackdropToCamera(RwCamera *camera)
  352. {
  353.     RwRaster *backdrop;
  354.     RwInt32   backdropWidth;
  355.     RwInt32   backdropHeight;
  356.     RwV3d     at;
  357.     RwReal    angle;
  358.     RwInt32   xOffset;
  359.     RwInt32   yOffset;
  360.     RwInt32   windowWidth;
  361.     RwInt32   windowHeight;
  362.  
  363.     backdrop = RwGetCameraBackdrop(camera);
  364.  
  365.     /*
  366.      * No-op if the camera has no backdrop.
  367.      */
  368.     if (backdrop != NULL)
  369.     {
  370.         /*
  371.          * Get the window and backdrop dimensions.
  372.          */
  373.         RwGetCameraViewport(camera, NULL, NULL, &windowWidth, &windowHeight);
  374.  
  375.         backdropWidth  = RwGetRasterWidth(backdrop);
  376.         backdropHeight = RwGetRasterHeight(backdrop);
  377.  
  378.         /*
  379.          * We use the look at vector for determining both
  380.          * horizontal and vertical positioning.
  381.          */
  382.         RwGetCameraLookAt(camera, &at);
  383.  
  384.         /*
  385.          * Compute the horizontal position. This is done
  386.          * by compute the camera's angle of rotate about
  387.          * the Z axis. The angle is then directly converted
  388.          * into a horizontal backdrop offset.
  389.          */
  390.  
  391.         /*
  392.          * Compute the angle in the range 0 => PI.
  393.          */
  394.         at.y = CREAL(0.0);
  395.         RwNormalize(&at);
  396.         if (at.z > CREAL(1.0))
  397.             at.z = CREAL(1.0);
  398.         else if (at.z < CREAL(-1.0))
  399.             at.z = CREAL(-1.0);
  400.         angle = FL2REAL(acos(REAL2FL(at.z)));
  401.  
  402.         /*
  403.          * Get the angle in the range 0 => 2 PI
  404.          */
  405.         if (at.x < CREAL(0.0))
  406.             angle = RSub(CREAL(M_2PI), angle);
  407.  
  408.         /*
  409.          * The backdrop X offset is derived simply from
  410.          * the angle computed above.
  411.          */
  412.         xOffset = -REAL2INT(RDiv(RMul(angle, INT2REAL(backdropWidth)), CREAL(M_2PI)));
  413.  
  414.         /*
  415.          * Compute the vertical position. This is done by getting
  416.          * the angle between the look at vector and the Y axis. We
  417.          * simply use the dot product (cosine of the angle) multiplied
  418.          * by a scale factor to compute the vertical offset.
  419.          */
  420.         RwGetCameraLookAt(Camera, &at);
  421.         yOffset = REAL2INT(RAdd(INT2REAL(windowHeight / 2), RMul(RMul(at.y, CREAL(1.5)), INT2REAL(windowHeight / 2)))) - (backdropHeight / 2);
  422.  
  423.         RwSetCameraBackdropOffset(Camera, xOffset, 0);
  424.         RwSetCameraBackdropViewportRect(Camera, 0, yOffset, windowWidth, backdropHeight);
  425.     }
  426.     return TRUE;
  427. }
  428.  
  429.  
  430. /**********************************************************************/
  431.  
  432. /*
  433.  * Put camera into ride mode.
  434.  */
  435. static void
  436. SwitchToRideView(void)
  437. {
  438.     CameraMode = cmRIDE;
  439.     SwitchToCoasterRideMode(CurrentCoaster);
  440.     /*UpdateMenu(window); */
  441. }
  442.  
  443. /**********************************************************************/
  444.  
  445. /*
  446.  * Put camera into ride mode.
  447.  */
  448. static void
  449. SwitchToSpotterView(void)
  450. {
  451.     CameraMode = cmSPOTTER;
  452.     SwitchToCoasterRideMode(CurrentCoaster);
  453.     /*UpdateMenu(window);*/
  454. }
  455.  
  456. /**********************************************************************/
  457.  
  458. /*
  459.  * Put camera into trail mode.
  460.  */
  461. static void
  462. SwitchToTrailView(void)
  463. {
  464.     CameraMode = cmTRAIL;
  465.     SwitchToCoasterRideMode(CurrentCoaster);
  466.     /*UpdateMenu(window); */
  467. }
  468.  
  469. /**********************************************************************/
  470.  
  471. /*
  472.  * Put camera into lead mode.
  473.  */
  474. static void
  475. SwitchToLeadView(void)
  476. {
  477.     CameraMode = cmLEAD;
  478.     SwitchToCoasterRideMode(CurrentCoaster);
  479.     /*UpdateMenu(window);   */
  480. }
  481.  
  482. /**********************************************************************/
  483.  
  484. /*
  485.  * Put camera into elevation mode.
  486.  */
  487. static void
  488. SwitchToElevationView(void)
  489. {
  490.     CameraMode = cmELEVATION;
  491.     SwitchToCoasterEditMode(CurrentCoaster);
  492.  
  493.     RwSetCameraPosition(Camera,
  494.                         CurrentCoaster->elevationPosition.x,
  495.                         CurrentCoaster->elevationPosition.y,
  496.                         CurrentCoaster->elevationPosition.z);
  497.     RwPointCamera(Camera,
  498.                   CREAL(0.0),
  499.                   CurrentCoaster->elevationPosition.y,
  500.                   CREAL(0.0));
  501.     RwSetCameraLookUp(Camera,
  502.                       CREAL(0.0),
  503.                       CREAL(1.0),
  504.                       CREAL(0.0));
  505.     TrackBackdropToCamera(Camera);
  506.     /*UpdateMenu(window);*/
  507. }
  508.  
  509. /**********************************************************************/
  510.  
  511. /*
  512.  * Put the camera into plan mode.
  513.  */
  514. static void
  515. SwitchToPlanView(void)
  516. {
  517.     CameraMode = cmPLAN;
  518.     SwitchToCoasterEditMode(CurrentCoaster);
  519.  
  520.     RwSetCameraPosition(Camera,
  521.                         CurrentCoaster->planPosition.x,
  522.                         CurrentCoaster->planPosition.y,
  523.                         CurrentCoaster->planPosition.z);
  524.  
  525.     /*
  526.      * Unsatisfactory hack to get the camera aligned in the
  527.      * way we wish. This itself will fail if the camera's is
  528.      * looking down the X-axis already - sigh!
  529.      */
  530.     RwSetCameraLookUp(Camera,
  531.                       CREAL(1.0),
  532.                       CREAL(0.0),
  533.                       CREAL(0.0));
  534.     RwPointCamera(Camera,
  535.                   CurrentCoaster->planPosition.x,
  536.                   CREAL(0.0),
  537.                   CurrentCoaster->planPosition.z);
  538.     RwSetCameraLookUp(Camera,
  539.                       CREAL(0.0),
  540.                       CREAL(0.0),
  541.                       CREAL(1.0));
  542.  
  543.     /*UpdateMenu(window); */
  544. }
  545.  
  546. /**********************************************************************/
  547.  
  548. static void
  549. SwitchCoaster(RollerCoasterType *coaster)
  550. {
  551.     DestroyRollerCoaster(CurrentCoaster);
  552.     CurrentCoaster = coaster;
  553.     switch (CameraMode)
  554.     {
  555.         case cmRIDE:
  556.             SwitchToRideView();
  557.             break;
  558.         case cmSPOTTER:
  559.             SwitchToSpotterView();
  560.             break;
  561.         case cmTRAIL:
  562.             SwitchToTrailView();
  563.             break;
  564.         case cmLEAD:
  565.             SwitchToLeadView();
  566.             break;
  567.         case cmELEVATION:
  568.             SwitchToElevationView();
  569.             break;
  570.         case cmPLAN:
  571.             SwitchToPlanView();
  572.             break;
  573.     }
  574.     if (ShowCar)
  575.         EnableCoasterCar(CurrentCoaster);
  576.     else
  577.         DisableCoasterCar(CurrentCoaster);
  578. }
  579.  
  580. /**********************************************************************/
  581.  
  582. /*
  583.  * This function initializes the 3D (i.e. RenderWare) components of the
  584.  * application. This function opens the RenderWare library, creates a
  585.  * camera, a scene, a light and a matrix for spinning.
  586.  */
  587. static RwBool
  588. Init3D()
  589. {
  590.   char     version[30];
  591.     char     buffer[128];
  592.     int      param;
  593.     int i;
  594.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  595.     long nError;
  596.   char     windowText[128];
  597.   RwRaster       *backdrop;
  598.   RwReal naBlack[] = {CREAL(0.0),CREAL(0.0),CREAL(0.0)};
  599.   int nBlack;
  600.   RwPointerImage piImage;
  601.     RollerCoasterType *coaster;
  602.  
  603.     /*
  604.      * Attempt to open (and initialize) the RenderWare library.
  605.      * Explicitly specifying the MS Windows driver. Previous
  606.      * versions of RenderWare required the application instance
  607.      * handle to be specified as the device dependent parameter
  608.      * of RwOpen(). Version 1.3 of RenderWare has removed this
  609.      * requirement and NULL should be passed instead.
  610.      */
  611.     /*
  612.     * Attempt to open (and initialize) the RenderWare library.
  613.     */
  614.  
  615.   if (!RwOpen("DOSMOUSE", &nError))
  616.     {
  617.         printf("Unable to access renderware!!\n");
  618.         switch (nError) {
  619.             case E_RW_DOS_MODE_UNAVAILABLE: {
  620.               printf("The installed VESA card is unable to switch to the resolution");
  621.                 printf(" requested.\n");
  622.                 printf("Either install a different video adapter or use a ");
  623.                 printf("supported video mode.");
  624.                 break;
  625.             };
  626.             case E_RW_DOS_NO_VESA_BIOS: {
  627.                 printf("A VESA bios is unavailable on this machine.\n");
  628.                 printf("Either use a VESA compatible Video Adapter or install a ");
  629.                 printf("VESA bios emulation TSR.\n");
  630.                 break;
  631.             };
  632.             case E_RW_DOS_INCOMPATIBLE_BIOS: {
  633.                 printf("The VESA bios on this machine is not of high enough version ");
  634.                 printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
  635.                 printf(" higher VESA bios or TSR.\n");
  636.                 break;
  637.             };
  638.             case E_RW_DOS_NO_MOUSE: {
  639.                 printf("No Microsoft compatible mouse driver present.\n");
  640.                 printf("Install a microsoft compatible mouse driver and try again.\n");
  641.                 break;
  642.             };
  643.             default: {
  644.                 printf("Unknown Error !!!!!!!!!!!!!!!\n");
  645.                 break;
  646.             };
  647.         };
  648.         return FALSE;
  649.     }
  650.  
  651.   /* load the palette */
  652.  
  653.   CheckAndReadPalette("rwroller.pal");
  654.  
  655.   nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  656.   nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack));
  657.  
  658.   /* Rematch the pointer image */
  659.  
  660.   piImage.image = NULL;
  661.   piImage.hotx=0;
  662.   piImage.hoty=0;
  663.   piImage.w = nBlack;
  664.   piImage.h = nGTextColour;
  665.  
  666.   RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
  667.  
  668.     /* Set up character set */
  669.  
  670.   RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
  671.   RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
  672.  
  673.     /*--- Only look for scripts and textures in subdirectories under the current
  674.     one. RWSHAPEPATH need not be set then */
  675.  
  676.     RwSetShapePath(".",rwPRECONCAT);
  677.  
  678.     strcpy(buffer,".");
  679.  
  680.     i = strlen(buffer);
  681.     while((buffer[i] != '\\')&&(i>=0)) {
  682.         i--;
  683.     };
  684.  
  685.  
  686.     if (i>=0) {
  687.         buffer[i+1] = 0;
  688.         strcat(buffer, "TEXTURES");
  689.         RwSetShapePath(buffer, rwPOSTCONCAT);
  690.  
  691.         buffer[i+1] = 0;
  692.         strcat(buffer, "SCRIPTS");
  693.         RwSetShapePath(buffer, rwPOSTCONCAT);
  694.     };
  695.  
  696.     RwSetShapePath("SCRIPTS", rwPRECONCAT);
  697.     RwSetShapePath("TEXTURES", rwPRECONCAT);
  698.  
  699.  
  700.      /*
  701.     * Label the display with information about the version of
  702.     * RenderWare being used. Its rather unlikely that
  703.     * RwGetSystemInfo() will fail so we ignore its return value.
  704.     */
  705.   RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
  706.   RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
  707.     sprintf(windowText, "DosRoller V%s %s",
  708.         version, (param ? "Fixed" : "Float"));
  709.     DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
  710.     DosPrintString(8*8,nGScrHeight-24,"Load    Save    New     EditPlan",nGTextColour);
  711.     DosPrintString(8*32,nGScrHeight-16,"EditSide",nGTextColour);
  712.  
  713.     /*
  714.     * Create the camera which will be used for rendering.
  715.     */
  716.  
  717.     Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
  718.     if (!Camera)
  719.     {
  720.         /*
  721.           * As with RwOpen(), the most common cause for a failure to create
  722.           * a camera is insufficient memory so we will explicitly check for
  723.           * this condition and report it. Otherwise a general error is issued.
  724.           */
  725.         if (RwGetError() == E_RW_NOMEM)
  726.         {
  727.             RwClose();
  728.             printf("Insufficient memory to create the RenderWare(tm) camera\n");
  729.         }
  730.         else
  731.         {
  732.             RwClose();
  733.             printf("Error creating the RenderWare(tm) camera\n");
  734.         }
  735.         exit(-1);
  736.     }
  737.  
  738.   RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
  739.     /*
  740.      * Set the camera's background color to blue.
  741.      */
  742.     RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.67));
  743.  
  744.     /*
  745.      * By default, the camera lies on the X-Z plane and points down Z
  746.      * into the screen. We shall retain the camera's orientation, but move
  747.      * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
  748.      */
  749.     RwTiltCamera(Camera, CameraTilt);
  750.     RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
  751.     RwSetCameraViewwindow(Camera, CREAL(0.8), CREAL(0.8));
  752.  
  753.   /*
  754.    Set up the backdrop
  755.    */
  756.  
  757.     backdrop = RwReadRaster(BACKDROPFILENAME, 0L);
  758.     if (backdrop != NULL)
  759.         RwSetCameraBackdrop(Camera, backdrop);
  760.  
  761.     /*
  762.      * Create a new, default rollercoaster.
  763.      */
  764.     CurrentCoaster = CreateRollerCoaster();
  765.     if (CurrentCoaster == NULL)
  766.     {
  767.     RwDestroyCamera(Camera);
  768.     RwClose();
  769.     return FALSE;
  770.     }
  771.  
  772.     coaster = ReadRollerCoaster("track4.rrc");
  773.     if (coaster != NULL)
  774.     {
  775.       SwitchCoaster(coaster);
  776.     }
  777.  
  778.     SwitchToRideView();
  779.  
  780.     /*
  781.      * All the 3D components are now successfully initialized, so
  782.      * work can begin...
  783.      */
  784.     ThreeDInitialized = TRUE;
  785.  
  786.     return TRUE;
  787. }
  788.  
  789. /**********************************************************************/
  790.  
  791. /*
  792.  * This function shuts down the 3D (i.e. RenderWare) components of the
  793.  * application in a polite fashion.
  794.  */
  795. static void
  796. TidyUp3D(void)
  797. {
  798.     /*
  799.      * Destroy the current coaster.
  800.      */
  801.     if (CurrentCoaster)
  802.         DestroyRollerCoaster(CurrentCoaster);
  803.  
  804.     /*
  805.      * Destroy the camera's backdrop (if any). Backdrops are not
  806.      * automatically destroyed by RwDestroyCamera() so we must
  807.      * manually destroy the backdrop.
  808.      */
  809.     if (RwGetCameraBackdrop(Camera))
  810.     RwDestroyRaster(RwGetCameraBackdrop(Camera));
  811.  
  812.     /*
  813.      * Destroy the camera.
  814.      */
  815.     RwDestroyCamera(Camera);
  816.  
  817.     /*
  818.      * Close the library. This will free up any internal resources and
  819.      * textures loaded.
  820.      */
  821.     RwClose();
  822. }
  823.  
  824. /**********************************************************************/
  825.  
  826. /*
  827.  * Render the scene and copy it to the window and device context
  828.  * given. This function encapsulates the very common RenderWare
  829.  * for rendering and updating the display.
  830.  */
  831. static void
  832. RenderScene(void)
  833. {
  834.     /*
  835.      * Setup the current camera and perform all necessary initialization
  836.      * before rendering takes place.
  837.      */
  838.     RwBeginCameraUpdate(Camera,NULL);
  839.  
  840.     /*
  841.      * Clear the areas of the camera's viewport which were damaged
  842.      * last time round. If this call is not made, ghost images of
  843.      * previous rendering will remain.
  844.      */
  845.     RwClearCameraViewport(Camera);
  846.  
  847.         /*
  848.          * Re-render the entire scene.
  849.          */
  850.         RwRenderScene(CurrentCoaster->scene);
  851.  
  852.     /*
  853.      * Perform all necessary housekeeping after rendering is complete.
  854.      * After this call, the camera's image buffer will be ready to be
  855.      * copied to the display.
  856.      */
  857.     RwEndCameraUpdate(Camera);
  858.  
  859.     /*
  860.      * Copy the camera's image buffer to the output window. Under
  861.      * MS Windows, RenderWare requires both the window handle of the
  862.      * output window and a device context for the client area of the
  863.      * window. Therefore, a LONG is created which holds both the
  864.      * window handle and device context of the output window. This
  865.      * LONG is then passed in as the device specific parameter of
  866.      * the RwShowCameraImage() call.
  867.      */
  868.     RwShowCameraImage(Camera, NULL);
  869. }
  870.  
  871. /*******************************************************************************
  872.  ReadLine
  873.  
  874.  On entry : (OUT) buffer to put string in
  875.  On exit  :
  876.  */
  877.  
  878. void ReadLine(char *cpLine)
  879. {
  880.     int nPos;
  881.     int nKey;
  882.  
  883.         RwDPointerRemove();
  884.         DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
  885.         DosPrintString(0,nGScrHeight-8,"Filename :  @",nGTextColour);
  886.  
  887.         nPos = 0;
  888.         cpLine[0]='\0';
  889.  
  890.         do {
  891.             nKey = DosGetKey();
  892.  
  893.             if ((nPos>0)&&(nKey==8)) {
  894.                 RwDPrintChar((nPos+11)<<3,nGScrHeight-8,'@',nGTextColour);
  895.                 RwDPrintChar((nPos+12)<<3,nGScrHeight-8,' ',nGTextColour);
  896.                 nPos--;
  897.                 cpLine[nPos]='\0';
  898.             };
  899.  
  900.             if ((nPos<25)&&(nKey>32)&&(nKey<127)) {
  901.                 cpLine[nPos]=nKey;
  902.                 nPos++;
  903.                 cpLine[nPos]='\0';
  904.  
  905.                 RwDPrintChar((nPos+11)<<3,nGScrHeight-8,nKey,nGTextColour);
  906.                 RwDPrintChar((nPos+1+11)<<3,nGScrHeight-8,'@',nGTextColour);
  907.             };
  908.  
  909.         } while (nKey!=13);
  910.  
  911.     DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
  912. }
  913.  
  914. /**********************************************************************/
  915.  
  916. /*
  917.  * This functions handles the left mouse button going down. Its main
  918.  * job is to determine the kind of action to be taken when the mouse
  919.  * moves, such as spinning a clump, or panning the camera. This involves
  920.  * examining the virtual keys that were depressed when the mouse button
  921.  * went down and attempting to pick a clump under the mouse pointer
  922.  * position.
  923.  */
  924. static void
  925. HandleLeftButtonDown(int x, int y, int vKeys)
  926. {
  927.     int nOption;
  928.     char sBuffer[128];
  929.     RollerCoasterType *coaster;
  930.  
  931.     if ((y>nGScrHeight-24)&&(y<nGScrHeight-16)) {
  932.         nOption = (x>>6);
  933.         switch(nOption) {
  934.             case 0: {
  935.                 DisplayModeFlip();
  936.                 break;
  937.             };
  938.             case 1: {
  939.                 /* Load */
  940.                 ReadLine(sBuffer);
  941.                 coaster = ReadRollerCoaster(sBuffer);
  942.                 if (coaster != NULL)
  943.                 {
  944.                     SwitchCoaster(coaster);
  945.                 }
  946.                 break;
  947.             };
  948.             case 2: {
  949.                 /* Save */
  950.                 ReadLine(sBuffer);
  951.                 WriteRollerCoaster(CurrentCoaster,sBuffer);
  952.                 break;
  953.             };
  954.             case 3: {
  955.                 /* New */
  956.                 coaster = CreateRollerCoaster();
  957.                 if (coaster != NULL)
  958.                 {
  959.                     SwitchCoaster(coaster);
  960.                 };
  961.                 break;
  962.             };
  963.             case 4: {
  964.                 /* EditPlan */
  965.                 SwitchToPlanView();
  966.                 break;
  967.             };
  968.             default: {
  969.                 break;
  970.             };
  971.         };
  972.     };
  973.  
  974.     if ((y>nGScrHeight-16)&&(y<nGScrHeight-8)) {
  975.         SwitchToElevationView();
  976.     };
  977.  
  978.     switch (CameraMode)
  979.     {
  980.         case cmRIDE:
  981.         case cmSPOTTER:
  982.         case cmTRAIL:
  983.         case cmLEAD:
  984.             /*
  985.              * The left button does nothing when riding the
  986.              * coaster.
  987.              */
  988.         MouseMoveMode = mmNONE;
  989.             break;
  990.  
  991.         case cmELEVATION:
  992.         case cmPLAN:
  993.             /*
  994.              * If a control point is picked, move the control
  995.              * point, otherwise, move the camera.
  996.              */
  997.             ControlPoint = IsCoasterControlPointPicked(CurrentCoaster, Camera, x, y);
  998.             if (ControlPoint == 0)
  999.             {
  1000.                 if (vKeys & MK_SHIFT)
  1001.                     MouseMoveMode = mmALTMOVECAMERA;
  1002.                 else
  1003.                     MouseMoveMode = mmMOVECAMERA;
  1004.             }
  1005.             else
  1006.             {
  1007.                 MouseMoveMode = mmMOVECONTROL;
  1008.             }
  1009.             break;
  1010.   }
  1011.  
  1012.     /*
  1013.      * If any form of action is to be taken on mouse move, remember the
  1014.      * the current x and y position of the mouse and capture future
  1015.      * mouse movement.
  1016.      */
  1017.     if (MouseMoveMode != mmNONE)
  1018.     {
  1019.         LastX = x;
  1020.         LastY = y;
  1021.     }
  1022. }
  1023.  
  1024. /**********************************************************************/
  1025.  
  1026. /*
  1027.  * This functions handles the right mouse button going down. Its main
  1028.  * job is to determine the kind of action to be taken when the mouse
  1029.  * moves such as panning the camera.
  1030.  */
  1031. static void
  1032. HandleRightButtonDown(int x, int y, int vKeys)
  1033. {
  1034.     /* Stop warnings */
  1035.  
  1036.     vKeys = vKeys;
  1037.  
  1038.     MouseMoveMode = mmMOVELIGHT;
  1039.  
  1040.     /*
  1041.      * If any form of action is to be taken on mouse move, remember the
  1042.      * the current x and y position of the mouse and capture future
  1043.      * mouse movement.
  1044.      */
  1045.     if (MouseMoveMode != mmNONE)
  1046.     {
  1047.         LastX = x;
  1048.         LastY = y;
  1049.     }
  1050.  
  1051. }
  1052.  
  1053. /**********************************************************************/
  1054.  
  1055. /*
  1056.  * Handle a movement of the mouse. If a previous left or right mouse
  1057.  * button down event has set a mouse move mode then this function will
  1058.  * take the necessary actions. For example, pan and zooming the camera,
  1059.  * panning the light, dragging or spinning a clump etc.
  1060.  */
  1061. static void
  1062. HandleMouseMove( int x, int y,int vKeys)
  1063. {
  1064.     RwV3d       position;
  1065.     RwV3d newPos;
  1066.  
  1067.     /* Stop warnings */
  1068.  
  1069.     vKeys = vKeys;
  1070.  
  1071.     /*
  1072.      * MouseMoveMode tells us what kind of action to perform.
  1073.      */
  1074.     switch (MouseMoveMode)
  1075.     {
  1076.         case mmNONE:
  1077.             break;
  1078.  
  1079.         case mmMOVECAMERA:
  1080.             switch (CameraMode)
  1081.             {
  1082.                 case cmNONE:
  1083.                 case cmRIDE:
  1084.                 case cmSPOTTER:
  1085.                 case cmTRAIL:
  1086.                 case cmLEAD:
  1087.                     break;
  1088.  
  1089.                 case cmELEVATION:
  1090.                     RwPushScratchMatrix();
  1091.                         RwRotateMatrix(RwScratchMatrix(),
  1092.                                        CREAL(0.0),
  1093.                                        CREAL(1.0),
  1094.                                        CREAL(0.0),
  1095.                                        RDiv(INT2REAL(LastX - x), CREAL(5.0)),
  1096.                                        rwREPLACE);
  1097.                         RwTransformCamera(Camera, RwScratchMatrix(), rwPOSTCONCAT);
  1098.                     RwPopScratchMatrix();
  1099.                     RwVCMoveCamera(Camera,
  1100.                                    CREAL(0.0),
  1101.                                    CREAL(0.0),
  1102.                                    RDiv(INT2REAL(LastY - y), CREAL(50.0)));
  1103.                     RwGetCameraPosition(Camera, &position);
  1104.                     if (position.x < CREAL(-1.5))
  1105.                         position.x = CREAL(-1.5);
  1106.                     if (position.x > CREAL( 1.5))
  1107.                         position.x = CREAL( 1.5);
  1108.                     if (position.z < CREAL(-1.5))
  1109.                         position.z = CREAL(-1.5);
  1110.                     if (position.z > CREAL( 1.5))
  1111.                         position.z = CREAL( 1.5);
  1112.                     RwSetCameraPosition(Camera, position.x, position.y, position.z);
  1113.                     TrackBackdropToCamera(Camera);
  1114.                     break;
  1115.  
  1116.                 case cmPLAN:
  1117.                     RwVCMoveCamera(Camera,
  1118.                                    RDiv(INT2REAL(LastX - x), CREAL(50.0)),
  1119.                                    RDiv(INT2REAL(y - LastY), CREAL(50.0)),
  1120.                                    CREAL(0.0));
  1121.                     RwGetCameraPosition(Camera, &position);
  1122.                     if (position.x < CREAL(-1.0))
  1123.                         position.x = CREAL(-1.0);
  1124.                     if (position.x > CREAL( 1.0))
  1125.                         position.x = CREAL( 1.0);
  1126.                     if (position.z < CREAL(-1.0))
  1127.                         position.z = CREAL(-1.0);
  1128.                     if (position.z > CREAL( 1.0))
  1129.                         position.z = CREAL( 1.0);
  1130.                     RwSetCameraPosition(Camera, position.x, position.y, position.z);
  1131.                     break;
  1132.             }
  1133.             break;
  1134.  
  1135.         case mmALTMOVECAMERA:
  1136.             switch (CameraMode)
  1137.             {
  1138.                 case cmNONE:
  1139.                 case cmRIDE:
  1140.                 case cmSPOTTER:
  1141.                 case cmTRAIL:
  1142.                 case cmLEAD:
  1143.                     break;
  1144.  
  1145.                 case cmELEVATION:
  1146.                     RwVCMoveCamera(Camera,
  1147.                                    CREAL(0.0),
  1148.                                    RDiv(INT2REAL(y - LastY), CREAL(50.0)),
  1149.                                    CREAL(0.0));
  1150.                     RwGetCameraPosition(Camera, &position);
  1151.                     if (position.y < DEFAULTGROUNDLEVEL)
  1152.                         position.y = DEFAULTGROUNDLEVEL;
  1153.                     if (position.y > DEFAULTSKYLEVEL)
  1154.                         position.y = DEFAULTSKYLEVEL;
  1155.                     RwSetCameraPosition(Camera, position.x, position.y, position.z);
  1156.                     TrackBackdropToCamera(Camera);
  1157.                     break;
  1158.  
  1159.                 case cmPLAN:
  1160.                     RwVCMoveCamera(Camera,
  1161.                                    CREAL(0.0),
  1162.                                    CREAL(0.0),
  1163.                                    RDiv(INT2REAL(y - LastY), CREAL(50.0)));
  1164.                     RwGetCameraPosition(Camera, &position);
  1165.                     if (position.y < DEFAULTGROUNDLEVEL)
  1166.                         position.y = DEFAULTGROUNDLEVEL;
  1167.                     if (position.y > DEFAULTSKYLEVEL)
  1168.                         position.y = DEFAULTSKYLEVEL;
  1169.                     RwSetCameraPosition(Camera, position.x, position.y, position.z);
  1170.                     break;
  1171.             }
  1172.             break;
  1173.  
  1174.         case mmMOVECONTROL:
  1175.             RwPushScratchMatrix();
  1176.                 /*
  1177.                  * This function (from pick.c) returns the new position for a clump which lies under
  1178.                  * the given viewport coordinates. This allows as to drag control points exactly
  1179.                  * under the mouse pointer.
  1180.                  */
  1181.                     GetClumpPositionUnderPointer(COASTERCONTROLPOINT(CurrentCoaster, ControlPoint),
  1182.                                                  Camera, x, y, &newPos);
  1183.                 RwTranslateMatrix(RwScratchMatrix(), newPos.x, newPos.y, newPos.z, rwREPLACE);
  1184.                 TransformCoasterControlPoint(CurrentCoaster, ControlPoint, RwScratchMatrix());
  1185.             RwPopScratchMatrix();
  1186.             break;
  1187.  
  1188.         case mmMOVELIGHT:
  1189.             /*
  1190.              * We are panning the light about the origin. We will rotate
  1191.              * the light about the Y axis for movements of the mouse in
  1192.              * X and rotate the light about the X axis for movements of
  1193.              * the mouse in Y. In this case we will ignore the effects
  1194.              * of camera orientation changes.
  1195.              */
  1196.             RwPushScratchMatrix();
  1197.                 /*
  1198.                  * Replace the CTM with a rotation matrix about Y. The number
  1199.                  * of degrees of rotation is given by the mouse X delta.
  1200.                  */
  1201.                 RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  1202.                                INT2REAL(LastX - x), rwREPLACE);
  1203.  
  1204.                 /*
  1205.                  * Postconcat another rotation onto the CTM. The new rotation
  1206.                  * is a rotation about X, the angle being given by the mouse
  1207.                  * Y delta.
  1208.                  */
  1209.                 RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
  1210.                                INT2REAL(LastY - y), rwPOSTCONCAT);
  1211.  
  1212.                 /*
  1213.                  * Transform the light by the resultant rotations.
  1214.                  */
  1215.                 RwTransformLight(CurrentCoaster->light, RwScratchMatrix(), rwPOSTCONCAT);
  1216.             RwPopScratchMatrix();
  1217.             break;
  1218.     }
  1219.  
  1220.     if (MouseMoveMode != mmNONE)
  1221.     {
  1222.     /*
  1223.      * Re-render the scene and copy the results to the display.
  1224.      */
  1225.     RenderScene();
  1226.  
  1227.     /*
  1228.      * Remember the current X and Y for next time.
  1229.      */
  1230.     LastX = x;
  1231.     LastY = y;
  1232.     }
  1233. }
  1234.  
  1235. /**********************************************************************/
  1236.  
  1237. /*
  1238.  * Handle the left mouse button comming back up. The basic action is
  1239.  * to turn off mouse move actions and release mouse capture.
  1240.  */
  1241. static void
  1242. HandleLeftButtonUp(void)
  1243. {
  1244.     /*
  1245.      * If we were engaged in a mouse move action and the button has come
  1246.      * back up, then terminate the action and release mouse capture.
  1247.      */
  1248.     switch (MouseMoveMode)
  1249.     {
  1250.         case mmNONE:
  1251.             break;
  1252.  
  1253.         case mmMOVECAMERA:
  1254.         case mmALTMOVECAMERA:
  1255.             MouseMoveMode = mmNONE;
  1256.             switch (CameraMode)
  1257.             {
  1258.                 case cmRIDE:
  1259.                 case cmSPOTTER:
  1260.                 case cmTRAIL:
  1261.                 case cmLEAD:
  1262.                     break;
  1263.  
  1264.                 case cmELEVATION:
  1265.                     RwGetCameraPosition(Camera, &CurrentCoaster->elevationPosition);
  1266.                     break;
  1267.  
  1268.                 case cmPLAN:
  1269.                     RwGetCameraPosition(Camera, &CurrentCoaster->planPosition);
  1270.                     break;
  1271.             }
  1272.             break;
  1273.  
  1274.       case mmMOVECONTROL:
  1275.         MouseMoveMode = mmNONE;
  1276.         UpdateCoasterClump(CurrentCoaster);
  1277.         RwInvalidateCameraViewport(Camera);
  1278.         RenderScene();
  1279.         break;
  1280.     }
  1281.  
  1282.  
  1283. }
  1284.  
  1285. /**********************************************************************/
  1286.  
  1287. /*
  1288.  * Handle the right mouse button comming back up. The basic action is
  1289.  * to turn of mouse move actions and release mouse capture.
  1290.  */
  1291. static void
  1292. HandleRightButtonUp()
  1293. {
  1294.     /*
  1295.      * If we were engaged in a mouse move action and the button has come
  1296.      * back up, then terminate the action and release mouse capture.
  1297.      */
  1298.   MouseMoveMode = mmNONE;
  1299. }
  1300.  
  1301.  
  1302. /**********************************************************************/
  1303.  
  1304. /*
  1305.  * Handle MS Window's timer expiry. This function will perform any
  1306.  * animation actions necessary, including spinning clumps and animating
  1307.  * textures.
  1308.  */
  1309. static void
  1310. OnTimer()
  1311. {
  1312.     RwReal    x;
  1313.     RwReal    y;
  1314.     RwReal    z;
  1315.  
  1316.     if (MouseMoveMode == mmNONE)
  1317.     {
  1318.         switch (CameraMode)
  1319.         {
  1320.             case cmRIDE:
  1321.                 UpdateViewParameters(CurrentCoaster);
  1322.                 RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1323.                 RwSetCameraLookAt(Camera,
  1324.                                   CurrentCoaster->tAt.x,
  1325.                                   CurrentCoaster->tAt.y,
  1326.                                   CurrentCoaster->tAt.z);
  1327.                 x = RAdd(CurrentCoaster->tPosition.x, RMul(CurrentCoaster->tUp.x, CREAL(0.1)));
  1328.                 y = RAdd(CurrentCoaster->tPosition.y, RMul(CurrentCoaster->tUp.y, CREAL(0.1)));
  1329.                 z = RAdd(CurrentCoaster->tPosition.z, RMul(CurrentCoaster->tUp.z, CREAL(0.1)));
  1330.                 RwSetCameraPosition(Camera, x, y, z);
  1331.                 TrackBackdropToCamera(Camera);
  1332.                 UpdateCoasterVelocity(CurrentCoaster);
  1333.                 break;
  1334.  
  1335.             case cmSPOTTER:
  1336.                 UpdateViewParameters(CurrentCoaster);
  1337.                 RwSetCameraPosition(Camera,
  1338.                                     CurrentCoaster->tPosition.x,
  1339.                                     CurrentCoaster->tPosition.y,
  1340.                                     CurrentCoaster->tPosition.z);
  1341.                 RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1342.                 RwSetCameraLookAt(Camera, CREAL(0.0), CREAL(0.0), CREAL(1.0));
  1343.                 RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1344.                 RwPanCamera(Camera, CameraAngle);
  1345.                 RwTiltCamera(Camera, CREAL(40.0));
  1346.                 RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.20));
  1347.                 TrackBackdropToCamera(Camera);
  1348.                 UpdateCoasterVelocity(CurrentCoaster);
  1349.  
  1350.                 CameraAngle = RAdd(CameraAngle, CREAL(5.0));
  1351.                 if (CameraAngle > CREAL(360.0))
  1352.                     CameraAngle = RSub(CameraAngle, CREAL(360.0));
  1353.                 break;
  1354.  
  1355.             case cmTRAIL:
  1356.                 UpdateViewParameters(CurrentCoaster);
  1357.                 RwSetCameraPosition(Camera,
  1358.                                     CurrentCoaster->tPosition.x,
  1359.                                     CurrentCoaster->tPosition.y,
  1360.                                     CurrentCoaster->tPosition.z);
  1361.                 RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1362.                 RwSetCameraLookAt(Camera,
  1363.                                   CurrentCoaster->tAt.x,
  1364.                                   CurrentCoaster->tAt.y,
  1365.                                   CurrentCoaster->tAt.z);
  1366.                 RwSetCameraLookUp(Camera,
  1367.                                   CurrentCoaster->tUp.x,
  1368.                                   CurrentCoaster->tUp.y,
  1369.                                   CurrentCoaster->tUp.z);
  1370.                 RwTiltCamera(Camera, CREAL(45.0));
  1371.                 RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.15));
  1372.                 TrackBackdropToCamera(Camera);
  1373.                 UpdateCoasterVelocity(CurrentCoaster);
  1374.                 break;
  1375.  
  1376.             case cmLEAD:
  1377.                 UpdateViewParameters(CurrentCoaster);
  1378.                 RwSetCameraPosition(Camera,
  1379.                                     CurrentCoaster->tPosition.x,
  1380.                                     CurrentCoaster->tPosition.y,
  1381.                                     CurrentCoaster->tPosition.z);
  1382.                 RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1383.                 RwSetCameraLookAt(Camera,
  1384.                                   CurrentCoaster->tAt.x,
  1385.                                   CurrentCoaster->tAt.y,
  1386.                                   CurrentCoaster->tAt.z);
  1387.                 RwSetCameraLookUp(Camera,
  1388.                                   CurrentCoaster->tUp.x,
  1389.                                   CurrentCoaster->tUp.y,
  1390.                                   CurrentCoaster->tUp.z);
  1391.                 RwPanCamera(Camera, CREAL(180.0));
  1392.                 RwTiltCamera(Camera, CREAL(60.0));
  1393.                 RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.15));
  1394.                 TrackBackdropToCamera(Camera);
  1395.                 UpdateCoasterVelocity(CurrentCoaster);
  1396.                 break;
  1397.  
  1398.             case cmELEVATION:
  1399.             case cmPLAN:
  1400.                 UpdateViewParameters(CurrentCoaster);
  1401.                 UpdateCoasterVelocity(CurrentCoaster);
  1402.                 break;
  1403.         }
  1404.     }
  1405.  
  1406.     /*
  1407.      * Re-render the scene and copy the results to the display.
  1408.      */
  1409.     RenderScene();
  1410. }
  1411.  
  1412. /**********************************************************************/
  1413.  
  1414.  
  1415. /***********************************************************************
  1416.  DisplayModeFlip
  1417.  
  1418.  On entry     :
  1419.  On exit    :
  1420.  */
  1421.  
  1422. void DisplayModeFlip(void)
  1423. {
  1424.     nGDisplayMode = (nGDisplayMode+1)&3;
  1425.  
  1426.     RwDPointerRemove();
  1427.  
  1428.     switch (nGDisplayMode) {
  1429.         case 0: {
  1430.             DosPrintString(0,nGScrHeight-24,"Ride    ",nGTextColour);
  1431.             SwitchToRideView();
  1432.             break;
  1433.         };
  1434.         case 1: {
  1435.             DosPrintString(0,nGScrHeight-24,"Trail   ",nGTextColour);
  1436.             SwitchToTrailView();
  1437.             break;
  1438.         };
  1439.         case 2: {
  1440.             DosPrintString(0,nGScrHeight-24,"Lead    ",nGTextColour);
  1441.             SwitchToLeadView();
  1442.             break;
  1443.         };
  1444.         case 3: {
  1445.             DosPrintString(0,nGScrHeight-24,"Spotter ",nGTextColour);
  1446.             SwitchToSpotterView();
  1447.             break;
  1448.         };
  1449.         default: {
  1450.             break;
  1451.         };
  1452.     };
  1453. }
  1454.  
  1455. /****************************************************************************
  1456.  Main
  1457.  */
  1458.  
  1459. void main(int nArgc,char *saArgv[])
  1460. {
  1461.     int nKey;
  1462.     int nMouseX,nMouseY,nMouseBut,nOldMouseBut;
  1463.     int nChange;
  1464.     int nShiftCtrl=0;
  1465.     int nDX,nDY;
  1466.  
  1467.   /* Stop warnings */
  1468.  
  1469.   nArgc = nArgc;
  1470.   saArgv = saArgv;
  1471.  
  1472.     if (!Init3D())
  1473.     {
  1474.         exit(-1);
  1475.     };
  1476.  
  1477.     /* Create pointer */
  1478.  
  1479.     RwDPointerDisplay(&LastX,&LastY,&nOldMouseBut);
  1480.  
  1481.     nKey = DosGetKey();
  1482.  
  1483.   DrawFPS = 0;
  1484.  
  1485.     /* Make sure current mode is displayed on the screen */
  1486.     DisplayModeFlip();
  1487.  
  1488.     while (nKey!=27) {              /* ESC quits */
  1489.         RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
  1490.  
  1491.         /* The other bits */
  1492.  
  1493.         nDX =(nMouseX-LastX);
  1494.         nDY =(nMouseY-LastY);
  1495.  
  1496.         nKey = DosGetKey();
  1497.         nShiftCtrl = DosShiftCtrl();
  1498.  
  1499.         nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
  1500.  
  1501.         switch (nChange) {
  1502.             case 0+0:
  1503.             case 2+1:
  1504.             case 8+4:
  1505.             case 8+2+4+1: {
  1506.                 /* No change */
  1507.                 break;
  1508.             };
  1509.             case 2:
  1510.             case 8+2+4: {
  1511.  
  1512.                 /* Left Button Down */
  1513.  
  1514.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1515.  
  1516.  
  1517.                 break;
  1518.             };
  1519.             case 8:
  1520.             case 8+2+1: {
  1521.                 /* Right Button Down */
  1522.  
  1523.  
  1524.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1525.  
  1526.  
  1527.                 break;
  1528.             };
  1529.             case 8+1: {
  1530.                 /* Right down left Up */
  1531.  
  1532.  
  1533.                 HandleLeftButtonUp();
  1534.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1535.  
  1536.  
  1537.                 break;
  1538.             };
  1539.             case 2+4: {
  1540.                 /* Right up left Down */
  1541.  
  1542.  
  1543.                 HandleRightButtonUp();
  1544.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1545.  
  1546.  
  1547.                 break;
  1548.             };
  1549.             case 8+2: {
  1550.                 /* Left down RIght Down */
  1551.  
  1552.  
  1553.                 HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1554.                 HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
  1555.  
  1556.  
  1557.                 break;
  1558.             };
  1559.             case 1+4: {
  1560.                 /* Left up Right Up */
  1561.  
  1562.  
  1563.                 HandleRightButtonUp();
  1564.                 HandleLeftButtonUp();
  1565.  
  1566.  
  1567.                 break;
  1568.             };
  1569.             case 1:
  1570.             case 8+4+1: {
  1571.                 /* Left up */
  1572.  
  1573.  
  1574.                 HandleLeftButtonUp();
  1575.  
  1576.  
  1577.                 break;
  1578.             };
  1579.             case 4:
  1580.             case 2+4+1: {
  1581.                 /* Right up */
  1582.                 HandleRightButtonUp();
  1583.                 break;
  1584.             };
  1585.         };
  1586.  
  1587.         if ((nDX)||(nDY)) {
  1588.             HandleMouseMove(nMouseX,nMouseY,nShiftCtrl);
  1589.     };
  1590.  
  1591.     OnTimer();
  1592.  
  1593.         nOldMouseBut = nMouseBut;
  1594.     };
  1595.  
  1596.     /*
  1597.     * Tidy up the 3D (RenderWare) components of the application.
  1598.     */
  1599.  
  1600.     TidyUp3D();
  1601.  
  1602.     exit(0);
  1603. }
  1604.