home *** CD-ROM | disk | FTP | other *** search
/ Enter 2005 March / ENTER.ISO / files / fwp-0.0.6-win32-installer.exe / Camera.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-01-22  |  24.1 KB  |  736 lines

  1. #ifdef WIN32
  2. #include <windows.h>
  3. #endif
  4. #include <GL/gl.h>
  5. #include <GL/glu.h>
  6.  
  7. #include <math.h>
  8.  
  9. #include "Camera.h"
  10. //#include "render.h"
  11. #include "collision.h"
  12.  
  13. #include "log.h"
  14. #include "Game.h"
  15. #include "Network.h"
  16.  
  17.  
  18. Camera::Camera(){
  19.     mode=CAMERA_MODE_FREE;
  20.     noclip=true;
  21.     moveSpeed=20.0;
  22.     turnSpeed=2.0;
  23.  
  24.     lastProcessMillis = SDL_GetTicks();
  25.     lastMoveMillis = SDL_GetTicks();
  26.  
  27.     vectorInit3d(-0.2f, -0.2f, -0.2f, moveAABB.min);
  28.     vectorInit3d(+0.2f, +0.2f, +0.2f, moveAABB.max);
  29. /*
  30.     vectorInit3d(0.0, 0.0, 0.0, pos);
  31.     vectorInit3d(0.0, 0.0, 0.0, vel);
  32.     vectorInit3d(0.0, 0.0, 1.0, dir);
  33.     vectorInit3d(0.0, 1.0, 0.0, up);
  34.     vectorInit3d(1.0, 0.0, 0.0, left);
  35. */
  36.     target = NULL;
  37.     reset();
  38. }
  39.  
  40. void Camera::setMode(int mode){
  41.     if(mode>=0 && mode<NUM_CAMERA_MODES){
  42.         this->mode=mode;
  43.         Game::info.cvar.game_camera_mode->setVal(mode);    // to be consistent...
  44.     }
  45. }
  46.  
  47. void Camera::setTarget(Vehicle* newTarget){
  48.     this->target = newTarget;
  49. }
  50.  
  51. void Camera::setPositionAndOrientation(vec3_t pos, vec3_t dir, vec3_t up){
  52.     vectorCopy3d(pos, this->pos);
  53.     vectorCopy3d(dir, this->dir);
  54.     vectorCopy3d(up, this->up);
  55.  
  56.     vectorCrossP3d(up, dir, left);
  57.     vectorCrossP3d(dir, left, up);    // THINKABOUTME: sicher ist sicher...
  58.  
  59.     vectorNormalize3d(dir, dir);
  60.     vectorNormalize3d(up, up);
  61.     vectorNormalize3d(left, left);
  62. }
  63.  
  64. void Camera::setPositionAndOrientation(float posx,float posy,float posz, float dirx, float diry, float dirz, float upx,float upy,float upz){
  65.     vectorInit3d(posx, posy, posz, pos);
  66.     vectorInit3d(dirx, diry, dirz, dir);
  67.     vectorInit3d(upx, upy, upz, up);
  68.  
  69.     vectorCrossP3d(up, dir, left);
  70.     vectorCrossP3d(dir, left, up);    // THINKABOUTME: sicher ist sicher...
  71.  
  72.     vectorNormalize3d(dir, dir);
  73.     vectorNormalize3d(up, up);
  74.     vectorNormalize3d(left, left);
  75. }
  76.  
  77.  
  78. void Camera::lookAtScene(){
  79.     vec3_t at;
  80.  
  81.     vectorAdd3d(pos, dir, at);
  82.  
  83.     gluLookAt(pos[0], pos[1], pos[2],
  84.         at[0], at[1], at[2],
  85.         up[0], up[1], up[2]);
  86.  
  87.     calculateFrustum();
  88. }
  89.  
  90. void Camera::processInputArray(inputArray_t inputArray){
  91.     unsigned int currentMillis = SDL_GetTicks();
  92.     
  93. //    if( lastProcessMillis >= currentMillis )    // sanity check
  94. //        return;
  95.         
  96.     float deltaT = (currentMillis - lastProcessMillis)/1000.0f;
  97.     lastProcessMillis = currentMillis;
  98.  
  99. //    printf("deltaT: %i\n", deltaT);
  100.  
  101.  
  102.     vectorInit3d(0.0f, 0.0f, 0.0f, vel);
  103.  
  104.     if( mode==CAMERA_MODE_FIRST_PERSON && target != NULL ){
  105.     }else if( mode==CAMERA_MODE_THIRD_PERSON && target != NULL ){
  106.         if(inputArray[CAMERA_ZOOM_IN].pressed){
  107.             zoomIn(deltaT);
  108.         }
  109.         if(inputArray[CAMERA_ZOOM_OUT].pressed){
  110.             zoomOut(deltaT);
  111.         }
  112.         if(inputArray[CAMERA_ROTATE_LEFT].pressed){
  113.             rotateLeft(deltaT);
  114.         }
  115.         if(inputArray[CAMERA_ROTATE_RIGHT].pressed){
  116.             rotateRight(deltaT);
  117.         }
  118.         if(inputArray[CAMERA_ROTATE_UP].pressed){
  119.             rotateUp(deltaT);
  120.         }
  121.         if(inputArray[CAMERA_ROTATE_DOWN].pressed){
  122.             rotateDown(deltaT);
  123.         }
  124.         if(inputArray[CAMERA_RESET].pressed){
  125.             reset();
  126.         }
  127.  
  128.     }else/* if( mode==CAMERA_MODE_FREE )*/{
  129.         if(inputArray[TURN_UP].pressed){
  130.             turnUp(deltaT);
  131.         }
  132.         if(inputArray[TURN_DOWN].pressed){
  133.             turnDown(deltaT);
  134.         }
  135.         if(inputArray[TURN_LEFT].pressed){
  136.             turnLeft(deltaT);
  137.         }
  138.         if(inputArray[TURN_RIGHT].pressed){
  139.             turnRight(deltaT);
  140.         }
  141.  
  142.         if(inputArray[MOVE_FORWARD].pressed){
  143.             moveForward(deltaT);
  144.         }
  145.         if(inputArray[MOVE_BACKWARD].pressed){
  146.             moveBackward(deltaT);
  147.         }
  148.         if(inputArray[MOVE_LEFT].pressed){
  149.             moveLeft(deltaT);
  150.         }
  151.         if(inputArray[MOVE_RIGHT].pressed){
  152.             moveRight(deltaT);
  153.         }
  154.         if(inputArray[MOVE_UP].pressed){
  155.             moveUp(deltaT);
  156.         }
  157.         if(inputArray[MOVE_DOWN].pressed){
  158.             moveDown(deltaT);
  159.         }
  160.     }
  161.  
  162.     vectorsFromAngles();
  163. }
  164.  
  165. void Camera::turnLeft(float deltaT){
  166.     yaw = (float)fmod( yaw-(turnSpeed * deltaT), (2*PI));
  167.     if(yaw<0.0f)
  168.         yaw=yaw+(2*PI);
  169. }
  170.  
  171. void Camera::turnRight(float deltaT){
  172.     yaw = (float)fmod( yaw+(turnSpeed * deltaT), (2*PI));
  173. }
  174.  
  175. void Camera::turnUp(float deltaT){
  176.     pitch -= (turnSpeed * deltaT);
  177.     if(pitch<GAME_OBJECT_MIN_PITCH)
  178.         pitch=GAME_OBJECT_MIN_PITCH;
  179. }
  180.  
  181. void Camera::turnDown(float deltaT){
  182.     pitch += (turnSpeed * deltaT);
  183.     if(pitch>GAME_OBJECT_MAX_PITCH)
  184.         pitch=GAME_OBJECT_MAX_PITCH;
  185. }
  186.  
  187. void Camera::moveForward(float deltaT){
  188.     vectorMA3d(vel, deltaT*moveSpeed, dir, vel);
  189. }
  190. void Camera::moveBackward(float deltaT){
  191.     vectorMA3d(vel, -deltaT*moveSpeed, dir, vel);
  192. }
  193. void Camera::moveLeft(float deltaT){
  194.     vectorMA3d(vel, deltaT*moveSpeed, left, vel);
  195. }
  196. void Camera::moveRight(float deltaT){
  197.     vectorMA3d(vel, -deltaT*moveSpeed, left, vel);
  198. }
  199. void Camera::moveUp(float deltaT){
  200.     vectorMA3d(vel, deltaT*moveSpeed, e2, vel);
  201. }
  202. void Camera::moveDown(float deltaT){
  203.     vectorMA3d(vel, -deltaT*moveSpeed, e2, vel);
  204. }
  205.  
  206. void Camera::rotateLeft(float deltaT){
  207.     azimutAngle -= deltaT * turnSpeed;
  208.     if( azimutAngle < 0.0f*PI )
  209.         azimutAngle += 2.0f*PI;
  210. }
  211. void Camera::rotateRight(float deltaT){
  212.     azimutAngle += deltaT * turnSpeed;
  213.     if( azimutAngle > 2.0f*PI )
  214.         azimutAngle -= 2.0f*PI;
  215. }
  216. void Camera::rotateUp(float deltaT){
  217.     elevationAngle += deltaT * turnSpeed;
  218.     if( elevationAngle > 2.0f*PI )
  219.         elevationAngle -= 2.0f*PI;
  220. }
  221. void Camera::rotateDown(float deltaT){
  222.     elevationAngle -= deltaT  * turnSpeed;
  223.     if( elevationAngle < 0.0f*PI )
  224.         elevationAngle += 2.0f*PI;
  225. }
  226.  
  227. void Camera::move(){
  228.     unsigned int currentMillis = SDL_GetTicks();
  229.     float deltaT = (currentMillis - lastMoveMillis)/1000.0f;
  230.     lastMoveMillis = currentMillis;
  231.  
  232. //    reconstructVectors();    // make sure local COSystem is orthonormal
  233.  
  234.     if( mode == CAMERA_MODE_FIRST_PERSON && target != NULL ){
  235.         setPositionAndOrientation(target->pos, target->dir, target->up);
  236.     }else if( mode == CAMERA_MODE_THIRD_PERSON && target != NULL ){
  237. //        vec3_t pos, dir, up, left;
  238.  
  239.         vectorRotateAroundNormal3d(target->dir, target->up, azimutAngle, dir);
  240.         vectorCrossP3d(target->up, dir, left);
  241.         vectorRotateAroundNormal3d(dir, left, elevationAngle, dir);
  242.         vectorCrossP3d(dir, left, up);
  243.  
  244.         vectorMA3d( target->pos, -zoom, dir, pos);
  245. //        setPositionAndOrientation(pos, dir, up);
  246.         anglesFromVectors();
  247.  
  248. //        yaw = target->yaw + azimutAngle;
  249. //        pitch = elevationAngle;
  250. //        vectorsFromAngles();
  251. //        vectorMA3d( target->pos, -zoom, dir, pos);
  252.     }else{    // free or no target
  253.  
  254.         if(vectorLengthSquared3d(vel)<0.0001f)
  255.             return;
  256.  
  257. //        vectorNormalize3d(vel, vel);
  258. //        vectorScale3d(deltaT*moveSpeed, vel, vel);
  259.         if(noclip || collisionDetection(vel))        // check if move is save
  260.             vectorAdd3d(pos, vel, pos);    // ...and move
  261.     }
  262. }
  263.  
  264. bool Camera::collisionDetection(vec3_t displacement){
  265.     Face* f;
  266.     int numIterations = 0;
  267.     vec3_t testPos;
  268.     float t;
  269.     trace_t trace;
  270. //    trace.ignoreBackfaces=true;    // collide only with front-facing faces
  271. //    trace.ignoreNonSolids=true; // ...and solid faces
  272.     trace.ignoreFlags = 0 | COLLISION_FLAG_BACKFACES | COLLISION_FLAG_WALK_THROUGH | COLLISION_FLAG_VEHICLES;
  273.  
  274.     do{
  275.         vectorAdd3d(pos, displacement, testPos);
  276.  
  277.         // check if pos is save inside arena
  278.         //trace.hits.clear();
  279.         //Game::arena->sptree->traceAABB(pos, testPos, min, max, &trace);
  280.         traceAABB(pos, testPos, moveAABB, &trace);
  281.         if( !trace.hits.empty() ){    // collision! -> change displ.
  282. //            printf("Collided with %i faces!\n", trace.hitFaces.size() );
  283.             for(unsigned int i=0;i<trace.hits.size();i++){
  284.                 f = trace.hits[i].face;    // only first face is of interest
  285.                 t = vectorDotP3d(f->normal, displacement);
  286.                 vectorMA3d(displacement, -t, f->normal, displacement);
  287.             }
  288.         }
  289.  
  290.  
  291.         // count iterations
  292.         numIterations++;
  293.         if(numIterations>5 ){
  294.             warn("(in Camera::collisionDetection()): Too many iterations. Aborting move.\n\n");
  295.             vectorInit3d(0.0f, 0.0f, 0.0f, displacement);
  296.             return false;
  297.         }
  298.  
  299.     }while( !trace.hits.empty() );
  300.     
  301.     // check if pos is in arenas box
  302.     if(testPos[0]+moveAABB.min[0] < Game::arena->min[0] && displacement[0] < 0.0f
  303.         || testPos[0]+moveAABB.max[0] > Game::arena->max[0] && displacement[0] > 0.0f){
  304.         displacement[0] = 0.0f;
  305.     }
  306.     if(testPos[1]+moveAABB.min[1] < Game::arena->min[1] && displacement[1] < 0.0f
  307.         || testPos[1]+moveAABB.max[1] > Game::arena->max[1] && displacement[1] > 0.0f){
  308.         displacement[1] = 0.0f;
  309.     }
  310.     if(testPos[2]+moveAABB.min[2] < Game::arena->min[2] && displacement[2] < 0.0f
  311.         || testPos[2]+moveAABB.max[2] > Game::arena->max[2] && displacement[2] > 0.0f){
  312.         displacement[2] = 0.0f;
  313.     }
  314.  
  315.  
  316.     return true;
  317. }
  318.  
  319.  
  320. void Camera::chaseNext(){
  321.     int i;
  322.     int startSlot = 0;
  323.     if( Game::cam.target == NULL ){
  324.         startSlot = 0;
  325.     }else{
  326.         for(i=0;i<GAME_MAX_VEHICLES;i++){
  327.             if( Game::vehicles[i] != NULL && Game::vehicles[i] == Game::cam.target ){
  328.                 startSlot = i;
  329.                 break;
  330.             }
  331.         }
  332.     }
  333.  
  334.     for(i=startSlot+1;i<GAME_MAX_VEHICLES;i++){
  335.         if( Game::vehicles[i] != NULL ){
  336.             Game::cam.setTarget(Game::vehicles[i]);
  337.             return;
  338.         }
  339.     }
  340.     for(i=0;i<=startSlot;i++){
  341.         if( Game::vehicles[i] != NULL ){
  342.             Game::cam.setTarget(Game::vehicles[i]);
  343.             return;
  344.         }
  345.     }
  346.  
  347.     Game::cam.setTarget(NULL);
  348. }
  349.  
  350. void Camera::chasePrevious(){
  351.     int i;
  352.     int startSlot = 0;
  353.     if( Game::cam.target == NULL ){
  354.         startSlot = 0;
  355.     }else{
  356.         for(i=0; i<GAME_MAX_VEHICLES; i++){
  357.             if( Game::vehicles[i] != NULL && Game::vehicles[i] == Game::cam.target ){
  358.                 startSlot = i;
  359.                 break;
  360.             }
  361.         }
  362.     }
  363.  
  364.     for(i=startSlot-1; i>=0; i--){
  365.         if( Game::vehicles[i] != NULL ){
  366.             Game::cam.setTarget(Game::vehicles[i]);
  367.             return;
  368.         }
  369.     }
  370.     for(i=Network::server->si.maxClients-1; i>=startSlot; i--){
  371.         if( Game::vehicles[i] != NULL ){
  372.             Game::cam.setTarget(Game::vehicles[i]);
  373.             return;
  374.         }
  375.     }
  376.  
  377.     Game::cam.setTarget(NULL);
  378. }
  379.  
  380.  
  381. void Camera::zoomIn(float deltaT){
  382.     zoom -= deltaT * moveSpeed;
  383.     if( zoom < 1.5f )
  384.         zoom = 1.5f;
  385. }
  386. void Camera::zoomOut(float deltaT){
  387.     zoom += deltaT * moveSpeed;
  388.     if( zoom > 100.0f )
  389.         zoom = 100.0f;
  390. }
  391.  
  392.  
  393. void Camera::reset(){
  394.     elevationAngle = 0.0f;
  395.     azimutAngle = 0.0f;
  396.     zoom = 5.0f;
  397. }
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409. // We create an enum of the sides so we don't have to call each side 0 or 1.
  410. // This way it makes it more understandable and readable when dealing with frustum sides.
  411. enum FrustumSide
  412. {
  413.     RIGHT    = 0,        // The RIGHT side of the frustum
  414.     LEFT    = 1,        // The LEFT     side of the frustum
  415.     BOTTOM    = 2,        // The BOTTOM side of the frustum
  416.     TOP        = 3,        // The TOP side of the frustum
  417.     BACK    = 4,        // The BACK    side of the frustum
  418.     FRONT    = 5            // The FRONT side of the frustum
  419. };
  420.  
  421. // Like above, instead of saying a number for the ABC and D of the plane, we
  422. // want to be more descriptive.
  423. enum PlaneData
  424. {
  425.     A = 0,                // The X value of the plane's normal
  426.     B = 1,                // The Y value of the plane's normal
  427.     C = 2,                // The Z value of the plane's normal
  428.     D = 3                // The distance the plane is from the origin
  429. };
  430.  
  431. ///////////////////////////////// NORMALIZE PLANE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  432. /////
  433. /////    This normalizes a plane (A side) from a given frustum.
  434. /////
  435. ///////////////////////////////// NORMALIZE PLANE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  436.  
  437. static void normalizePlane(float frustum[6][4], int side)
  438. {
  439.     // Here we calculate the magnitude of the normal to the plane (point A B C)
  440.     // Remember that (A, B, C) is that same thing as the normal's (X, Y, Z).
  441.     // To calculate magnitude you use the equation:  magnitude = sqrt( x^2 + y^2 + z^2)
  442.     float magnitude = (float)sqrt( frustum[side][A] * frustum[side][A] +
  443.                                    frustum[side][B] * frustum[side][B] +
  444.                                    frustum[side][C] * frustum[side][C] );
  445.  
  446.     // Then we divide the plane's values by it's magnitude.
  447.     // This makes it easier to work with.
  448.     frustum[side][A] /= magnitude;
  449.     frustum[side][B] /= magnitude;
  450.     frustum[side][C] /= magnitude;
  451.     frustum[side][D] /= magnitude;
  452. }
  453.  
  454.  
  455. ///////////////////////////////// CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  456. /////
  457. /////    This extracts our frustum from the projection and modelview matrix.
  458. /////
  459. ///////////////////////////////// CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  460.  
  461. void Camera::calculateFrustum()
  462. {
  463.     float   proj[16];                                // This will hold our projection matrix
  464.     float   modl[16];                                // This will hold our modelview matrix
  465.     float   clip[16];                                // This will hold the clipping planes
  466.  
  467.     // glGetFloatv() is used to extract information about our OpenGL world.
  468.     // Below, we pass in GL_PROJECTION_MATRIX to abstract our projection matrix.
  469.     // It then stores the matrix into an array of [16].
  470.     glGetFloatv( GL_PROJECTION_MATRIX, proj );
  471.  
  472.     // By passing in GL_MODELVIEW_MATRIX, we can abstract our model view matrix.
  473.     // This also stores it in an array of [16].
  474.     glGetFloatv( GL_MODELVIEW_MATRIX, modl );
  475.  
  476.     // Now that we have our modelview and projection matrix, if we combine these 2 matrices,
  477.     // it will give us our clipping planes.  To combine 2 matrices, we multiply them.
  478.  
  479.     clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
  480.     clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
  481.     clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
  482.     clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
  483.  
  484.     clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
  485.     clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
  486.     clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
  487.     clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
  488.  
  489.     clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
  490.     clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
  491.     clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
  492.     clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
  493.  
  494.     clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
  495.     clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
  496.     clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
  497.     clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
  498.  
  499.     // Now we actually want to get the sides of the frustum.  To do this we take
  500.     // the clipping planes we received above and extract the sides from them.
  501.  
  502.     // This will extract the RIGHT side of the frustum
  503.     frustum[RIGHT][A] = clip[ 3] - clip[ 0];
  504.     frustum[RIGHT][B] = clip[ 7] - clip[ 4];
  505.     frustum[RIGHT][C] = clip[11] - clip[ 8];
  506.     frustum[RIGHT][D] = clip[15] - clip[12];
  507.  
  508.     // Now that we have a normal (A,B,C) and a distance (D) to the plane,
  509.     // we want to normalize that normal and distance.
  510.  
  511.     // Normalize the RIGHT side
  512.     normalizePlane(frustum, RIGHT);
  513.  
  514.     // This will extract the LEFT side of the frustum
  515.     frustum[LEFT][A] = clip[ 3] + clip[ 0];
  516.     frustum[LEFT][B] = clip[ 7] + clip[ 4];
  517.     frustum[LEFT][C] = clip[11] + clip[ 8];
  518.     frustum[LEFT][D] = clip[15] + clip[12];
  519.  
  520.     // Normalize the LEFT side
  521.     normalizePlane(frustum, LEFT);
  522.  
  523.     // This will extract the BOTTOM side of the frustum
  524.     frustum[BOTTOM][A] = clip[ 3] + clip[ 1];
  525.     frustum[BOTTOM][B] = clip[ 7] + clip[ 5];
  526.     frustum[BOTTOM][C] = clip[11] + clip[ 9];
  527.     frustum[BOTTOM][D] = clip[15] + clip[13];
  528.  
  529.     // Normalize the BOTTOM side
  530.     normalizePlane(frustum, BOTTOM);
  531.  
  532.     // This will extract the TOP side of the frustum
  533.     frustum[TOP][A] = clip[ 3] - clip[ 1];
  534.     frustum[TOP][B] = clip[ 7] - clip[ 5];
  535.     frustum[TOP][C] = clip[11] - clip[ 9];
  536.     frustum[TOP][D] = clip[15] - clip[13];
  537.  
  538.     // Normalize the TOP side
  539.     normalizePlane(frustum, TOP);
  540.  
  541.     // This will extract the BACK side of the frustum
  542.     frustum[BACK][A] = clip[ 3] - clip[ 2];
  543.     frustum[BACK][B] = clip[ 7] - clip[ 6];
  544.     frustum[BACK][C] = clip[11] - clip[10];
  545.     frustum[BACK][D] = clip[15] - clip[14];
  546.  
  547.     // Normalize the BACK side
  548.     normalizePlane(frustum, BACK);
  549.  
  550.     // This will extract the FRONT side of the frustum
  551.     frustum[FRONT][A] = clip[ 3] + clip[ 2];
  552.     frustum[FRONT][B] = clip[ 7] + clip[ 6];
  553.     frustum[FRONT][C] = clip[11] + clip[10];
  554.     frustum[FRONT][D] = clip[15] + clip[14];
  555.  
  556.     // Normalize the FRONT side
  557.     normalizePlane(frustum, FRONT);
  558. }
  559.  
  560. // The code below will allow us to make checks within the frustum.  For example,
  561. // if we want to see if a point, a sphere, or a cube lies inside of the frustum.
  562. // Because all of our planes point INWARDS (The normals are all pointing inside the frustum)
  563. // we then can assume that if a point is in FRONT of all of the planes, it's inside.
  564.  
  565. ///////////////////////////////// POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  566. /////
  567. /////    This determines if a point is inside of the frustum
  568. /////
  569. ///////////////////////////////// POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  570.  
  571. bool Camera::pointInFrustum( float x, float y, float z )
  572. {
  573.     // If you remember the plane equation (A*x + B*y + C*z + D = 0), then the rest
  574.     // of this code should be quite obvious and easy to figure out yourself.
  575.     // In case don't know the plane equation, it might be a good idea to look
  576.     // at our Plane Collision tutorial at www.GameTutorials.com in OpenGL Tutorials.
  577.     // I will briefly go over it here.  (A,B,C) is the (X,Y,Z) of the normal to the plane.
  578.     // They are the same thing... but just called ABC because you don't want to say:
  579.     // (x*x + y*y + z*z + d = 0).  That would be wrong, so they substitute them.
  580.     // the (x, y, z) in the equation is the point that you are testing.  The D is
  581.     // The distance the plane is from the origin.  The equation ends with "= 0" because
  582.     // that is true when the point (x, y, z) is ON the plane.  When the point is NOT on
  583.     // the plane, it is either a negative number (the point is behind the plane) or a
  584.     // positive number (the point is in front of the plane).  We want to check if the point
  585.     // is in front of the plane, so all we have to do is go through each point and make
  586.     // sure the plane equation goes out to a positive number on each side of the frustum.
  587.     // The result (be it positive or negative) is the distance the point is front the plane.
  588.  
  589.     // Go through all the sides of the frustum
  590.     for(int i = 0; i < 6; i++ )
  591.     {
  592.         // Calculate the plane equation and check if the point is behind a side of the frustum
  593.         if(frustum[i][A] * x + frustum[i][B] * y + frustum[i][C] * z + frustum[i][D] <= 0)
  594.         {
  595.             // The point was behind a side, so it ISN'T in the frustum
  596.             return false;
  597.         }
  598.     }
  599.  
  600.     // The point was inside of the frustum (In front of ALL the sides of the frustum)
  601.     return true;
  602. }
  603.  
  604.  
  605. ///////////////////////////////// SPHERE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  606. /////
  607. /////    This determines if a sphere is inside of our frustum by it's center and radius.
  608. /////
  609. ///////////////////////////////// SPHERE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  610.  
  611. bool Camera::sphereInFrustum( float x, float y, float z, float radius )
  612. {
  613.     // Now this function is almost identical to the PointInFrustum(), except we
  614.     // now have to deal with a radius around the point.  The point is the center of
  615.     // the radius.  So, the point might be outside of the frustum, but it doesn't
  616.     // mean that the rest of the sphere is.  It could be half and half.  So instead of
  617.     // checking if it's less than 0, we need to add on the radius to that.  Say the
  618.     // equation produced -2, which means the center of the sphere is the distance of
  619.     // 2 behind the plane.  Well, what if the radius was 5?  The sphere is still inside,
  620.     // so we would say, if(-2 < -5) then we are outside.  In that case it's false,
  621.     // so we are inside of the frustum, but a distance of 3.  This is reflected below.
  622.  
  623.     // Go through all the sides of the frustum
  624.     for(int i = 0; i < 6; i++ )
  625.     {
  626.         // If the center of the sphere is farther away from the plane than the radius
  627.         if( frustum[i][A] * x + frustum[i][B] * y + frustum[i][C] * z + frustum[i][D] <= -radius )
  628.         {
  629.             // The distance was greater than the radius so the sphere is outside of the frustum
  630.             return false;
  631.         }
  632.     }
  633.  
  634.     // The sphere was inside of the frustum!
  635.     return true;
  636. }
  637.  
  638. bool Camera::sphereInFrustum( vec3_t pos, float radius )
  639. {
  640.     
  641.     // Go through all the sides of the frustum
  642.     for(int i = 0; i < 6; i++ )
  643.     {
  644.         // If the center of the sphere is farther away from the plane than the radius
  645.         if( frustum[i][A] * pos[0] + frustum[i][B] * pos[1] + frustum[i][C] * pos[2] + frustum[i][D] <= -radius )
  646.         {
  647.             // The distance was greater than the radius so the sphere is outside of the frustum
  648.             return false;
  649.         }
  650.     }
  651.  
  652.     // The sphere was inside of the frustum!
  653.     return true;
  654. }
  655.  
  656.  
  657. ///////////////////////////////// CUBE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  658. /////
  659. /////    This determines if a cube is in or around our frustum by it's center and 1/2 it's length
  660. /////
  661. ///////////////////////////////// CUBE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
  662.  
  663. bool Camera::cubeInFrustum( float x, float y, float z, float size )
  664. {
  665.     // This test is a bit more work, but not too much more complicated.
  666.     // Basically, what is going on is, that we are given the center of the cube,
  667.     // and half the length.  Think of it like a radius.  Then we checking each point
  668.     // in the cube and seeing if it is inside the frustum.  If a point is found in front
  669.     // of a side, then we skip to the next side.  If we get to a plane that does NOT have
  670.     // a point in front of it, then it will return false.
  671.  
  672.     // *Note* - This will sometimes say that a cube is inside the frustum when it isn't.
  673.     // This happens when all the corners of the bounding box are not behind any one plane.
  674.     // This is rare and shouldn't effect the overall rendering speed.
  675.  
  676.     for(int i = 0; i < 6; i++ )
  677.     {
  678.         if(frustum[i][A] * (x - size) + frustum[i][B] * (y - size) + frustum[i][C] * (z - size) + frustum[i][D] > 0)
  679.            continue;
  680.         if(frustum[i][A] * (x + size) + frustum[i][B] * (y - size) + frustum[i][C] * (z - size) + frustum[i][D] > 0)
  681.            continue;
  682.         if(frustum[i][A] * (x - size) + frustum[i][B] * (y + size) + frustum[i][C] * (z - size) + frustum[i][D] > 0)
  683.            continue;
  684.         if(frustum[i][A] * (x + size) + frustum[i][B] * (y + size) + frustum[i][C] * (z - size) + frustum[i][D] > 0)
  685.            continue;
  686.         if(frustum[i][A] * (x - size) + frustum[i][B] * (y - size) + frustum[i][C] * (z + size) + frustum[i][D] > 0)
  687.            continue;
  688.         if(frustum[i][A] * (x + size) + frustum[i][B] * (y - size) + frustum[i][C] * (z + size) + frustum[i][D] > 0)
  689.            continue;
  690.         if(frustum[i][A] * (x - size) + frustum[i][B] * (y + size) + frustum[i][C] * (z + size) + frustum[i][D] > 0)
  691.            continue;
  692.         if(frustum[i][A] * (x + size) + frustum[i][B] * (y + size) + frustum[i][C] * (z + size) + frustum[i][D] > 0)
  693.            continue;
  694.  
  695.         // If we get here, it isn't in the frustum
  696.         return false;
  697.     }
  698.  
  699.     return true;
  700. }
  701.  
  702. bool Camera::AABBInFrustum(vec3_t min, vec3_t max)
  703. {
  704.     float x=(min[0]+max[0])*0.5f;
  705.     float y=(min[1]+max[1])*0.5f;
  706.     float z=(min[2]+max[2])*0.5f;
  707.     
  708.     vec3_t size;
  709.     vectorInit3d(max[0]-min[0], max[1]-min[1], max[2]-min[2], size); 
  710.  
  711.     for(int i = 0; i < 6; i++ )
  712.     {
  713.         if(frustum[i][A] * (x - size[0]) + frustum[i][B] * (y - size[1]) + frustum[i][C] * (z - size[2]) + frustum[i][D] > 0)
  714.            continue;
  715.         if(frustum[i][A] * (x + size[0]) + frustum[i][B] * (y - size[1]) + frustum[i][C] * (z - size[2]) + frustum[i][D] > 0)
  716.            continue;
  717.         if(frustum[i][A] * (x - size[0]) + frustum[i][B] * (y + size[1]) + frustum[i][C] * (z - size[2]) + frustum[i][D] > 0)
  718.            continue;
  719.         if(frustum[i][A] * (x + size[0]) + frustum[i][B] * (y + size[1]) + frustum[i][C] * (z - size[2]) + frustum[i][D] > 0)
  720.            continue;
  721.         if(frustum[i][A] * (x - size[0]) + frustum[i][B] * (y - size[1]) + frustum[i][C] * (z + size[2]) + frustum[i][D] > 0)
  722.            continue;
  723.         if(frustum[i][A] * (x + size[0]) + frustum[i][B] * (y - size[1]) + frustum[i][C] * (z + size[2]) + frustum[i][D] > 0)
  724.            continue;
  725.         if(frustum[i][A] * (x - size[0]) + frustum[i][B] * (y + size[1]) + frustum[i][C] * (z + size[2]) + frustum[i][D] > 0)
  726.            continue;
  727.         if(frustum[i][A] * (x + size[0]) + frustum[i][B] * (y + size[1]) + frustum[i][C] * (z + size[2]) + frustum[i][D] > 0)
  728.            continue;
  729.  
  730.         // If we get here, it isn't in the frustum
  731.         return false;
  732.     }
  733.  
  734.     return true;
  735. }
  736.