1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #if !defined( INCLUDED_MATH_FRUSTUM_H )
23 #define INCLUDED_MATH_FRUSTUM_H
24
25 /// \file
26 /// \brief View-frustum data types and related operations.
27
28 #include "generic/enumeration.h"
29 #include "math/matrix.h"
30 #include "math/plane.h"
31 #include "math/aabb.h"
32 #include "math/line.h"
33
matrix4_frustum(float left,float right,float bottom,float top,float nearval,float farval)34 inline Matrix4 matrix4_frustum( float left, float right, float bottom, float top, float nearval, float farval ){
35 return Matrix4(
36 static_cast<float>( ( 2 * nearval ) / ( right - left ) ),
37 0,
38 0,
39 0,
40 0,
41 static_cast<float>( ( 2 * nearval ) / ( top - bottom ) ),
42 0,
43 0,
44 static_cast<float>( ( right + left ) / ( right - left ) ),
45 static_cast<float>( ( top + bottom ) / ( top - bottom ) ),
46 static_cast<float>( -( farval + nearval ) / ( farval - nearval ) ),
47 -1,
48 0,
49 0,
50 static_cast<float>( -( 2 * farval * nearval ) / ( farval - nearval ) ),
51 0
52 );
53 }
54
55
56
57 typedef unsigned char ClipResult;
58 const ClipResult c_CLIP_PASS = 0x00; // 000000
59 const ClipResult c_CLIP_LT_X = 0x01; // 000001
60 const ClipResult c_CLIP_GT_X = 0x02; // 000010
61 const ClipResult c_CLIP_LT_Y = 0x04; // 000100
62 const ClipResult c_CLIP_GT_Y = 0x08; // 001000
63 const ClipResult c_CLIP_LT_Z = 0x10; // 010000
64 const ClipResult c_CLIP_GT_Z = 0x20; // 100000
65 const ClipResult c_CLIP_FAIL = 0x3F; // 111111
66
67 template<typename Index>
68 class Vector4ClipLT
69 {
70 public:
compare(const Vector4 & self)71 static bool compare( const Vector4& self ){
72 return self[Index::VALUE] < self[3];
73 }
scale(const Vector4 & self,const Vector4 & other)74 static double scale( const Vector4& self, const Vector4& other ){
75 return ( self[Index::VALUE] - self[3] ) / ( other[3] - other[Index::VALUE] );
76 }
77 };
78
79 template<typename Index>
80 class Vector4ClipGT
81 {
82 public:
compare(const Vector4 & self)83 static bool compare( const Vector4& self ){
84 return self[Index::VALUE] > -self[3];
85 }
scale(const Vector4 & self,const Vector4 & other)86 static double scale( const Vector4& self, const Vector4& other ){
87 return ( self[Index::VALUE] + self[3] ) / ( -other[3] - other[Index::VALUE] );
88 }
89 };
90
91 template<typename ClipPlane>
92 class Vector4ClipPolygon
93 {
94 public:
95 typedef Vector4* iterator;
96 typedef const Vector4* const_iterator;
97
apply(const_iterator first,const_iterator last,iterator out)98 static std::size_t apply( const_iterator first, const_iterator last, iterator out ){
99 const_iterator next = first, i = last - 1;
100 iterator tmp( out );
101 bool b0 = ClipPlane::compare( *i );
102 while ( next != last )
103 {
104 bool b1 = ClipPlane::compare( *next );
105 if ( b0 ^ b1 ) {
106 *out = vector4_subtracted( *next, *i );
107
108 double scale = ClipPlane::scale( *i, *out );
109
110 ( *out )[0] = static_cast<float>( ( *i )[0] + scale * ( ( *out )[0] ) );
111 ( *out )[1] = static_cast<float>( ( *i )[1] + scale * ( ( *out )[1] ) );
112 ( *out )[2] = static_cast<float>( ( *i )[2] + scale * ( ( *out )[2] ) );
113 ( *out )[3] = static_cast<float>( ( *i )[3] + scale * ( ( *out )[3] ) );
114
115 ++out;
116 }
117
118 if ( b1 ) {
119 *out = *next;
120 ++out;
121 }
122
123 i = next;
124 ++next;
125 b0 = b1;
126 }
127
128 return out - tmp;
129 }
130 };
131
132 #define CLIP_X_LT_W( p ) ( Vector4ClipLT< IntegralConstant<0> >::compare( p ) )
133 #define CLIP_X_GT_W( p ) ( Vector4ClipGT< IntegralConstant<0> >::compare( p ) )
134 #define CLIP_Y_LT_W( p ) ( Vector4ClipLT< IntegralConstant<1> >::compare( p ) )
135 #define CLIP_Y_GT_W( p ) ( Vector4ClipGT< IntegralConstant<1> >::compare( p ) )
136 #define CLIP_Z_LT_W( p ) ( Vector4ClipLT< IntegralConstant<2> >::compare( p ) )
137 #define CLIP_Z_GT_W( p ) ( Vector4ClipGT< IntegralConstant<2> >::compare( p ) )
138
homogenous_clip_point(const Vector4 & clipped)139 inline ClipResult homogenous_clip_point( const Vector4& clipped ){
140 ClipResult result = c_CLIP_FAIL;
141 if ( CLIP_X_LT_W( clipped ) ) {
142 result &= ~c_CLIP_LT_X; // X < W
143 }
144 if ( CLIP_X_GT_W( clipped ) ) {
145 result &= ~c_CLIP_GT_X; // X > -W
146 }
147 if ( CLIP_Y_LT_W( clipped ) ) {
148 result &= ~c_CLIP_LT_Y; // Y < W
149 }
150 if ( CLIP_Y_GT_W( clipped ) ) {
151 result &= ~c_CLIP_GT_Y; // Y > -W
152 }
153 if ( CLIP_Z_LT_W( clipped ) ) {
154 result &= ~c_CLIP_LT_Z; // Z < W
155 }
156 if ( CLIP_Z_GT_W( clipped ) ) {
157 result &= ~c_CLIP_GT_Z; // Z > -W
158 }
159 return result;
160 }
161
162 /// \brief Clips \p point by canonical matrix \p self.
163 /// Stores the result in \p clipped.
164 /// Returns a bitmask indicating which clip-planes the point was outside.
matrix4_clip_point(const Matrix4 & self,const Vector3 & point,Vector4 & clipped)165 inline ClipResult matrix4_clip_point( const Matrix4& self, const Vector3& point, Vector4& clipped ){
166 clipped[0] = point[0];
167 clipped[1] = point[1];
168 clipped[2] = point[2];
169 clipped[3] = 1;
170 matrix4_transform_vector4( self, clipped );
171 return homogenous_clip_point( clipped );
172 }
173
174
homogenous_clip_triangle(Vector4 clipped[9])175 inline std::size_t homogenous_clip_triangle( Vector4 clipped[9] ){
176 Vector4 buffer[9];
177 std::size_t count = 3;
178 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<0> > >::apply( clipped, clipped + count, buffer );
179 count = Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<0> > >::apply( buffer, buffer + count, clipped );
180 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<1> > >::apply( clipped, clipped + count, buffer );
181 count = Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<1> > >::apply( buffer, buffer + count, clipped );
182 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<2> > >::apply( clipped, clipped + count, buffer );
183 return Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<2> > >::apply( buffer, buffer + count, clipped );
184 }
185
186 /// \brief Transforms and clips the triangle formed by \p p0, \p p1, \p p2 by the canonical matrix \p self.
187 /// Stores the resulting polygon in \p clipped.
188 /// Returns the number of points in the resulting polygon.
matrix4_clip_triangle(const Matrix4 & self,const Vector3 & p0,const Vector3 & p1,const Vector3 & p2,Vector4 clipped[9])189 inline std::size_t matrix4_clip_triangle( const Matrix4& self, const Vector3& p0, const Vector3& p1, const Vector3& p2, Vector4 clipped[9] ){
190 clipped[0][0] = p0[0];
191 clipped[0][1] = p0[1];
192 clipped[0][2] = p0[2];
193 clipped[0][3] = 1;
194 clipped[1][0] = p1[0];
195 clipped[1][1] = p1[1];
196 clipped[1][2] = p1[2];
197 clipped[1][3] = 1;
198 clipped[2][0] = p2[0];
199 clipped[2][1] = p2[1];
200 clipped[2][2] = p2[2];
201 clipped[2][3] = 1;
202
203 matrix4_transform_vector4( self, clipped[0] );
204 matrix4_transform_vector4( self, clipped[1] );
205 matrix4_transform_vector4( self, clipped[2] );
206
207 return homogenous_clip_triangle( clipped );
208 }
209
homogenous_clip_line(Vector4 clipped[2])210 inline std::size_t homogenous_clip_line( Vector4 clipped[2] ){
211 const Vector4& p0 = clipped[0];
212 const Vector4& p1 = clipped[1];
213
214 // early out
215 {
216 ClipResult mask0 = homogenous_clip_point( clipped[0] );
217 ClipResult mask1 = homogenous_clip_point( clipped[1] );
218
219 if ( ( mask0 | mask1 ) == c_CLIP_PASS ) { // both points passed all planes
220 return 2;
221 }
222
223 if ( mask0 & mask1 ) { // both points failed any one plane
224 return 0;
225 }
226 }
227
228 {
229 const bool index = CLIP_X_LT_W( p0 );
230 if ( index ^ CLIP_X_LT_W( p1 ) ) {
231 Vector4 clip( vector4_subtracted( p1, p0 ) );
232
233 double scale = ( p0[0] - p0[3] ) / ( clip[3] - clip[0] );
234
235 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
236 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
237 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
238 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
239
240 clipped[index] = clip;
241 }
242 else if ( index == 0 ) {
243 return 0;
244 }
245 }
246
247 {
248 const bool index = CLIP_X_GT_W( p0 );
249 if ( index ^ CLIP_X_GT_W( p1 ) ) {
250 Vector4 clip( vector4_subtracted( p1, p0 ) );
251
252 double scale = ( p0[0] + p0[3] ) / ( -clip[3] - clip[0] );
253
254 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
255 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
256 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
257 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
258
259 clipped[index] = clip;
260 }
261 else if ( index == 0 ) {
262 return 0;
263 }
264 }
265
266 {
267 const bool index = CLIP_Y_LT_W( p0 );
268 if ( index ^ CLIP_Y_LT_W( p1 ) ) {
269 Vector4 clip( vector4_subtracted( p1, p0 ) );
270
271 double scale = ( p0[1] - p0[3] ) / ( clip[3] - clip[1] );
272
273 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
274 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
275 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
276 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
277
278 clipped[index] = clip;
279 }
280 else if ( index == 0 ) {
281 return 0;
282 }
283 }
284
285 {
286 const bool index = CLIP_Y_GT_W( p0 );
287 if ( index ^ CLIP_Y_GT_W( p1 ) ) {
288 Vector4 clip( vector4_subtracted( p1, p0 ) );
289
290 double scale = ( p0[1] + p0[3] ) / ( -clip[3] - clip[1] );
291
292 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
293 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
294 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
295 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
296
297 clipped[index] = clip;
298 }
299 else if ( index == 0 ) {
300 return 0;
301 }
302 }
303
304 {
305 const bool index = CLIP_Z_LT_W( p0 );
306 if ( index ^ CLIP_Z_LT_W( p1 ) ) {
307 Vector4 clip( vector4_subtracted( p1, p0 ) );
308
309 double scale = ( p0[2] - p0[3] ) / ( clip[3] - clip[2] );
310
311 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
312 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
313 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
314 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
315
316 clipped[index] = clip;
317 }
318 else if ( index == 0 ) {
319 return 0;
320 }
321 }
322
323 {
324 const bool index = CLIP_Z_GT_W( p0 );
325 if ( index ^ CLIP_Z_GT_W( p1 ) ) {
326 Vector4 clip( vector4_subtracted( p1, p0 ) );
327
328 double scale = ( p0[2] + p0[3] ) / ( -clip[3] - clip[2] );
329
330 clip[0] = static_cast<float>( p0[0] + scale * clip[0] );
331 clip[1] = static_cast<float>( p0[1] + scale * clip[1] );
332 clip[2] = static_cast<float>( p0[2] + scale * clip[2] );
333 clip[3] = static_cast<float>( p0[3] + scale * clip[3] );
334
335 clipped[index] = clip;
336 }
337 else if ( index == 0 ) {
338 return 0;
339 }
340 }
341
342 return 2;
343 }
344
345 /// \brief Transforms and clips the line formed by \p p0, \p p1 by the canonical matrix \p self.
346 /// Stores the resulting line in \p clipped.
347 /// Returns the number of points in the resulting line.
matrix4_clip_line(const Matrix4 & self,const Vector3 & p0,const Vector3 & p1,Vector4 clipped[2])348 inline std::size_t matrix4_clip_line( const Matrix4& self, const Vector3& p0, const Vector3& p1, Vector4 clipped[2] ){
349 clipped[0][0] = p0[0];
350 clipped[0][1] = p0[1];
351 clipped[0][2] = p0[2];
352 clipped[0][3] = 1;
353 clipped[1][0] = p1[0];
354 clipped[1][1] = p1[1];
355 clipped[1][2] = p1[2];
356 clipped[1][3] = 1;
357
358 matrix4_transform_vector4( self, clipped[0] );
359 matrix4_transform_vector4( self, clipped[1] );
360
361 return homogenous_clip_line( clipped );
362 }
363
364
365
366
367 struct Frustum
368 {
369 Plane3 right, left, bottom, top, back, front;
370
FrustumFrustum371 Frustum(){
372 }
FrustumFrustum373 Frustum( const Plane3& _right,
374 const Plane3& _left,
375 const Plane3& _bottom,
376 const Plane3& _top,
377 const Plane3& _back,
378 const Plane3& _front )
379 : right( _right ), left( _left ), bottom( _bottom ), top( _top ), back( _back ), front( _front ){
380 }
381 };
382
frustum_transformed(const Frustum & frustum,const Matrix4 & transform)383 inline Frustum frustum_transformed( const Frustum& frustum, const Matrix4& transform ){
384 return Frustum(
385 plane3_transformed( frustum.right, transform ),
386 plane3_transformed( frustum.left, transform ),
387 plane3_transformed( frustum.bottom, transform ),
388 plane3_transformed( frustum.top, transform ),
389 plane3_transformed( frustum.back, transform ),
390 plane3_transformed( frustum.front, transform )
391 );
392 }
393
frustum_inverse_transformed(const Frustum & frustum,const Matrix4 & transform)394 inline Frustum frustum_inverse_transformed( const Frustum& frustum, const Matrix4& transform ){
395 return Frustum(
396 plane3_inverse_transformed( frustum.right, transform ),
397 plane3_inverse_transformed( frustum.left, transform ),
398 plane3_inverse_transformed( frustum.bottom, transform ),
399 plane3_inverse_transformed( frustum.top, transform ),
400 plane3_inverse_transformed( frustum.back, transform ),
401 plane3_inverse_transformed( frustum.front, transform )
402 );
403 }
404
viewproj_test_point(const Matrix4 & viewproj,const Vector3 & point)405 inline bool viewproj_test_point( const Matrix4& viewproj, const Vector3& point ){
406 Vector4 hpoint( matrix4_transformed_vector4( viewproj, Vector4( point, 1.0f ) ) );
407 if ( fabs( hpoint[0] ) < fabs( hpoint[3] )
408 && fabs( hpoint[1] ) < fabs( hpoint[3] )
409 && fabs( hpoint[2] ) < fabs( hpoint[3] ) ) {
410 return true;
411 }
412 return false;
413 }
414
viewproj_test_transformed_point(const Matrix4 & viewproj,const Vector3 & point,const Matrix4 & localToWorld)415 inline bool viewproj_test_transformed_point( const Matrix4& viewproj, const Vector3& point, const Matrix4& localToWorld ){
416 return viewproj_test_point( viewproj, matrix4_transformed_point( localToWorld, point ) );
417 }
418
frustum_from_viewproj(const Matrix4 & viewproj)419 inline Frustum frustum_from_viewproj( const Matrix4& viewproj ){
420 return Frustum
421 (
422 plane3_normalised( Plane3( viewproj[ 3] - viewproj[ 0], viewproj[ 7] - viewproj[ 4], viewproj[11] - viewproj[ 8], viewproj[15] - viewproj[12] ) ),
423 plane3_normalised( Plane3( viewproj[ 3] + viewproj[ 0], viewproj[ 7] + viewproj[ 4], viewproj[11] + viewproj[ 8], viewproj[15] + viewproj[12] ) ),
424 plane3_normalised( Plane3( viewproj[ 3] + viewproj[ 1], viewproj[ 7] + viewproj[ 5], viewproj[11] + viewproj[ 9], viewproj[15] + viewproj[13] ) ),
425 plane3_normalised( Plane3( viewproj[ 3] - viewproj[ 1], viewproj[ 7] - viewproj[ 5], viewproj[11] - viewproj[ 9], viewproj[15] - viewproj[13] ) ),
426 plane3_normalised( Plane3( viewproj[ 3] - viewproj[ 2], viewproj[ 7] - viewproj[ 6], viewproj[11] - viewproj[10], viewproj[15] - viewproj[14] ) ),
427 plane3_normalised( Plane3( viewproj[ 3] + viewproj[ 2], viewproj[ 7] + viewproj[ 6], viewproj[11] + viewproj[10], viewproj[15] + viewproj[14] ) )
428 );
429 }
430
431 struct VolumeIntersection
432 {
433 enum Value
434 {
435 OUTSIDE,
436 INSIDE,
437 PARTIAL
438 };
439 };
440
441 typedef EnumeratedValue<VolumeIntersection> VolumeIntersectionValue;
442
443 const VolumeIntersectionValue c_volumeOutside( VolumeIntersectionValue::OUTSIDE );
444 const VolumeIntersectionValue c_volumeInside( VolumeIntersectionValue::INSIDE );
445 const VolumeIntersectionValue c_volumePartial( VolumeIntersectionValue::PARTIAL );
446
frustum_test_aabb(const Frustum & frustum,const AABB & aabb)447 inline VolumeIntersectionValue frustum_test_aabb( const Frustum& frustum, const AABB& aabb ){
448 VolumeIntersectionValue result = c_volumeInside;
449
450 switch ( aabb_classify_plane( aabb, frustum.right ) )
451 {
452 case 2:
453 return c_volumeOutside;
454 case 1:
455 result = c_volumePartial;
456 }
457
458 switch ( aabb_classify_plane( aabb, frustum.left ) )
459 {
460 case 2:
461 return c_volumeOutside;
462 case 1:
463 result = c_volumePartial;
464 }
465
466 switch ( aabb_classify_plane( aabb, frustum.bottom ) )
467 {
468 case 2:
469 return c_volumeOutside;
470 case 1:
471 result = c_volumePartial;
472 }
473
474 switch ( aabb_classify_plane( aabb, frustum.top ) )
475 {
476 case 2:
477 return c_volumeOutside;
478 case 1:
479 result = c_volumePartial;
480 }
481
482 switch ( aabb_classify_plane( aabb, frustum.back ) )
483 {
484 case 2:
485 return c_volumeOutside;
486 case 1:
487 result = c_volumePartial;
488 }
489
490 switch ( aabb_classify_plane( aabb, frustum.front ) )
491 {
492 case 2:
493 return c_volumeOutside;
494 case 1:
495 result = c_volumePartial;
496 }
497
498 return result;
499 }
500
plane_distance_to_point(const Plane3 & plane,const Vector3 & point)501 inline double plane_distance_to_point( const Plane3& plane, const Vector3& point ){
502 return vector3_dot( plane.normal(), point ) + plane.d;
503 }
504
plane_distance_to_oriented_extents(const Plane3 & plane,const Vector3 & extents,const Matrix4 & orientation)505 inline double plane_distance_to_oriented_extents( const Plane3& plane, const Vector3& extents, const Matrix4& orientation ){
506 return fabs( extents[0] * vector3_dot( plane.normal(), vector4_to_vector3( orientation.x() ) ) )
507 + fabs( extents[1] * vector3_dot( plane.normal(), vector4_to_vector3( orientation.y() ) ) )
508 + fabs( extents[2] * vector3_dot( plane.normal(), vector4_to_vector3( orientation.z() ) ) );
509 }
510
511 /// \brief Return false if \p aabb with \p orientation is partially or completely outside \p plane.
plane_contains_oriented_aabb(const Plane3 & plane,const AABB & aabb,const Matrix4 & orientation)512 inline bool plane_contains_oriented_aabb( const Plane3& plane, const AABB& aabb, const Matrix4& orientation ){
513 double dot = plane_distance_to_point( plane, aabb.origin );
514 return !( dot > 0 || -dot < plane_distance_to_oriented_extents( plane, aabb.extents, orientation ) );
515 }
516
frustum_intersects_transformed_aabb(const Frustum & frustum,const AABB & aabb,const Matrix4 & localToWorld)517 inline VolumeIntersectionValue frustum_intersects_transformed_aabb( const Frustum& frustum, const AABB& aabb, const Matrix4& localToWorld ){
518 AABB aabb_world( aabb );
519 matrix4_transform_point( localToWorld, aabb_world.origin );
520
521 if ( plane_contains_oriented_aabb( frustum.right, aabb_world, localToWorld )
522 || plane_contains_oriented_aabb( frustum.left, aabb_world, localToWorld )
523 || plane_contains_oriented_aabb( frustum.bottom, aabb_world, localToWorld )
524 || plane_contains_oriented_aabb( frustum.top, aabb_world, localToWorld )
525 || plane_contains_oriented_aabb( frustum.back, aabb_world, localToWorld )
526 || plane_contains_oriented_aabb( frustum.front, aabb_world, localToWorld ) ) {
527 return c_volumeOutside;
528 }
529 return c_volumeInside;
530 }
531
plane3_test_point(const Plane3 & plane,const Vector3 & point)532 inline bool plane3_test_point( const Plane3& plane, const Vector3& point ){
533 return vector3_dot( point, plane.normal() ) + plane.dist() <= 0;
534 }
535
plane3_test_line(const Plane3 & plane,const Segment & segment)536 inline bool plane3_test_line( const Plane3& plane, const Segment& segment ){
537 return segment_classify_plane( segment, plane ) == 2;
538 }
539
frustum_test_point(const Frustum & frustum,const Vector3 & point)540 inline bool frustum_test_point( const Frustum& frustum, const Vector3& point ){
541 return !plane3_test_point( frustum.right, point )
542 && !plane3_test_point( frustum.left, point )
543 && !plane3_test_point( frustum.bottom, point )
544 && !plane3_test_point( frustum.top, point )
545 && !plane3_test_point( frustum.back, point )
546 && !plane3_test_point( frustum.front, point );
547 }
548
frustum_test_line(const Frustum & frustum,const Segment & segment)549 inline bool frustum_test_line( const Frustum& frustum, const Segment& segment ){
550 return !plane3_test_line( frustum.right, segment )
551 && !plane3_test_line( frustum.left, segment )
552 && !plane3_test_line( frustum.bottom, segment )
553 && !plane3_test_line( frustum.top, segment )
554 && !plane3_test_line( frustum.back, segment )
555 && !plane3_test_line( frustum.front, segment );
556 }
557
viewer_test_plane(const Vector4 & viewer,const Plane3 & plane)558 inline bool viewer_test_plane( const Vector4& viewer, const Plane3& plane ){
559 return ( ( plane.a * viewer[0] )
560 + ( plane.b * viewer[1] )
561 + ( plane.c * viewer[2] )
562 + ( plane.d * viewer[3] ) ) > 0;
563 }
564
triangle_cross(const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)565 inline Vector3 triangle_cross( const Vector3& p0, const Vector3& p1, const Vector3& p2 ){
566 return vector3_cross( vector3_subtracted( p1, p0 ), vector3_subtracted( p1, p2 ) );
567 }
568
viewer_test_triangle(const Vector4 & viewer,const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)569 inline bool viewer_test_triangle( const Vector4& viewer, const Vector3& p0, const Vector3& p1, const Vector3& p2 ){
570 Vector3 cross( triangle_cross( p0, p1, p2 ) );
571 return ( ( viewer[0] * cross[0] )
572 + ( viewer[1] * cross[1] )
573 + ( viewer[2] * cross[2] )
574 + ( viewer[3] * 0 ) ) > 0;
575 }
576
viewer_from_transformed_viewer(const Vector4 & viewer,const Matrix4 & transform)577 inline Vector4 viewer_from_transformed_viewer( const Vector4& viewer, const Matrix4& transform ){
578 if ( viewer[3] == 0 ) {
579 return Vector4( matrix4_transformed_direction( transform, vector4_to_vector3( viewer ) ), 0 );
580 }
581 else
582 {
583 return Vector4( matrix4_transformed_point( transform, vector4_to_vector3( viewer ) ), viewer[3] );
584 }
585 }
586
viewer_test_transformed_plane(const Vector4 & viewer,const Plane3 & plane,const Matrix4 & localToWorld)587 inline bool viewer_test_transformed_plane( const Vector4& viewer, const Plane3& plane, const Matrix4& localToWorld ){
588 #if 0
589 return viewer_test_plane( viewer_from_transformed_viewer( viewer, matrix4_affine_inverse( localToWorld ) ), plane );
590 #else
591 return viewer_test_plane( viewer, plane3_transformed( plane, localToWorld ) );
592 #endif
593 }
594
viewer_from_viewproj(const Matrix4 & viewproj)595 inline Vector4 viewer_from_viewproj( const Matrix4& viewproj ){
596 // get viewer pos in object coords
597 Vector4 viewer( matrix4_transformed_vector4( matrix4_full_inverse( viewproj ), Vector4( 0, 0, -1, 0 ) ) );
598 if ( viewer[3] != 0 ) { // non-affine matrix
599 viewer[0] /= viewer[3];
600 viewer[1] /= viewer[3];
601 viewer[2] /= viewer[3];
602 viewer[3] /= viewer[3];
603 }
604 return viewer;
605 }
606
607 #endif
608