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

sglFrustum.hpp

00001 /*****************************************************************************
00002  * SGL: A Scene Graph Library
00003  *
00004  * Copyright (C) 1997-2001  Scott McMillan   All Rights Reserved.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public
00017  * License along with this library; if not, write to the Free
00018  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  *****************************************************************************
00020  *     File: sglFrustum.hpp
00021  *  Created: 17 November 1998
00022  *  Summary: a polytope with 6 planes that defines a truncated pyramid
00023  *****************************************************************************/
00024 
00025 #ifndef __SGL_FRUSTUM_HPP
00026 #define __SGL_FRUSTUM_HPP
00027 
00028 #include <sgl.h>
00029 #include <sglPolytope.hpp>
00030 
00031 //----------------------------------------------------------------------------
00032 // convenience types:
00033 //    template class 'should' only be float or double
00034 
00035 template <class T> class sglFrustum;
00036 
00037 typedef sglFrustum<float>  sglFrustumf;
00038 typedef sglFrustum<double> sglFrustumd;
00039 
00040 //----------------------------------------------------------------------------
00041 
00051 template <class T>
00052 class sglFrustum : public sglPolytope<T>
00053 {
00054 public:
00056    enum { eLEFT = 0,  eUP = 1, eRIGHT = 2, eDOWN = 3, eFRONT = 4, eBACK = 5,
00057           eNUM_PLANES = 6};
00058 
00059 public:
00061    sglFrustum() : sglPolytope<T>(), m_ortho_flag(true), m_fov_y((T)-1) {}
00062 
00064    template <class S>
00065    sglFrustum(const sglFrustum<S> &rhs)
00066            : sglPolytope<T>(rhs),
00067              m_ortho_flag(rhs.getOrthoFlag()),
00068              m_fov_y((T)rhs.getFOVY())
00069         {}
00070 
00072    virtual ~sglFrustum() {}
00073 
00075    template <class S>
00076    sglFrustum &operator=(const sglFrustum<S> &rhs)
00077       {
00078          if (this != (sglPolytope<T>*)&rhs)
00079          {
00080              sglPolytope<T>::operator=(rhs);
00081              m_ortho_flag = rhs.getOrthoFlag();
00082              m_fov_y = rhs.getFOVY();
00083          }
00084          return *this;
00085       }
00086 
00090    bool getOrthoFlag() const { return m_ortho_flag; }
00091 
00095    double getAspect() const { return m_aspect; }
00096 
00101    double getFOVY() const { return m_fov_y; }
00102 
00103    // HACK is the following DEPRECATED?
00110    bool build(sglMat4<T>& projection_matrix);
00111 
00118    bool buildPerspective(double fovY,  // radians
00119                          double aspect,
00120                          double near_clip, double far_clip);
00121 
00132    bool buildPerspective(double near_left, double near_right,
00133                          double near_bottom, double near_top,
00134                          double near_clip, double far_clip);
00135 
00144    bool buildOrtho(double left, double right, double bottom, double top,
00145                    double near_clip, double far_clip);
00146 
00147 #ifdef SGL_FRUSTUM_DEBUG
00148    // draw the frustum
00149    void drawImmediate() const;
00150 
00151 private:
00152    sglVec3f m_vertices[8];  // for drawing the frustum:
00153                             //  4      5
00154                             //    0  1
00155                             //    3  2
00156                             //  7      6
00157 #endif
00158 
00159 private:
00160     bool buildPerspectiveInternal(double near_left, double near_right,
00161                                   double near_bottom, double near_top,
00162                                   double near_clip, double far_clip);
00163 
00164 private:
00165     bool   m_ortho_flag;
00166     double m_aspect;
00167     double m_fov_y;
00168 };
00169 
00170 //----------------------------------------------------------------------------
00171 template <class T>
00172 inline bool sglFrustum<T>::build(sglMat4<T>& projectionMatrix)
00173 {
00174    // in case something goes wrong
00175    m_num_planes = 0;
00176 
00177    sglVec3<T> p1, p2, p3;
00178    sglVec4<T> r1, r2, r3;
00179    // get the inverse of the projection matrix
00180    sglMat4<T> inv;
00181    inv.inverse(projectionMatrix);
00182 
00183    for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00184    {
00185       switch(i)
00186       {
00187          case sglFrustum::eLEFT:
00188             p1.set(-1.f,  1.f,  1.f);
00189             p2.set(-1.f, -1.f,  1.f);
00190             p3.set(-1.f, -1.f, -1.f);
00191             break;
00192          case sglFrustum::eUP:
00193             p1.set(-1.f,  1.f,  1.f);
00194             p2.set(-1.f,  1.f, -1.f);
00195             p3.set( 1.f,  1.f, -1.f);
00196             break;
00197          case sglFrustum::eRIGHT:
00198             p1.set( 1.f,  1.f, -1.f);
00199             p2.set( 1.f, -1.f, -1.f);
00200             p3.set( 1.f, -1.f,  1.f);
00201             break;
00202          case sglFrustum::eDOWN:
00203             p1.set(-1.f, -1.f, -1.f);
00204             p2.set(-1.f, -1.f,  1.f);
00205             p3.set( 1.f, -1.f,  1.f);
00206             break;
00207          case sglFrustum::eFRONT:
00208             p1.set(-1.f,  1.f, -1.f);
00209             p2.set(-1.f, -1.f, -1.f);
00210             p3.set( 1.f, -1.f, -1.f);
00211             break;
00212          case sglFrustum::eBACK:
00213             p1.set( 1.f,  1.f,  1.f);
00214             p2.set( 1.f, -1.f,  1.f);
00215             p3.set(-1.f, -1.f,  1.f);
00216             break;
00217       }
00218 
00219       ::mul(p1,(T)1.0,inv, r1);
00220       ::mul(p2,(T)1.0,inv, r2);
00221       ::mul(p3,(T)1.0,inv, r3);
00222 
00223       if (r1[3] == 0.0 || r2[3] == 0.0 || r3[3] == 0.0)
00224       {
00225          return false;
00226       }
00227 
00228       r1 *= (1.0/r1[3]);
00229       r2 *= (1.0/r2[3]);
00230       r3 *= (1.0/r3[3]);
00231 
00232       p1.set(r1[0],r1[1],r1[2]);
00233       p2.set(r2[0],r2[1],r2[2]);
00234       p3.set(r3[0],r3[1],r3[2]);
00235 
00236       if (!m_plane[i].build(p1,p2,p3))
00237       {
00238          return false;
00239       }
00240    }
00241 
00242 #ifdef SGL_FRUSTUM_DEBUG
00243    // build the frustum geometry
00244    //  7      6
00245    //    3  2
00246    //    0  1
00247    //  4      5
00248    m_vertices[0].set(-1.f,-1.f,-1.f);   // front
00249    m_vertices[1].set( 1.f,-1.f,-1.f);
00250    m_vertices[2].set( 1.f, 1.f,-1.f);
00251    m_vertices[3].set(-1.f, 1.f,-1.f);
00252 
00253    m_vertices[4].set(-1.f,-1.f, 1.f);   // back
00254    m_vertices[5].set( 1.f,-1.f, 1.f);
00255    m_vertices[6].set( 1.f, 1.f, 1.f);
00256    m_vertices[7].set(-1.f, 1.f, 1.f);
00257 
00258    sglVec4f vertices[8];
00259    for (unsigned int ix=0; ix<8; ix++)
00260    {
00261       ::mul(m_vertices[ix], (T)1.0, inv, vertices[ix]);
00262       vertices[ix] *= (1.0/vertices[ix][3]);
00263       m_vertices[ix].set(vertices[ix][0], vertices[ix][1], vertices[ix][2]);
00264    }
00265 #endif
00266 
00267    m_num_planes = 6;
00268    return true;
00269 }
00270 
00271 
00272 //----------------------------------------------------------------------------
00273 template <class T>
00274 inline bool sglFrustum<T>::buildPerspective(double near_left,
00275                                             double near_right,
00276                                             double near_bottom,
00277                                             double near_top,
00278                                             double near_clip, double far_clip)
00279 {
00280    if (near_clip <= 0.0)
00281    {
00282        return false;
00283    }
00284 
00285    m_ortho_flag = false;
00286    m_aspect = (near_right - near_left)/(near_top - near_bottom);
00287    m_fov_y = atan2(near_top, near_clip) - atan2(near_bottom, near_clip);
00288 
00289    return buildPerspectiveInternal(near_left, near_right,
00290                                    near_bottom, near_top,
00291                                    near_clip, far_clip);
00292 }
00293 
00294 
00295 //----------------------------------------------------------------------------
00296 template <class T>
00297 inline bool sglFrustum<T>::buildPerspective(double fovy, double aspect,
00298                                             double near_clip, double far_clip)
00299 {
00300    m_ortho_flag = false;
00301    m_aspect = aspect;
00302    m_fov_y = fovy;
00303 
00304    // ============== from Mesa 3.0 distribution =======================
00305    // ============== Copyright 1998, Brian Paul =======================
00306    GLdouble near_top, near_bottom, near_left, near_right;
00307 
00308    near_top    = near_clip * tan( fovy * 0.5 );
00309    near_bottom = -near_top;
00310 
00311    near_left   = near_bottom * aspect;
00312    near_right  = near_top * aspect;
00313    // =================================================================
00314 
00315    return buildPerspectiveInternal(near_left, near_right,
00316                                    near_bottom, near_top,
00317                                    near_clip, far_clip);
00318 }
00319 
00320 //----------------------------------------------------------------------------
00321 template <class T>
00322 inline bool sglFrustum<T>::buildPerspectiveInternal(double near_left,
00323                                                     double near_right,
00324                                                     double near_bottom,
00325                                                     double near_top,
00326                                                     double near_clip,
00327                                                     double far_clip)
00328 {
00329    // in case something goes wrong
00330    m_num_planes = 0;
00331 
00332    sglVec3<T> p1, p2, p3;
00333    GLdouble far_top, far_bottom, far_left, far_right;
00334    GLdouble factor = far_clip/near_clip;
00335 
00336    far_top    = near_top*factor;
00337    far_bottom = near_bottom*factor;
00338 
00339    far_left   = near_left*factor;
00340    far_right  = near_right*factor;
00341 
00342    for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00343    {
00344       switch(i)
00345       {
00346          case sglFrustum::eLEFT:
00347             p1.set(far_left,  far_top,     -far_clip);
00348             p2.set(far_left,  far_bottom,  -far_clip);
00349             p3.set(near_left, near_bottom, -near_clip);
00350             break;
00351          case sglFrustum::eUP:
00352             p1.set(far_left,   far_top,  -far_clip);
00353             p2.set(near_left,  near_top, -near_clip);
00354             p3.set(near_right, near_top, -near_clip);
00355             break;
00356          case sglFrustum::eRIGHT:
00357             p1.set(near_right, near_top,    -near_clip);
00358             p2.set(near_right, near_bottom, -near_clip);
00359             p3.set(far_right,  far_bottom,  -far_clip);
00360             break;
00361          case sglFrustum::eDOWN:
00362             p1.set(near_left, near_bottom, -near_clip);
00363             p2.set(far_left,  far_bottom,  -far_clip);
00364             p3.set(far_right, far_bottom,  -far_clip);
00365             break;
00366          case sglFrustum::eFRONT:
00367             p1.set(near_left,  near_top,    -near_clip);
00368             p2.set(near_left,  near_bottom, -near_clip);
00369             p3.set(near_right, near_bottom, -near_clip);
00370             break;
00371          case sglFrustum::eBACK:
00372             p1.set(far_right, far_top,    -far_clip);
00373             p2.set(far_right, far_bottom, -far_clip);
00374             p3.set(far_left,  far_bottom, -far_clip);
00375             break;
00376       }
00377 
00378       if (!m_plane[i].build(p1,p2,p3))
00379       {
00380          return false;
00381       }
00382    }
00383 
00384 #ifdef SGL_FRUSTUM_DEBUG
00385    // build the frustum geometry
00386    //  7      6
00387    //    3  2
00388    //    0  1
00389    //  4      5
00390    m_vertices[0].set(near_left,  near_bottom, -near_clip);
00391    m_vertices[1].set(near_right, near_bottom, -near_clip);
00392    m_vertices[2].set(near_right, near_top,    -near_clip);
00393    m_vertices[3].set(near_left,  near_top,    -near_clip);
00394 
00395    m_vertices[4].set(far_left,  far_bottom, -far_clip);;
00396    m_vertices[5].set(far_right, far_bottom, -far_clip);
00397    m_vertices[6].set(far_right, far_top,    -far_clip);
00398    m_vertices[7].set(far_left,  far_top,    -far_clip);
00399 #endif
00400 
00401    m_num_planes = 6;
00402    return true;
00403 }
00404 
00405 //----------------------------------------------------------------------------
00406 template <class T>
00407 inline bool sglFrustum<T>::buildOrtho(double left, double right,
00408                                       double bottom, double top,
00409                                       double near_clip, double far_clip)
00410 {
00411    // in case something goes wrong
00412    m_num_planes = 0;
00413 
00414    m_ortho_flag = true;
00415    m_aspect = (right - left)/(top - bottom);
00416    m_fov_y = -1.0;
00417 
00418    sglVec3<T> p1, p2, p3;
00419 
00420    for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00421    {
00422       switch(i)
00423       {
00424          case sglFrustum::eLEFT:
00425             p1.set(left, top,    -far_clip);
00426             p2.set(left, bottom, -far_clip);
00427             p3.set(left, bottom, -near_clip);
00428             break;
00429          case sglFrustum::eUP:
00430             p1.set(left,  top, -far_clip);
00431             p2.set(left,  top, -near_clip);
00432             p3.set(right, top, -near_clip);
00433             break;
00434          case sglFrustum::eRIGHT:
00435             p1.set(right, top,    -near_clip);
00436             p2.set(right, bottom, -near_clip);
00437             p3.set(right, bottom, -far_clip);
00438             break;
00439          case sglFrustum::eDOWN:
00440             p1.set(left,  bottom, -near_clip);
00441             p2.set(left,  bottom, -far_clip);
00442             p3.set(right, bottom, -far_clip);
00443             break;
00444          case sglFrustum::eFRONT:
00445             p1.set(left,  top,    -near_clip);
00446             p2.set(left,  bottom, -near_clip);
00447             p3.set(right, bottom, -near_clip);
00448             break;
00449          case sglFrustum::eBACK:
00450             p1.set(right, top,    -far_clip);
00451             p2.set(right, bottom, -far_clip);
00452             p3.set(left,  bottom, -far_clip);
00453             break;
00454       }
00455 
00456       if (!m_plane[i].build(p1,p2,p3))
00457       {
00458          return false;
00459       }
00460    }
00461 
00462 #ifdef SGL_FRUSTUM_DEBUG
00463    // build the frustum geometry
00464    //  7      6
00465    //    3  2
00466    //    0  1
00467    //  4      5
00468    m_vertices[0].set(left,  bottom, -near_clip);;
00469    m_vertices[1].set(right, bottom, -near_clip);
00470    m_vertices[2].set(right, top,    -near_clip);
00471    m_vertices[3].set(left,  top,    -near_clip);
00472 
00473    m_vertices[4].set(left,  bottom, -far_clip);;
00474    m_vertices[5].set(right, bottom, -far_clip);
00475    m_vertices[6].set(right, top,    -far_clip);
00476    m_vertices[7].set(left,  top,    -far_clip);
00477 #endif
00478 
00479    m_num_planes = 6;
00480    return true;
00481 }
00482 
00483 #ifdef SGL_FRUSTUM_DEBUG
00484 //----------------------------------------------------------------------------
00485 template <class T>
00486 inline void sglFrustum<T>::drawImmediate() const
00487 {
00488    //  7      6
00489    //    3  2
00490    //    0  1
00491    //  4      5
00492    glColor3f(1.f, 1.f, 1.f);
00493 
00494    glBegin(GL_LINE_STRIP);
00495    glVertex3f(m_vertices[0][0], m_vertices[0][1], m_vertices[0][2]);
00496    glVertex3f(m_vertices[1][0], m_vertices[1][1], m_vertices[1][2]);
00497    glVertex3f(m_vertices[2][0], m_vertices[2][1], m_vertices[2][2]);
00498    glVertex3f(m_vertices[3][0], m_vertices[3][1], m_vertices[3][2]);
00499    glVertex3f(m_vertices[0][0], m_vertices[0][1], m_vertices[0][2]);
00500    glVertex3f(m_vertices[4][0], m_vertices[4][1], m_vertices[4][2]);
00501    glVertex3f(m_vertices[5][0], m_vertices[5][1], m_vertices[5][2]);
00502    glVertex3f(m_vertices[6][0], m_vertices[6][1], m_vertices[6][2]);
00503    glVertex3f(m_vertices[7][0], m_vertices[7][1], m_vertices[7][2]);
00504    glVertex3f(m_vertices[4][0], m_vertices[4][1], m_vertices[4][2]);
00505    glEnd();
00506 
00507    glBegin(GL_LINES);
00508    glVertex3f(m_vertices[1][0], m_vertices[1][1], m_vertices[1][2]);
00509    glVertex3f(m_vertices[5][0], m_vertices[5][1], m_vertices[5][2]);
00510    glVertex3f(m_vertices[2][0], m_vertices[2][1], m_vertices[2][2]);
00511    glVertex3f(m_vertices[6][0], m_vertices[6][1], m_vertices[6][2]);
00512    glVertex3f(m_vertices[3][0], m_vertices[3][1], m_vertices[3][2]);
00513    glVertex3f(m_vertices[7][0], m_vertices[7][1], m_vertices[7][2]);
00514    glEnd();
00515 }
00516 #endif // SGL_FRUSTUM_DEBUG
00517 
00518 #endif

Generated at Mon Jul 1 18:00:04 2002 for SGL by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001