1 /*
2 * VMMLib - Vector & Matrix Math Lib
3 *
4 * @author Stefan Eilemann
5 *
6 * @license revised BSD license, check LICENSE
7 */
8
9 #ifndef __VMML__FRUSTUM__HPP__
10 #define __VMML__FRUSTUM__HPP__
11
12 #include <vmmlib/vmmlib_config.hpp>
13 #include <vmmlib/matrix.hpp>
14
15 #include <cmath>
16
17 // - declaration -
18
19 namespace vmml
20 {
21 template< typename T > class frustum
22 {
23 public:
24 VMMLIB_ALIGN( T array[6] );
25
26 // contructors
27 frustum(); // warning: components NOT initialised ( for performance )
28 frustum( const T left, const T right, const T bottom, const T top,
29 const T near_plane, const T far_plane );
30
31 template< typename U > frustum( const frustum< U >& source_ );
32
33 //the pointer 'values' must be a valid 6 component c array of the resp. type
34 template< typename U > frustum( const U* values );
35
36 ~frustum();
37
38 const frustum& operator=( const frustum& source_ );
39 template< typename U >
40 void operator=( const frustum< U >& source_ );
41
42 void set( const T _left, const T _right, const T _bottom,
43 const T _top, const T _near, const T _far );
44
45 // set the frustum using the same parameters as gluPerspective.
46 void set_perspective( T field_of_view_y, T aspect_ratio, T near_plane_,
47 T far_plane );
48
49 matrix< 4, 4, T > compute_matrix() const;
50 matrix< 4, 4, T > compute_ortho_matrix() const;
51
52 void compute_matrix( matrix< 4, 4, T >& matrix_ ) const;
53 void compute_ortho_matrix( matrix< 4, 4, T >& matrix_ ) const;
54 void apply_jitter( const vector< 2, T >& jitter_ );
55
56 // 'move' the frustum. this function changes the near_plane, and adjusts the
57 // other parameters in a way that the 'perspective pyramid' stays the same.
58 void adjust_near( const T near_plane );
59
60 inline T& left();
61 inline const T& left() const;
62
63 inline T& right();
64 inline const T& right() const;
65
66 inline T& bottom();
67 inline const T& bottom() const;
68
69 inline T& top();
70 inline const T& top() const;
71
72 inline T& near_plane();
73 inline const T& near_plane() const;
74
75 inline T& far_plane();
76 inline const T& far_plane() const;
77
78 inline T get_width() const;
79 inline T get_height() const;
80
operator <<(std::ostream & os,const frustum & f)81 friend std::ostream& operator << ( std::ostream& os, const frustum& f )
82 {
83 const std::ios::fmtflags flags = os.flags();
84 const int prec = os.precision();
85
86 os.setf( std::ios::right, std::ios::adjustfield );
87 os.precision( 5 );
88 os << "[" << std::setw(10) << f.left() << " "
89 << std::setw(10) << f.right() << " "
90 << std::setw(10) << f.bottom() << " "
91 << std::setw(10) << f.top() << " "
92 << std::setw(10) << f.near_plane() << " "
93 << std::setw(10) << f.far_plane() << "]";
94 os.precision( prec );
95 os.setf( flags );
96 return os;
97 };
98
99 static const frustum DEFAULT;
100 };
101
102 #ifndef VMMLIB_NO_TYPEDEFS
103 typedef frustum< float > frustumf;
104 typedef frustum< double > frustumd;
105 #endif
106
107 } // namespace vmml
108
109 // - implementation - //
110
111 namespace vmml
112 {
113
114 template< typename T >
115 const frustum< T > frustum< T >::DEFAULT( static_cast< T >( -1.0 ),
116 static_cast< T >( 1.0 ),
117 static_cast< T >( -1.0 ),
118 static_cast< T >( 1.0 ),
119 static_cast< T >( 0.1 ),
120 static_cast< T >( 100.0 ) );
121
122
123
124 template < typename T >
frustum()125 frustum< T >::frustum()
126 {}
127
128
129
130 template < typename T >
frustum(const T _left,const T _right,const T _bottom,const T _top,const T _near,const T _far)131 frustum<T>::frustum( const T _left, const T _right, const T _bottom,
132 const T _top, const T _near, const T _far )
133 {
134 set( _left, _right, _bottom, _top, _near, _far );
135 }
136
137
138 template < typename T >
139 template< typename U >
frustum(const frustum<U> & source_)140 frustum< T >::frustum( const frustum< U >& source_ )
141 {
142 (*this) = source_;
143 }
144
145
146
147 template < typename T >
148 template< typename U >
frustum(const U * values)149 frustum< T >::frustum( const U* values )
150 {
151 assert( values &&
152 "frustum: Nullpointer argument as source for initialisation!" );
153 left() = static_cast< T > ( values[0] );
154 right() = static_cast< T > ( values[1] );
155 bottom() = static_cast< T > ( values[2] );
156 top() = static_cast< T > ( values[3] );
157 near_plane() = static_cast< T > ( values[4] );
158 far_plane() = static_cast< T > ( values[5] );
159 }
160
161
162
163 template < typename T >
~frustum()164 frustum< T >::~frustum()
165 {}
166
167
168
169 template< typename T >
170 const frustum< T >&
operator =(const frustum & source_)171 frustum< T >::operator=( const frustum& source_ )
172 {
173 memcpy( array, source_.array, 6 * sizeof( T ) );
174 return *this;
175 }
176
177 template< typename T > template< typename U >
operator =(const frustum<U> & source_)178 void frustum< T >::operator = ( const frustum< U >& source_ )
179 {
180 for( size_t index = 0; index < 6; ++index )
181 {
182 array[ index ] = static_cast< T >( source_.array[ index ] );
183 }
184 }
185
186
187
188 template < typename T >
189 void
set(const T _left,const T _right,const T _bottom,const T _top,const T _near,const T _far)190 frustum< T >::set( const T _left, const T _right, const T _bottom,
191 const T _top, const T _near, const T _far )
192 {
193 left() = _left;
194 right() = _right;
195 bottom() = _bottom;
196 top() = _top;
197 near_plane() = _near;
198 far_plane() = _far;
199 }
200
201
202 // 'move' the frustum. this function changes the near_plane, and adjusts the
203 // other parameters in a way that the 'perspective pyramid' stays the same.
204 template < typename T >
205 void
adjust_near(const T new_near)206 frustum<T>::adjust_near( const T new_near )
207 {
208 if( new_near == near_plane() )
209 return;
210
211 const T ratio = new_near / near_plane();
212 right() *= ratio;
213 left() *= ratio;
214 top() *= ratio;
215 bottom() *= ratio;
216 near_plane() = new_near;
217 }
218
219
220
221 // set the frustum using the same parameters as gluPerspective.
222 template < typename T >
223 void
set_perspective(T fov_y,T aspect_ratio,T near_plane_,T far_plane_)224 frustum<T>::set_perspective( T fov_y, T aspect_ratio, T near_plane_,
225 T far_plane_ )
226 {
227 near_plane() = near_plane_;
228 far_plane() = far_plane_;
229
230 top() = tan( 0.5 * fov_y * M_PI / 180.0 ) * 0.5;
231 bottom() = - top();
232
233 left() = bottom() * aspect_ratio;
234 right() = top() * aspect_ratio;
235 }
236
237
238
239 template < typename T >
240 matrix< 4, 4, T >
compute_matrix() const241 frustum<T>::compute_matrix() const
242 {
243 matrix< 4, 4, T > matrix_;
244 compute_matrix( matrix_ );
245 return matrix_;
246 }
247
248
249
250 template < typename T >
251 void
compute_matrix(matrix<4,4,T> & M) const252 frustum<T>::compute_matrix( matrix< 4, 4, T >& M ) const
253 {
254 M( 0,0 ) = 2.0 * near_plane() / ( right() - left() );
255 M( 0,1 ) = 0.0;
256 M( 0,2 ) = ( right() + left() ) / ( right() - left() );
257 M( 0,3 ) = 0.0;
258
259 M( 1,0 ) = 0.0;
260 M( 1,1 ) = 2.0 * near_plane() / ( top() - bottom() );
261 M( 1,2 ) = ( top() + bottom() ) / ( top() - bottom() );
262 M( 1,3 ) = 0.0;
263
264 M( 2,0 ) = 0.0;
265 M( 2,1 ) = 0.0;
266 // NOTE: Some glfrustum man pages say wrongly '(far + near) / (far - near)'
267 M( 2,2 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() );
268 M( 2,3 ) = -2.0 * far_plane() * near_plane() / ( far_plane() - near_plane() );
269
270 M( 3,0 ) = 0.0;
271 M( 3,1 ) = 0.0;
272 M( 3,2 ) = -1.0;
273 M( 3,3 ) = 0.0;
274 }
275
276
277
278 template < typename T >
279 matrix< 4, 4, T >
compute_ortho_matrix() const280 frustum< T >::compute_ortho_matrix() const
281 {
282 matrix< 4, 4, T > matrix_;
283 compute_ortho_matrix( matrix_ );
284 return matrix_;
285 }
286
287
288
289 template < typename T >
290 void
compute_ortho_matrix(matrix<4,4,T> & M) const291 frustum< T >::compute_ortho_matrix( matrix< 4, 4, T >& M ) const
292 {
293 M( 0,0 ) = 2.0 / ( right() - left() );
294 M( 0,1 ) = 0.0;
295 M( 0,2 ) = 0.0;
296 M( 0,3 ) = -( right() + left() ) / ( right() - left() );
297
298 M( 1,0 ) = 0.0;
299 M( 1,1 ) = 2.0 / ( top() - bottom() );
300 M( 1,2 ) = 0.0f;
301 M( 1,3 ) = -( top() + bottom() ) / ( top() - bottom() );
302
303 M( 2,0 ) = 0.0;
304 M( 2,1 ) = 0.0;
305 M( 2,2 ) = -2.0 / ( far_plane() - near_plane() );
306 M( 2,3 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() );
307
308 M( 3,0 ) = 0.0;
309 M( 3,1 ) = 0.0;
310 M( 3,2 ) = 0.0;
311 M( 3,3 ) = 1.0f;
312 }
313
314 template < typename T >
apply_jitter(const vector<2,T> & jitter_)315 void frustum< T >::apply_jitter( const vector< 2, T >& jitter_ )
316 {
317 left() = left() + jitter_.x();
318 right() = right() + jitter_.x();
319 bottom() = bottom() + jitter_.y();
320 top() = top() + jitter_.y();
321 }
322
323 template< typename T >
left()324 inline T& frustum< T >::left()
325 {
326 return array[ 0 ];
327 }
328
329 template< typename T >
left() const330 inline const T& frustum< T >::left() const
331 {
332 return array[ 0 ];
333 }
334
335 template< typename T >
right()336 inline T& frustum< T >::right()
337 {
338 return array[ 1 ];
339 }
340
341 template< typename T >
right() const342 inline const T& frustum< T >::right() const
343 {
344 return array[ 1 ];
345 }
346
347 template< typename T >
bottom()348 inline T& frustum< T >::bottom()
349 {
350 return array[ 2 ];
351 }
352
353 template< typename T >
bottom() const354 inline const T& frustum< T >::bottom() const
355 {
356 return array[ 2 ];
357 }
358
359 template< typename T >
top()360 inline T& frustum< T >::top()
361 {
362 return array[ 3 ];
363 }
364
365 template< typename T >
top() const366 inline const T& frustum< T >::top() const
367 {
368 return array[ 3 ];
369 }
370
371 template< typename T >
near_plane()372 inline T& frustum< T >::near_plane()
373 {
374 return array[ 4 ];
375 }
376
377 template< typename T >
near_plane() const378 inline const T& frustum< T >::near_plane() const
379 {
380 return array[ 4 ];
381 }
382
383 template< typename T >
far_plane()384 inline T& frustum< T >::far_plane()
385 {
386 return array[ 5 ];
387 }
388
389 template< typename T >
far_plane() const390 inline const T& frustum< T >::far_plane() const
391 {
392 return array[ 5 ];
393 }
394
get_width() const395 template< typename T > inline T frustum< T >::get_width() const
396 {
397 return fabs( right() - left( ));
398 }
399
get_height() const400 template< typename T > inline T frustum< T >::get_height() const
401 {
402 return fabs( top() - bottom( ));
403 }
404
405
406 } //namespace vmml
407
408 #endif
409