Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Camera.cpp

Go to the documentation of this file.
00001 
00002 /*
00003     TEDDY - General graphics application library
00004     Copyright (C) 1999-2002  Timo Suoranta
00005     tksuoran@cc.helsinki.fi
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2.1 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021     $Id: Camera.cpp,v 1.8 2002/02/16 12:41:39 tksuoran Exp $
00022 */
00023 
00024 
00025 #include "Teddy/TeddyConfig.h"
00026 #include "Teddy/Graphics/View.h"
00027 #include "Teddy/Graphics/PsRenderer.h"
00028 #include "Teddy/Models/Model.h"
00029 #include "Teddy/Models/Geometry.h"
00030 #include "Teddy/PhysicalComponents/Projection.h"
00031 #include "Teddy/Scenes/Camera.h"
00032 #include "Teddy/Scenes/Scene.h"
00033 #include "Teddy/SysSupport/Messages.h"
00034 #include "Teddy/SysSupport/StdMaths.h"
00035 using namespace Teddy::Graphics;
00036 using namespace Teddy::Models;
00037 using namespace Teddy::PhysicalComponents;
00038 using namespace Teddy::SysSupport;
00039 
00040 
00041 namespace Teddy  {
00042 namespace Scenes {
00043 
00044 
00050 Camera::Camera( const std::string &name, Scene *scene )
00051 :
00052 Model    ( name  ),
00053 scene    ( scene ),
00054 near_clip(    2  ),
00055 far_clip ( 4096  ),
00056 fov      (   80  )
00057 {
00058     for( int i=0; i<MSD; i++ ){
00059         model_view_matrix[i] = Matrix::IDENTITY;
00060     }
00061     model_view_matrix_sp = 0;
00062     active_projection    = NULL;
00063     mirror_x             = false;
00064     projection_dirty     = true;
00065 }
00066 
00067 
00068 void Camera::setMirrorX( const bool mirror_x ){
00069     this->mirror_x = mirror_x;
00070     msg( M_INIT, "SetMirror %s", mirror_x?"true":"false" );
00071 }
00072 
00077 void Camera::doProjection( Projection *p, const bool load_matrix ){
00078     projection_matrix = getPerspectiveMatrix( fov, p->getRatio(), near_clip, far_clip );
00079     if( mirror_x ){
00080         projection_matrix = projection_matrix * Matrix::MIRROR_X;
00081     }
00082     if( load_matrix == true ){      
00083         p->setProjectionMatrix( projection_matrix );
00084         glMatrixMode( GL_MODELVIEW );
00085     }
00086     updatePlanes();
00087 }
00088 
00089 
00096 void Camera::doCamera( Projection *p, const bool load_matrix ){
00097     //  YUneed origo camera fix
00098     //  view_matrix = getViewMatrix();
00099     view_matrix = getWorldToLocalMatrix();
00100 
00101     if( load_matrix == true ){
00102         p->setModelViewMatrix( view_matrix );
00103     }
00104 }
00105 
00106 
00107 void Camera::pushObjectMatrix(){
00108     model_view_matrix_sp++;
00109 }
00110 
00111 
00112 void Camera::popObjectMatrix(){
00113     model_view_matrix_sp--;
00114 }
00115 
00116 
00118 void Camera::doObjectMatrix( Projection *p, const Matrix &m, const bool load_matrix ){
00119     if( model_view_matrix_sp>0 ){
00120         model_view_matrix[model_view_matrix_sp] = 
00121             model_view_matrix[model_view_matrix_sp-1] * m;
00122     }else{
00123         model_view_matrix[model_view_matrix_sp] = view_matrix * m;
00124     }
00125     to_screen_s_matrix = projection_matrix * model_view_matrix[model_view_matrix_sp];
00126     if( load_matrix == true ){
00127         p->setModelViewMatrix( model_view_matrix[model_view_matrix_sp] );
00128     }
00129 }
00130 
00131 
00133 Vector4 Camera::projectVector( const Vector4 &v ) const{
00134     return to_screen_s_matrix.transformVector4( v );
00135 }
00136 
00137 
00139 /*virtual*/ void Camera::projectScene( Projection *p ){
00140     View *view              = p->getView();
00141     this->active_projection = p;
00142     this->rect              = IntRect( p->getRect() );
00143 
00144     Geometry::draw_count = 0;
00145 //  debug_index = 0;
00146 
00147 //  Update and load projection matrix
00148 //  if( projection_dirty ){
00149         doProjection( p );
00150 //      projection_dirty = false;
00151 //  }
00152 
00153     doCamera( p );
00154 
00155     //  Draw Scene
00156     scene->lock  ();
00157     scene->draw  ( this, p );
00158     scene->unlock();
00159 }
00160 
00161 
00166 Model *Camera::pick( Projection *p, const IntVector2 &pos ){
00167     Vector2 pick_pos  = pos;
00168     Vector2 pick_size = Vector2( 3.0, 3.0 );
00169     projection_matrix =
00170         getPickMatrix       ( pick_pos, pick_size, p->getRect()            ) *
00171         getPerspectiveMatrix( fov,      p->getRatio(), near_clip, far_clip );
00172     p->setProjectionMatrix( projection_matrix );
00173 
00174     doCamera( p, true );
00175     return scene->pick( this, p );
00176 }   
00177 
00178 
00179 void Camera::setNearFar( const float near_clip, const float far_clip ){
00180     this->near_clip = near_clip;
00181     this->far_clip  = far_clip;
00182 }
00183 
00184 
00185 double Camera::getNear(){
00186     return this->near_clip;
00187 }
00188 
00189 
00190 double Camera::getFar(){
00191     return this->far_clip;
00192 }
00193 
00194 
00196 void Camera::setFov( const float fov ){
00197     this->fov = fov;
00198 }
00199 
00200 
00201 void Camera::modFov( const float mod ){
00202     fov += mod;
00203 }
00204 
00205 
00207 float Camera::getFov() const {
00208     return fov;
00209 }
00210 
00211 
00213 void Camera::setScene( Scene *scene ){
00214     this->scene = scene;
00215 }
00216 
00217 
00219 Scene *Camera::getScene() const {
00220     return scene;
00221 }
00222 
00223 
00225 bool Camera::cull( const Model &model ){
00226     Matrix m   = model_view_matrix[model_view_matrix_sp];
00227     Vector loc = m * Vector(0,0,0);
00228     float  rad = model.getClipRadius();
00229 
00230     double d0 = view_plane[0].distance( loc ) + rad;
00231     double d1 = view_plane[1].distance( loc ) + rad;
00232     double d2 = view_plane[2].distance( loc ) + rad;
00233     double d3 = view_plane[3].distance( loc ) + rad;
00234     double d4 = view_plane[4].distance( loc ) + rad;
00235     double d5 = view_plane[5].distance( loc ) + rad;
00236     
00237 /*  debug_double[debug_index][0] = d0;
00238     debug_double[debug_index][1] = d1;
00239     debug_double[debug_index][2] = d2;
00240     debug_double[debug_index][3] = d3;
00241     debug_double[debug_index][4] = d4;
00242     debug_double[debug_index][5] = d5;
00243     debug_matrix[ debug_index ] = m;
00244     debug_index++;
00245     if( debug_index > 4 ) debug_index = 4;*/
00246 
00247     if( d0 < 0 ) return true;
00248     if( d1 < 0 ) return true;
00249     if( d2 < 0 ) return true;
00250     if( d3 < 0 ) return true;
00251     if( d4 < 0 ) return true;
00252     if( d5 < 0 ) return true;
00253     return false;
00254 }
00255 
00256 
00258 Matrix Camera::getFrustumMatrix( const float left, const float right, const float bottom, const float top, const float nearval, const float farval ) const {
00259     float x, y, a, b, c, d;
00260     Matrix frustum_matrix;
00261 
00262     x =  (nearval + nearval) / (right  - left   );
00263     y =  (nearval + nearval) / (top    - bottom );
00264     a =  (right   + left   ) / (right  - left   );
00265     b =  (top     + bottom ) / (top    - bottom );
00266     c = -(farval  + nearval) / (farval - nearval);
00267     d = -(2 * farval * nearval) / (farval - nearval);
00268 
00269 #   define M(row,col) frustum_matrix.m[col][row]
00270     M(0,0) = x;  M(0,1) = 0;  M(0,2) =  a;  M(0,3) = 0;
00271     M(1,0) = 0;  M(1,1) = y;  M(1,2) =  b;  M(1,3) = 0;
00272     M(2,0) = 0;  M(2,1) = 0;  M(2,2) =  c;  M(2,3) = d;
00273     M(3,0) = 0;  M(3,1) = 0;  M(3,2) = -1;  M(3,3) = 0;
00274 #   undef M
00275 
00276     return frustum_matrix;
00277 }
00278 
00279 
00281 Matrix Camera::getPerspectiveMatrix( const float fovy, const float aspect, const float zNear, const float zFar ) const {
00282     float xmin, xmax, ymin, ymax;
00283 
00284     ymax =  zNear * tan( fovy * M_PI / 360.0 );
00285     ymin = -ymax;
00286     xmin =  ymin * aspect;
00287     xmax =  ymax * aspect;
00288 
00289     return getFrustumMatrix( xmin, xmax, ymin, ymax, zNear, zFar );
00290 }
00291 
00292 
00294 Matrix Camera::getPickMatrix( const IntVector2 &pick_pos, const IntVector2 &pick_size, const IntRect &viewport ) const {
00295     Matrix pick_matrix;
00296 
00297     Vector2 scale     = viewport.getSize() / pick_size;
00298     //  sx =  viewport[2] / width;
00299     //  sy =  viewport[3] / height;
00300     Vector2 offset    = viewport.min - pick_pos;
00301     Vector2 translate = (viewport.getSize() + offset + offset) / pick_size;
00302     //tx = (viewport[2] + 2 * (viewport[0] - x )) / width;
00303     //ty = (viewport[3] + 2 * (viewport[1] - y )) / height;
00304 
00305 #   define M(row,col) pick_matrix.m[col][row]
00306     M(0, 0) = scale[0];      //  sx;
00307     M(0, 1) =  0;
00308     M(0, 2) =  0;
00309     M(0, 3) = translate[0];  //  tx;
00310     M(1, 0) =  0;
00311     M(1, 1) = scale[1];      //  sy;
00312     M(1, 2) =  0;
00313     M(1, 3) = translate[1];  //  ty;
00314     M(2, 0) =  0;
00315     M(2, 1) =  0;
00316     M(2, 2) =  1;
00317     M(2, 3) =  0;
00318     M(3, 0) =  0;
00319     M(3, 1) =  0;
00320     M(3, 2) =  0;
00321     M(3, 3) =  1;
00322 #   undef M
00323 
00324     return pick_matrix;
00325 }
00326 
00327 
00329 void Camera::updatePlanes(){
00330     Matrix m = projection_matrix;
00331     m.transpose();
00332     Vector4 v1 = m.transformVector4(  Vector4(-1, 0, 0, 1 )  );
00333     Vector4 v2 = m.transformVector4(  Vector4( 1, 0, 0, 1 )  );
00334     Vector4 v3 = m.transformVector4(  Vector4( 0,-1, 0, 1 )  );
00335     Vector4 v4 = m.transformVector4(  Vector4( 0, 1, 0, 1 )  );
00336     Vector4 v5 = m.transformVector4(  Vector4( 0, 0,-1, 1 )  );
00337     Vector4 v6 = m.transformVector4(  Vector4( 0, 0, 1, 1 )  );
00338     v1 /= sqrt( v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] );
00339     v2 /= sqrt( v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2] );
00340     v3 /= sqrt( v3[0] * v3[0] + v3[1] * v3[1] + v3[2] * v3[2] );
00341     v4 /= sqrt( v4[0] * v4[0] + v4[1] * v4[1] + v4[2] * v4[2] );
00342     v5 /= sqrt( v5[0] * v5[0] + v5[1] * v5[1] + v5[2] * v5[2] );
00343     v6 /= sqrt( v6[0] * v6[0] + v6[1] * v6[1] + v6[2] * v6[2] );
00344     view_plane[0] = v1;
00345     view_plane[1] = v2;
00346     view_plane[2] = v3;
00347     view_plane[3] = v4;
00348     view_plane[4] = v5;
00349     view_plane[5] = v6;
00350 }
00351 
00352 
00353 void Camera::updateFrustum(){  // Extracts The Current View Frustum Plane Equations
00354     float  proj[16];           // For Grabbing The PROJECTION Matrix
00355     float  modl[16];           // For Grabbing The MODELVIEW Matrix
00356     float  clip[16];           // Result Of Concatenating PROJECTION and MODELVIEW
00357     float  t;                  // Temporary Work Variable
00358     
00359     glGetFloatv( GL_PROJECTION_MATRIX, proj );  // Grab The Current PROJECTION Matrix
00360     glGetFloatv( GL_MODELVIEW_MATRIX,  modl );  // Grab The Current MODELVIEW Matrix
00361 
00362     // Concatenate (Multiply) The Two Matricies
00363     clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
00364     clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
00365     clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
00366     clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
00367 
00368     clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
00369     clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
00370     clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
00371     clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
00372 
00373     clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
00374     clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
00375     clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
00376     clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
00377 
00378     clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
00379     clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
00380     clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
00381     clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
00382 
00383 
00384     // Extract the RIGHT clipping plane
00385     frustum[0][0] = clip[ 3] - clip[ 0];
00386     frustum[0][1] = clip[ 7] - clip[ 4];
00387     frustum[0][2] = clip[11] - clip[ 8];
00388     frustum[0][3] = clip[15] - clip[12];
00389 
00390     // Normalize it
00391     t = (float) sqrt( frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2] );
00392     frustum[0][0] /= t;
00393     frustum[0][1] /= t;
00394     frustum[0][2] /= t;
00395     frustum[0][3] /= t;
00396 
00397 
00398     // Extract the LEFT clipping plane
00399     frustum[1][0] = clip[ 3] + clip[ 0];
00400     frustum[1][1] = clip[ 7] + clip[ 4];
00401     frustum[1][2] = clip[11] + clip[ 8];
00402     frustum[1][3] = clip[15] + clip[12];
00403 
00404     // Normalize it
00405     t = (float) sqrt( frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2] );
00406     frustum[1][0] /= t;
00407     frustum[1][1] /= t;
00408     frustum[1][2] /= t;
00409     frustum[1][3] /= t;
00410 
00411 
00412     // Extract the BOTTOM clipping plane
00413     frustum[2][0] = clip[ 3] + clip[ 1];
00414     frustum[2][1] = clip[ 7] + clip[ 5];
00415     frustum[2][2] = clip[11] + clip[ 9];
00416     frustum[2][3] = clip[15] + clip[13];
00417 
00418     // Normalize it
00419     t = (float) sqrt( frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2] );
00420     frustum[2][0] /= t;
00421     frustum[2][1] /= t;
00422     frustum[2][2] /= t;
00423     frustum[2][3] /= t;
00424 
00425 
00426     // Extract the TOP clipping plane
00427     frustum[3][0] = clip[ 3] - clip[ 1];
00428     frustum[3][1] = clip[ 7] - clip[ 5];
00429     frustum[3][2] = clip[11] - clip[ 9];
00430     frustum[3][3] = clip[15] - clip[13];
00431 
00432     // Normalize it
00433     t = (float) sqrt( frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2] );
00434     frustum[3][0] /= t;
00435     frustum[3][1] /= t;
00436     frustum[3][2] /= t;
00437     frustum[3][3] /= t;
00438 
00439 
00440     // Extract the FAR clipping plane
00441     frustum[4][0] = clip[ 3] - clip[ 2];
00442     frustum[4][1] = clip[ 7] - clip[ 6];
00443     frustum[4][2] = clip[11] - clip[10];
00444     frustum[4][3] = clip[15] - clip[14];
00445 
00446     // Normalize it
00447     t = (float) sqrt( frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2] );
00448     frustum[4][0] /= t;
00449     frustum[4][1] /= t;
00450     frustum[4][2] /= t;
00451     frustum[4][3] /= t;
00452 
00453 
00454     // Extract the NEAR clipping plane.  This is last on purpose (see pointinfrustum() for reason)
00455     frustum[5][0] = clip[ 3] + clip[ 2];
00456     frustum[5][1] = clip[ 7] + clip[ 6];
00457     frustum[5][2] = clip[11] + clip[10];
00458     frustum[5][3] = clip[15] + clip[14];
00459 
00460     // Normalize it
00461     t = (float) sqrt( frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2] );
00462     frustum[5][0] /= t;
00463     frustum[5][1] /= t;
00464     frustum[5][2] /= t;
00465     frustum[5][3] /= t;
00466 }
00467 
00468 
00473 bool Camera::cullPoint( const Vector &v ) const {
00474     for( int p = 0; p < 6; p++ ){
00475         if( frustum[p][0] * v[0] + frustum[p][1] * v[1] + frustum[p][2] * v[2] + frustum[p][3] <= 0 ){
00476             return false;
00477         }
00478     }
00479     return true;
00480 }
00481 
00482 
00483 /*
00484     \brief Test If A Sphere Is In The Frustum
00485     \todo  Optimization: remember which plane caused false last time and test it first
00486 */
00487 bool Camera::cullSphere( const Vector &v, float radius ) const {
00488     for( int p=0; p<6; p++ ){
00489         if( frustum[p][0] * v[0] + frustum[p][1] * v[1] + frustum[p][2] * v[2] + frustum[p][3] <= -radius ){
00490             return false;
00491         }
00492     }
00493     return true;
00494 }
00495 
00496 
00501 bool Camera::cullAABox( const Vector &pos, const Vector &size ){
00502     for( int p=0; p<6; p++ ){
00503         Vector min = pos - size;
00504         Vector max = pos + size;
00505         if( frustum[p][0] * min[0] + frustum[p][1] * min[1] + frustum[p][2] * min[2] + frustum[p][3] > 0 ) continue;
00506         if( frustum[p][0] * max[0] + frustum[p][1] * min[1] + frustum[p][2] * min[2] + frustum[p][3] > 0 ) continue;
00507         if( frustum[p][0] * min[0] + frustum[p][1] * max[1] + frustum[p][2] * min[2] + frustum[p][3] > 0 ) continue;
00508         if( frustum[p][0] * max[0] + frustum[p][1] * max[1] + frustum[p][2] * min[2] + frustum[p][3] > 0 ) continue;
00509         if( frustum[p][0] * min[0] + frustum[p][1] * min[1] + frustum[p][2] * max[2] + frustum[p][3] > 0 ) continue;
00510         if( frustum[p][0] * max[0] + frustum[p][1] * min[1] + frustum[p][2] * max[2] + frustum[p][3] > 0 ) continue;
00511         if( frustum[p][0] * min[0] + frustum[p][1] * max[1] + frustum[p][2] * max[2] + frustum[p][3] > 0 ) continue;
00512         if( frustum[p][0] * max[0] + frustum[p][1] * max[1] + frustum[p][2] * max[2] + frustum[p][3] > 0 ) continue;
00513         return false;
00514     }
00515     return true;
00516 }
00517 
00518 
00519 };  //  namespace Scenes
00520 };  //  namespace Teddy
00521