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 {
36 return Matrix4(
37 static_cast<float>( (2*nearval) / (right-left) ),
38 0,
39 0,
40 0,
41 0,
42 static_cast<float>( (2*nearval) / (top-bottom) ),
43 0,
44 0,
45 static_cast<float>( (right+left) / (right-left) ),
46 static_cast<float>( (top+bottom) / (top-bottom) ),
47 static_cast<float>( -(farval+nearval) / (farval-nearval) ),
48 -1,
49 0,
50 0,
51 static_cast<float>( -(2*farval*nearval) / (farval-nearval) ),
52 0
53 );
54 }
55
56
57
58 typedef unsigned char ClipResult;
59 const ClipResult c_CLIP_PASS = 0x00; // 000000
60 const ClipResult c_CLIP_LT_X = 0x01; // 000001
61 const ClipResult c_CLIP_GT_X = 0x02; // 000010
62 const ClipResult c_CLIP_LT_Y = 0x04; // 000100
63 const ClipResult c_CLIP_GT_Y = 0x08; // 001000
64 const ClipResult c_CLIP_LT_Z = 0x10; // 010000
65 const ClipResult c_CLIP_GT_Z = 0x20; // 100000
66 const ClipResult c_CLIP_FAIL = 0x3F; // 111111
67
68 template<typename Index>
69 class Vector4ClipLT
70 {
71 public:
compare(const Vector4 & self)72 static bool compare(const Vector4& self)
73 {
74 return self[Index::VALUE] < self[3];
75 }
scale(const Vector4 & self,const Vector4 & other)76 static double scale(const Vector4& self, const Vector4& other)
77 {
78 return (self[Index::VALUE] - self[3]) / (other[3] - other[Index::VALUE]);
79 }
80 };
81
82 template<typename Index>
83 class Vector4ClipGT
84 {
85 public:
compare(const Vector4 & self)86 static bool compare(const Vector4& self)
87 {
88 return self[Index::VALUE] > -self[3];
89 }
scale(const Vector4 & self,const Vector4 & other)90 static double scale(const Vector4& self, const Vector4& other)
91 {
92 return (self[Index::VALUE] + self[3]) / (-other[3] - other[Index::VALUE]);
93 }
94 };
95
96 template<typename ClipPlane>
97 class Vector4ClipPolygon
98 {
99 public:
100 typedef Vector4* iterator;
101 typedef const Vector4* const_iterator;
102
apply(const_iterator first,const_iterator last,iterator out)103 static std::size_t apply(const_iterator first, const_iterator last, iterator out)
104 {
105 const_iterator next = first, i = last - 1;
106 iterator tmp(out);
107 bool b0 = ClipPlane::compare(*i);
108 while(next != last)
109 {
110 bool b1 = ClipPlane::compare(*next);
111 if(b0 ^ b1)
112 {
113 *out = vector4_subtracted(*next, *i);
114
115 double scale = ClipPlane::scale(*i, *out);
116
117 (*out)[0] = static_cast<float>((*i)[0] + scale*((*out)[0]));
118 (*out)[1] = static_cast<float>((*i)[1] + scale*((*out)[1]));
119 (*out)[2] = static_cast<float>((*i)[2] + scale*((*out)[2]));
120 (*out)[3] = static_cast<float>((*i)[3] + scale*((*out)[3]));
121
122 ++out;
123 }
124
125 if(b1)
126 {
127 *out = *next;
128 ++out;
129 }
130
131 i = next;
132 ++next;
133 b0 = b1;
134 }
135
136 return out - tmp;
137 }
138 };
139
140 #define CLIP_X_LT_W(p) (Vector4ClipLT< IntegralConstant<0> >::compare(p))
141 #define CLIP_X_GT_W(p) (Vector4ClipGT< IntegralConstant<0> >::compare(p))
142 #define CLIP_Y_LT_W(p) (Vector4ClipLT< IntegralConstant<1> >::compare(p))
143 #define CLIP_Y_GT_W(p) (Vector4ClipGT< IntegralConstant<1> >::compare(p))
144 #define CLIP_Z_LT_W(p) (Vector4ClipLT< IntegralConstant<2> >::compare(p))
145 #define CLIP_Z_GT_W(p) (Vector4ClipGT< IntegralConstant<2> >::compare(p))
146
homogenous_clip_point(const Vector4 & clipped)147 inline ClipResult homogenous_clip_point(const Vector4& clipped)
148 {
149 ClipResult result = c_CLIP_FAIL;
150 if(CLIP_X_LT_W(clipped)) result &= ~c_CLIP_LT_X; // X < W
151 if(CLIP_X_GT_W(clipped)) result &= ~c_CLIP_GT_X; // X > -W
152 if(CLIP_Y_LT_W(clipped)) result &= ~c_CLIP_LT_Y; // Y < W
153 if(CLIP_Y_GT_W(clipped)) result &= ~c_CLIP_GT_Y; // Y > -W
154 if(CLIP_Z_LT_W(clipped)) result &= ~c_CLIP_LT_Z; // Z < W
155 if(CLIP_Z_GT_W(clipped)) result &= ~c_CLIP_GT_Z; // Z > -W
156 return result;
157 }
158
159 /// \brief Clips \p point by canonical matrix \p self.
160 /// Stores the result in \p clipped.
161 /// Returns a bitmask indicating which clip-planes the point was outside.
matrix4_clip_point(const Matrix4 & self,const Vector3 & point,Vector4 & clipped)162 inline ClipResult matrix4_clip_point(const Matrix4& self, const Vector3& point, Vector4& clipped)
163 {
164 clipped[0] = point[0];
165 clipped[1] = point[1];
166 clipped[2] = point[2];
167 clipped[3] = 1;
168 matrix4_transform_vector4(self, clipped);
169 return homogenous_clip_point(clipped);
170 }
171
172
homogenous_clip_triangle(Vector4 clipped[9])173 inline std::size_t homogenous_clip_triangle(Vector4 clipped[9])
174 {
175 Vector4 buffer[9];
176 std::size_t count = 3;
177 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<0> > >::apply(clipped, clipped + count, buffer);
178 count = Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<0> > >::apply(buffer, buffer + count, clipped);
179 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<1> > >::apply(clipped, clipped + count, buffer);
180 count = Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<1> > >::apply(buffer, buffer + count, clipped);
181 count = Vector4ClipPolygon< Vector4ClipLT< IntegralConstant<2> > >::apply(clipped, clipped + count, buffer);
182 return Vector4ClipPolygon< Vector4ClipGT< IntegralConstant<2> > >::apply(buffer, buffer + count, clipped);
183 }
184
185 /// \brief Transforms and clips the triangle formed by \p p0, \p p1, \p p2 by the canonical matrix \p self.
186 /// Stores the resulting polygon in \p clipped.
187 /// 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])188 inline std::size_t matrix4_clip_triangle(const Matrix4& self, const Vector3& p0, const Vector3& p1, const Vector3& p2, Vector4 clipped[9])
189 {
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 {
212 const Vector4& p0 = clipped[0];
213 const Vector4& p1 = clipped[1];
214
215 // early out
216 {
217 ClipResult mask0 = homogenous_clip_point(clipped[0]);
218 ClipResult mask1 = homogenous_clip_point(clipped[1]);
219
220 if((mask0 | mask1) == c_CLIP_PASS) // both points passed all planes
221 return 2;
222
223 if(mask0 & mask1) // both points failed any one plane
224 return 0;
225 }
226
227 {
228 const bool index = CLIP_X_LT_W(p0);
229 if(index ^ CLIP_X_LT_W(p1))
230 {
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 const bool index = CLIP_X_GT_W(p0);
248 if(index ^ CLIP_X_GT_W(p1))
249 {
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 const bool index = CLIP_Y_LT_W(p0);
267 if(index ^ CLIP_Y_LT_W(p1))
268 {
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 const bool index = CLIP_Y_GT_W(p0);
286 if(index ^ CLIP_Y_GT_W(p1))
287 {
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 const bool index = CLIP_Z_LT_W(p0);
305 if(index ^ CLIP_Z_LT_W(p1))
306 {
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 const bool index = CLIP_Z_GT_W(p0);
324 if(index ^ CLIP_Z_GT_W(p1))
325 {
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 return 2;
342 }
343
344 /// \brief Transforms and clips the line formed by \p p0, \p p1 by the canonical matrix \p self.
345 /// Stores the resulting line in \p clipped.
346 /// Returns the number of points in the resulting line.
matrix4_clip_line(const Matrix4 & self,const Vector3 & p0,const Vector3 & p1,Vector4 clipped[2])347 inline std::size_t matrix4_clip_line(const Matrix4& self, const Vector3& p0, const Vector3& p1, Vector4 clipped[2])
348 {
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 {
373 }
FrustumFrustum374 Frustum(const Plane3& _right,
375 const Plane3& _left,
376 const Plane3& _bottom,
377 const Plane3& _top,
378 const Plane3& _back,
379 const Plane3& _front)
380 : right(_right), left(_left), bottom(_bottom), top(_top), back(_back), front(_front)
381 {
382 }
383 };
384
frustum_transformed(const Frustum & frustum,const Matrix4 & transform)385 inline Frustum frustum_transformed(const Frustum& frustum, const Matrix4& transform)
386 {
387 return Frustum(
388 plane3_transformed(frustum.right, transform),
389 plane3_transformed(frustum.left, transform),
390 plane3_transformed(frustum.bottom, transform),
391 plane3_transformed(frustum.top, transform),
392 plane3_transformed(frustum.back, transform),
393 plane3_transformed(frustum.front, transform)
394 );
395 }
396
frustum_inverse_transformed(const Frustum & frustum,const Matrix4 & transform)397 inline Frustum frustum_inverse_transformed(const Frustum& frustum, const Matrix4& transform)
398 {
399 return Frustum(
400 plane3_inverse_transformed(frustum.right, transform),
401 plane3_inverse_transformed(frustum.left, transform),
402 plane3_inverse_transformed(frustum.bottom, transform),
403 plane3_inverse_transformed(frustum.top, transform),
404 plane3_inverse_transformed(frustum.back, transform),
405 plane3_inverse_transformed(frustum.front, transform)
406 );
407 }
408
viewproj_test_point(const Matrix4 & viewproj,const Vector3 & point)409 inline bool viewproj_test_point(const Matrix4& viewproj, const Vector3& point)
410 {
411 Vector4 hpoint(matrix4_transformed_vector4(viewproj, Vector4(point, 1.0f)));
412 if(fabs(hpoint[0]) < fabs(hpoint[3])
413 && fabs(hpoint[1]) < fabs(hpoint[3])
414 && fabs(hpoint[2]) < fabs(hpoint[3]))
415 return true;
416 return false;
417 }
418
viewproj_test_transformed_point(const Matrix4 & viewproj,const Vector3 & point,const Matrix4 & localToWorld)419 inline bool viewproj_test_transformed_point(const Matrix4& viewproj, const Vector3& point, const Matrix4& localToWorld)
420 {
421 return viewproj_test_point(viewproj, matrix4_transformed_point(localToWorld, point));
422 }
423
frustum_from_viewproj(const Matrix4 & viewproj)424 inline Frustum frustum_from_viewproj(const Matrix4& viewproj)
425 {
426 return Frustum
427 (
428 plane3_normalised(Plane3(viewproj[ 3] - viewproj[ 0], viewproj[ 7] - viewproj[ 4], viewproj[11] - viewproj[ 8], viewproj[15] - viewproj[12])),
429 plane3_normalised(Plane3(viewproj[ 3] + viewproj[ 0], viewproj[ 7] + viewproj[ 4], viewproj[11] + viewproj[ 8], viewproj[15] + viewproj[12])),
430 plane3_normalised(Plane3(viewproj[ 3] + viewproj[ 1], viewproj[ 7] + viewproj[ 5], viewproj[11] + viewproj[ 9], viewproj[15] + viewproj[13])),
431 plane3_normalised(Plane3(viewproj[ 3] - viewproj[ 1], viewproj[ 7] - viewproj[ 5], viewproj[11] - viewproj[ 9], viewproj[15] - viewproj[13])),
432 plane3_normalised(Plane3(viewproj[ 3] - viewproj[ 2], viewproj[ 7] - viewproj[ 6], viewproj[11] - viewproj[10], viewproj[15] - viewproj[14])),
433 plane3_normalised(Plane3(viewproj[ 3] + viewproj[ 2], viewproj[ 7] + viewproj[ 6], viewproj[11] + viewproj[10], viewproj[15] + viewproj[14]))
434 );
435 }
436
437 struct VolumeIntersection
438 {
439 enum Value
440 {
441 OUTSIDE,
442 INSIDE,
443 PARTIAL
444 };
445 };
446
447 typedef EnumeratedValue<VolumeIntersection> VolumeIntersectionValue;
448
449 const VolumeIntersectionValue c_volumeOutside(VolumeIntersectionValue::OUTSIDE);
450 const VolumeIntersectionValue c_volumeInside(VolumeIntersectionValue::INSIDE);
451 const VolumeIntersectionValue c_volumePartial(VolumeIntersectionValue::PARTIAL);
452
frustum_test_aabb(const Frustum & frustum,const AABB & aabb)453 inline VolumeIntersectionValue frustum_test_aabb(const Frustum& frustum, const AABB& aabb)
454 {
455 VolumeIntersectionValue result = c_volumeInside;
456
457 switch(aabb_classify_plane(aabb, frustum.right))
458 {
459 case 2:
460 return c_volumeOutside;
461 case 1:
462 result = c_volumePartial;
463 }
464
465 switch(aabb_classify_plane(aabb, frustum.left))
466 {
467 case 2:
468 return c_volumeOutside;
469 case 1:
470 result = c_volumePartial;
471 }
472
473 switch(aabb_classify_plane(aabb, frustum.bottom))
474 {
475 case 2:
476 return c_volumeOutside;
477 case 1:
478 result = c_volumePartial;
479 }
480
481 switch(aabb_classify_plane(aabb, frustum.top))
482 {
483 case 2:
484 return c_volumeOutside;
485 case 1:
486 result = c_volumePartial;
487 }
488
489 switch(aabb_classify_plane(aabb, frustum.back))
490 {
491 case 2:
492 return c_volumeOutside;
493 case 1:
494 result = c_volumePartial;
495 }
496
497 switch(aabb_classify_plane(aabb, frustum.front))
498 {
499 case 2:
500 return c_volumeOutside;
501 case 1:
502 result = c_volumePartial;
503 }
504
505 return result;
506 }
507
plane_distance_to_point(const Plane3 & plane,const Vector3 & point)508 inline double plane_distance_to_point(const Plane3& plane, const Vector3& point)
509 {
510 return vector3_dot(plane.normal(), point) + plane.d;
511 }
512
plane_distance_to_oriented_extents(const Plane3 & plane,const Vector3 & extents,const Matrix4 & orientation)513 inline double plane_distance_to_oriented_extents(const Plane3& plane, const Vector3& extents, const Matrix4& orientation)
514 {
515 return fabs(extents[0] * vector3_dot(plane.normal(), vector4_to_vector3(orientation.x())))
516 + fabs(extents[1] * vector3_dot(plane.normal(), vector4_to_vector3(orientation.y())))
517 + fabs(extents[2] * vector3_dot(plane.normal(), vector4_to_vector3(orientation.z())));
518 }
519
520 /// \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)521 inline bool plane_contains_oriented_aabb(const Plane3& plane, const AABB& aabb, const Matrix4& orientation)
522 {
523 double dot = plane_distance_to_point(plane, aabb.origin);
524 return !(dot > 0 || -dot < plane_distance_to_oriented_extents(plane, aabb.extents, orientation));
525 }
526
frustum_intersects_transformed_aabb(const Frustum & frustum,const AABB & aabb,const Matrix4 & localToWorld)527 inline VolumeIntersectionValue frustum_intersects_transformed_aabb(const Frustum& frustum, const AABB& aabb, const Matrix4& localToWorld)
528 {
529 AABB aabb_world(aabb);
530 matrix4_transform_point(localToWorld, aabb_world.origin);
531
532 if(plane_contains_oriented_aabb(frustum.right, aabb_world, localToWorld)
533 || plane_contains_oriented_aabb(frustum.left, aabb_world, localToWorld)
534 || plane_contains_oriented_aabb(frustum.bottom, aabb_world, localToWorld)
535 || plane_contains_oriented_aabb(frustum.top, aabb_world, localToWorld)
536 || plane_contains_oriented_aabb(frustum.back, aabb_world, localToWorld)
537 || plane_contains_oriented_aabb(frustum.front, aabb_world, localToWorld))
538 return c_volumeOutside;
539 return c_volumeInside;
540 }
541
plane3_test_point(const Plane3 & plane,const Vector3 & point)542 inline bool plane3_test_point(const Plane3& plane, const Vector3& point)
543 {
544 return vector3_dot(point, plane.normal()) + plane.dist() <= 0;
545 }
546
plane3_test_line(const Plane3 & plane,const Segment & segment)547 inline bool plane3_test_line(const Plane3& plane, const Segment& segment)
548 {
549 return segment_classify_plane(segment, plane) == 2;
550 }
551
frustum_test_point(const Frustum & frustum,const Vector3 & point)552 inline bool frustum_test_point(const Frustum& frustum, const Vector3& point)
553 {
554 return !plane3_test_point(frustum.right, point)
555 && !plane3_test_point(frustum.left, point)
556 && !plane3_test_point(frustum.bottom, point)
557 && !plane3_test_point(frustum.top, point)
558 && !plane3_test_point(frustum.back, point)
559 && !plane3_test_point(frustum.front, point);
560 }
561
frustum_test_line(const Frustum & frustum,const Segment & segment)562 inline bool frustum_test_line(const Frustum& frustum, const Segment& segment)
563 {
564 return !plane3_test_line(frustum.right, segment)
565 && !plane3_test_line(frustum.left, segment)
566 && !plane3_test_line(frustum.bottom, segment)
567 && !plane3_test_line(frustum.top, segment)
568 && !plane3_test_line(frustum.back, segment)
569 && !plane3_test_line(frustum.front, segment);
570 }
571
viewer_test_plane(const Vector4 & viewer,const Plane3 & plane)572 inline bool viewer_test_plane(const Vector4& viewer, const Plane3& plane)
573 {
574 return ((plane.a * viewer[0])
575 + (plane.b * viewer[1])
576 + (plane.c * viewer[2])
577 + (plane.d * viewer[3])) > 0;
578 }
579
triangle_cross(const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)580 inline Vector3 triangle_cross(const Vector3& p0, const Vector3& p1, const Vector3& p2)
581 {
582 return vector3_cross(vector3_subtracted(p1, p0), vector3_subtracted(p1, p2));
583 }
584
viewer_test_triangle(const Vector4 & viewer,const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)585 inline bool viewer_test_triangle(const Vector4& viewer, const Vector3& p0, const Vector3& p1, const Vector3& p2)
586 {
587 Vector3 cross(triangle_cross(p0, p1, p2));
588 return ((viewer[0] * cross[0])
589 + (viewer[1] * cross[1])
590 + (viewer[2] * cross[2])
591 + (viewer[3] * 0)) > 0;
592 }
593
viewer_from_transformed_viewer(const Vector4 & viewer,const Matrix4 & transform)594 inline Vector4 viewer_from_transformed_viewer(const Vector4& viewer, const Matrix4& transform)
595 {
596 if(viewer[3] == 0)
597 {
598 return Vector4(matrix4_transformed_direction(transform, vector4_to_vector3(viewer)), 0);
599 }
600 else
601 {
602 return Vector4(matrix4_transformed_point(transform, vector4_to_vector3(viewer)), viewer[3]);
603 }
604 }
605
viewer_test_transformed_plane(const Vector4 & viewer,const Plane3 & plane,const Matrix4 & localToWorld)606 inline bool viewer_test_transformed_plane(const Vector4& viewer, const Plane3& plane, const Matrix4& localToWorld)
607 {
608 #if 0
609 return viewer_test_plane(viewer_from_transformed_viewer(viewer, matrix4_affine_inverse(localToWorld)), plane);
610 #else
611 return viewer_test_plane(viewer, plane3_transformed(plane, localToWorld));
612 #endif
613 }
614
viewer_from_viewproj(const Matrix4 & viewproj)615 inline Vector4 viewer_from_viewproj(const Matrix4& viewproj)
616 {
617 // get viewer pos in object coords
618 Vector4 viewer(matrix4_transformed_vector4(matrix4_full_inverse(viewproj), Vector4(0, 0, -1, 0)));
619 if(viewer[3] != 0) // non-affine matrix
620 {
621 viewer[0] /= viewer[3];
622 viewer[1] /= viewer[3];
623 viewer[2] /= viewer[3];
624 viewer[3] /= viewer[3];
625 }
626 return viewer;
627 }
628
629 #endif
630