vmmlib  1.7.0
 All Classes Namespaces Functions Pages
frustum.hpp
1 /*
2  * Copyright (c) 2006-2014, Visualization and Multimedia Lab,
3  * University of Zurich <http://vmml.ifi.uzh.ch>,
4  * Eyescale Software GmbH,
5  * Blue Brain Project, EPFL
6  *
7  * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer. Redistributions in binary
14  * form must reproduce the above copyright notice, this list of conditions and
15  * the following disclaimer in the documentation and/or other materials provided
16  * with the distribution. Neither the name of the Visualization and Multimedia
17  * Lab, University of Zurich nor the names of its contributors may be used to
18  * endorse or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef __VMML__FRUSTUM__HPP__
34 #define __VMML__FRUSTUM__HPP__
35 
36 #include <vmmlib/vmmlib_config.hpp>
37 #include <vmmlib/matrix.hpp>
38 
39 #include <cmath>
40 
41 // - declaration -
42 
43 namespace vmml
44 {
45 template< typename T > class frustum
46 {
47 public:
48  VMMLIB_ALIGN( T array[6] );
49 
50  // contructors
51  frustum() : array() {} // http://stackoverflow.com/questions/5602030
52  frustum( const T left, const T right, const T bottom, const T top,
53  const T near_plane, const T far_plane );
54 
55  template< typename U > frustum( const frustum< U >& source_ );
56 
57  //the pointer 'values' must be a valid 6 component c array of the resp. type
58  template< typename U > frustum( const U* values );
59 
60  ~frustum();
61 
62  frustum& operator=( const frustum& source_ );
63  template< typename U >
64  void operator=( const frustum< U >& source_ );
65 
66  void set( const T _left, const T _right, const T _bottom,
67  const T _top, const T _near, const T _far );
68 
69  // set the frustum using the same parameters as gluPerspective.
70  void set_perspective( T field_of_view_y, T aspect_ratio, T near_plane_,
71  T far_plane );
72 
73  matrix< 4, 4, T > compute_matrix() const;
74  matrix< 4, 4, T > compute_ortho_matrix() const;
75 
76  void compute_matrix( matrix< 4, 4, T >& matrix_ ) const;
77  void compute_ortho_matrix( matrix< 4, 4, T >& matrix_ ) const;
78  void apply_jitter( const vector< 2, T >& jitter_ );
79 
80  // 'move' the frustum. this function changes the near_plane, and adjusts the
81  // other parameters in a way that the 'perspective pyramid' stays the same.
82  void adjust_near( const T near_plane );
83 
84  inline T& left();
85  inline const T& left() const;
86 
87  inline T& right();
88  inline const T& right() const;
89 
90  inline T& bottom();
91  inline const T& bottom() const;
92 
93  inline T& top();
94  inline const T& top() const;
95 
96  inline T& near_plane();
97  inline const T& near_plane() const;
98 
99  inline T& far_plane();
100  inline const T& far_plane() const;
101 
102  inline T get_width() const;
103  inline T get_height() const;
104 
105  friend std::ostream& operator << ( std::ostream& os, const frustum& f )
106  {
107  const std::ios::fmtflags flags = os.flags();
108  const int prec = os.precision();
109 
110  os.setf( std::ios::right, std::ios::adjustfield );
111  os.precision( 5 );
112  os << "[" << std::setw(10) << f.left() << " "
113  << std::setw(10) << f.right() << " "
114  << std::setw(10) << f.bottom() << " "
115  << std::setw(10) << f.top() << " "
116  << std::setw(10) << f.near_plane() << " "
117  << std::setw(10) << f.far_plane() << "]";
118  os.precision( prec );
119  os.setf( flags );
120  return os;
121  };
122 
123  static const frustum DEFAULT;
124 };
125 
126 #ifndef VMMLIB_NO_TYPEDEFS
127 typedef frustum< float > frustumf;
129 #endif
130 
131 } // namespace vmml
132 
133 // - implementation - //
134 
135 namespace vmml
136 {
137 
138 template< typename T >
139 const frustum< T > frustum< T >::DEFAULT( static_cast< T >( -1.0 ),
140  static_cast< T >( 1.0 ),
141  static_cast< T >( -1.0 ),
142  static_cast< T >( 1.0 ),
143  static_cast< T >( 0.1 ),
144  static_cast< T >( 100.0 ) );
145 
146 
147 template < typename T >
148 frustum<T>::frustum( const T _left, const T _right, const T _bottom,
149  const T _top, const T _near, const T _far )
150 {
151  set( _left, _right, _bottom, _top, _near, _far );
152 }
153 
154 
155 template < typename T >
156 template< typename U >
157 frustum< T >::frustum( const frustum< U >& source_ )
158 {
159  (*this) = source_;
160 }
161 
162 
163 
164 template < typename T >
165 template< typename U >
166 frustum< T >::frustum( const U* values )
167 {
168  assert( values &&
169  "frustum: Nullpointer argument as source for initialisation!" );
170  left() = static_cast< T > ( values[0] );
171  right() = static_cast< T > ( values[1] );
172  bottom() = static_cast< T > ( values[2] );
173  top() = static_cast< T > ( values[3] );
174  near_plane() = static_cast< T > ( values[4] );
175  far_plane() = static_cast< T > ( values[5] );
176 }
177 
178 
179 
180 template < typename T >
181 frustum< T >::~frustum()
182 {}
183 
184 
185 
186 template< typename T >
187 frustum< T >& frustum< T >::operator=( const frustum& source_ )
188 {
189  memcpy( array, source_.array, 6 * sizeof( T ) );
190  return *this;
191 }
192 
193 template< typename T > template< typename U >
194 void frustum< T >::operator = ( const frustum< U >& source_ )
195 {
196  for( size_t index = 0; index < 6; ++index )
197  {
198  array[ index ] = static_cast< T >( source_.array[ index ] );
199  }
200 }
201 
202 
203 
204 template < typename T >
205 void
206 frustum< T >::set( const T _left, const T _right, const T _bottom,
207  const T _top, const T _near, const T _far )
208 {
209  left() = _left;
210  right() = _right;
211  bottom() = _bottom;
212  top() = _top;
213  near_plane() = _near;
214  far_plane() = _far;
215 }
216 
217 
218 // 'move' the frustum. this function changes the near_plane, and adjusts the
219 // other parameters in a way that the 'perspective pyramid' stays the same.
220 template < typename T >
221 void
222 frustum<T>::adjust_near( const T new_near )
223 {
224  if( new_near == near_plane() )
225  return;
226 
227  const T ratio = new_near / near_plane();
228  right() *= ratio;
229  left() *= ratio;
230  top() *= ratio;
231  bottom() *= ratio;
232  near_plane() = new_near;
233 }
234 
235 
236 
237 // set the frustum using the same parameters as gluPerspective.
238 template < typename T >
239 void
240 frustum<T>::set_perspective( T fov_y, T aspect_ratio, T near_plane_,
241  T far_plane_ )
242 {
243  near_plane() = near_plane_;
244  far_plane() = far_plane_;
245 
246  top() = tan( 0.5 * fov_y * M_PI / 180.0 ) * 0.5;
247  bottom() = - top();
248 
249  left() = bottom() * aspect_ratio;
250  right() = top() * aspect_ratio;
251 }
252 
253 
254 
255 template < typename T >
256 matrix< 4, 4, T >
257 frustum<T>::compute_matrix() const
258 {
259  matrix< 4, 4, T > matrix_;
260  compute_matrix( matrix_ );
261  return matrix_;
262 }
263 
264 
265 
266 template < typename T >
267 void
268 frustum<T>::compute_matrix( matrix< 4, 4, T >& M ) const
269 {
270  M( 0,0 ) = 2.0 * near_plane() / ( right() - left() );
271  M( 0,1 ) = 0.0;
272  M( 0,2 ) = ( right() + left() ) / ( right() - left() );
273  M( 0,3 ) = 0.0;
274 
275  M( 1,0 ) = 0.0;
276  M( 1,1 ) = 2.0 * near_plane() / ( top() - bottom() );
277  M( 1,2 ) = ( top() + bottom() ) / ( top() - bottom() );
278  M( 1,3 ) = 0.0;
279 
280  M( 2,0 ) = 0.0;
281  M( 2,1 ) = 0.0;
282  // NOTE: Some glfrustum man pages say wrongly '(far + near) / (far - near)'
283  M( 2,2 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() );
284  M( 2,3 ) = -2.0 * far_plane() * near_plane() / ( far_plane() - near_plane() );
285 
286  M( 3,0 ) = 0.0;
287  M( 3,1 ) = 0.0;
288  M( 3,2 ) = -1.0;
289  M( 3,3 ) = 0.0;
290 }
291 
292 
293 
294 template < typename T >
295 matrix< 4, 4, T >
296 frustum< T >::compute_ortho_matrix() const
297 {
298  matrix< 4, 4, T > matrix_;
299  compute_ortho_matrix( matrix_ );
300  return matrix_;
301 }
302 
303 
304 
305 template < typename T >
306 void
307 frustum< T >::compute_ortho_matrix( matrix< 4, 4, T >& M ) const
308 {
309  M( 0,0 ) = 2.0 / ( right() - left() );
310  M( 0,1 ) = 0.0;
311  M( 0,2 ) = 0.0;
312  M( 0,3 ) = -( right() + left() ) / ( right() - left() );
313 
314  M( 1,0 ) = 0.0;
315  M( 1,1 ) = 2.0 / ( top() - bottom() );
316  M( 1,2 ) = 0.0f;
317  M( 1,3 ) = -( top() + bottom() ) / ( top() - bottom() );
318 
319  M( 2,0 ) = 0.0;
320  M( 2,1 ) = 0.0;
321  M( 2,2 ) = -2.0 / ( far_plane() - near_plane() );
322  M( 2,3 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() );
323 
324  M( 3,0 ) = 0.0;
325  M( 3,1 ) = 0.0;
326  M( 3,2 ) = 0.0;
327  M( 3,3 ) = 1.0f;
328 }
329 
330 template < typename T >
331 void frustum< T >::apply_jitter( const vector< 2, T >& jitter_ )
332 {
333  left() = left() + jitter_.x();
334  right() = right() + jitter_.x();
335  bottom() = bottom() + jitter_.y();
336  top() = top() + jitter_.y();
337 }
338 
339 template< typename T >
340 inline T& frustum< T >::left()
341 {
342  return array[ 0 ];
343 }
344 
345 template< typename T >
346 inline const T& frustum< T >::left() const
347 {
348  return array[ 0 ];
349 }
350 
351 template< typename T >
352 inline T& frustum< T >::right()
353 {
354  return array[ 1 ];
355 }
356 
357 template< typename T >
358 inline const T& frustum< T >::right() const
359 {
360  return array[ 1 ];
361 }
362 
363 template< typename T >
364 inline T& frustum< T >::bottom()
365 {
366  return array[ 2 ];
367 }
368 
369 template< typename T >
370 inline const T& frustum< T >::bottom() const
371 {
372  return array[ 2 ];
373 }
374 
375 template< typename T >
376 inline T& frustum< T >::top()
377 {
378  return array[ 3 ];
379 }
380 
381 template< typename T >
382 inline const T& frustum< T >::top() const
383 {
384  return array[ 3 ];
385 }
386 
387 template< typename T >
388 inline T& frustum< T >::near_plane()
389 {
390  return array[ 4 ];
391 }
392 
393 template< typename T >
394 inline const T& frustum< T >::near_plane() const
395 {
396  return array[ 4 ];
397 }
398 
399 template< typename T >
400 inline T& frustum< T >::far_plane()
401 {
402  return array[ 5 ];
403 }
404 
405 template< typename T >
406 inline const T& frustum< T >::far_plane() const
407 {
408  return array[ 5 ];
409 }
410 
411 template< typename T > inline T frustum< T >::get_width() const
412 {
413  return fabs( right() - left( ));
414 }
415 
416 template< typename T > inline T frustum< T >::get_height() const
417 {
418  return fabs( top() - bottom( ));
419 }
420 
421 
422 } //namespace vmml
423 
424 #endif