Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreFrustum.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 43.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreFrustum.h"
31
32#include "OgreMath.h"
33#include "OgreMatrix3.h"
34#include "OgreSceneNode.h"
35#include "OgreSphere.h"
36#include "OgreLogManager.h"
37#include "OgreException.h"
38#include "OgreRoot.h"
39#include "OgreCamera.h"
40#include "OgreHardwareBufferManager.h"
41#include "OgreHardwareVertexBuffer.h"
42#include "OgreHardwareIndexBuffer.h"
43#include "OgreMaterialManager.h"
44#include "OgreRenderSystem.h"
45
46namespace Ogre {
47
48    String Frustum::msMovableType = "Frustum";
49    const Real Frustum::INFINITE_FAR_PLANE_ADJUST = 0.00001;
50    //-----------------------------------------------------------------------
51    Frustum::Frustum() : 
52        mProjType(PT_PERSPECTIVE), 
53        mFOVy(Radian(Math::PI/4.0)), 
54        mFarDist(100000.0f), 
55        mNearDist(100.0f), 
56        mAspect(1.33333333333333f), 
57        mFrustumOffset(Vector2::ZERO),
58        mFocalLength(1.0f),
59        mLastParentOrientation(Quaternion::IDENTITY),
60        mLastParentPosition(Vector3::ZERO),
61        mRecalcFrustum(true), 
62        mRecalcView(true), 
63        mRecalcFrustumPlanes(true),
64        mRecalcWorldSpaceCorners(true),
65        mRecalcVertexData(true),
66                mCustomViewMatrix(false),
67                mCustomProjMatrix(false),
68        mReflect(false), 
69        mLinkedReflectPlane(0),
70        mObliqueDepthProjection(false), 
71        mLinkedObliqueProjPlane(0)
72    {
73        // Initialise material
74        mMaterial = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
75       
76        // Alter superclass members
77        mVisible = false;
78        mParentNode = 0;
79
80        mLastLinkedReflectionPlane.normal = Vector3::ZERO;
81        mLastLinkedObliqueProjPlane.normal = Vector3::ZERO;
82
83
84        updateView();
85        updateFrustum();
86    }
87
88    //-----------------------------------------------------------------------
89    Frustum::~Frustum()
90    {
91        // Do nothing
92    }
93
94    //-----------------------------------------------------------------------
95    void Frustum::setFOVy(const Radian& fov)
96    {
97        mFOVy = fov;
98        invalidateFrustum();
99    }
100
101    //-----------------------------------------------------------------------
102    const Radian& Frustum::getFOVy(void) const
103    {
104        return mFOVy;
105    }
106
107
108    //-----------------------------------------------------------------------
109    void Frustum::setFarClipDistance(Real farPlane)
110    {
111        mFarDist = farPlane;
112        invalidateFrustum();
113    }
114
115    //-----------------------------------------------------------------------
116    Real Frustum::getFarClipDistance(void) const
117    {
118        return mFarDist;
119    }
120
121    //-----------------------------------------------------------------------
122    void Frustum::setNearClipDistance(Real nearPlane)
123    {
124        if (nearPlane <= 0)
125            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Near clip distance must be greater than zero.",
126                "Frustum::setNearClipDistance");
127        mNearDist = nearPlane;
128        invalidateFrustum();
129    }
130
131    //-----------------------------------------------------------------------
132    Real Frustum::getNearClipDistance(void) const
133    {
134        return mNearDist;
135    }
136
137    //---------------------------------------------------------------------
138    void Frustum::setFrustumOffset(const Vector2& offset)
139    {
140        mFrustumOffset = offset;
141        invalidateFrustum();
142    }
143    //---------------------------------------------------------------------
144    void Frustum::setFrustumOffset(Real horizontal, Real vertical)
145    {
146        setFrustumOffset(Vector2(horizontal, vertical));
147    }
148    //---------------------------------------------------------------------
149    const Vector2& Frustum::getFrustumOffset() const
150    {
151        return mFrustumOffset;
152    }
153    //---------------------------------------------------------------------
154    void Frustum::setFocalLength(Real focalLength)
155    {
156        if (focalLength <= 0)
157        {
158            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
159                "Focal length must be greater than zero.",
160                "Frustum::setFocalLength");
161        }
162
163        mFocalLength = focalLength;
164        invalidateFrustum();
165    }
166    //---------------------------------------------------------------------
167    Real Frustum::getFocalLength() const
168    {
169        return mFocalLength;
170    }
171    //-----------------------------------------------------------------------
172    const Matrix4& Frustum::getProjectionMatrix(void) const
173    {
174
175        updateFrustum();
176
177        return mProjMatrix;
178    }
179    //-----------------------------------------------------------------------
180    const Matrix4& Frustum::getProjectionMatrixWithRSDepth(void) const
181    {
182
183        updateFrustum();
184
185        return mProjMatrixRSDepth;
186    }
187    //-----------------------------------------------------------------------
188    const Matrix4& Frustum::getProjectionMatrixRS(void) const
189    {
190
191        updateFrustum();
192
193        return mProjMatrixRS;
194    }
195    //-----------------------------------------------------------------------
196    const Matrix4& Frustum::getViewMatrix(void) const
197    {
198        updateView();
199
200        return mViewMatrix;
201
202    }
203
204    //-----------------------------------------------------------------------
205    const Plane* Frustum::getFrustumPlanes(void) const
206    {
207        // Make any pending updates to the calculated frustum planes
208        updateFrustumPlanes();
209
210        return mFrustumPlanes;
211    }
212
213    //-----------------------------------------------------------------------
214    const Plane& Frustum::getFrustumPlane(unsigned short plane) const
215    {
216        // Make any pending updates to the calculated frustum planes
217        updateFrustumPlanes();
218
219        return mFrustumPlanes[plane];
220
221    }
222
223    //-----------------------------------------------------------------------
224    bool Frustum::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const
225    {
226        // Null boxes always invisible
227        if (bound.isNull()) return false;
228
229        // Infinite boxes always visible
230        if (bound.isInfinite()) return true;
231
232        // Make any pending updates to the calculated frustum planes
233        updateFrustumPlanes();
234
235        // Get centre of the box
236        Vector3 centre = bound.getCenter();
237        // Get the half-size of the box
238        Vector3 halfSize = bound.getHalfSize();
239
240        // For each plane, see if all points are on the negative side
241        // If so, object is not visible
242        for (int plane = 0; plane < 6; ++plane)
243        {
244            // Skip far plane if infinite view frustum
245            if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
246                continue;
247
248            Plane::Side side = mFrustumPlanes[plane].getSide(centre, halfSize);
249            if (side == Plane::NEGATIVE_SIDE)
250            {
251                // ALL corners on negative side therefore out of view
252                if (culledBy)
253                    *culledBy = (FrustumPlane)plane;
254                return false;
255            }
256
257        }
258
259        return true;
260    }
261
262    //-----------------------------------------------------------------------
263    bool Frustum::isVisible(const Vector3& vert, FrustumPlane* culledBy) const
264    {
265        // Make any pending updates to the calculated frustum planes
266        updateFrustumPlanes();
267
268        // For each plane, see if all points are on the negative side
269        // If so, object is not visible
270        for (int plane = 0; plane < 6; ++plane)
271        {
272            // Skip far plane if infinite view frustum
273            if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
274                continue;
275
276            if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE)
277            {
278                // ALL corners on negative side therefore out of view
279                if (culledBy)
280                    *culledBy = (FrustumPlane)plane;
281                return false;
282            }
283
284        }
285
286        return true;
287    }
288
289    //-----------------------------------------------------------------------
290    bool Frustum::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const
291    {
292        // Make any pending updates to the calculated frustum planes
293        updateFrustumPlanes();
294
295        // For each plane, see if sphere is on negative side
296        // If so, object is not visible
297        for (int plane = 0; plane < 6; ++plane)
298        {
299            // Skip far plane if infinite view frustum
300            if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
301                continue;
302
303            // If the distance from sphere center to plane is negative, and 'more negative'
304            // than the radius of the sphere, sphere is outside frustum
305            if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius())
306            {
307                // ALL corners on negative side therefore out of view
308                if (culledBy)
309                    *culledBy = (FrustumPlane)plane;
310                return false;
311            }
312
313        }
314
315        return true;
316    }
317    //-----------------------------------------------------------------------
318    void Frustum::calcProjectionParameters(Real& left, Real& right, Real& bottom, Real& top) const
319    { 
320                if (mCustomProjMatrix)
321                {
322                        // Convert clipspace corners to camera space
323                        Matrix4 invProj = mProjMatrix.inverse();
324                        Vector3 topLeft(-0.5f, 0.5f, 0.0f);
325                        Vector3 bottomRight(0.5f, -0.5f, 0.0f);
326
327                        topLeft = invProj * topLeft;
328                        bottomRight = invProj * bottomRight;
329
330                        left = topLeft.x;
331                        top = topLeft.y;
332                        right = bottomRight.x;
333                        bottom = bottomRight.y;
334
335                }
336                else
337                {
338                        // Calculate general projection parameters
339
340                        Radian thetaY (mFOVy * 0.5f);
341                        Real tanThetaY = Math::Tan(thetaY);
342                        Real tanThetaX = tanThetaY * mAspect;
343
344                        // Unknow how to apply frustum offset to orthographic camera, just ignore here
345                        Real nearFocal = (mProjType == PT_PERSPECTIVE) ? mNearDist / mFocalLength : 0;
346                        Real nearOffsetX = mFrustumOffset.x * nearFocal;
347                        Real nearOffsetY = mFrustumOffset.y * nearFocal;
348                        Real half_w = tanThetaX * mNearDist;
349                        Real half_h = tanThetaY * mNearDist;
350
351                        left   = - half_w + nearOffsetX;
352                        right  = + half_w + nearOffsetX;
353                        bottom = - half_h + nearOffsetY;
354                        top    = + half_h + nearOffsetY;
355                }
356    }
357        //-----------------------------------------------------------------------
358        void Frustum::updateFrustumImpl(void) const
359        {
360                // Common calcs
361                Real left, right, bottom, top;
362                calcProjectionParameters(left, right, bottom, top);
363
364                if (!mCustomProjMatrix)
365                {
366
367                        // The code below will dealing with general projection
368                        // parameters, similar glFrustum and glOrtho.
369                        // Doesn't optimise manually except division operator, so the
370                        // code more self-explaining.
371
372                        Real inv_w = 1 / (right - left);
373                        Real inv_h = 1 / (top - bottom);
374                        Real inv_d = 1 / (mFarDist - mNearDist);
375
376                        // Recalc if frustum params changed
377                        if (mProjType == PT_PERSPECTIVE)
378                        {
379                                // Calc matrix elements
380                                Real A = 2 * mNearDist * inv_w;
381                                Real B = 2 * mNearDist * inv_h;
382                                Real C = (right + left) * inv_w;
383                                Real D = (top + bottom) * inv_h;
384                                Real q, qn;
385                                if (mFarDist == 0)
386                                {
387                                        // Infinite far plane
388                                        q = Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
389                                        qn = mNearDist * (Frustum::INFINITE_FAR_PLANE_ADJUST - 2);
390                                }
391                                else
392                                {
393                                        q = - (mFarDist + mNearDist) * inv_d;
394                                        qn = -2 * (mFarDist * mNearDist) * inv_d;
395                                }
396
397                                // NB: This creates 'uniform' perspective projection matrix,
398                                // which depth range [-1,1], right-handed rules
399                                //
400                                // [ A   0   C   0  ]
401                                // [ 0   B   D   0  ]
402                                // [ 0   0   q   qn ]
403                                // [ 0   0   -1  0  ]
404                                //
405                                // A = 2 * near / (right - left)
406                                // B = 2 * near / (top - bottom)
407                                // C = (right + left) / (right - left)
408                                // D = (top + bottom) / (top - bottom)
409                                // q = - (far + near) / (far - near)
410                                // qn = - 2 * (far * near) / (far - near)
411
412                                mProjMatrix = Matrix4::ZERO;
413                                mProjMatrix[0][0] = A;
414                                mProjMatrix[0][2] = C;
415                                mProjMatrix[1][1] = B;
416                                mProjMatrix[1][2] = D;
417                                mProjMatrix[2][2] = q;
418                                mProjMatrix[2][3] = qn;
419                                mProjMatrix[3][2] = -1;
420
421                                if (mObliqueDepthProjection)
422                                {
423                                        // Translate the plane into view space
424
425                                        // Don't use getViewMatrix here, incase overrided by
426                                        // camera and return a cull frustum view matrix
427                                        updateView();
428                                        Plane plane = mViewMatrix * mObliqueProjPlane;
429
430                                        // Thanks to Eric Lenyel for posting this calculation
431                                        // at www.terathon.com
432
433                                        // Calculate the clip-space corner point opposite the
434                                        // clipping plane
435                                        // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
436                                        // transform it into camera space by multiplying it
437                                        // by the inverse of the projection matrix
438
439                                        /* generalised version
440                                        Vector4 q = matrix.inverse() *
441                                        Vector4(Math::Sign(plane.normal.x),
442                                        Math::Sign(plane.normal.y), 1.0f, 1.0f);
443                                        */
444                                        Vector4 q;
445                                        q.x = (Math::Sign(plane.normal.x) + mProjMatrix[0][2]) / mProjMatrix[0][0];
446                                        q.y = (Math::Sign(plane.normal.y) + mProjMatrix[1][2]) / mProjMatrix[1][1];
447                                        q.z = -1;
448                                        q.w = (1 + mProjMatrix[2][2]) / mProjMatrix[2][3];
449
450                                        // Calculate the scaled plane vector
451                                        Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
452                                        Vector4 c = clipPlane4d * (2 / (clipPlane4d.dotProduct(q)));
453
454                                        // Replace the third row of the projection matrix
455                                        mProjMatrix[2][0] = c.x;
456                                        mProjMatrix[2][1] = c.y;
457                                        mProjMatrix[2][2] = c.z + 1;
458                                        mProjMatrix[2][3] = c.w; 
459                                }
460                        } // perspective
461                        else if (mProjType == PT_ORTHOGRAPHIC)
462                        {
463                                Real A = 2 * inv_w;
464                                Real B = 2 * inv_h;
465                                Real C = - (right + left) * inv_w;
466                                Real D = - (top + bottom) * inv_h;
467                                Real q, qn;
468                                if (mFarDist == 0)
469                                {
470                                        // Can not do infinite far plane here, avoid divided zero only
471                                        q = - Frustum::INFINITE_FAR_PLANE_ADJUST / mNearDist;
472                                        qn = - Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
473                                }
474                                else
475                                {
476                                        q = - 2 * inv_d;
477                                        qn = - (mFarDist + mNearDist)  * inv_d;
478                                }
479
480                                // NB: This creates 'uniform' orthographic projection matrix,
481                                // which depth range [-1,1], right-handed rules
482                                //
483                                // [ A   0   0   C  ]
484                                // [ 0   B   0   D  ]
485                                // [ 0   0   q   qn ]
486                                // [ 0   0   0   1  ]
487                                //
488                                // A = 2 * / (right - left)
489                                // B = 2 * / (top - bottom)
490                                // C = - (right + left) / (right - left)
491                                // D = - (top + bottom) / (top - bottom)
492                                // q = - 2 / (far - near)
493                                // qn = - (far + near) / (far - near)
494
495                                mProjMatrix = Matrix4::ZERO;
496                                mProjMatrix[0][0] = A;
497                                mProjMatrix[0][3] = C;
498                                mProjMatrix[1][1] = B;
499                                mProjMatrix[1][3] = D;
500                                mProjMatrix[2][2] = q;
501                                mProjMatrix[2][3] = qn;
502                                mProjMatrix[3][3] = 1;
503                        } // ortho
504                } // !mCustomProjMatrix
505
506                RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
507                // API specific
508                renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
509                // API specific for Gpu Programs
510                renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRSDepth, true);
511
512
513                // Calculate bounding box (local)
514                // Box is from 0, down -Z, max dimensions as determined from far plane
515                // If infinite view frustum just pick a far value
516                Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
517                // Near plane bounds
518                Vector3 min(left, bottom, -farDist);
519                Vector3 max(right, top, 0);
520
521                if (mCustomProjMatrix)
522                {
523                        // Some custom projection matrices can have unusual inverted settings
524                        // So make sure the AABB is the right way around to start with
525                        Vector3 tmp = min;
526                        min.makeFloor(max);
527                        max.makeCeil(tmp);
528                }
529
530                if (mProjType == PT_PERSPECTIVE)
531                {
532                        // Merge with far plane bounds
533                        Real radio = farDist / mNearDist;
534                        min.makeFloor(Vector3(left * radio, bottom * radio, -farDist));
535                        max.makeCeil(Vector3(right * radio, top * radio, 0));
536                }
537                mBoundingBox.setExtents(min, max);
538
539                mRecalcFrustum = false;
540
541                // Signal to update frustum clipping planes
542                mRecalcFrustumPlanes = true;
543        }
544    //-----------------------------------------------------------------------
545    void Frustum::updateFrustum(void) const
546    {
547        if (isFrustumOutOfDate())
548        {
549                        updateFrustumImpl();
550        }
551    }
552
553    //-----------------------------------------------------------------------
554    void Frustum::updateVertexData(void) const
555    {
556        if (mRecalcVertexData)
557        {
558            if (mVertexData.vertexBufferBinding->getBufferCount() <= 0)
559            {
560                // Initialise vertex & index data
561                mVertexData.vertexDeclaration->addElement(0, 0, VET_FLOAT3, VES_POSITION);
562                mVertexData.vertexCount = 32;
563                mVertexData.vertexStart = 0;
564                mVertexData.vertexBufferBinding->setBinding( 0,
565                    HardwareBufferManager::getSingleton().createVertexBuffer(
566                        sizeof(float)*3, 32, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY) );
567            }
568
569            // Note: Even though we can dealing with general projection matrix here,
570            //       but because it's incompatibly with infinite far plane, thus, we
571            //       still need to working with projection parameters.
572
573            // Calc near plane corners
574            Real vpLeft, vpRight, vpBottom, vpTop;
575            calcProjectionParameters(vpLeft, vpRight, vpBottom, vpTop);
576
577            // Treat infinite fardist as some arbitrary far value
578            Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
579
580            // Calc far palne corners
581            Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
582            Real farLeft = vpLeft * radio;
583            Real farRight = vpRight * radio;
584            Real farBottom = vpBottom * radio;
585            Real farTop = vpTop * radio;
586
587            // Calculate vertex positions (local)
588            // 0 is the origin
589            // 1, 2, 3, 4 are the points on the near plane, top left first, clockwise
590            // 5, 6, 7, 8 are the points on the far plane, top left first, clockwise
591            HardwareVertexBufferSharedPtr vbuf = mVertexData.vertexBufferBinding->getBuffer(0);
592            float* pFloat = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
593
594            // near plane (remember frustum is going in -Z direction)
595            *pFloat++ = vpLeft;  *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
596            *pFloat++ = vpRight; *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
597
598            *pFloat++ = vpRight; *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
599            *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
600
601            *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
602            *pFloat++ = vpLeft;  *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
603
604            *pFloat++ = vpLeft;  *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
605            *pFloat++ = vpLeft;  *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
606
607            // far plane (remember frustum is going in -Z direction)
608            *pFloat++ = farLeft;  *pFloat++ = farTop;    *pFloat++ = -farDist;
609            *pFloat++ = farRight; *pFloat++ = farTop;    *pFloat++ = -farDist;
610
611            *pFloat++ = farRight; *pFloat++ = farTop;    *pFloat++ = -farDist;
612            *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
613
614            *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
615            *pFloat++ = farLeft;  *pFloat++ = farBottom; *pFloat++ = -farDist;
616
617            *pFloat++ = farLeft;  *pFloat++ = farBottom; *pFloat++ = -farDist;
618            *pFloat++ = farLeft;  *pFloat++ = farTop;    *pFloat++ = -farDist;
619
620            // Sides of the pyramid
621            *pFloat++ = 0.0f;    *pFloat++ = 0.0f;   *pFloat++ = 0.0f;
622            *pFloat++ = vpLeft;  *pFloat++ = vpTop;  *pFloat++ = -mNearDist;
623
624            *pFloat++ = 0.0f;    *pFloat++ = 0.0f;   *pFloat++ = 0.0f;
625            *pFloat++ = vpRight; *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
626
627            *pFloat++ = 0.0f;    *pFloat++ = 0.0f;   *pFloat++ = 0.0f;
628            *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
629
630            *pFloat++ = 0.0f;    *pFloat++ = 0.0f;   *pFloat++ = 0.0f;
631            *pFloat++ = vpLeft;  *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
632
633            // Sides of the box
634
635            *pFloat++ = vpLeft;  *pFloat++ = vpTop;  *pFloat++ = -mNearDist;
636            *pFloat++ = farLeft;  *pFloat++ = farTop;  *pFloat++ = -farDist;
637
638            *pFloat++ = vpRight; *pFloat++ = vpTop;    *pFloat++ = -mNearDist;
639            *pFloat++ = farRight; *pFloat++ = farTop;    *pFloat++ = -farDist;
640
641            *pFloat++ = vpRight; *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
642            *pFloat++ = farRight; *pFloat++ = farBottom; *pFloat++ = -farDist;
643
644            *pFloat++ = vpLeft;  *pFloat++ = vpBottom; *pFloat++ = -mNearDist;
645            *pFloat++ = farLeft;  *pFloat++ = farBottom; *pFloat++ = -farDist;
646
647
648            vbuf->unlock();
649
650            mRecalcVertexData = false;
651        }
652    }
653
654    //-----------------------------------------------------------------------
655    bool Frustum::isViewOutOfDate(void) const
656    {
657        // Attached to node?
658        if (mParentNode)
659        {
660            if (mRecalcView ||
661                mParentNode->_getDerivedOrientation() != mLastParentOrientation ||
662                mParentNode->_getDerivedPosition() != mLastParentPosition)
663            {
664                // Ok, we're out of date with SceneNode we're attached to
665                mLastParentOrientation = mParentNode->_getDerivedOrientation();
666                mLastParentPosition = mParentNode->_getDerivedPosition();
667                mRecalcView = true;
668            }
669        }
670        // Deriving reflection from linked plane?
671        if (mLinkedReflectPlane && 
672            !(mLastLinkedReflectionPlane == mLinkedReflectPlane->_getDerivedPlane()))
673        {
674            mReflectPlane = mLinkedReflectPlane->_getDerivedPlane();
675            mReflectMatrix = Math::buildReflectionMatrix(mReflectPlane);
676            mLastLinkedReflectionPlane = mLinkedReflectPlane->_getDerivedPlane();
677            mRecalcView = true;
678        }
679
680        return mRecalcView;
681    }
682
683    //-----------------------------------------------------------------------
684    bool Frustum::isFrustumOutOfDate(void) const
685    {
686        // Deriving custom near plane from linked plane?
687        if (mObliqueDepthProjection)
688        {
689            // Out of date when view out of data since plane needs to be in view space
690            if (isViewOutOfDate())
691            {
692                mRecalcFrustum = true;
693            }
694            // Update derived plane
695            if (mLinkedObliqueProjPlane && 
696                !(mLastLinkedObliqueProjPlane == mLinkedObliqueProjPlane->_getDerivedPlane()))
697            {
698                mObliqueProjPlane = mLinkedObliqueProjPlane->_getDerivedPlane();
699                mLastLinkedObliqueProjPlane = mObliqueProjPlane;
700                mRecalcFrustum = true;
701            }
702        }
703
704        return mRecalcFrustum;
705    }
706
707    //-----------------------------------------------------------------------
708        void Frustum::updateViewImpl(void) const
709        {
710                // ----------------------
711                // Update the view matrix
712                // ----------------------
713
714                // View matrix is:
715                //
716                //  [ Lx  Uy  Dz  Tx  ]
717                //  [ Lx  Uy  Dz  Ty  ]
718                //  [ Lx  Uy  Dz  Tz  ]
719                //  [ 0   0   0   1   ]
720                //
721                // Where T = -(Transposed(Rot) * Pos)
722
723                // This is most efficiently done using 3x3 Matrices
724
725                // Get orientation from quaternion
726
727                if (!mCustomViewMatrix)
728                {
729                        Matrix3 rot;
730                        const Quaternion& orientation = getOrientationForViewUpdate();
731                        const Vector3& position = getPositionForViewUpdate();
732                        orientation.ToRotationMatrix(rot);
733
734                        // Make the translation relative to new axes
735                        Matrix3 rotT = rot.Transpose();
736                        Vector3 trans = -rotT * position;
737
738                        // Make final matrix
739                        mViewMatrix = Matrix4::IDENTITY;
740                        mViewMatrix = rotT; // fills upper 3x3
741                        mViewMatrix[0][3] = trans.x;
742                        mViewMatrix[1][3] = trans.y;
743                        mViewMatrix[2][3] = trans.z;
744
745                        // Deal with reflections
746                        if (mReflect)
747                        {
748                                mViewMatrix = mViewMatrix * mReflectMatrix;
749                        }
750                }
751
752                mRecalcView = false;
753
754                // Signal to update frustum clipping planes
755                mRecalcFrustumPlanes = true;
756                // Signal to update world space corners
757                mRecalcWorldSpaceCorners = true;
758                // Signal to update frustum if oblique plane enabled,
759                // since plane needs to be in view space
760                if (mObliqueDepthProjection)
761                {
762                        mRecalcFrustum = true;
763                }
764        }
765        //-----------------------------------------------------------------------
766    void Frustum::updateView(void) const
767    {
768        if (isViewOutOfDate())
769        {
770                        updateViewImpl();
771        }
772    }
773
774        //-----------------------------------------------------------------------
775        void Frustum::updateFrustumPlanesImpl(void) const
776        {
777                // -------------------------
778                // Update the frustum planes
779                // -------------------------
780                Matrix4 combo = mProjMatrix * mViewMatrix;
781
782                mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
783                mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
784                mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
785                mFrustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
786
787                mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
788                mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
789                mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
790                mFrustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
791
792                mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
793                mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
794                mFrustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
795                mFrustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
796
797                mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
798                mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
799                mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
800                mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
801
802                mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
803                mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
804                mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
805                mFrustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
806
807                mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
808                mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
809                mFrustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
810                mFrustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
811
812                // Renormalise any normals which were not unit length
813                for(int i=0; i<6; i++ ) 
814                {
815                        float length = mFrustumPlanes[i].normal.normalise();
816                        mFrustumPlanes[i].d /= length;
817                }
818
819                mRecalcFrustumPlanes = false;
820        }
821    //-----------------------------------------------------------------------
822    void Frustum::updateFrustumPlanes(void) const
823    {
824        updateView();
825        updateFrustum();
826
827        if (mRecalcFrustumPlanes)
828        {
829                        updateFrustumPlanesImpl();
830        }
831    }
832        //-----------------------------------------------------------------------
833        void Frustum::updateWorldSpaceCornersImpl(void) const
834        {
835                Matrix4 eyeToWorld = mViewMatrix.inverseAffine();
836
837                // Note: Even though we can dealing with general projection matrix here,
838                //       but because it's incompatibly with infinite far plane, thus, we
839                //       still need to working with projection parameters.
840
841                // Calc near plane corners
842                Real nearLeft, nearRight, nearBottom, nearTop;
843                calcProjectionParameters(nearLeft, nearRight, nearBottom, nearTop);
844
845                // Treat infinite fardist as some arbitrary far value
846                Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
847
848                // Calc far palne corners
849                Real radio = mProjType == PT_PERSPECTIVE ? farDist / mNearDist : 1;
850                Real farLeft = nearLeft * radio;
851                Real farRight = nearRight * radio;
852                Real farBottom = nearBottom * radio;
853                Real farTop = nearTop * radio;
854
855                // near
856                mWorldSpaceCorners[0] = eyeToWorld.transformAffine(Vector3(nearRight, nearTop,    -mNearDist));
857                mWorldSpaceCorners[1] = eyeToWorld.transformAffine(Vector3(nearLeft,  nearTop,    -mNearDist));
858                mWorldSpaceCorners[2] = eyeToWorld.transformAffine(Vector3(nearLeft,  nearBottom, -mNearDist));
859                mWorldSpaceCorners[3] = eyeToWorld.transformAffine(Vector3(nearRight, nearBottom, -mNearDist));
860                // far
861                mWorldSpaceCorners[4] = eyeToWorld.transformAffine(Vector3(farRight,  farTop,     -farDist));
862                mWorldSpaceCorners[5] = eyeToWorld.transformAffine(Vector3(farLeft,   farTop,     -farDist));
863                mWorldSpaceCorners[6] = eyeToWorld.transformAffine(Vector3(farLeft,   farBottom,  -farDist));
864                mWorldSpaceCorners[7] = eyeToWorld.transformAffine(Vector3(farRight,  farBottom,  -farDist));
865
866
867                mRecalcWorldSpaceCorners = false;
868        }
869    //-----------------------------------------------------------------------
870    void Frustum::updateWorldSpaceCorners(void) const
871    {
872        updateView();
873
874        if (mRecalcWorldSpaceCorners)
875        {
876                        updateWorldSpaceCornersImpl();
877        }
878
879    }
880
881    //-----------------------------------------------------------------------
882    Real Frustum::getAspectRatio(void) const
883    {
884        return mAspect;
885    }
886
887    //-----------------------------------------------------------------------
888    void Frustum::setAspectRatio(Real r)
889    {
890        mAspect = r;
891        invalidateFrustum();
892    }
893
894    //-----------------------------------------------------------------------
895    const AxisAlignedBox& Frustum::getBoundingBox(void) const
896    {
897        return mBoundingBox;
898    }
899    //-----------------------------------------------------------------------
900    void Frustum::_updateRenderQueue(RenderQueue* queue)
901    {
902        // Add self
903        queue->addRenderable(this);
904    }
905    //-----------------------------------------------------------------------
906    const String& Frustum::getMovableType(void) const
907    {
908        return msMovableType;
909    }
910    //-----------------------------------------------------------------------
911        Real Frustum::getBoundingRadius(void) const
912        {
913        return (mFarDist == 0)? 100000 : mFarDist;
914        }
915    //-----------------------------------------------------------------------
916    const MaterialPtr& Frustum::getMaterial(void) const
917    {
918        return mMaterial;
919    }
920    //-----------------------------------------------------------------------
921    void Frustum::getRenderOperation(RenderOperation& op) 
922    {
923        updateVertexData();
924        op.operationType = RenderOperation::OT_LINE_LIST;
925        op.useIndexes = false;
926        op.vertexData = &mVertexData;
927    }
928    //-----------------------------------------------------------------------
929    void Frustum::getWorldTransforms(Matrix4* xform) const 
930    {
931        if (mParentNode)
932            *xform = mParentNode->_getFullTransform();
933        else
934            *xform = Matrix4::IDENTITY;
935    }
936    //-----------------------------------------------------------------------
937    const Quaternion& Frustum::getWorldOrientation(void) const 
938    {
939        if (mParentNode)
940            return mParentNode->_getDerivedOrientation();
941        else
942            return Quaternion::IDENTITY;
943    }
944    //-----------------------------------------------------------------------
945    const Vector3& Frustum::getWorldPosition(void) const 
946    {
947        if (mParentNode)
948            return mParentNode->_getDerivedPosition();
949        else
950            return Vector3::ZERO;
951    }
952    //-----------------------------------------------------------------------
953    Real Frustum::getSquaredViewDepth(const Camera* cam) const 
954    {
955        // Calc from centre
956        if (mParentNode)
957            return (cam->getDerivedPosition() 
958                - mParentNode->_getDerivedPosition()).squaredLength();
959        else
960            return 0;
961    }
962    //-----------------------------------------------------------------------
963    const LightList& Frustum::getLights(void) const 
964    {
965        // N/A
966        static LightList ll;
967        return ll;
968    }
969    //-----------------------------------------------------------------------
970    void Frustum::_notifyCurrentCamera(Camera* cam)
971    {
972        // Make sure bounding box up-to-date
973        updateFrustum();
974
975        MovableObject::_notifyCurrentCamera(cam);
976    }
977
978    // -------------------------------------------------------------------
979    void Frustum::invalidateFrustum() const
980    {
981        mRecalcFrustum = true;
982        mRecalcFrustumPlanes = true;
983        mRecalcWorldSpaceCorners = true;
984        mRecalcVertexData = true;
985    }
986    // -------------------------------------------------------------------
987    void Frustum::invalidateView() const
988    {
989        mRecalcView = true;
990        mRecalcFrustumPlanes = true;
991        mRecalcWorldSpaceCorners = true;
992    }
993    // -------------------------------------------------------------------
994    const Vector3* Frustum::getWorldSpaceCorners(void) const
995    {
996        updateWorldSpaceCorners();
997
998        return mWorldSpaceCorners;
999    }
1000    //-----------------------------------------------------------------------
1001    void Frustum::setProjectionType(ProjectionType pt)
1002    {
1003        mProjType = pt;
1004        invalidateFrustum();
1005    }
1006
1007    //-----------------------------------------------------------------------
1008    ProjectionType Frustum::getProjectionType(void) const
1009    {
1010        return mProjType;
1011    }
1012    //-----------------------------------------------------------------------
1013    const Vector3& Frustum::getPositionForViewUpdate(void) const
1014    {
1015        return mLastParentPosition;
1016    }
1017    //-----------------------------------------------------------------------
1018    const Quaternion& Frustum::getOrientationForViewUpdate(void) const
1019    {
1020        return mLastParentOrientation;
1021    }
1022    //-----------------------------------------------------------------------
1023    void Frustum::enableReflection(const Plane& p)
1024    {
1025        mReflect = true;
1026        mReflectPlane = p;
1027        mLinkedReflectPlane = 0;
1028        mReflectMatrix = Math::buildReflectionMatrix(p);
1029        invalidateView();
1030
1031    }
1032    //-----------------------------------------------------------------------
1033    void Frustum::enableReflection(const MovablePlane* p)
1034    {
1035        mReflect = true;
1036        mLinkedReflectPlane = p;
1037        mReflectPlane = mLinkedReflectPlane->_getDerivedPlane();
1038        mReflectMatrix = Math::buildReflectionMatrix(mReflectPlane);
1039        mLastLinkedReflectionPlane = mLinkedReflectPlane->_getDerivedPlane();
1040        invalidateView();
1041    }
1042    //-----------------------------------------------------------------------
1043    void Frustum::disableReflection(void)
1044    {
1045        mReflect = false;
1046        mLinkedReflectPlane = 0;
1047        mLastLinkedReflectionPlane.normal = Vector3::ZERO;
1048        invalidateView();
1049    }
1050    //---------------------------------------------------------------------
1051    bool Frustum::projectSphere(const Sphere& sphere, 
1052        Real* left, Real* top, Real* right, Real* bottom) const
1053    {
1054                // See http://www.gamasutra.com/features/20021011/lengyel_06.htm
1055        // Transform light position into camera space
1056
1057        updateView();
1058        Vector3 eyeSpacePos = mViewMatrix.transformAffine(sphere.getCenter());
1059
1060                // initialise
1061                *left = *bottom = -1.0f;
1062                *right = *top = 1.0f;
1063
1064        if (eyeSpacePos.z < 0)
1065        {
1066                        updateFrustum();
1067                        const Matrix4& projMatrix = getProjectionMatrix();
1068            Real r = sphere.getRadius();
1069                        Real rsq = r * r;
1070
1071            // early-exit
1072            if (eyeSpacePos.squaredLength() <= rsq)
1073                return false;
1074
1075                        Real Lxz = Math::Sqr(eyeSpacePos.x) + Math::Sqr(eyeSpacePos.z);
1076                        Real Lyz = Math::Sqr(eyeSpacePos.y) + Math::Sqr(eyeSpacePos.z);
1077
1078                        // Find the tangent planes to the sphere
1079                        // XZ first
1080                        // calculate quadratic discriminant: b*b - 4ac
1081                        // x = Nx
1082                        // a = Lx^2 + Lz^2
1083                        // b = -2rLx
1084                        // c = r^2 - Lz^2
1085                        Real a = Lxz;
1086                        Real b = -2.0 * r * eyeSpacePos.x;
1087                        Real c = rsq - Math::Sqr(eyeSpacePos.z);
1088                        Real D = b*b - 4*a*c;
1089
1090                        // two roots?
1091                        if (D > 0)
1092                        {
1093                                Real sqrootD = Math::Sqrt(D);
1094                                // solve the quadratic to get the components of the normal
1095                                Real Nx0 = (-b + sqrootD) / (2 * a);
1096                                Real Nx1 = (-b - sqrootD) / (2 * a);
1097                               
1098                                // Derive Z from this
1099                                Real Nz0 = (r - Nx0 * eyeSpacePos.x) / eyeSpacePos.z;
1100                                Real Nz1 = (r - Nx1 * eyeSpacePos.x) / eyeSpacePos.z;
1101
1102                                // Get the point of tangency
1103                                // Only consider points of tangency in front of the camera
1104                                Real Pz0 = (Lxz - rsq) / (eyeSpacePos.z - ((Nz0 / Nx0) * eyeSpacePos.x));
1105                                if (Pz0 < 0)
1106                                {
1107                                        // Project point onto near plane in worldspace
1108                                        Real nearx0 = (Nz0 * mNearDist) / Nx0;
1109                                        // now we need to map this to viewport coords
1110                                        // use projection matrix since that will take into account all factors
1111                                        Vector3 relx0 = projMatrix * Vector3(nearx0, 0, -mNearDist);
1112
1113                                        // find out whether this is a left side or right side
1114                                        Real Px0 = -(Pz0 * Nz0) / Nx0;
1115                                        if (Px0 > eyeSpacePos.x)
1116                                        {
1117                                                *right = std::min(*right, relx0.x);
1118                                        }
1119                                        else
1120                                        {
1121                                                *left = std::max(*left, relx0.x);
1122                                        }
1123                                }
1124                                Real Pz1 = (Lxz - rsq) / (eyeSpacePos.z - ((Nz1 / Nx1) * eyeSpacePos.x));
1125                                if (Pz1 < 0)
1126                                {
1127                                        // Project point onto near plane in worldspace
1128                                        Real nearx1 = (Nz1 * mNearDist) / Nx1;
1129                                        // now we need to map this to viewport coords
1130                                        // use projection matrix since that will take into account all factors
1131                                        Vector3 relx1 = projMatrix * Vector3(nearx1, 0, -mNearDist);
1132
1133                                        // find out whether this is a left side or right side
1134                                        Real Px1 = -(Pz1 * Nz1) / Nx1;
1135                                        if (Px1 > eyeSpacePos.x)
1136                                        {
1137                                                *right = std::min(*right, relx1.x);
1138                                        }
1139                                        else
1140                                        {
1141                                                *left = std::max(*left, relx1.x);
1142                                        }
1143                                }
1144                        }
1145
1146
1147                        // Now YZ
1148                        // calculate quadratic discriminant: b*b - 4ac
1149                        // x = Ny
1150                        // a = Ly^2 + Lz^2
1151                        // b = -2rLy
1152                        // c = r^2 - Lz^2
1153                        a = Lyz;
1154                        b = -2.0 * r * eyeSpacePos.y;
1155                        c = rsq - Math::Sqr(eyeSpacePos.z);
1156                        D = b*b - 4*a*c;
1157
1158                        // two roots?
1159                        if (D > 0)
1160                        {
1161                                Real sqrootD = Math::Sqrt(D);
1162                                // solve the quadratic to get the components of the normal
1163                                Real Ny0 = (-b + sqrootD) / (2 * a);
1164                                Real Ny1 = (-b - sqrootD) / (2 * a);
1165
1166                                // Derive Z from this
1167                                Real Nz0 = (r - Ny0 * eyeSpacePos.y) / eyeSpacePos.z;
1168                                Real Nz1 = (r - Ny1 * eyeSpacePos.y) / eyeSpacePos.z;
1169
1170                                // Get the point of tangency
1171                                // Only consider points of tangency in front of the camera
1172                                Real Pz0 = (Lyz - rsq) / (eyeSpacePos.z - ((Nz0 / Ny0) * eyeSpacePos.y));
1173                                if (Pz0 < 0)
1174                                {
1175                                        // Project point onto near plane in worldspace
1176                                        Real neary0 = (Nz0 * mNearDist) / Ny0;
1177                                        // now we need to map this to viewport coords
1178                                        // use projection matriy since that will take into account all factors
1179                                        Vector3 rely0 = projMatrix * Vector3(0, neary0, -mNearDist);
1180
1181                                        // find out whether this is a top side or bottom side
1182                                        Real Py0 = -(Pz0 * Nz0) / Ny0;
1183                                        if (Py0 > eyeSpacePos.y)
1184                                        {
1185                                                *top = std::min(*top, rely0.y);
1186                                        }
1187                                        else
1188                                        {
1189                                                *bottom = std::max(*bottom, rely0.y);
1190                                        }
1191                                }
1192                                Real Pz1 = (Lyz - rsq) / (eyeSpacePos.z - ((Nz1 / Ny1) * eyeSpacePos.y));
1193                                if (Pz1 < 0)
1194                                {
1195                                        // Project point onto near plane in worldspace
1196                                        Real neary1 = (Nz1 * mNearDist) / Ny1;
1197                                        // now we need to map this to viewport coords
1198                                        // use projection matriy since that will take into account all factors
1199                                        Vector3 rely1 = projMatrix * Vector3(0, neary1, -mNearDist);
1200
1201                                        // find out whether this is a top side or bottom side
1202                                        Real Py1 = -(Pz1 * Nz1) / Ny1;
1203                                        if (Py1 > eyeSpacePos.y)
1204                                        {
1205                                                *top = std::min(*top, rely1.y);
1206                                        }
1207                                        else
1208                                        {
1209                                                *bottom = std::max(*bottom, rely1.y);
1210                                        }
1211                                }
1212                        }
1213        }
1214
1215        return (*left != -1.0f) || (*top != 1.0f) || (*right != 1.0f) || (*bottom != -1.0f);
1216
1217    }
1218    //---------------------------------------------------------------------
1219    void Frustum::enableCustomNearClipPlane(const MovablePlane* plane)
1220    {
1221        mObliqueDepthProjection = true;
1222        mLinkedObliqueProjPlane = plane;
1223        mObliqueProjPlane = plane->_getDerivedPlane();
1224        invalidateFrustum();
1225    }
1226    //---------------------------------------------------------------------
1227    void Frustum::enableCustomNearClipPlane(const Plane& plane)
1228    {
1229        mObliqueDepthProjection = true;
1230        mLinkedObliqueProjPlane = 0;
1231        mObliqueProjPlane = plane;
1232        invalidateFrustum();
1233    }
1234    //---------------------------------------------------------------------
1235    void Frustum::disableCustomNearClipPlane(void)
1236    {
1237        mObliqueDepthProjection = false;
1238        mLinkedObliqueProjPlane = 0;
1239        invalidateFrustum();
1240    }
1241    //---------------------------------------------------------------------
1242        void Frustum::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
1243        {
1244                mCustomViewMatrix = enable;
1245                if (enable)
1246                {
1247            assert(viewMatrix.isAffine());
1248                        mViewMatrix = viewMatrix;
1249                }
1250                invalidateView();
1251        }
1252    //---------------------------------------------------------------------
1253        void Frustum::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
1254        {
1255                mCustomProjMatrix = enable;
1256                if (enable)
1257                {
1258                        mProjMatrix = projMatrix;
1259                }
1260                invalidateFrustum();
1261        }
1262
1263
1264
1265} // namespace Ogre
Note: See TracBrowser for help on using the repository browser.