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