home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwwin / rwcyber.c_ / rwcyber.bin
Text File  |  1995-11-14  |  49KB  |  1,570 lines

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