PBRT
/home/felix/UBC/projects/AdaptiveLightfieldSampling/pbrt_v2/src/3rdparty/ilmbase-1.0.2/ImathFrustum.h
00001 
00002 //
00003 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
00004 // Digital Ltd. LLC
00005 // 
00006 // All rights reserved.
00007 // 
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions are
00010 // met:
00011 // *       Redistributions of source code must retain the above copyright
00012 // notice, this list of conditions and the following disclaimer.
00013 // *       Redistributions in binary form must reproduce the above
00014 // copyright notice, this list of conditions and the following disclaimer
00015 // in the documentation and/or other materials provided with the
00016 // distribution.
00017 // *       Neither the name of Industrial Light & Magic nor the names of
00018 // its contributors may be used to endorse or promote products derived
00019 // from this software without specific prior written permission. 
00020 // 
00021 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00024 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00025 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00027 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00028 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00029 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00030 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00031 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 //
00034 
00035 
00036 
00037 #ifndef INCLUDED_IMATHFRUSTUM_H
00038 #define INCLUDED_IMATHFRUSTUM_H
00039 
00040 
00041 #include "ImathVec.h"
00042 #include "ImathPlane.h"
00043 #include "ImathLine.h"
00044 #include "ImathMatrix.h"
00045 #include "ImathLimits.h"
00046 #include "ImathFun.h"
00047 #include "IexMathExc.h"
00048 
00049 #if defined _WIN32 || defined _WIN64
00050     #ifdef near
00051         #define _redef_near
00052         #undef near
00053     #endif
00054     #ifdef far
00055         #define _redef_far
00056         #undef far
00057     #endif
00058 #endif
00059 
00060 namespace Imath {
00061 
00062 //
00063 //      template class Frustum<T>
00064 //
00065 //      The frustum is always located with the eye point at the
00066 //      origin facing down -Z. This makes the Frustum class 
00067 //      compatable with OpenGL (or anything that assumes a camera
00068 //      looks down -Z, hence with a right-handed coordinate system) 
00069 //      but not with RenderMan which assumes the camera looks down
00070 //      +Z. Additional functions are provided for conversion from
00071 //      and from various camera coordinate spaces.
00072 //
00073 
00074 
00075 template<class T>
00076 class Frustum
00077 {
00078   public:
00079     Frustum();
00080     Frustum(const Frustum &);
00081     Frustum(T near, T far, T left, T right, T top, T bottom, bool ortho=false);
00082     Frustum(T near, T far, T fovx, T fovy, T aspect);
00083     virtual ~Frustum();
00084 
00085     //--------------------
00086     // Assignment operator
00087     //--------------------
00088 
00089     const Frustum &operator     = (const Frustum &);
00090 
00091     //--------------------
00092     //  Operators:  ==, !=
00093     //--------------------
00094     
00095     bool                        operator == (const Frustum<T> &src) const;
00096     bool                        operator != (const Frustum<T> &src) const;
00097 
00098     //--------------------------------------------------------
00099     //  Set functions change the entire state of the Frustum
00100     //--------------------------------------------------------
00101 
00102     void                set(T near, T far, 
00103                             T left, T right, 
00104                             T top, T bottom, 
00105                             bool ortho=false);
00106 
00107     void                set(T near, T far, T fovx, T fovy, T aspect);
00108 
00109     //------------------------------------------------------
00110     //  These functions modify an already valid frustum state
00111     //------------------------------------------------------
00112 
00113     void                modifyNearAndFar(T near, T far);
00114     void                setOrthographic(bool);
00115 
00116     //--------------
00117     //  Access
00118     //--------------
00119 
00120     bool                orthographic() const    { return _orthographic; }
00121     T                   near() const            { return _near;         }
00122     T           hither() const      { return _near;     }
00123     T                   far() const             { return _far;          }
00124     T           yon() const     { return _far;      }
00125     T                   left() const            { return _left;         }
00126     T                   right() const           { return _right;        }
00127     T                   bottom() const          { return _bottom;       }
00128     T                   top() const             { return _top;          }
00129 
00130     //-----------------------------------------------------------------------
00131     //  Sets the planes in p to be the six bounding planes of the frustum, in
00132     //  the following order: top, right, bottom, left, near, far.
00133     //  Note that the planes have normals that point out of the frustum.
00134     //  The version of this routine that takes a matrix applies that matrix
00135     //  to transform the frustum before setting the planes.
00136     //-----------------------------------------------------------------------
00137 
00138     void                planes(Plane3<T> p[6]);
00139     void                planes(Plane3<T> p[6], const Matrix44<T> &M);
00140 
00141     //----------------------
00142     //  Derived Quantities
00143     //----------------------
00144 
00145     T                   fovx() const;
00146     T                   fovy() const;
00147     T                   aspect() const;
00148     Matrix44<T>         projectionMatrix() const;
00149 
00150     //-----------------------------------------------------------------------
00151     //  Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1 
00152     //  and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
00153     //  Frustum whose near clipping-plane window is that rectangle in local
00154     //  space.  
00155     //-----------------------------------------------------------------------
00156 
00157     Frustum<T>          window(T left, T right, T top, T bottom) const;
00158 
00159     //----------------------------------------------------------
00160     // Projection is in screen space / Conversion from Z-Buffer
00161     //----------------------------------------------------------
00162 
00163     Line3<T>            projectScreenToRay( const Vec2<T> & ) const;
00164     Vec2<T>             projectPointToScreen( const Vec3<T> & ) const;
00165 
00166     T                   ZToDepth(long zval, long min, long max) const;
00167     T                   normalizedZToDepth(T zval) const;
00168     long                DepthToZ(T depth, long zmin, long zmax) const;
00169 
00170     T                   worldRadius(const Vec3<T> &p, T radius) const;
00171     T                   screenRadius(const Vec3<T> &p, T radius) const;
00172 
00173 
00174   protected:
00175 
00176     Vec2<T>             screenToLocal( const Vec2<T> & ) const;
00177     Vec2<T>             localToScreen( const Vec2<T> & ) const;
00178 
00179   protected:
00180     T                   _near;
00181     T                   _far;
00182     T                   _left;
00183     T                   _right;
00184     T                   _top;
00185     T                   _bottom;
00186     bool                _orthographic;
00187 };
00188 
00189 
00190 template<class T>
00191 inline Frustum<T>::Frustum()
00192 {
00193     set(T (0.1),
00194         T (1000.0),
00195         T (-1.0),
00196         T (1.0),
00197         T (1.0),
00198         T (-1.0),
00199         false);
00200 }
00201 
00202 template<class T>
00203 inline Frustum<T>::Frustum(const Frustum &f)
00204 {
00205     *this = f;
00206 }
00207 
00208 template<class T>
00209 inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
00210 {
00211     set(n,f,l,r,t,b,o);
00212 }
00213 
00214 template<class T>
00215 inline Frustum<T>::Frustum(T near, T far, T fovx, T fovy, T aspect)
00216 {
00217     set(near,far,fovx,fovy,aspect);
00218 }
00219 
00220 template<class T>
00221 Frustum<T>::~Frustum()
00222 {
00223 }
00224 
00225 template<class T>
00226 const Frustum<T> &
00227 Frustum<T>::operator = (const Frustum &f)
00228 {
00229     _near         = f._near;
00230     _far          = f._far;
00231     _left         = f._left;
00232     _right        = f._right;
00233     _top          = f._top;
00234     _bottom       = f._bottom;
00235     _orthographic = f._orthographic;
00236 
00237     return *this;
00238 }
00239 
00240 template <class T>
00241 bool
00242 Frustum<T>::operator == (const Frustum<T> &src) const
00243 {
00244     return
00245         _near         == src._near   &&
00246         _far          == src._far    &&
00247         _left         == src._left   &&
00248         _right        == src._right  &&
00249         _top          == src._top    &&
00250         _bottom       == src._bottom &&
00251         _orthographic == src._orthographic;
00252 }
00253 
00254 template <class T>
00255 inline bool
00256 Frustum<T>::operator != (const Frustum<T> &src) const
00257 {
00258     return !operator== (src);
00259 }
00260 
00261 template<class T>
00262 void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
00263 {
00264     _near           = n;
00265     _far            = f;
00266     _left           = l;
00267     _right          = r;
00268     _bottom         = b;
00269     _top            = t;
00270     _orthographic   = o;
00271 }
00272 
00273 template<class T>
00274 void Frustum<T>::modifyNearAndFar(T n, T f)
00275 {
00276     if ( _orthographic )
00277     {
00278         _near = n;
00279     }
00280     else
00281     {
00282         Line3<T>  lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_near) );
00283         Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_near) );
00284         Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
00285 
00286         Vec3<T> ll,ur;
00287         nearPlane.intersect(lowerLeft,ll);
00288         nearPlane.intersect(upperRight,ur);
00289 
00290         _left   = ll.x;
00291         _right  = ur.x;
00292         _top    = ur.y;
00293         _bottom = ll.y;
00294         _near   = n;
00295         _far    = f;
00296     }
00297 
00298     _far = f;
00299 }
00300 
00301 template<class T>
00302 void Frustum<T>::setOrthographic(bool ortho)
00303 {
00304     _orthographic   = ortho;
00305 }
00306 
00307 template<class T>
00308 void Frustum<T>::set(T near, T far, T fovx, T fovy, T aspect)
00309 {
00310     if (fovx != 0 && fovy != 0)
00311         throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
00312 
00313     if (fovx != 0)
00314     {
00315         _right      = near * Math<T>::tan (fovx / 2);
00316         _left       = -_right;
00317         _top        = ((_right - _left) / aspect) / 2;
00318         _bottom     = -_top;
00319     }
00320     else
00321     {
00322         _top        = near * Math<T>::tan (fovy / 2);
00323         _bottom     = -_top;
00324         _right      = (_top - _bottom) * aspect / 2;
00325         _left       = -_right;
00326     }
00327     _near           = near;
00328     _far            = far;
00329     _orthographic   = false;
00330 }
00331 
00332 template<class T>
00333 T Frustum<T>::fovx() const
00334 {
00335     return Math<T>::atan2(_right,_near) - Math<T>::atan2(_left,_near);
00336 }
00337 
00338 template<class T>
00339 T Frustum<T>::fovy() const
00340 {
00341     return Math<T>::atan2(_top,_near) - Math<T>::atan2(_bottom,_near);
00342 }
00343 
00344 template<class T>
00345 T Frustum<T>::aspect() const
00346 {
00347     T rightMinusLeft = _right-_left;
00348     T topMinusBottom = _top-_bottom;
00349 
00350     if (abs(topMinusBottom) < 1 &&
00351         abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
00352     {
00353         throw Iex::DivzeroExc ("Bad viewing frustum: "
00354                                "aspect ratio cannot be computed.");
00355     }
00356 
00357     return rightMinusLeft / topMinusBottom;
00358 }
00359 
00360 template<class T>
00361 Matrix44<T> Frustum<T>::projectionMatrix() const
00362 {
00363     T rightPlusLeft  = _right+_left;
00364     T rightMinusLeft = _right-_left;
00365 
00366     T topPlusBottom  = _top+_bottom;
00367     T topMinusBottom = _top-_bottom;
00368 
00369     T farPlusNear    = _far+_near;
00370     T farMinusNear   = _far-_near;
00371 
00372     if ((abs(rightMinusLeft) < 1 &&
00373          abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
00374         (abs(topMinusBottom) < 1 &&
00375          abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
00376         (abs(farMinusNear) < 1 &&
00377          abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
00378     {
00379         throw Iex::DivzeroExc ("Bad viewing frustum: "
00380                                "projection matrix cannot be computed.");
00381     }
00382 
00383     if ( _orthographic )
00384     {
00385         T tx = -rightPlusLeft / rightMinusLeft;
00386         T ty = -topPlusBottom / topMinusBottom;
00387         T tz = -farPlusNear   / farMinusNear;
00388 
00389         if ((abs(rightMinusLeft) < 1 &&
00390              2 > limits<T>::max() * abs(rightMinusLeft)) ||
00391             (abs(topMinusBottom) < 1 &&
00392              2 > limits<T>::max() * abs(topMinusBottom)) ||
00393             (abs(farMinusNear) < 1 &&
00394              2 > limits<T>::max() * abs(farMinusNear)))
00395         {
00396             throw Iex::DivzeroExc ("Bad viewing frustum: "
00397                                    "projection matrix cannot be computed.");
00398         }
00399 
00400         T A  =  2 / rightMinusLeft;
00401         T B  =  2 / topMinusBottom;
00402         T C  = -2 / farMinusNear;
00403 
00404         return Matrix44<T>( A,  0,  0,  0,
00405                             0,  B,  0,  0,
00406                             0,  0,  C,  0,
00407                             tx, ty, tz, 1.f );
00408     }
00409     else
00410     {
00411         T A =  rightPlusLeft / rightMinusLeft;
00412         T B =  topPlusBottom / topMinusBottom;
00413         T C = -farPlusNear   / farMinusNear;
00414 
00415         T farTimesNear = -2 * _far * _near;
00416         if (abs(farMinusNear) < 1 &&
00417             abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
00418         {
00419             throw Iex::DivzeroExc ("Bad viewing frustum: "
00420                                    "projection matrix cannot be computed.");
00421         }
00422 
00423         T D = farTimesNear / farMinusNear;
00424 
00425         T twoTimesNear = 2 * _near;
00426 
00427         if ((abs(rightMinusLeft) < 1 &&
00428              abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
00429             (abs(topMinusBottom) < 1 &&
00430              abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
00431         {
00432             throw Iex::DivzeroExc ("Bad viewing frustum: "
00433                                    "projection matrix cannot be computed.");
00434         }
00435 
00436         T E = twoTimesNear / rightMinusLeft;
00437         T F = twoTimesNear / topMinusBottom;
00438 
00439         return Matrix44<T>( E,  0,  0,  0,
00440                             0,  F,  0,  0,
00441                             A,  B,  C, -1,
00442                             0,  0,  D,  0 );
00443     }
00444 }
00445 
00446 template<class T>
00447 Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
00448 {
00449     // move it to 0->1 space
00450 
00451     Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
00452     Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
00453 
00454     return Frustum<T>(_near, _far, bl.x, tr.x, tr.y, bl.y, _orthographic);
00455 }
00456 
00457 
00458 template<class T>
00459 Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
00460 {
00461     return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
00462                     _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
00463 }
00464 
00465 template<class T>
00466 Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
00467 {
00468     T leftPlusRight  = _left - 2 * p.x + _right;
00469     T leftMinusRight = _left-_right;
00470     T bottomPlusTop  = _bottom - 2 * p.y + _top;
00471     T bottomMinusTop = _bottom-_top;
00472 
00473     if ((abs(leftMinusRight) < 1 &&
00474          abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
00475         (abs(bottomMinusTop) < 1 &&
00476          abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
00477     {
00478         throw Iex::DivzeroExc
00479             ("Bad viewing frustum: "
00480              "local-to-screen transformation cannot be computed");
00481     }
00482 
00483     return Vec2<T>( leftPlusRight / leftMinusRight,
00484                     bottomPlusTop / bottomMinusTop );
00485 }
00486 
00487 template<class T>
00488 Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
00489 {
00490     Vec2<T> point = screenToLocal(p);
00491     if (orthographic())
00492         return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
00493                          Vec3<T>(point.x,point.y,-_near));
00494     else
00495         return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_near));
00496 }
00497 
00498 template<class T>
00499 Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
00500 {
00501     if (orthographic() || point.z == 0)
00502         return localToScreen( Vec2<T>( point.x, point.y ) );
00503     else
00504         return localToScreen( Vec2<T>( point.x * _near / -point.z, 
00505                                        point.y * _near / -point.z ) );
00506 }
00507 
00508 template<class T>
00509 T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
00510 {
00511     int zdiff = zmax - zmin;
00512 
00513     if (zdiff == 0)
00514     {
00515         throw Iex::DivzeroExc
00516             ("Bad call to Frustum::ZToDepth: zmax == zmin");
00517     }
00518 
00519     if ( zval > zmax+1 ) zval -= zdiff;
00520 
00521     T fzval = (T(zval) - T(zmin)) / T(zdiff);
00522     return normalizedZToDepth(fzval);
00523 }
00524 
00525 template<class T>
00526 T Frustum<T>::normalizedZToDepth(T zval) const
00527 {
00528     T Zp = zval * 2.0 - 1;
00529 
00530     if ( _orthographic )
00531     {
00532         return   -(Zp*(_far-_near) + (_far+_near))/2;
00533     }
00534     else 
00535     {
00536         T farTimesNear = 2 * _far * _near;
00537         T farMinusNear = Zp * (_far - _near) - _far - _near;
00538 
00539         if (abs(farMinusNear) < 1 &&
00540             abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
00541         {
00542             throw Iex::DivzeroExc
00543                 ("Frustum::normalizedZToDepth cannot be computed.  The "
00544                  "near and far clipping planes of the viewing frustum "
00545                  "may be too close to each other");
00546         }
00547 
00548         return farTimesNear / farMinusNear;
00549     }
00550 }
00551 
00552 template<class T>
00553 long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
00554 {
00555     long zdiff     = zmax - zmin;
00556     T farMinusNear = _far-_near;
00557 
00558     if ( _orthographic )
00559     {
00560         T farPlusNear = 2*depth + _far + _near;
00561 
00562         if (abs(farMinusNear) < 1 &&
00563             abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
00564         {
00565             throw Iex::DivzeroExc
00566                 ("Bad viewing frustum: near and far clipping planes "
00567                  "are too close to each other");
00568         }
00569 
00570         T Zp = -farPlusNear/farMinusNear;
00571         return long(0.5*(Zp+1)*zdiff) + zmin;
00572     }
00573     else 
00574     { 
00575         // Perspective
00576 
00577         T farTimesNear = 2*_far*_near;
00578         if (abs(depth) < 1 &&
00579             abs(farTimesNear) > limits<T>::max() * abs(depth))
00580         {
00581             throw Iex::DivzeroExc
00582                 ("Bad call to DepthToZ function: value of `depth' "
00583                  "is too small");
00584         }
00585 
00586         T farPlusNear = farTimesNear/depth + _far + _near;
00587         if (abs(farMinusNear) < 1 &&
00588             abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
00589         {
00590             throw Iex::DivzeroExc
00591                 ("Bad viewing frustum: near and far clipping planes "
00592                  "are too close to each other");
00593         }
00594 
00595         T Zp = farPlusNear/farMinusNear;
00596         return long(0.5*(Zp+1)*zdiff) + zmin;
00597     }
00598 }
00599 
00600 template<class T>
00601 T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
00602 {
00603     // Derivation:
00604     // Consider X-Z plane.
00605     // X coord of projection of p = xp = p.x * (-_near / p.z)
00606     // Let q be p + (radius, 0, 0).
00607     // X coord of projection of q = xq = (p.x - radius)  * (-_near / p.z)
00608     // X coord of projection of segment from p to q = r = xp - xq
00609     //         = radius * (-_near / p.z)
00610     // A similar analysis holds in the Y-Z plane.
00611     // So r is the quantity we want to return.
00612 
00613     if (abs(p.z) > 1 || abs(-_near) < limits<T>::max() * abs(p.z))
00614     {
00615         return radius * (-_near / p.z);
00616     }
00617     else
00618     {
00619         throw Iex::DivzeroExc
00620             ("Bad call to Frustum::screenRadius: the magnitude of `p' "
00621              "is too small");
00622     }
00623 
00624     return radius * (-_near / p.z);
00625 }
00626 
00627 template<class T>
00628 T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
00629 {
00630     if (abs(-_near) > 1 || abs(p.z) < limits<T>::max() * abs(-_near))
00631     {
00632         return radius * (p.z / -_near);
00633     }
00634     else
00635     {
00636         throw Iex::DivzeroExc
00637             ("Bad viewing frustum: the near clipping plane is too "
00638              "close to zero");
00639     }
00640 }
00641 
00642 template<class T>
00643 void Frustum<T>::planes(Plane3<T> p[6])
00644 {
00645     //
00646     //  Plane order: Top, Right, Bottom, Left, Near, Far.
00647     //  Normals point outwards.
00648     //
00649 
00650     if (! _orthographic)
00651     {
00652         Vec3<T> a( _left,  _bottom, -_near);
00653         Vec3<T> b( _left,  _top,    -_near);
00654         Vec3<T> c( _right, _top,    -_near);
00655         Vec3<T> d( _right, _bottom, -_near);
00656         Vec3<T> o(0,0,0);
00657 
00658         p[0].set( o, c, b );
00659         p[1].set( o, d, c );
00660         p[2].set( o, a, d );
00661         p[3].set( o, b, a );
00662     }
00663     else
00664     {
00665         p[0].set( Vec3<T>( 0, 1, 0), _top );
00666         p[1].set( Vec3<T>( 1, 0, 0), _right );
00667         p[2].set( Vec3<T>( 0,-1, 0),-_bottom );
00668         p[3].set( Vec3<T>(-1, 0, 0),-_left );
00669     }
00670     p[4].set( Vec3<T>(0, 0, 1), -_near );
00671     p[5].set( Vec3<T>(0, 0,-1), _far );
00672 }
00673 
00674 
00675 template<class T>
00676 void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
00677 {
00678     //
00679     //  Plane order: Top, Right, Bottom, Left, Near, Far.
00680     //  Normals point outwards.
00681     //
00682 
00683     Vec3<T> a   = Vec3<T>( _left,  _bottom, -_near) * M;
00684     Vec3<T> b   = Vec3<T>( _left,  _top,    -_near) * M;
00685     Vec3<T> c   = Vec3<T>( _right, _top,    -_near) * M;
00686     Vec3<T> d   = Vec3<T>( _right, _bottom, -_near) * M;
00687     if (! _orthographic)
00688     {
00689         double s    = _far / double(_near);
00690         T farLeft   = (T) (s * _left);
00691         T farRight  = (T) (s * _right);
00692         T farTop    = (T) (s * _top);
00693         T farBottom = (T) (s * _bottom);
00694         Vec3<T> e   = Vec3<T>( farLeft,  farBottom, -_far) * M;
00695         Vec3<T> f   = Vec3<T>( farLeft,  farTop,    -_far) * M;
00696         Vec3<T> g   = Vec3<T>( farRight, farTop,    -_far) * M;
00697         Vec3<T> o   = Vec3<T>(0,0,0) * M;
00698         p[0].set( o, c, b );
00699         p[1].set( o, d, c );
00700         p[2].set( o, a, d );
00701         p[3].set( o, b, a );
00702         p[4].set( a, d, c );
00703         p[5].set( e, f, g );
00704      }
00705     else
00706     {
00707         Vec3<T> e   = Vec3<T>( _left,  _bottom, -_far) * M;
00708         Vec3<T> f   = Vec3<T>( _left,  _top,    -_far) * M;
00709         Vec3<T> g   = Vec3<T>( _right, _top,    -_far) * M;
00710         Vec3<T> h   = Vec3<T>( _right, _bottom, -_far) * M;
00711         p[0].set( c, g, f );
00712         p[1].set( d, h, g );
00713         p[2].set( a, e, h );
00714         p[3].set( b, f, e );
00715         p[4].set( a, d, c );
00716         p[5].set( e, f, g );
00717     }
00718 }
00719 
00720 typedef Frustum<float>  Frustumf;
00721 typedef Frustum<double> Frustumd;
00722 
00723 
00724 } // namespace Imath
00725 
00726 
00727 #if defined _WIN32 || defined _WIN64
00728     #ifdef _redef_near
00729         #define near
00730     #endif
00731     #ifdef _redef_far
00732         #define far
00733     #endif
00734 #endif
00735 
00736 #endif