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

  1. /**********************************************************************
  2.  *
  3.  * File :     doscyber.c
  4.  *
  5.  * Abstract : This is the main module of the cyberstreet demo. It contains
  6.  *            the code that handles all of the user interaction and the
  7.  *            interaction between the other modules.
  8.  *
  9.  **********************************************************************
  10.  *
  11.  * This file is a product of Criterion Software Ltd.
  12.  *
  13.  * This file is provided as is with no warranties of any kind and is
  14.  * provided without any obligation on Criterion Software Ltd. or
  15.  * Canon Inc. to assist in its use or modification.
  16.  *
  17.  * Criterion Software Ltd. will not, under any
  18.  * circumstances, be liable for any lost revenue or other damages arising
  19.  * from the use of this file.
  20.  *
  21.  * Copyright (c) 1995 Criterion Software Ltd.
  22.  * All Rights Reserved.
  23.  *
  24.  * RenderWare is a trademark of Canon Inc.
  25.  *
  26.  ************************************************************************/
  27.  
  28. /*--- Include files ---*/
  29.  
  30. #define DEFINE_GLOBAL
  31. #include "global.h"     /* Application general includes */
  32. #include "palette.h"
  33.  
  34. /*--- Magic Number Definitions ---*/
  35.  
  36. #define M_PI 3.1415926535897932
  37.  
  38. /* Default size of the viewer's window. */
  39.  
  40. #define CLOSEST         0.1  /* Closest we can get to a wall */
  41. #define LOWEST          0.2  /* Closest we can get to the ground */
  42.  
  43. #define STREET_HIGHEST  2.5  /* Maximum height we can fly above street */
  44. #define HALL_HIGHEST    0.4  /* Maximum height we can fly above hall */
  45. #define POOL_HIGHEST    1.4  /* Maximum height we can fly above pool */
  46.  
  47. #define MAX_TILT        80.0 /* The maximum tilt angle for the camera */
  48.  
  49. /*--- Structure and enumerated type definitions ---*/
  50.  
  51. /* This enumerated type tells us what kind of action should be taken
  52.  * on mouse events.
  53.  */
  54.  
  55. typedef enum
  56. {
  57.     MMNoAction,
  58.     MMTravelCamera,
  59.     MMTiltCamera,
  60.     MMChangeHeight
  61. } MMMode;
  62.  
  63. /* This enumerated type determines which cell of the world we are
  64.  * currently in
  65.  */
  66.  
  67. typedef enum
  68. {
  69.     CELL_STREET,
  70.     CELL_HALL,
  71.     CELL_POOL
  72. } Cell;
  73.  
  74. /*--- Module Global Variables ---*/
  75.  
  76. /* These variables are used to hold the polygons that define the lights
  77.  * above the billboard. The lights are turned on and off by varying the
  78.  * ambient surface property of these polygons.
  79.  */
  80.  
  81. RwPolygon3d *ppGLight1;
  82. RwPolygon3d *ppGLight2;
  83.  
  84. /* These variables are used to hold the textures for the billboard. Each
  85.  * of these textures contains 2 frames. One image shows the billboard lit
  86.  * and the other is unlit. The billboard is made to appear lit or unlit by
  87.  * the lights defined above by varying the current texture frame.
  88.  */
  89.  
  90. RwTexture *tpGBillboardLeft;
  91. RwTexture *tpGBillboardRight;
  92.  
  93. /* These variables hold the clumps that make up the world.
  94.  */
  95.  
  96. static RwClump *cpGCity   = NULL;  /* The main street clump */
  97. static RwClump *cpGHall   = NULL;  /* The hall between the street and the poolroom */
  98. static RwClump *cpGPool   = NULL;  /* The poolroom clump */
  99. static RwClump *cpGSky1,*cpGSky2;  /* These 2 clumps are dummies that are used
  100.                                       to calculate the area of the display
  101.                                       that is covered by the skyline backdrop */
  102.  
  103. /* The camera can fly around a predetermined path. These variables define the
  104.    path and the control variable.
  105.  */
  106.  
  107. static RwSpline *spGPath = NULL;    /* The flight path for the camera */
  108. static RwReal nGAlpha;              /* The control variable for the path */
  109.  
  110. static RwReal nGSpeed;              /* The current speed of the camera */
  111. static RwReal nGTilt;               /* The absolute tilt angle of the camera */
  112. static RwReal nGGroundHeight;       /* The current ground height */
  113.  
  114. static int nGOnPad = 0;             /* If Camera is over the pad that activates
  115.                                        the door then this variable is TRUE */
  116. static int nGDoorPos = 0;           /* The current position for the door.
  117.                                        0 = closed, DOOR_OPEN = open */
  118.  
  119. static RwV3d vaGDoor[20];           /* The door appears to open by having
  120.                                        the vertices modified. This variable
  121.                                        is used to hold the current value of
  122.                                        vertices used */
  123. static RwInt32 naGDoor[20];            /* This variable holds the indices for the
  124.                                        vertices defined above */
  125.  
  126. static Cell eGWhichCell;            /* The current cell (STREET, HALL or
  127.                                        POOLROOM) */
  128. static int nGFlyCamera;             /* TRUE is camera is flying, FALSE
  129.                                        otherwise */
  130.  
  131. /*
  132.  * This variable tells us what kind of action to take on a mouse move.
  133.  * The action depends on the object that was picked when the mouse button
  134.  * went down, and on the selection of virtual keys that were depressed at
  135.  * that time. By default no action is taken on mouse move.
  136.  */
  137.  
  138. static MMMode mGMouseMoveMode = MMNoAction;
  139.  
  140. /*
  141.  * Global variables used to remember the last mouse X and Y coordinates
  142.  * when involved in a pan, zoom, drag or spin.
  143.  */
  144. static RwInt32 nGLastX;
  145. static RwInt32 nGLastY;
  146.  
  147. /*--- Function Definitions ---*/
  148.  
  149. /************************************************************************
  150.  *
  151.  *      Function:       GetPosHeight()
  152.  *
  153.  *      Description:    Get the height of the ground at a given position
  154.  *
  155.  *      Parameters:     vpPos - 3D position for which we want the ground
  156.  *                              height.
  157.  *
  158.  *      Return Value:   height of the ground at the specified point.
  159.  *
  160.  ************************************************************************/
  161. RwReal
  162. GetPosHeight(RwV3d *vpPos)
  163. {
  164.     RwInt32 nStep;
  165.  
  166.     if (vpPos->x < CREAL(RIGHT_STREET))
  167.     {
  168.         /* In the street */
  169.  
  170.         if ((vpPos->x > CREAL(LEFT_KERB)) && (vpPos->x < CREAL(RIGHT_KERB)))
  171.         {
  172.             return (CREAL(STREET_HEIGHT + LOWEST));
  173.         }
  174.         else
  175.         {
  176.             return (CREAL(KERB_HEIGHT + LOWEST));
  177.         }
  178.     }
  179.     else
  180.     {
  181.         /* In pool room or on steps */
  182.  
  183.         nStep = REAL2INT(RDiv(RSub(vpPos->x, CREAL(RIGHT_STREET)), CREAL(STEP_WIDTH)));
  184.         if (nStep < 0)
  185.         {
  186.             nStep = 0;
  187.         }
  188.         if (nStep > MAX_STEPS)
  189.       {
  190.             nStep = MAX_STEPS;
  191.         }
  192.         return RSub(CREAL(KERB_HEIGHT + LOWEST), RMul(INT2REAL(nStep), CREAL(STEP_HEIGHT)));
  193.     }
  194. }
  195.  
  196. /************************************************************************
  197.  *
  198.  *      Function:       WhichCell()
  199.  *
  200.  *      Description:    Work out which cell the given position is in.
  201.  *
  202.  *      Parameters:     vpPos - 3D point that we want the cell for
  203.  *
  204.  *      Return Value:   Cell that contains the point
  205.  *
  206.  ************************************************************************/
  207. static Cell
  208. WhichCell(RwV3d *vpPos)
  209. {
  210.     /* Check if we are in the street */
  211.  
  212.     if ((vpPos->x > CREAL(LEFT_STREET)) &&
  213.         (vpPos->x < CREAL(RIGHT_STREET)) &&
  214.         (vpPos->z > CREAL(FAR_STREET)) &&
  215.         (vpPos->z < CREAL(NEAR_STREET)))
  216.     {
  217.         /* We're in the street */
  218.         return(CELL_STREET);
  219.     }
  220.  
  221.     /* Check if we are in the hall */
  222.  
  223.     if ( (vpPos->x > CREAL(LEFT_HALL)) &&
  224.          (vpPos->x < CREAL(RIGHT_HALL)) &&
  225.          (vpPos->z > CREAL(FAR_HALL)) &&
  226.          (vpPos->z < CREAL(NEAR_HALL)) )
  227.     {
  228.         /* We're in the hall */
  229.         return(CELL_HALL);
  230.     }
  231.  
  232.     /* The only place left is the poolroom */
  233.  
  234.     return(CELL_POOL);
  235. }
  236.  
  237. /************************************************************************
  238.  *
  239.  *      Function:       MoveForward()
  240.  *
  241.  *      Description:    Move the global Camera forward by the specified
  242.  *                      distance.
  243.  *
  244.  *      Parameters:     nDist The distance to move forward
  245.  *
  246.  *      Return Value:   None
  247.  *
  248.  ************************************************************************/
  249. static void
  250. MoveForward(RwReal nDist)
  251. {
  252.     RwV3d vAt, vOld, vNew;
  253.     RwReal nOldHeight;
  254.     RwReal nNewHeight;
  255.  
  256.     /* Find the forward movement vector for the Camera */
  257.  
  258.     RwGetCameraLookAt(cpGCamera, &vAt);
  259.  
  260.     /* We only want to move in x & z so remove the Y component and
  261.        renormalise the forward vector */
  262.  
  263.     vAt.y = CREAL(0.0);
  264.     RwNormalize(&vAt);
  265.  
  266.     /* Move the camera forward and get the new position */
  267.  
  268.     RwGetCameraPosition(cpGCamera, &vOld);
  269.     RwWCMoveCamera(cpGCamera,
  270.                     RMul(vAt.x, nDist), CREAL(0.0), RMul(vAt.z, nDist));
  271.     RwGetCameraPosition(cpGCamera, &vNew);
  272.  
  273.     /* Find out which cell we were in */
  274.  
  275.     eGWhichCell = WhichCell(&vOld);
  276.  
  277.     switch(eGWhichCell)
  278.     {
  279.     case CELL_STREET:
  280.         /* In the street so constrain movement to within street bounds */
  281.  
  282.         if (vNew.z < CREAL(FAR_STREET + CLOSEST))
  283.         {
  284.             vNew.z = CREAL(FAR_STREET + CLOSEST);
  285.         }
  286.         else if (vNew.z > CREAL(NEAR_STREET - CLOSEST))
  287.         {
  288.             vNew.z = CREAL(NEAR_STREET - CLOSEST);
  289.         }
  290.  
  291.         if (vNew.x < CREAL(LEFT_STREET + CLOSEST))
  292.         {
  293.             vNew.x = CREAL(LEFT_STREET + CLOSEST);
  294.         }
  295.         else if (vNew.x > CREAL(RIGHT_STREET - CLOSEST))
  296.         {
  297.             /* constrain if door is not open or not in front of door */
  298.  
  299.             if ((nGDoorPos < DOOR_OPEN) ||
  300.                 (vNew.y > RAdd(nGGroundHeight, CREAL(DOOR_HEIGHT + CLOSEST))) ||
  301.                 (vNew.z < CREAL(FAR_HALL)) ||
  302.                 (vNew.z > CREAL(NEAR_HALL)))
  303.             {
  304.                 vNew.x = CREAL(RIGHT_STREET - CLOSEST);
  305.             }
  306.         }
  307.  
  308.         /* check if we're over pressure pad */
  309.  
  310.         if ((vNew.x > CREAL(PAD_X)) &&
  311.             (vNew.y < RAdd(nGGroundHeight, CREAL(PAD_Y))) &&
  312.             (vNew.z > CREAL(FAR_HALL)) &&
  313.             (vNew.z < CREAL(NEAR_HALL)))
  314.         {
  315.             nGOnPad = TRUE;
  316.         }
  317.         else
  318.         {
  319.             nGOnPad = FALSE;
  320.         }
  321.         break;
  322.  
  323.     case CELL_HALL:
  324.         /* In the hall so constrain against passage walls */
  325.  
  326.         if (vNew.z < CREAL(FAR_HALL + CLOSEST))
  327.         {
  328.             vNew.z = CREAL(FAR_HALL + CLOSEST);
  329.         }
  330.         else if (vNew.z > CREAL(NEAR_HALL - CLOSEST))
  331.         {
  332.             vNew.z = CREAL(NEAR_HALL - CLOSEST);
  333.         }
  334.         break;
  335.  
  336.       case CELL_POOL:
  337.         /* In the poolroom so constrain movement to within poolroom bounds */
  338.  
  339.         if (vNew.z < CREAL(FAR_POOL + CLOSEST))
  340.         {
  341.             vNew.z = CREAL(FAR_POOL + CLOSEST);
  342.         }
  343.         else if (vNew.z > CREAL(NEAR_POOL - CLOSEST))
  344.         {
  345.             vNew.z = CREAL(NEAR_POOL - CLOSEST);
  346.         }
  347.  
  348.         if (vNew.x < CREAL(LEFT_POOL + CLOSEST))
  349.         {
  350.             /* constrain if not in front of door otherwise allow through
  351.                the door */
  352.  
  353.             if ((vNew.y > RAdd(nGGroundHeight, CREAL(DOOR_HEIGHT - CLOSEST))) ||
  354.                 (vNew.z < CREAL(FAR_HALL)) ||
  355.                 (vNew.z > CREAL(NEAR_HALL)))
  356.             {
  357.                 vNew.x = CREAL(LEFT_POOL + CLOSEST);
  358.             }
  359.         }
  360.         else if (vNew.x > CREAL(RIGHT_POOL - CLOSEST))
  361.         {
  362.             vNew.x = CREAL(RIGHT_POOL - CLOSEST);
  363.         }
  364.         break;
  365.     }
  366.  
  367.     /* The camera height follows the ground height so adjust the height
  368.        of the camera by any change in the ground height */
  369.  
  370.     nOldHeight = GetPosHeight(&vOld);
  371.     nNewHeight = GetPosHeight(&vNew);
  372.  
  373.     nGGroundHeight = nNewHeight;
  374.     vNew.y += nNewHeight - nOldHeight;
  375.  
  376.     RwSetCameraPosition(cpGCamera, vNew.x, vNew.y, vNew.z);
  377. }
  378.  
  379. /************************************************************************
  380.  *
  381.  *      Function:       MoveUp()
  382.  *
  383.  *      Description:    Move the global Camera up by the specified
  384.  *                      distance.
  385.  *
  386.  *      Parameters:     nDist The distance to move up
  387.  *
  388.  *      Return Value:   None
  389.  *
  390.  ************************************************************************/
  391. static void
  392. MoveUp(RwReal up)
  393. {
  394.     RwV3d vPos;
  395.  
  396.     /* Move the camera up (or down!) and get the new position */
  397.  
  398.     RwWCMoveCamera(cpGCamera, CREAL(0.0), up, CREAL(0.0));
  399.     RwGetCameraPosition(cpGCamera, &vPos);
  400.  
  401.     /* Check new height against upper and lower limits. The lower limit
  402.        is the current ground height. The upper limit is dependant on which
  403.        cell we are in */
  404.  
  405.     if (vPos.y < nGGroundHeight)
  406.     {
  407.         /* We can't move below the ground so clamp at this height */
  408.         vPos.y = nGGroundHeight;
  409.     }
  410.     else switch(eGWhichCell)
  411.     {
  412.         /* Check the upper limit against the current cell and clamp
  413.            if above the limit */
  414.  
  415.     case CELL_STREET:
  416.         if (vPos.y > CREAL(STREET_HEIGHT + STREET_HIGHEST))
  417.             vPos.y = CREAL(STREET_HEIGHT + STREET_HIGHEST);
  418.         break;
  419.  
  420.     case CELL_HALL:
  421.         if (vPos.y > RAdd(nGGroundHeight, CREAL(HALL_HIGHEST)))
  422.             vPos.y = RAdd(nGGroundHeight, CREAL(HALL_HIGHEST));
  423.         break;
  424.  
  425.     case CELL_POOL:
  426.         if (vPos.y > RAdd(nGGroundHeight, CREAL(POOL_HIGHEST)))
  427.             vPos.y = RAdd(nGGroundHeight, CREAL(POOL_HIGHEST));
  428.            break;
  429.     }
  430.     /* Move the camera to the new (possibly clamped) position */
  431.  
  432.     RwSetCameraPosition(cpGCamera, vPos.x, vPos.y, vPos.z);
  433. }
  434.  
  435. /************************************************************************
  436.  *
  437.  *      Function:       RandomVec()
  438.  *
  439.  *      Description:    Generate a random vector
  440.  *
  441.  *      Parameters:     vpVec - the vector to store the random value.
  442.  *
  443.  *      Return Value:   None
  444.  *
  445.  ************************************************************************/
  446. void RandomVec(RwV3d *vpVec)
  447. {
  448.     vpVec->x = RANDOM_REAL(CREAL(-1.0), CREAL(1.0));
  449.     vpVec->y = RANDOM_REAL(CREAL(-1.0), CREAL(1.0));
  450.     vpVec->z = RANDOM_REAL(CREAL(-1.0), CREAL(1.0));
  451. }
  452.  
  453. /************************************************************************
  454.  *
  455.  *      Function:       DoRwReadShape()
  456.  *
  457.  *      Description:    Read a RenderWare script file and generate an
  458.  *                      error on failure.
  459.  *
  460.  *      Parameters:     cpShape - the name of the script to load
  461.  *
  462.  *      Return Value:   None
  463.  *
  464.  ************************************************************************/
  465. RwClump
  466. *DoRwReadShape(char *cpShape)
  467. {
  468.     RwClump *cpClump;
  469.  
  470.     cpClump = RwReadShape(cpShape);
  471.  
  472.     if (!cpClump)
  473.     {
  474.         OsError("Unable to read <%s>", cpShape);
  475.     }
  476.     return cpClump;
  477. }
  478.  
  479. /************************************************************************
  480.  *
  481.  *      Function:       ResetCamera()
  482.  *
  483.  *      Description:    Move the camera back to its initial position
  484.  *                      and orientation.
  485.  *
  486.  *      Parameters:     cpShape - the name of the script to load
  487.  *
  488.  *      Return Value:   None
  489.  *
  490.  ************************************************************************/
  491. void
  492. ResetCamera(void)
  493. {
  494.     RwV3d vPos;
  495.  
  496.     nGSpeed = CREAL(0.0);    /* Camera is stationary */
  497.     nGTilt = CREAL(0.0);     /* Camera is looking straight ahead */
  498.  
  499.     /* Reset camera position */
  500.     RwSetCameraPosition(cpGCamera,
  501.                         CREAL(CAMERA_START_X),
  502.                         CREAL(CAMERA_START_Y),
  503.                         CREAL(CAMERA_START_Z));
  504.  
  505.     /* Camera is looking in the same direction as the -ve Z axis */
  506.     RwSetCameraLookAt(cpGCamera, CREAL(0.0),CREAL(0.0),CREAL(-1.0));
  507.  
  508.     /* And is level */
  509.     RwSetCameraLookUp(cpGCamera, CREAL(0.0),CREAL(1.0),CREAL(0.0));
  510.  
  511.     /* Set the ground height for this new position */
  512.     RwGetCameraPosition(cpGCamera, &vPos);
  513.     nGGroundHeight = GetPosHeight(&vPos);
  514.  
  515.     /* Set the current cell */
  516.     eGWhichCell = WhichCell(&vPos);
  517.  
  518.     nGOnPad = 0;     /* Not on the door pad */
  519.     nGFlyCamera = 0; /* Not flying */
  520. }
  521.  
  522. /************************************************************************
  523.  *
  524.  *      Function:       ToggleFlyCamera()
  525.  *
  526.  *      Description:    If camera is flying then stop it and move back to
  527.  *                      the start position. Otherwise start the camera flying
  528.  *
  529.  *      Parameters:     None
  530.  *
  531.  *      Return Value:   None
  532.  *
  533.  ************************************************************************/
  534. void
  535. ToggleFlyCamera(void)
  536. {
  537.     if (nGFlyCamera)
  538.     {
  539.         /* We are currently flying - so stop and reset camera */
  540.         nGFlyCamera = 0;
  541.         ResetCamera();
  542.     }
  543.     else
  544.     {
  545.         nGOnPad = 0;                /* If we're flying then we're not on
  546.                                        the door pad */
  547.         nGFlyCamera = 1;
  548.         eGWhichCell = CELL_STREET;  /* The spline path is in the street */
  549.         nGAlpha = CREAL(0.0);       /* Reset to the start of the path */
  550.     }
  551. }
  552.  
  553. /************************************************************************
  554.  *
  555.  *      Function:       Render()
  556.  *
  557.  *      Description:    This function controls the rendering of the scene
  558.  *
  559.  *      Parameters:     None
  560.  *
  561.  *      Return Value:   None
  562.  *
  563.  ************************************************************************/
  564. static void
  565. Render(void)
  566. {
  567.     RwV3d lookat;
  568.     RwReal    dot;
  569.     RwInt32 w, h, dx, dy, cw, ch;
  570.     static Cell eOldCell;
  571.  
  572.     /* If we have moved into or out of the street cell then enable or
  573.        disable the gun */
  574.  
  575.     if (eOldCell != eGWhichCell)
  576.     {
  577.         /* We've changed cells */
  578.  
  579.         eOldCell = eGWhichCell;
  580.  
  581.         if (eGWhichCell == CELL_STREET)
  582.         {
  583.             /* Moving into the street - Enable the gun */
  584.             GunEnable();
  585.         }
  586.         else
  587.         {
  588.             /* Disable the Gun */
  589.             GunDisable();
  590.         }
  591.     }
  592.  
  593.  
  594.     /* Only the STREET cell uses a bitmap backdrop. Enable it for this cell
  595.        and disable for the others */
  596.  
  597.     switch(eGWhichCell)
  598.     {
  599.         case CELL_STREET:
  600.             RwGetCameraViewport(cpGCamera, NULL, NULL, &cw, &ch);
  601.             RwSetCameraBackdropViewportRect(cpGCamera, 0, 0, cw, ch);
  602.             break;
  603.         case CELL_HALL:
  604.         case CELL_POOL:
  605.             GunDisable();   /* the gun should never be on here */
  606.             /* Don't need bitmap backdrop */
  607.             RwSetCameraBackdropViewportRect(cpGCamera, 0, 0, 0, 0);
  608.             break;
  609.     }
  610.  
  611.     /* clear the old damaged areas */
  612.  
  613.     RwUndamageCameraViewport(cpGCamera, 0,0, (RwInt32)512, (RwInt32)512);
  614.  
  615.     if (eGWhichCell == CELL_STREET)
  616.     {
  617.         /* Determine the position of the bitmap backdrop based on the current
  618.            camera orientation. This is achieved by assuming that the backdrop 
  619.            bitmap is applied to a cylinder which wraps around the world. Taking
  620.            the current view direction from the camera, it is possible to calculate
  621.            the point on the cylinder and hence the portion if the bitmap that 
  622.            should be in the centre of the screen */
  623.  
  624.            RwGetCameraLookAt(cpGCamera, &lookat);
  625.     
  626.            w = RwGetRasterWidth(RwGetCameraBackdrop(cpGCamera));
  627.            h = RwGetRasterHeight(RwGetCameraBackdrop(cpGCamera));
  628.     
  629.         /* Use the Y component of the look at directly. This is accurate
  630.            as long as the camera doesn't point directly up or down. This can't
  631.            happen in this application */
  632.  
  633.         /* Set the Y offset such that for a camera angle that is parallel
  634.            with the horizon, we are looking at the centre row of the backdrop
  635.            bitmap */
  636.  
  637.         dy = REAL2INT(RMul(lookat.y, INT2REAL(-h/2)));
  638.  
  639.         /* Then add a little bit to move the backdrop up to where we want it */
  640.  
  641.         dy += h - (ch * 3)/4;
  642.  
  643.         /* The X component of the backdrop offset needs to take account of both
  644.            the X and Z components of the look at vector. An range of angles from
  645.            0 to 360 degrees (0 - PI radians) maps onto the backdrop as 0 - w */
  646.  
  647.         dot = FL2REAL((M_PI - atan2(REAL2FL(lookat.x), REAL2FL(lookat.z)))/M_PI);
  648.         dx = REAL2INT(RMul(INT2REAL(w),dot));
  649.  
  650.         /* Set our calculated offset */
  651.  
  652.         RwSetCameraBackdropOffset(cpGCamera, dx,dy);
  653.  
  654.         /* RwSetCameraBackdropOffset damages the backdrop portion of the camera
  655.            we want to override this since we know that only portions of the
  656.            backdrop are visible through the scene */
  657.  
  658.         /* We use 2 dummy clumps to determine which portions of the
  659.            backdrop need updating */
  660.  
  661.         /* first the portion visible as sky above everything */
  662.  
  663.         RwGetClumpViewportRect(cpGSky1, cpGCamera, &dx ,&dy, &w, &h);
  664.         RwDamageCameraViewport(cpGCamera, dx-32, dy, w+64, h+64);
  665.  
  666.         /* Then the portion visible through the fence at the end */
  667.  
  668.         RwGetClumpViewportRect(cpGSky2, cpGCamera, &dx ,&dy, &w, &h);
  669.         RwDamageCameraViewport(cpGCamera, dx-32, dy, w+64, h+64);
  670.     }
  671.  
  672.     if ((eGWhichCell == CELL_STREET) || (eGWhichCell == CELL_HALL)) 
  673.     {
  674.         /* If we are in the street or the hall then update all of
  675.            these things */
  676.  
  677.         AllBitsUpdate();
  678.         AllObjectsUpdate();
  679.         GunUpdate();
  680.     }
  681.  
  682.     /* Render the objects */
  683.  
  684.     OsBeginCameraUpdate(cpGCamera);
  685.     RwClearCameraViewport(cpGCamera);
  686.  
  687.     switch (eGWhichCell)
  688.     {
  689.     case CELL_STREET:
  690.         /* We're in the street */
  691.         if (nGDoorPos) 
  692.         {
  693.             /* The door is open so render the pool room and the hall first */
  694.             RwRenderScene(spGPoolScene);
  695.             RwRenderClump(cpGHall);
  696.         }
  697.  
  698.         /* Render the street */
  699.         RwRenderScene(spGScene);
  700.  
  701.         /* Render all the objects in the street (rats + explosions) */
  702.         AllObjectsRender();
  703.         break;
  704.  
  705.     case CELL_HALL:
  706.         /* We're in the hall */
  707.         /* From here we can see everything so render it all */
  708.  
  709.         /* Render the street */
  710.  
  711.         RwRenderScene(spGScene);
  712.         
  713.         /* Render the rats and explosions */
  714.  
  715.         AllObjectsRender();
  716.         
  717.         /* Render the pool room and the hall */
  718.         RwRenderScene(spGPoolScene);
  719.         RwRenderClump(cpGHall);
  720.         break;
  721.  
  722.     case CELL_POOL:
  723.         /* We're in the poolroom */
  724.  
  725.         /* render the hall first */
  726.         RwRenderClump(cpGHall);
  727.  
  728.         /* Then the pool room */
  729.  
  730.         RwRenderScene(spGPoolScene);
  731.         break;
  732.     }
  733.     /* Overlay the gun on top of the scene */
  734.  
  735.     GunRender();
  736.     
  737. #ifdef WITH_SCORE
  738.     if (GunVisible())
  739.     {
  740.         OsDisplayScore(NumDeadRats(), NumRats());
  741.     }
  742. #endif
  743.  
  744.     RwEndCameraUpdate(cpGCamera);
  745.     OsShowCameraImage();
  746. }
  747.  
  748. /************************************************************************
  749.  *
  750.  *      Function:       AddLamppost()
  751.  *                      
  752.  *      Description:    Add a lampost to the street
  753.  *
  754.  *      Parameters:     x, z the position on the ground for the lamppost.
  755.  *
  756.  *      Return Value:   TRUE if lamppost added, FALSE otherwise
  757.  *
  758.  ************************************************************************/
  759. #define LAMPPOST_HEIGHT 1.5
  760. #define LAMPPOST_OFFSET 0.075
  761.  
  762. static int AddLamppost(RwReal x, RwReal z)
  763. {
  764.     if (!AddStaticObject(x, CREAL(0.1), z, "lamppost.rwx") ||
  765.         !AddStaticObject((x < CREAL(0.0)) ? RAdd(x, CREAL(LAMPPOST_OFFSET)) 
  766.                                           : RSub(x, CREAL(LAMPPOST_OFFSET)), 
  767.         CREAL(0.1 + LAMPPOST_HEIGHT), z,  "lamplite.rwx"))
  768.     {
  769.         return(FALSE);
  770.     }
  771.     return (TRUE);
  772. }
  773.  
  774. /************************************************************************
  775.  *
  776.  *      Function:       Init3D()
  777.  *                      
  778.  *      Description:    Initialise the 3D components. This function creates
  779.  *                      the global camera, creates all the scenes and lights 
  780.  *                      and loads all of the scripts.
  781.  *
  782.  *      Parameters:     None
  783.  *
  784.  *      Return Value:   None
  785.  *
  786.  ************************************************************************/
  787. int
  788. Init3D(void)
  789. {
  790.     RwLight         *Light;
  791.     int              i;
  792.     RwRaster            *rpBackdrop;
  793.  
  794.     RwSRandom((RwInt32)time(0)); /* Seed the random number generator */
  795.  
  796.     if (!OsOpen())      /* Open RenderWare in an OS specific way */
  797.         return(FALSE);
  798.  
  799.     /* Load the palette that this program will use. Note: this palette must
  800.        be loaded before any of the textures that will be matched to it */
  801.  
  802.     CheckAndReadPalette("rwcyber.pal");
  803.  
  804.     /* Create the global camera that will be used for all of the rendering.
  805.        The size of the camera is OS specific */
  806.  
  807.     cpGCamera = RwCreateCamera(OsMaxCameraWidth(), OsMaxCameraHeight(), NULL);
  808.  
  809.     if (!cpGCamera)
  810.     {
  811.         /*
  812.          * The most common cause for a failure to create a camera is 
  813.          * insufficient memory so we will explicitly check for this 
  814.          * condition and report it. Otherwise a general error is issued.
  815.          */
  816.  
  817.         if (RwGetError() == E_RW_NOMEM)
  818.         {
  819.             OsError("Insufficient memory to create the RenderWare(tm) camera");
  820.         }
  821.         else
  822.         {
  823.             OsError("Error Creating the RenderWare camera");
  824.         }
  825.         RwClose();
  826.         return FALSE;
  827.     }
  828.  
  829.     /* Do the OS Specific initialisation stuff */
  830.  
  831.     if (!OsInit())
  832.     {
  833.         RwClose();
  834.         return(FALSE);
  835.     }
  836.  
  837.     /* Set the camera's background color to black.*/
  838.  
  839.     RwSetCameraBackColor(cpGCamera, CREAL(0.0), CREAL(0.0), CREAL(0.0));
  840.  
  841.     /* Read the cityscape backdrop */
  842.  
  843.     if (!(rpBackdrop = RwReadRaster("backdrop", 0L))) 
  844.     {
  845.         OsError("Unable to read <backdrop>");
  846.         RwClose();
  847.         return FALSE;
  848.     }
  849.     RwSetCameraBackdrop(cpGCamera, rpBackdrop);
  850.     RwSetCameraBackdropOffset(cpGCamera, 0,0);
  851.  
  852.     /* Setup initial position and field of view for the camera */
  853.     ResetCamera();
  854.     RwSetCameraViewwindow(cpGCamera, CREAL(1.0), CREAL(0.75));
  855.  
  856.     /* Create a scene which will contain the clumps and lights for the 
  857.      *  street
  858.      */
  859.  
  860.     spGScene = RwCreateScene();
  861.     if (!spGScene)
  862.     {
  863.         RwDestroyCamera(cpGCamera);
  864.         RwClose();
  865.         return FALSE;
  866.     }
  867.  
  868.     /* Create a scene which will contain the clumps and lights for the 
  869.      *  poolroom
  870.      */
  871.  
  872.     spGPoolScene = RwCreateScene();
  873.     if (!spGPoolScene)
  874.     {
  875.         RwDestroyCamera(cpGCamera);
  876.         RwClose();
  877.         return FALSE;
  878.     }
  879.  
  880.     /* Create a scene which will contain the clumps which are used as targets
  881.      * for the rats
  882.      */
  883.  
  884.     spGTargetScene = RwCreateScene();
  885.     if (!spGTargetScene)
  886.     {
  887.         RwDestroyCamera(cpGCamera);
  888.         RwClose();
  889.         return FALSE;
  890.     }
  891.  
  892.     /* Create the light that will illuminate the poolroom. The light is a
  893.        directional light with an illumination vector of (0.5, -1.0, -0.5)
  894.      */
  895.  
  896.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(0.5), CREAL(-1.0), CREAL(-0.5),
  897.                           CREAL(1.0));
  898.  
  899.     /* Add the light to the poolroom scene */
  900.     RwAddLightToScene(spGPoolScene, Light);
  901.  
  902.     /* Read the geometry for the street */
  903.     if (!(cpGCity = DoRwReadShape("city.rwx"))) 
  904.     {
  905.         RwClose();
  906.         return FALSE;
  907.     }
  908.  
  909.     /* Find the polygons that represent the billboard lights */
  910.  
  911.     ppGLight1 = RwFindTaggedPolygon(cpGCity, 1);
  912.     ppGLight2 = RwFindTaggedPolygon(cpGCity, 2);
  913.  
  914.     /* And the textures that represent the billboard */
  915.  
  916.     tpGBillboardLeft = RwFindNamedTexture("bbleft");
  917.     tpGBillboardRight = RwFindNamedTexture("bbrite");
  918.  
  919.     /* And add the clump to the scene */
  920.     RwAddClumpToScene(spGScene, cpGCity);
  921.  
  922.     /* Get the vertices of the secret door. These are the first 18
  923.        vertices in the street script */
  924.     for (i=0; i<18; i++)
  925.     {
  926.         naGDoor[i] = i + 1;
  927.         RwGetClumpVertex(cpGCity, naGDoor[i], &vaGDoor[i]);
  928.     }
  929.  
  930.     /* Duplicate the light and add it to the default scene. This light 
  931.        will light all of the clumps not explicitly added to a scene (ie the
  932.        rats and bits of explosions) */
  933.  
  934.     Light = RwDuplicateLight(Light);
  935.     RwAddLightToScene(RwDefaultScene(), Light);
  936.  
  937.     /* Read the script that represents the get hallway between the street and
  938.        the poolroom */
  939.     if (!(cpGHall = DoRwReadShape("hall.rwx"))) 
  940.     {
  941.         RwClose();
  942.         return FALSE;
  943.     }
  944.  
  945.     /* Read the script that represents the poolroom */
  946.     if (!(cpGPool = DoRwReadShape("pool.rwx"))) 
  947.     {
  948.         RwClose();
  949.         return FALSE;
  950.     }
  951.  
  952.     /* And add it to the poolroom scene */    
  953.     RwAddClumpToScene(spGPoolScene, cpGPool);
  954.  
  955.     /* Set up the rest of the objects */
  956.  
  957.     if (!AllObjectsSetup() ||
  958.         !GunSetup() ||
  959.         !ManSetup() ||
  960.     !TrophySetup() ||
  961.         !AllRatsSetup() ||
  962.         !AllBitsSetup())
  963.     {
  964.         RwClose();
  965.         return FALSE;
  966.     }
  967.  
  968. #ifdef WITH_SOUND
  969.     if (!(AllSoundsSetup())) 
  970.     {
  971.         /* Theres no sound card but dont do anything about it */
  972.     }
  973. #endif
  974.  
  975.     /* Add all of the static objects */
  976.  
  977.     if (!AddStaticObject(CREAL(1.5), CREAL(0.1), CREAL(1.0), "bin.rwx") ||
  978.         !AddStaticObject(CREAL(1.3), CREAL(0.1), CREAL(1.5), "bin.rwx") ||
  979.         !AddStaticObject(CREAL(0.4), CREAL(0.0), CREAL(0.5), "binboxes.rwx") ||
  980.         !AddStaticObject(CREAL(-0.2),CREAL(0.0), CREAL(0.35),"rubbish.rwx") ||
  981.         !AddStaticObject(CREAL(1.5), CREAL(0.1), CREAL(2.0), "rubbish.rwx") ||
  982.         !AddLamppost(CREAL(-1.35), CREAL(4.2)) ||
  983.         !AddLamppost(CREAL(1.35),  CREAL(5.5)) ||
  984.         !AddLamppost(CREAL(-1.35), CREAL(7.6)) ||
  985.         !AddLamppost(CREAL(1.35), CREAL(9.0)) ||
  986.         !AddLamppost(CREAL(-1.35), CREAL(11.0)))
  987.     {
  988.         RwClose();
  989.         return FALSE;
  990.     }
  991.  
  992.     /* Create 2 dummy clumps. These clumps are used to determine the 
  993.        area of the viewport that represents the bitmap backdrop on each frame.
  994.        One clump represents the Sky and the other the view of the skyline
  995.        at the end of the alley */
  996.  
  997.     /* Create the Sky clump */
  998.  
  999.     RwModelBegin();
  1000.     RwClumpBegin();
  1001.     RwVertex(CREAL(LEFT_STREET),  CREAL(3.1), CREAL(-0.5));
  1002.     RwVertex(CREAL(RIGHT_STREET), CREAL(3.1), CREAL(-0.5));
  1003.     RwVertex(CREAL(LEFT_STREET),  CREAL(3.1), CREAL(NEAR_STREET));
  1004.     RwVertex(CREAL(RIGHT_STREET), CREAL(3.1), CREAL(NEAR_STREET));
  1005.     RwVertex(CREAL(0.0), CREAL(4.0), CREAL(4.0));
  1006.     RwQuad(1,3,4,2);
  1007.     RwClumpEnd(&cpGSky1);
  1008.     RwModelEnd();
  1009.  
  1010.     /* Create the End of Alley dummy clump */
  1011.  
  1012.     RwModelBegin();
  1013.     RwClumpBegin();
  1014.     RwVertex(CREAL(LEFT_STREET), CREAL(0.0), CREAL(NEAR_STREET));
  1015.     RwVertex(CREAL(RIGHT_STREET),CREAL(0.0), CREAL(NEAR_STREET));
  1016.     RwVertex(CREAL(LEFT_STREET), CREAL(4.0), CREAL(NEAR_STREET));
  1017.     RwVertex(CREAL(RIGHT_STREET),CREAL(4.0), CREAL(NEAR_STREET));
  1018.     RwQuad(1,3,4,2);
  1019.     RwClumpEnd(&cpGSky2);
  1020.     RwModelEnd();
  1021.  
  1022. /* Create a spline that the camera will fly along in flythrough mode */
  1023.  
  1024. #define ASSIGNVECTOR(A,X,Y,Z)    A.x = CREAL(X); A.y = CREAL(Y); A.z = CREAL(Z);
  1025.  
  1026.     {    
  1027.         RwV3d points[20];
  1028.  
  1029.         ASSIGNVECTOR(points[0], 1.7,  1.8, 7);
  1030.         ASSIGNVECTOR(points[1], 1,    1.0, 8);
  1031.         ASSIGNVECTOR(points[2], 0,    0.7, 5);
  1032.         ASSIGNVECTOR(points[3],-1.8,  0.5, 3);
  1033.         ASSIGNVECTOR(points[4],-1.5,  0.3, 1);
  1034.         ASSIGNVECTOR(points[5],-0.5,  0.5, 0.5);
  1035.         ASSIGNVECTOR(points[6], 0,    0.4, 1);
  1036.         ASSIGNVECTOR(points[7], 1,    0.5, 1.5);
  1037.         ASSIGNVECTOR(points[8], 1,    0.5, 4.5);
  1038.         ASSIGNVECTOR(points[9], 1,    0.5, 7.5);
  1039.         ASSIGNVECTOR(points[10], 0,    0.5, 8.5);
  1040.         ASSIGNVECTOR(points[11],-1,    0.3, 8.5);
  1041.         ASSIGNVECTOR(points[12],-1,    0.2, 7.5);
  1042.         ASSIGNVECTOR(points[13],-1,    0.2, 4.5);
  1043.         ASSIGNVECTOR(points[14],-1,    0.4, 1.5);
  1044.         ASSIGNVECTOR(points[15], 0,    0.6, 1.5);
  1045.         ASSIGNVECTOR(points[16], 1.2,  0.4, 1.5);
  1046.         ASSIGNVECTOR(points[17], 1.7,  1.5, 5.0);
  1047.  
  1048.         spGPath = RwCreateSpline(18, rwCLOSEDLOOP, points);
  1049.     }
  1050.     return TRUE;
  1051. }
  1052.  
  1053. /************************************************************************
  1054.  *
  1055.  *      Function:       TidyUp3D()
  1056.  *                      
  1057.  *      Description:    Clean Up the 3D components of the application. This
  1058.  *                      function destroys all the clumps, lights, scenes
  1059.  *                      and splines that are created in Init3D.
  1060.  *
  1061.  *      Parameters:     None
  1062.  *
  1063.  *      Return Value:   None
  1064.  *
  1065.  ************************************************************************/
  1066. void
  1067. TidyUp3D(void)
  1068. {
  1069.     RwRaster *rpBackdrop;    
  1070.  
  1071.     /* Tidy up the OS Specific 3D stuff */
  1072.  
  1073.     OsTidy();   
  1074.  
  1075.     /* Destroy the camera's flight path */
  1076.  
  1077.     RwDestroySpline(spGPath);
  1078.  
  1079.     /* Destroy all of the 3D components created by the modules */
  1080.  
  1081.     AllBitsDestroy();
  1082.     AllRatsDestroy();
  1083.     ManDestroy();
  1084.     GunDestroy();
  1085.     AllObjectsDestroy();
  1086.  
  1087.     /* Destroy the scenes. This will destroy all the clumps and lights currently
  1088.        contained within the scenes */
  1089.     
  1090.     RwDestroyScene(spGPoolScene);
  1091.     RwDestroyScene(spGScene);
  1092.     RwDestroyScene(spGTargetScene);
  1093.  
  1094.     /* Destroy the camera and the backdrop */
  1095.  
  1096.     rpBackdrop = RwGetCameraBackdrop(cpGCamera);
  1097.     if (rpBackdrop)
  1098.         RwDestroyRaster(rpBackdrop);
  1099.     RwDestroyCamera(cpGCamera);
  1100.  
  1101.     /* Destroy everything else */
  1102.  
  1103.     if (rpGPanel)
  1104.         RwDestroyRaster(rpGPanel);
  1105.  
  1106.  
  1107. #ifdef WITH_SOUND
  1108.     AllSoundsDestroy();
  1109. #endif
  1110.  
  1111.     /* Close the library. This will destroy all of the clumps and lights
  1112.      * that aren't explicitly added to another Scene. All of the memory
  1113.      * allocated for internal resources and textures will also be freed.
  1114.      */
  1115.     RwClose();
  1116. }
  1117.  
  1118.  
  1119. /************************************************************************
  1120.  *
  1121.  *      Function:       HandlePaint()
  1122.  *                      
  1123.  *      Description:    Redraw the entire viewport. The viewport may be 
  1124.  *                      larger than the camera so the backing panel is drawn
  1125.  *                      in sections.
  1126.  *
  1127.  *      Parameters:     None
  1128.  *
  1129.  *      Return Value:   None
  1130.  *
  1131.  ************************************************************************/
  1132. void
  1133. HandlePaint(void)
  1134. {
  1135.     RwInt32 x, y;
  1136.     RwInt32 vx,vy,vw,vh;
  1137.     RwInt32 offx,offy;
  1138.     RwRaster *raster;
  1139.  
  1140.     /* Save all of the camera settings that we will modify and restore 
  1141.      * them once we are finished with them.
  1142.      */
  1143.  
  1144.     RwGetCameraViewport(cpGCamera, &vx, &vy, &vw, &vh);
  1145.     RwGetCameraBackdropOffset(cpGCamera, &offx, &offy);
  1146.     raster = RwGetCameraBackdrop(cpGCamera);
  1147.  
  1148.     /* If no panel exists then there is no surround to draw so skip this bit */
  1149.  
  1150.     if (rpGPanel)
  1151.     {
  1152.         /* Use all of the camera's viewport to draw the panel */
  1153.  
  1154.         RwSetCameraBackdrop(cpGCamera, rpGPanel);
  1155.         RwSetCameraBackdropViewportRect(cpGCamera, 0,0, OsMaxCameraWidth(), OsMaxCameraHeight());
  1156.  
  1157.         for (y=0; y < OsMaxScreenHeight(); y += OsMaxCameraHeight())
  1158.         {
  1159.             for (x=0; x < OsMaxScreenWidth(); x += OsMaxCameraWidth())
  1160.             {
  1161.                 RwSetCameraViewport(cpGCamera, x,y, OsMaxCameraWidth(), OsMaxCameraHeight());
  1162.                 RwSetCameraBackdropOffset(cpGCamera, x,y);
  1163.                 RwInvalidateCameraViewport(cpGCamera);
  1164.                 OsBeginCameraUpdate(cpGCamera);
  1165.                     RwClearCameraViewport(cpGCamera);
  1166.                 RwEndCameraUpdate(cpGCamera);
  1167.                 OsShowCameraImage();
  1168.             }
  1169.         }
  1170.     }
  1171.  
  1172.     /* Restore the saved camera settings */
  1173.  
  1174.     RwSetCameraViewport(cpGCamera, vx, vy, vw, vh);
  1175.     RwSetCameraBackdrop(cpGCamera, raster);
  1176.     RwSetCameraBackdropOffset(cpGCamera, offx, offy);
  1177.  
  1178.     /* We need to redraw the entire viewport next time we copy to the display */
  1179.     RwInvalidateCameraViewport(cpGCamera);
  1180.  
  1181. }
  1182.  
  1183. /************************************************************************
  1184.  *
  1185.  *      Function:       HandleLeftButtonDown()
  1186.  *                      
  1187.  *      Description:    Set up the action to be performed when 
  1188.  *                      left mouse button is pressed. 
  1189.  *                      
  1190.  *
  1191.  *      Parameters:     x, y - Camera Viewport co-ordinates for the current
  1192.  *                      cursor position.
  1193.  *                      control - the status of the Control Key. 
  1194.  *                        TRUE = key pressed
  1195.  *                      shift - the status of the Shift Key. 
  1196.  *                        TRUE = key pressed
  1197.  *
  1198.  *      Return Value:   None
  1199.  *
  1200.  ************************************************************************/
  1201. void
  1202. HandleLeftButtonDown(RwInt32 x, RwInt32 y, int control, int shift)
  1203. {
  1204.     if (nGFlyCamera)
  1205.     {
  1206.         /* If we are flying then turn it off */
  1207.  
  1208.         nGFlyCamera = 0;
  1209.         ResetCamera();
  1210.     }
  1211.  
  1212.     /* Define the action that will be taken by subsequent mouse movements */
  1213.  
  1214.     if (control)
  1215.     {
  1216.         /* Raise or lower the Camera */
  1217.         mGMouseMoveMode = MMChangeHeight;
  1218.     }
  1219.     else if (shift)
  1220.     {
  1221.         /* Tilt the Camera */
  1222.         mGMouseMoveMode = MMTiltCamera;
  1223.     }
  1224.     else
  1225.     {
  1226.         /* Rotate the camera and move backwards and forwards */
  1227.         mGMouseMoveMode = MMTravelCamera;
  1228.         nGSpeed = CREAL(0);
  1229.     }
  1230.  
  1231.     /* Remember the current x & y position to allow a relative
  1232.        movement determination to be performed later */
  1233.     nGLastX = x;
  1234.     nGLastY = y;
  1235. }
  1236.  
  1237. /************************************************************************
  1238.  *
  1239.  *      Function:       HandleRightButtonDown()
  1240.  *                      
  1241.  *      Description:    Set up the action to be performed when 
  1242.  *                      right mouse button is pressed. For this 
  1243.  *                      application the action is the same as the
  1244.  *                      left button with the additional feature that the
  1245.  *                      gun also fires.
  1246.  *
  1247.  *      Parameters:     x, y - Camera Viewport co-ordinates for the current
  1248.  *                      cursor position.
  1249.  *                      control - the status of the Control Key. 
  1250.  *                        TRUE = key pressed
  1251.  *                      shift - the status of the Shift Key. 
  1252.  *                        TRUE = key pressed
  1253.  *
  1254.  *      Return Value:   None
  1255.  *
  1256.  ************************************************************************/
  1257. void
  1258. HandleRightButtonDown(RwInt32 x, RwInt32 y, int control, int shift)
  1259. {
  1260.     GunFiring(TRUE);
  1261.  
  1262.     /* Define the action that will be taken by subsequent mouse movements */
  1263.  
  1264.     if (control)
  1265.     {
  1266.         /* Raise or lower the Camera */
  1267.         mGMouseMoveMode = MMChangeHeight;
  1268.     }
  1269.     else if (shift)
  1270.     {
  1271.         /* Tilt the Camera */
  1272.         mGMouseMoveMode = MMTiltCamera;
  1273.     }
  1274.     else
  1275.     {
  1276.         /* Rotate the camera and move backwards and forwards */
  1277.         mGMouseMoveMode = MMTravelCamera;
  1278.         nGSpeed = CREAL(0);
  1279.     }
  1280.  
  1281.     /* Remember the current x & y position to allow a relative
  1282.        movement determination to be performed later */
  1283.     nGLastX = x;
  1284.     nGLastY = y;
  1285. }
  1286.  
  1287. /************************************************************************
  1288.  *
  1289.  *      Function:       HandleMouseMove()
  1290.  *                      
  1291.  *      Description:    Handle a movement of the mouse. If a previous left 
  1292.  *                      or right mouse button down event has set a mouse 
  1293.  *                      move mode then this function will take the necessary 
  1294.  *                      actions.
  1295.  *
  1296.  *      Parameters:     x, y - Camera Viewport co-ordinates for the current
  1297.  *                      cursor position.
  1298.  *
  1299.  *      Return Value:   None
  1300.  *
  1301.  ************************************************************************/
  1302. void
  1303. HandleMouseMove(RwInt32 x, RwInt32 y)
  1304. {
  1305.     RwV3d vAt;
  1306.  
  1307.     /* mGMouseMoveMode tells us what kind of action to perform. */
  1308.  
  1309.     switch (mGMouseMoveMode)
  1310.     {
  1311.     case MMNoAction:
  1312.         break;
  1313.  
  1314.     case MMTravelCamera:
  1315.         /* We are travelling through the scene. Movement of the
  1316.          * mouse in the X direction will rotate the camera about the
  1317.          * Y Axis, and movement of the mouse in the Y direction will 
  1318.          * move the camera forwards and backwards through the scene.
  1319.          */
  1320.  
  1321.         /* Rotate the camera by mouse X delta degrees. */
  1322.  
  1323.         RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  1324.                        INT2REAL(nGLastX - x), rwREPLACE);
  1325.         RwTransformCameraOrientation(cpGCamera, RwScratchMatrix());
  1326.  
  1327.         /* Move the camera forward. The speed of forward motion is deterimined
  1328.          * by the mouse Y delta divided by 100 units.
  1329.          */
  1330.  
  1331.         nGSpeed = RDiv(INT2REAL(nGLastY - y), CREAL(100.0));
  1332.         MoveForward(nGSpeed);
  1333.         break;
  1334.  
  1335.     case MMChangeHeight:
  1336.         /* Raised or lower the eyepoint of the camera */
  1337.         MoveUp(RDiv(INT2REAL(nGLastY - y),CREAL(50)));
  1338.         break;
  1339.  
  1340.     case MMTiltCamera:
  1341.         /* Movement of the mouse in the X axis rotates about the Y axis as
  1342.          *   above. Movement in the Y axis tilts the camera
  1343.          */
  1344.  
  1345.         /* Rotate the camera */
  1346.         RwRotateMatrix(RwScratchMatrix(), CREAL(0.0),CREAL(1.0),CREAL(0.0),
  1347.                       INT2REAL(nGLastX - x),rwREPLACE);
  1348.         RwTransformCameraOrientation(cpGCamera, RwScratchMatrix());
  1349.  
  1350.         /* Tilt the Camera by maintaining an absolute tilt value. This is
  1351.          * necessary to prevent accumulative roundoff errors and to allow the
  1352.          * amount of tilt to be limited.
  1353.          */
  1354.         nGTilt = RAdd(nGTilt, INT2REAL(y - nGLastY));
  1355.       
  1356.         if (nGTilt > CREAL(MAX_TILT))
  1357.             nGTilt = CREAL(MAX_TILT);
  1358.         else if (nGTilt < CREAL(-MAX_TILT))
  1359.             nGTilt = CREAL(-MAX_TILT);
  1360.      
  1361.         /* force the camera to lie in a plane parallel with the ground 
  1362.          * plane */
  1363.         RwGetCameraLookAt(cpGCamera, &vAt);
  1364.         RwSetCameraLookAt(cpGCamera, vAt.x, CREAL(0.0),  vAt.z);
  1365.         RwSetCameraLookUp(cpGCamera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
  1366.         /* Then tilt it */
  1367.         RwTiltCamera(cpGCamera, nGTilt);
  1368.         break;
  1369.     }
  1370.  
  1371.     /* Remember the current X and Y for next time. */
  1372.     nGLastX = x;
  1373.     nGLastY = y;
  1374. }
  1375.  
  1376. /************************************************************************
  1377.  *
  1378.  *      Function:       HandleLeftButtonUp()
  1379.  *                      
  1380.  *      Description:    Handle the release of the left mouse button. This
  1381.  *                      resets any current mouse movement action.
  1382.  *
  1383.  *      Parameters:     None
  1384.  *
  1385.  *      Return Value:   None
  1386.  *
  1387.  ************************************************************************/
  1388. void
  1389. HandleLeftButtonUp(void)
  1390. {
  1391.   if (mGMouseMoveMode != MMNoAction)
  1392.   {
  1393.     mGMouseMoveMode = MMNoAction;
  1394.   }
  1395. }
  1396.  
  1397. /************************************************************************
  1398.  *
  1399.  *      Function:       HandleRightButtonUp()
  1400.  *                      
  1401.  *      Description:    Handle the release of the right mouse button. This
  1402.  *                      has the same behaviour as the raising of the left
  1403.  *                      mouse button with the additional feature that the 
  1404.  *                      gun will stop firing.
  1405.  *
  1406.  *      Parameters:     None
  1407.  *
  1408.  *      Return Value:   None
  1409.  *
  1410.  ************************************************************************/
  1411. void
  1412. HandleRightButtonUp()
  1413. {
  1414.     /* Stop the gun firing */
  1415.  
  1416.     GunFiring(FALSE);
  1417.     HandleLeftButtonUp();
  1418. }
  1419.  
  1420. /************************************************************************
  1421.  *
  1422.  *      Function:       HandleTimer()
  1423.  *                      
  1424.  *      Description:    Handle the action that should be taken on each 
  1425.  *                      frame. This includes advancing all animated clumps
  1426.  *                      and textures by a frame and rerendering the scene
  1427.  *                      based on the current camera position
  1428.  *
  1429.  *      Parameters:     None
  1430.  *
  1431.  *      Return Value:   None
  1432.  *
  1433.  ************************************************************************/
  1434. void
  1435. HandleTimer(void)
  1436. {
  1437.     int i;                      /* temporary loop control variable */
  1438.     static int nGState = 0;     /* Remember the current state of the 
  1439.                                    billboard lights */
  1440.  
  1441.     if ((RwRandom() & 0xff) < 16) 
  1442.     {
  1443.         /* At a random interval, trigger the effect of the billboard lights
  1444.          * flickering. This is achieved by altering the ambient surface
  1445.          * property of the polygons representing the light and advancing the 
  1446.          * billboard textures to the next frame 
  1447.          */
  1448.  
  1449.         if ((nGState++)&1) 
  1450.         {
  1451.             /* Lights are off, turn them on */
  1452.             RwSetPolygonAmbient(ppGLight1,CREAL(1.0));
  1453.             RwSetPolygonAmbient(ppGLight2,CREAL(1.0));
  1454.             RwSetTextureFrame(tpGBillboardLeft, 0);
  1455.             RwSetTextureFrame(tpGBillboardRight, 0);
  1456.         } 
  1457.         else 
  1458.         {
  1459.             /* Lights are on, turn them off */
  1460.             RwSetPolygonAmbient(ppGLight1,CREAL(0.0));
  1461.             RwSetPolygonAmbient(ppGLight2,CREAL(0.0));
  1462.             RwSetTextureFrame(tpGBillboardLeft, 1);
  1463.             RwSetTextureFrame(tpGBillboardRight, 1);
  1464.         }
  1465.     }
  1466.  
  1467.     /* Every so often release another Rat */
  1468.     AllRatsRelease();
  1469.  
  1470.     /* If the camera is flying then advance it to the next position along
  1471.      * the spline path 
  1472.      */
  1473.  
  1474.     if (nGFlyCamera)
  1475.     { 
  1476.         RwV3d up;
  1477.  
  1478.         /* Force the camera to preserve the correct up direction */
  1479.         up.x = CREAL(0.0);
  1480.         up.y = CREAL(1.0);
  1481.         up.z = CREAL(0.0);
  1482.         
  1483.         /* Get the current spline transform matrix */
  1484.         RwSplineTransform(spGPath, rwSMOOTH, nGAlpha, &up, RwScratchMatrix());
  1485.  
  1486.         /* And apply it to the camera */
  1487.         RwTransformCamera(cpGCamera, RwScratchMatrix(), rwREPLACE);
  1488.  
  1489.         /* Increment the spline control variable */
  1490.         nGAlpha = RAdd(nGAlpha, CREAL(0.002));
  1491.     }
  1492.  
  1493.     /* Update the animation of the Man in the poolroom */
  1494.  
  1495.     ManUpdate();
  1496.  
  1497.     /* If we are over the pad that activates the door then open the door */
  1498.     if (nGOnPad)
  1499.     {
  1500.         if (nGDoorPos < 20)
  1501.         {
  1502.             /* The door isn't open yet. Open it some more */
  1503.             for (i=0; i<9; i++)
  1504.             {
  1505.                 vaGDoor[i].z -= CREAL(0.02);
  1506.                 vaGDoor[i+9].z += CREAL(0.02);
  1507.             }
  1508.             nGDoorPos++;
  1509.             RwSetClumpVertices(cpGCity, naGDoor, vaGDoor, 18);
  1510.             /* Setting clump vertices forces the rwEDITABLE hint 
  1511.              * we don't need this so turn it off again
  1512.              */
  1513.             RwSetClumpHints(cpGCity, 0L);
  1514.         }
  1515.     }
  1516.     else
  1517.     {
  1518.         /* We're not over the pad. Close the door if it is open */
  1519.         if (nGDoorPos > 0)
  1520.         {
  1521.             /* The door is still open. Close it some more */
  1522.             for (i=0; i<9; i++)
  1523.             {
  1524.                 vaGDoor[i].z += CREAL(0.02);
  1525.                 vaGDoor[i+9].z -= CREAL(0.02);
  1526.             }
  1527.             nGDoorPos--;
  1528.             RwSetClumpVertices(cpGCity, naGDoor, vaGDoor, 18);
  1529.             /* Setting clump vertices forces the rwEDITABLE hint 
  1530.              * we don't need this so turn it off again
  1531.              */
  1532.             RwSetClumpHints(cpGCity, 0L);
  1533.         }
  1534.     }
  1535.  
  1536.     /* The camera has momentum and will continue to move forward once the 
  1537.        mouse button is released */
  1538.  
  1539.     if (mGMouseMoveMode == MMNoAction)
  1540.     {
  1541.         /* No mouse button is pressed. Check if the camera was moving
  1542.            forward */
  1543.  
  1544.         if (nGSpeed) 
  1545.         {
  1546.             /* The camera is moving so update its position */
  1547.             MoveForward(nGSpeed);
  1548.  
  1549.             /* slow it down */
  1550.             nGSpeed = RMul(nGSpeed, CREAL(0.9));
  1551.             if (RAbs(nGSpeed) < CREAL(0.005)) 
  1552.             {
  1553.                 nGSpeed = CREAL(0);
  1554.             }
  1555.         }
  1556.     }
  1557.     /* Call the main render function to perform the rendering of the 
  1558.      * view
  1559.      */
  1560.     Render();
  1561. }
  1562.  
  1563.