]> Dogcows Code - chaz/yoink/blob - src/Moof/cml/mathlib/frustum.h
bugfix: win32 packaging script temp directories
[chaz/yoink] / src / Moof / cml / mathlib / frustum.h
1 /* -*- C++ -*- ------------------------------------------------------------
2
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
4
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
7
8 *-----------------------------------------------------------------------*/
9 /** @file
10 * @brief
11 */
12
13 #ifndef frustum_h
14 #define frustum_h
15
16 #include <cml/mathlib/matrix_concat.h>
17 #include <cml/mathlib/checking.h>
18
19 namespace cml {
20
21 /* @todo: plane class, and perhaps named arguments instead of an array. */
22
23 /* Extract the planes of a frustum given a modelview matrix and a projection
24 * matrix with the given near z-clipping range. The planes are normalized by
25 * default, but this can be turned off with the 'normalize' argument.
26 *
27 * The planes are in ax+by+cz+d = 0 form, and are in the order:
28 * left
29 * right
30 * bottom
31 * top
32 * near
33 * far
34 */
35
36 template < class MatT, typename Real > void
37 extract_frustum_planes(
38 const MatT& modelview,
39 const MatT& projection,
40 Real planes[6][4],
41 ZClip z_clip,
42 bool normalize = true)
43 {
44 extract_frustum_planes(
45 detail::matrix_concat_transforms_4x4(modelview,projection),
46 planes,
47 z_clip,
48 normalize
49 );
50 }
51
52 /* Extract the planes of a frustum from a single matrix assumed to contain any
53 * model and view transforms followed by a projection transform with the given
54 * near z-cliping range. The planes are normalized by default, but this can be
55 * turned off with the 'normalize' argument.
56 *
57 * The planes are in ax+by+cz+d = 0 form, and are in the order:
58 * left
59 * right
60 * bottom
61 * top
62 * near
63 * far
64 */
65
66 template < class MatT, typename Real > void
67 extract_frustum_planes(
68 const MatT& m,
69 Real planes[6][4],
70 ZClip z_clip,
71 bool normalize = true)
72 {
73 detail::CheckMatHomogeneous3D(m);
74
75 /* Left: [03+00, 13+10, 23+20, 33+30] */
76
77 planes[0][0] = m.basis_element(0,3) + m.basis_element(0,0);
78 planes[0][1] = m.basis_element(1,3) + m.basis_element(1,0);
79 planes[0][2] = m.basis_element(2,3) + m.basis_element(2,0);
80 planes[0][3] = m.basis_element(3,3) + m.basis_element(3,0);
81
82 /* Right: [03-00, 13-10, 23-20, 33-30] */
83
84 planes[1][0] = m.basis_element(0,3) - m.basis_element(0,0);
85 planes[1][1] = m.basis_element(1,3) - m.basis_element(1,0);
86 planes[1][2] = m.basis_element(2,3) - m.basis_element(2,0);
87 planes[1][3] = m.basis_element(3,3) - m.basis_element(3,0);
88
89 /* Bottom: [03+01, 13+11, 23+21, 33+31] */
90
91 planes[2][0] = m.basis_element(0,3) + m.basis_element(0,1);
92 planes[2][1] = m.basis_element(1,3) + m.basis_element(1,1);
93 planes[2][2] = m.basis_element(2,3) + m.basis_element(2,1);
94 planes[2][3] = m.basis_element(3,3) + m.basis_element(3,1);
95
96 /* Top: [03-01, 13-11, 23-21, 33-31] */
97
98 planes[3][0] = m.basis_element(0,3) - m.basis_element(0,1);
99 planes[3][1] = m.basis_element(1,3) - m.basis_element(1,1);
100 planes[3][2] = m.basis_element(2,3) - m.basis_element(2,1);
101 planes[3][3] = m.basis_element(3,3) - m.basis_element(3,1);
102
103 /* Far: [03-02, 13-12, 23-22, 33-32] */
104
105 planes[5][0] = m.basis_element(0,3) - m.basis_element(0,2);
106 planes[5][1] = m.basis_element(1,3) - m.basis_element(1,2);
107 planes[5][2] = m.basis_element(2,3) - m.basis_element(2,2);
108 planes[5][3] = m.basis_element(3,3) - m.basis_element(3,2);
109
110 /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */
111 extract_near_frustum_plane(m, planes[4], z_clip);
112
113 /* @todo: This will be handled by the plane class */
114 if (normalize) {
115 for (size_t i = 0; i < 6; ++i) {
116 Real invl = inv_sqrt(planes[i][0] * planes[i][0] +
117 planes[i][1] * planes[i][1] +
118 planes[i][2] * planes[i][2]);
119
120 planes[i][0] *= invl;
121 planes[i][1] *= invl;
122 planes[i][2] *= invl;
123 planes[i][3] *= invl;
124 }
125 }
126 }
127
128 /** Extract the near plane of a frustum given a concatenated modelview and
129 * projection matrix with the given near z-clipping range. The plane is
130 * not normalized.
131 *
132 * @note The plane is in ax+by+cz+d = 0 form.
133 *
134 * @warning The matrix is assumed to be a homogeneous transformation
135 * matrix.
136 */
137 template < class MatT, class PlaneT > void
138 extract_near_frustum_plane(
139 const MatT& m,
140 PlaneT& plane,
141 ZClip z_clip
142 )
143 {
144 /* Near: [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */
145 if (z_clip == z_clip_neg_one) {
146 plane[0] = m.basis_element(0,3) + m.basis_element(0,2);
147 plane[1] = m.basis_element(1,3) + m.basis_element(1,2);
148 plane[2] = m.basis_element(2,3) + m.basis_element(2,2);
149 plane[3] = m.basis_element(3,3) + m.basis_element(3,2);
150 } else { // z_clip == z_clip_zero
151 plane[0] = m.basis_element(0,2);
152 plane[1] = m.basis_element(1,2);
153 plane[2] = m.basis_element(2,2);
154 plane[3] = m.basis_element(3,2);
155 }
156 }
157
158 namespace detail {
159
160 /* This is currently only in support of finding the corners of a frustum.
161 * The input planes are assumed to have a single unique intersection, so
162 * no tolerance is used.
163 */
164
165 template < typename Real > vector< Real, fixed<3> >
166 intersect_planes(Real p1[4], Real p2[4], Real p3[4])
167 {
168 typedef vector< Real, fixed<3> > vector_type;
169 typedef typename vector_type::value_type value_type;
170
171 vector_type n1(p1[0],p1[1],p1[2]);
172 vector_type n2(p2[0],p2[1],p2[2]);
173 vector_type n3(p3[0],p3[1],p3[2]);
174
175 value_type d1 = -p1[3];
176 value_type d2 = -p2[3];
177 value_type d3 = -p3[3];
178
179 vector_type numer =
180 d1*cross(n2,n3) + d2*cross(n3,n1) + d3*cross(n1,n2);
181 value_type denom = triple_product(n1,n2,n3);
182 return numer/denom;
183 }
184
185 } // namespace detail
186
187 /* Get the corners of a frustum defined by 6 planes. The planes are in
188 * ax+by+cz+d = 0 form, and are in the order:
189 * left
190 * right
191 * bottom
192 * top
193 * near
194 * far
195 *
196 * The corners are in CCW order starting in the lower-left, first at the near
197 * plane, then at the far plane.
198 */
199
200 template < typename Real, typename E, class A > void
201 get_frustum_corners(Real planes[6][4], vector<E,A> corners[8])
202 {
203 // NOTE: Prefixed with 'PLANE_' due to symbol conflict with Windows
204 // macros PLANE_LEFT and PLANE_RIGHT.
205 enum {
206 PLANE_LEFT,
207 PLANE_RIGHT,
208 PLANE_BOTTOM,
209 PLANE_TOP,
210 PLANE_NEAR,
211 PLANE_FAR
212 };
213
214 corners[0] = detail::intersect_planes(
215 planes[PLANE_LEFT],
216 planes[PLANE_BOTTOM],
217 planes[PLANE_NEAR]
218 );
219 corners[1] = detail::intersect_planes(
220 planes[PLANE_RIGHT],
221 planes[PLANE_BOTTOM],
222 planes[PLANE_NEAR]
223 );
224 corners[2] = detail::intersect_planes(
225 planes[PLANE_RIGHT],
226 planes[PLANE_TOP],
227 planes[PLANE_NEAR]
228 );
229 corners[3] = detail::intersect_planes(
230 planes[PLANE_LEFT],
231 planes[PLANE_TOP],
232 planes[PLANE_NEAR]
233 );
234 corners[4] = detail::intersect_planes(
235 planes[PLANE_LEFT],
236 planes[PLANE_BOTTOM],
237 planes[PLANE_FAR]
238 );
239 corners[5] = detail::intersect_planes(
240 planes[PLANE_RIGHT],
241 planes[PLANE_BOTTOM],
242 planes[PLANE_FAR]
243 );
244 corners[6] = detail::intersect_planes(
245 planes[PLANE_RIGHT],
246 planes[PLANE_TOP],
247 planes[PLANE_FAR]
248 );
249 corners[7] = detail::intersect_planes(
250 planes[PLANE_LEFT],
251 planes[PLANE_TOP],
252 planes[PLANE_FAR]
253 );
254 }
255
256 } // namespace cml
257
258 #endif
This page took 0.042925 seconds and 4 git commands to generate.