frustum.h

Go to the documentation of this file.
00001 
00006 /*
00007  Copyright (C) 2001-2006, William Joseph.
00008  All Rights Reserved.
00009 
00010  This file is part of GtkRadiant.
00011 
00012  GtkRadiant is free software; you can redistribute it and/or modify
00013  it under the terms of the GNU General Public License as published by
00014  the Free Software Foundation; either version 2 of the License, or
00015  (at your option) any later version.
00016 
00017  GtkRadiant is distributed in the hope that it will be useful,
00018  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  GNU General Public License for more details.
00021 
00022  You should have received a copy of the GNU General Public License
00023  along with GtkRadiant; if not, write to the Free Software
00024  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00025  */
00026 
00027 #if !defined(INCLUDED_MATH_FRUSTUM_H)
00028 #define INCLUDED_MATH_FRUSTUM_H
00029 
00030 #include "generic/enumeration.h"
00031 #include "math/matrix.h"
00032 #include "math/plane.h"
00033 #include "math/aabb.h"
00034 #include "math/line.h"
00035 
00036 inline Matrix4 matrix4_frustum (float left, float right, float bottom, float top, float nearval, float farval)
00037 {
00038     return Matrix4(static_cast<float> ((2 * nearval) / (right - left)), 0, 0, 0, 0, static_cast<float> ((2 * nearval)
00039             / (top - bottom)), 0, 0, static_cast<float> ((right + left) / (right - left)), static_cast<float> ((top
00040             + bottom) / (top - bottom)), static_cast<float> (-(farval + nearval) / (farval - nearval)), -1, 0, 0,
00041             static_cast<float> (-(2 * farval * nearval) / (farval - nearval)), 0);
00042 }
00043 
00044 typedef unsigned char ClipResult;
00045 const ClipResult c_CLIP_PASS = 0x00; // 000000
00046 const ClipResult c_CLIP_LT_X = 0x01; // 000001
00047 const ClipResult c_CLIP_GT_X = 0x02; // 000010
00048 const ClipResult c_CLIP_LT_Y = 0x04; // 000100
00049 const ClipResult c_CLIP_GT_Y = 0x08; // 001000
00050 const ClipResult c_CLIP_LT_Z = 0x10; // 010000
00051 const ClipResult c_CLIP_GT_Z = 0x20; // 100000
00052 const ClipResult c_CLIP_FAIL = 0x3F; // 111111
00053 
00054 template<typename Index>
00055 class Vector4ClipLT
00056 {
00057     public:
00058         static bool compare (const Vector4& self)
00059         {
00060             return self[Index::VALUE] < self[3];
00061         }
00062         static double scale (const Vector4& self, const Vector4& other)
00063         {
00064             return (self[Index::VALUE] - self[3]) / (other[3] - other[Index::VALUE]);
00065         }
00066 };
00067 
00068 template<typename Index>
00069 class Vector4ClipGT
00070 {
00071     public:
00072         static bool compare (const Vector4& self)
00073         {
00074             return self[Index::VALUE] > -self[3];
00075         }
00076         static double scale (const Vector4& self, const Vector4& other)
00077         {
00078             return (self[Index::VALUE] + self[3]) / (-other[3] - other[Index::VALUE]);
00079         }
00080 };
00081 
00082 template<typename ClipPlane>
00083 class Vector4ClipPolygon
00084 {
00085     public:
00086         typedef Vector4* iterator;
00087         typedef const Vector4* const_iterator;
00088 
00089         static std::size_t apply (const_iterator first, const_iterator last, iterator out)
00090         {
00091             const_iterator next = first, i = last - 1;
00092             iterator tmp(out);
00093             bool b0 = ClipPlane::compare(*i);
00094             while (next != last) {
00095                 bool b1 = ClipPlane::compare(*next);
00096                 if (b0 ^ b1) {
00097                     *out = *next - *i;
00098 
00099                     double scale = ClipPlane::scale(*i, *out);
00100 
00101                     (*out)[0] = static_cast<float> ((*i)[0] + scale * ((*out)[0]));
00102                     (*out)[1] = static_cast<float> ((*i)[1] + scale * ((*out)[1]));
00103                     (*out)[2] = static_cast<float> ((*i)[2] + scale * ((*out)[2]));
00104                     (*out)[3] = static_cast<float> ((*i)[3] + scale * ((*out)[3]));
00105 
00106                     ++out;
00107                 }
00108 
00109                 if (b1) {
00110                     *out = *next;
00111                     ++out;
00112                 }
00113 
00114                 i = next;
00115                 ++next;
00116                 b0 = b1;
00117             }
00118 
00119             return out - tmp;
00120         }
00121 };
00122 
00123 #define CLIP_X_LT_W(p) (Vector4ClipLT< IntegralConstant<0> >::compare(p))
00124 #define CLIP_X_GT_W(p) (Vector4ClipGT< IntegralConstant<0> >::compare(p))
00125 #define CLIP_Y_LT_W(p) (Vector4ClipLT< IntegralConstant<1> >::compare(p))
00126 #define CLIP_Y_GT_W(p) (Vector4ClipGT< IntegralConstant<1> >::compare(p))
00127 #define CLIP_Z_LT_W(p) (Vector4ClipLT< IntegralConstant<2> >::compare(p))
00128 #define CLIP_Z_GT_W(p) (Vector4ClipGT< IntegralConstant<2> >::compare(p))
00129 
00130 inline ClipResult homogenous_clip_point (const Vector4& clipped)
00131 {
00132     ClipResult result = c_CLIP_FAIL;
00133     if (CLIP_X_LT_W(clipped))
00134         result &= ~c_CLIP_LT_X; // X < W
00135     if (CLIP_X_GT_W(clipped))
00136         result &= ~c_CLIP_GT_X; // X > -W
00137     if (CLIP_Y_LT_W(clipped))
00138         result &= ~c_CLIP_LT_Y; // Y < W
00139     if (CLIP_Y_GT_W(clipped))
00140         result &= ~c_CLIP_GT_Y; // Y > -W
00141     if (CLIP_Z_LT_W(clipped))
00142         result &= ~c_CLIP_LT_Z; // Z < W
00143     if (CLIP_Z_GT_W(clipped))
00144         result &= ~c_CLIP_GT_Z; // Z > -W
00145     return result;
00146 }
00147 
00151 inline ClipResult matrix4_clip_point (const Matrix4& self, const Vector3& point, Vector4& clipped)
00152 {
00153     clipped[0] = point[0];
00154     clipped[1] = point[1];
00155     clipped[2] = point[2];
00156     clipped[3] = 1;
00157     matrix4_transform_vector4(self, clipped);
00158     return homogenous_clip_point(clipped);
00159 }
00160 
00161 inline std::size_t homogenous_clip_triangle (Vector4 clipped[9])
00162 {
00163     Vector4 buffer[9];
00164     std::size_t count = 3;
00165     count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<0> > >::apply(clipped, clipped + count, buffer);
00166     count = Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<0> > >::apply(buffer, buffer + count, clipped);
00167     count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<1> > >::apply(clipped, clipped + count, buffer);
00168     count = Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<1> > >::apply(buffer, buffer + count, clipped);
00169     count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<2> > >::apply(clipped, clipped + count, buffer);
00170     return Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<2> > >::apply(buffer, buffer + count, clipped);
00171 }
00172 
00176 inline std::size_t matrix4_clip_triangle (const Matrix4& self, const Vector3& p0, const Vector3& p1, const Vector3& p2,
00177         Vector4 clipped[9])
00178 {
00179     clipped[0][0] = p0[0];
00180     clipped[0][1] = p0[1];
00181     clipped[0][2] = p0[2];
00182     clipped[0][3] = 1;
00183     clipped[1][0] = p1[0];
00184     clipped[1][1] = p1[1];
00185     clipped[1][2] = p1[2];
00186     clipped[1][3] = 1;
00187     clipped[2][0] = p2[0];
00188     clipped[2][1] = p2[1];
00189     clipped[2][2] = p2[2];
00190     clipped[2][3] = 1;
00191 
00192     matrix4_transform_vector4(self, clipped[0]);
00193     matrix4_transform_vector4(self, clipped[1]);
00194     matrix4_transform_vector4(self, clipped[2]);
00195 
00196     return homogenous_clip_triangle(clipped);
00197 }
00198 
00199 inline std::size_t homogenous_clip_line (Vector4 clipped[2])
00200 {
00201     const Vector4& p0 = clipped[0];
00202     const Vector4& p1 = clipped[1];
00203 
00204     // early out
00205     {
00206         ClipResult mask0 = homogenous_clip_point(clipped[0]);
00207         ClipResult mask1 = homogenous_clip_point(clipped[1]);
00208 
00209         if ((mask0 | mask1) == c_CLIP_PASS) // both points passed all planes
00210             return 2;
00211 
00212         if (mask0 & mask1) // both points failed any one plane
00213             return 0;
00214     }
00215 
00216     {
00217         const bool index = CLIP_X_LT_W(p0);
00218         if (index ^ CLIP_X_LT_W(p1)) {
00219             Vector4 clip(p1 - p0);
00220 
00221             double scale = (p0[0] - p0[3]) / (clip[3] - clip[0]);
00222 
00223             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00224             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00225             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00226             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00227 
00228             clipped[index] = clip;
00229         } else if (index == 0)
00230             return 0;
00231     }
00232 
00233     {
00234         const bool index = CLIP_X_GT_W(p0);
00235         if (index ^ CLIP_X_GT_W(p1)) {
00236             Vector4 clip(p1 - p0);
00237 
00238             double scale = (p0[0] + p0[3]) / (-clip[3] - clip[0]);
00239 
00240             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00241             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00242             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00243             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00244 
00245             clipped[index] = clip;
00246         } else if (index == 0)
00247             return 0;
00248     }
00249 
00250     {
00251         const bool index = CLIP_Y_LT_W(p0);
00252         if (index ^ CLIP_Y_LT_W(p1)) {
00253             Vector4 clip(p1 - p0);
00254 
00255             double scale = (p0[1] - p0[3]) / (clip[3] - clip[1]);
00256 
00257             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00258             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00259             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00260             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00261 
00262             clipped[index] = clip;
00263         } else if (index == 0)
00264             return 0;
00265     }
00266 
00267     {
00268         const bool index = CLIP_Y_GT_W(p0);
00269         if (index ^ CLIP_Y_GT_W(p1)) {
00270             Vector4 clip(p1 - p0);
00271 
00272             double scale = (p0[1] + p0[3]) / (-clip[3] - clip[1]);
00273 
00274             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00275             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00276             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00277             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00278 
00279             clipped[index] = clip;
00280         } else if (index == 0)
00281             return 0;
00282     }
00283 
00284     {
00285         const bool index = CLIP_Z_LT_W(p0);
00286         if (index ^ CLIP_Z_LT_W(p1)) {
00287             Vector4 clip(p1 - p0);
00288 
00289             double scale = (p0[2] - p0[3]) / (clip[3] - clip[2]);
00290 
00291             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00292             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00293             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00294             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00295 
00296             clipped[index] = clip;
00297         } else if (index == 0)
00298             return 0;
00299     }
00300 
00301     {
00302         const bool index = CLIP_Z_GT_W(p0);
00303         if (index ^ CLIP_Z_GT_W(p1)) {
00304             Vector4 clip(p1 - p0);
00305 
00306             double scale = (p0[2] + p0[3]) / (-clip[3] - clip[2]);
00307 
00308             clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00309             clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00310             clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00311             clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00312 
00313             clipped[index] = clip;
00314         } else if (index == 0)
00315             return 0;
00316     }
00317 
00318     return 2;
00319 }
00320 
00324 inline std::size_t matrix4_clip_line (const Matrix4& self, const Vector3& p0, const Vector3& p1, Vector4 clipped[2])
00325 {
00326     clipped[0][0] = p0[0];
00327     clipped[0][1] = p0[1];
00328     clipped[0][2] = p0[2];
00329     clipped[0][3] = 1;
00330     clipped[1][0] = p1[0];
00331     clipped[1][1] = p1[1];
00332     clipped[1][2] = p1[2];
00333     clipped[1][3] = 1;
00334 
00335     matrix4_transform_vector4(self, clipped[0]);
00336     matrix4_transform_vector4(self, clipped[1]);
00337 
00338     return homogenous_clip_line(clipped);
00339 }
00340 
00341 struct Frustum
00342 {
00343         Plane3 right, left, bottom, top, back, front;
00344 
00345         Frustum ()
00346         {
00347         }
00348         Frustum (const Plane3& _right, const Plane3& _left, const Plane3& _bottom, const Plane3& _top,
00349                 const Plane3& _back, const Plane3& _front) :
00350             right(_right), left(_left), bottom(_bottom), top(_top), back(_back), front(_front)
00351         {
00352         }
00353 };
00354 
00355 inline Frustum frustum_transformed (const Frustum& frustum, const Matrix4& transform)
00356 {
00357     return Frustum(plane3_transformed(frustum.right, transform), plane3_transformed(frustum.left, transform),
00358             plane3_transformed(frustum.bottom, transform), plane3_transformed(frustum.top, transform),
00359             plane3_transformed(frustum.back, transform), plane3_transformed(frustum.front, transform));
00360 }
00361 
00362 inline Frustum frustum_inverse_transformed (const Frustum& frustum, const Matrix4& transform)
00363 {
00364     return Frustum(plane3_inverse_transformed(frustum.right, transform), plane3_inverse_transformed(frustum.left,
00365             transform), plane3_inverse_transformed(frustum.bottom, transform), plane3_inverse_transformed(frustum.top,
00366             transform), plane3_inverse_transformed(frustum.back, transform), plane3_inverse_transformed(frustum.front,
00367             transform));
00368 }
00369 
00370 inline bool viewproj_test_point (const Matrix4& viewproj, const Vector3& point)
00371 {
00372     Vector4 hpoint(matrix4_transformed_vector4(viewproj, Vector4(point, 1.0f)));
00373     if (fabs(hpoint[0]) < fabs(hpoint[3]) && fabs(hpoint[1]) < fabs(hpoint[3]) && fabs(hpoint[2]) < fabs(hpoint[3]))
00374         return true;
00375     return false;
00376 }
00377 
00378 inline bool viewproj_test_transformed_point (const Matrix4& viewproj, const Vector3& point, const Matrix4& localToWorld)
00379 {
00380     return viewproj_test_point(viewproj, matrix4_transformed_point(localToWorld, point));
00381 }
00382 
00383 inline Frustum frustum_from_viewproj (const Matrix4& viewproj)
00384 {
00385     return Frustum(plane3_normalised(Plane3(viewproj[3] - viewproj[0], viewproj[7] - viewproj[4], viewproj[11]
00386             - viewproj[8], viewproj[15] - viewproj[12])), plane3_normalised(Plane3(viewproj[3] + viewproj[0],
00387             viewproj[7] + viewproj[4], viewproj[11] + viewproj[8], viewproj[15] + viewproj[12])), plane3_normalised(
00388             Plane3(viewproj[3] + viewproj[1], viewproj[7] + viewproj[5], viewproj[11] + viewproj[9], viewproj[15]
00389                     + viewproj[13])), plane3_normalised(Plane3(viewproj[3] - viewproj[1], viewproj[7] - viewproj[5],
00390             viewproj[11] - viewproj[9], viewproj[15] - viewproj[13])), plane3_normalised(Plane3(viewproj[3]
00391             - viewproj[2], viewproj[7] - viewproj[6], viewproj[11] - viewproj[10], viewproj[15] - viewproj[14])),
00392             plane3_normalised(Plane3(viewproj[3] + viewproj[2], viewproj[7] + viewproj[6], viewproj[11] + viewproj[10],
00393                     viewproj[15] + viewproj[14])));
00394 }
00395 
00396 struct VolumeIntersection
00397 {
00398         enum Value
00399         {
00400             OUTSIDE, INSIDE, PARTIAL
00401         };
00402 };
00403 
00404 typedef EnumeratedValue<VolumeIntersection> VolumeIntersectionValue;
00405 
00406 const VolumeIntersectionValue c_volumeOutside(VolumeIntersectionValue::OUTSIDE);
00407 const VolumeIntersectionValue c_volumeInside(VolumeIntersectionValue::INSIDE);
00408 const VolumeIntersectionValue c_volumePartial(VolumeIntersectionValue::PARTIAL);
00409 
00410 inline VolumeIntersectionValue frustum_test_aabb (const Frustum& frustum, const AABB& aabb)
00411 {
00412     VolumeIntersectionValue result = c_volumeInside;
00413 
00414     switch (aabb_classify_plane(aabb, frustum.right)) {
00415     case 2:
00416         return c_volumeOutside;
00417     case 1:
00418         result = c_volumePartial;
00419     }
00420 
00421     switch (aabb_classify_plane(aabb, frustum.left)) {
00422     case 2:
00423         return c_volumeOutside;
00424     case 1:
00425         result = c_volumePartial;
00426     }
00427 
00428     switch (aabb_classify_plane(aabb, frustum.bottom)) {
00429     case 2:
00430         return c_volumeOutside;
00431     case 1:
00432         result = c_volumePartial;
00433     }
00434 
00435     switch (aabb_classify_plane(aabb, frustum.top)) {
00436     case 2:
00437         return c_volumeOutside;
00438     case 1:
00439         result = c_volumePartial;
00440     }
00441 
00442     switch (aabb_classify_plane(aabb, frustum.back)) {
00443     case 2:
00444         return c_volumeOutside;
00445     case 1:
00446         result = c_volumePartial;
00447     }
00448 
00449     switch (aabb_classify_plane(aabb, frustum.front)) {
00450     case 2:
00451         return c_volumeOutside;
00452     case 1:
00453         result = c_volumePartial;
00454     }
00455 
00456     return result;
00457 }
00458 
00459 inline double plane_distance_to_point (const Plane3& plane, const Vector3& point)
00460 {
00461     return plane.normal().dot(point) + plane.d;
00462 }
00463 
00464 inline double plane_distance_to_oriented_extents (const Plane3& plane, const Vector3& extents,
00465         const Matrix4& orientation)
00466 {
00467     return fabs(extents[0] * plane.normal().dot(orientation.x().getVector3())) + fabs(extents[1] * plane.normal().dot(
00468             orientation.y().getVector3())) + fabs(extents[2] * plane.normal().dot(orientation.z().getVector3()));
00469 }
00470 
00472 inline bool plane_contains_oriented_aabb (const Plane3& plane, const AABB& aabb, const Matrix4& orientation)
00473 {
00474     double dot = plane_distance_to_point(plane, aabb.origin);
00475     return !(dot > 0 || -dot < plane_distance_to_oriented_extents(plane, aabb.extents, orientation));
00476 }
00477 
00478 inline VolumeIntersectionValue frustum_intersects_transformed_aabb (const Frustum& frustum, const AABB& aabb,
00479         const Matrix4& localToWorld)
00480 {
00481     AABB aabb_world(aabb);
00482     matrix4_transform_point(localToWorld, aabb_world.origin);
00483 
00484     if (plane_contains_oriented_aabb(frustum.right, aabb_world, localToWorld) || plane_contains_oriented_aabb(
00485             frustum.left, aabb_world, localToWorld) || plane_contains_oriented_aabb(frustum.bottom, aabb_world,
00486             localToWorld) || plane_contains_oriented_aabb(frustum.top, aabb_world, localToWorld)
00487             || plane_contains_oriented_aabb(frustum.back, aabb_world, localToWorld) || plane_contains_oriented_aabb(
00488             frustum.front, aabb_world, localToWorld))
00489         return c_volumeOutside;
00490     return c_volumeInside;
00491 }
00492 
00493 inline bool plane3_test_point (const Plane3& plane, const Vector3& point)
00494 {
00495     return point.dot(plane.normal()) + plane.dist() <= 0;
00496 }
00497 
00498 inline bool plane3_test_line (const Plane3& plane, const Segment& segment)
00499 {
00500     return segment_classify_plane(segment, plane) == 2;
00501 }
00502 
00503 inline bool frustum_test_point (const Frustum& frustum, const Vector3& point)
00504 {
00505     return !plane3_test_point(frustum.right, point) && !plane3_test_point(frustum.left, point) && !plane3_test_point(
00506             frustum.bottom, point) && !plane3_test_point(frustum.top, point) && !plane3_test_point(frustum.back, point)
00507             && !plane3_test_point(frustum.front, point);
00508 }
00509 
00510 inline bool frustum_test_line (const Frustum& frustum, const Segment& segment)
00511 {
00512     return !plane3_test_line(frustum.right, segment) && !plane3_test_line(frustum.left, segment) && !plane3_test_line(
00513             frustum.bottom, segment) && !plane3_test_line(frustum.top, segment) && !plane3_test_line(frustum.back,
00514             segment) && !plane3_test_line(frustum.front, segment);
00515 }
00516 
00517 inline bool viewer_test_plane (const Vector4& viewer, const Plane3& plane)
00518 {
00519     return ((plane.a * viewer[0]) + (plane.b * viewer[1]) + (plane.c * viewer[2]) + (plane.d * viewer[3])) > 0;
00520 }
00521 
00522 inline Vector3 triangle_cross (const Vector3& p0, const Vector3& p1, const Vector3& p2)
00523 {
00524     return (p1 - p0).crossProduct(p1 - p2);
00525 }
00526 
00527 inline bool viewer_test_triangle (const Vector4& viewer, const Vector3& p0, const Vector3& p1, const Vector3& p2)
00528 {
00529     Vector3 cross(triangle_cross(p0, p1, p2));
00530     return ((viewer[0] * cross[0]) + (viewer[1] * cross[1]) + (viewer[2] * cross[2]) + (viewer[3] * 0)) > 0;
00531 }
00532 
00533 inline Vector4 viewer_from_transformed_viewer (const Vector4& viewer, const Matrix4& transform)
00534 {
00535     if (viewer[3] == 0) {
00536         return Vector4(matrix4_transformed_direction(transform, viewer.getVector3()), 0);
00537     } else {
00538         return Vector4(matrix4_transformed_point(transform, viewer.getVector3()), viewer[3]);
00539     }
00540 }
00541 
00542 inline bool viewer_test_transformed_plane (const Vector4& viewer, const Plane3& plane, const Matrix4& localToWorld)
00543 {
00544 #if 0
00545     return viewer_test_plane(viewer_from_transformed_viewer(viewer, matrix4_affine_inverse(localToWorld)), plane);
00546 #else
00547     return viewer_test_plane(viewer, plane3_transformed(plane, localToWorld));
00548 #endif
00549 }
00550 
00551 inline Vector4 viewer_from_viewproj (const Matrix4& viewproj)
00552 {
00553     // get viewer pos in object coords
00554     Vector4 viewer(matrix4_transformed_vector4(matrix4_full_inverse(viewproj), Vector4(0, 0, -1, 0)));
00555     if (viewer[3] != 0) // non-affine matrix
00556     {
00557         viewer[0] /= viewer[3];
00558         viewer[1] /= viewer[3];
00559         viewer[2] /= viewer[3];
00560         viewer[3] /= viewer[3];
00561     }
00562     return viewer;
00563 }
00564 
00565 #endif

Generated by  doxygen 1.6.2