KiCad PCB EDA Suite
ccamera.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program 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 this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include "ccamera.h"
31 #include <wx/log.h>
32 
33 
40 const wxChar *CCAMERA::m_logTrace = wxT( "KI_TRACE_CCAMERA" );
41 
42 #define MIN_ZOOM 0.10f
43 #define MAX_ZOOM 1.25f
44 
45 CCAMERA::CCAMERA( float aRangeScale )
46 {
47  wxLogTrace( m_logTrace, wxT( "CCAMERA::CCAMERA" ) );
48 
49  m_range_scale = aRangeScale;
50  m_camera_pos_init = SFVEC3F( 0.0f, 0.0f, -(aRangeScale * 2.0f ) );
52  m_windowSize = SFVEC2I( 0, 0 );
55 
56  Reset();
57 }
58 
59 
61 {
62  m_parametersChanged = true;
63  m_projectionMatrix = glm::mat4( 1.0f );
64  m_projectionMatrixInv = glm::mat4( 1.0f );
65  m_rotationMatrix = glm::mat4( 1.0f );
66  m_rotationMatrixAux = glm::mat4( 1.0f );
67  m_lastPosition = wxPoint( 0, 0 );
68 
69  m_zoom = 1.0f;
70  m_zoom_t0 = 1.0f;
71  m_zoom_t1 = 1.0f;
78 
79  m_rotate_aux = SFVEC3F( 0.0f );
80  m_rotate_aux_t0 = SFVEC3F( 0.0f );
81  m_rotate_aux_t1 = SFVEC3F( 0.0f );
82 
85  m_viewMatrixInverse = glm::inverse( m_viewMatrix );
86  m_scr_nX.clear();
87  m_scr_nY.clear();
89 }
90 
91 
93 {
95  m_zoom_t1 = 1.0f;
96  m_rotate_aux_t1 = SFVEC3F( 0.0f );
98 }
99 
100 
102 {
103  m_viewMatrix = glm::translate( glm::mat4( 1.0f ), m_camera_pos ) *
105  glm::translate( glm::mat4( 1.0f ), -m_lookat_pos );
106 }
107 
108 
110 {
111  m_rotationMatrixAux = glm::rotate( glm::mat4( 1.0f ),
112  m_rotate_aux.x,
113  SFVEC3F( 1.0f, 0.0f, 0.0f ) );
114 
116  m_rotate_aux.y,
117  SFVEC3F( 0.0f, 1.0f, 0.0f ) );
118 
120  m_rotate_aux.z,
121  SFVEC3F( 0.0f, 0.0f, 1.0f ) );
122 
123  m_parametersChanged = true;
124 
126  updateFrustum();
127 }
128 
129 
130 const glm::mat4 CCAMERA::GetRotationMatrix() const
131 {
133 }
134 
135 
137 {
138  if( (m_windowSize.x == 0) ||
139  (m_windowSize.y == 0) )
140  return;
141 
142  m_frustum.ratio = (float) m_windowSize.x / (float)m_windowSize.y;
143 
144  // Consider that we can render double the length multiplied by the 2/sqrt(2)
145  //
146  m_frustum.farD = glm::length( m_camera_pos_init ) * 2.0f * ( 2.0f * sqrtf( 2.0f ) );
147 
148  switch( m_projectionType )
149  {
150  default:
152 
153  m_frustum.nearD = 0.10f;
154 
155  // Ratio width / height of the window display
156  m_frustum.angle = 45.0f * m_zoom;
157 
158 
159  m_projectionMatrix = glm::perspective( glm::radians( m_frustum.angle ),
162  m_frustum.farD );
163 
164  m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
165 
166  m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f ) ;
167 
168  m_focalLen.x = ( (float)m_windowSize.y / (float)m_windowSize.x ) / m_frustum.tang;
169  m_focalLen.y = 1.0f / m_frustum.tang;
170 
175  break;
176 
177  case PROJECTION_ORTHO:
178 
179  m_frustum.nearD = -m_frustum.farD; // Use a symmetrical clip plane for ortho projection
180 
181  const float orthoReductionFactor = m_zoom / 75.0f;
182 
183  // Initialize Projection Matrix for Ortographic View
184  m_projectionMatrix = glm::ortho( -m_windowSize.x * orthoReductionFactor,
185  m_windowSize.x * orthoReductionFactor,
186  -m_windowSize.y * orthoReductionFactor,
187  m_windowSize.y * orthoReductionFactor,
189 
190  m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
191 
192  m_frustum.nw = m_windowSize.x * orthoReductionFactor * 2.0f;
193  m_frustum.nh = m_windowSize.y * orthoReductionFactor * 2.0f;
196 
197  break;
198  }
199 
200  if ( (m_windowSize.x > 0) &&
201  (m_windowSize.y > 0) )
202  {
203  m_scr_nX.resize( m_windowSize.x + 1 );
204  m_scr_nY.resize( m_windowSize.y + 1 );
205 
206  // Precalc X values for camera -> ray generation
207  for( unsigned int x = 0; x < (unsigned int)m_windowSize.x + 1; ++x )
208  {
209  // Converts 0.0 .. 1.0
210  const float xNormalizedDeviceCoordinates = ( ( (float)x + 0.5f ) /
211  (m_windowSize.x - 0.0f) );
212 
213  // Converts -1.0 .. 1.0
214  m_scr_nX[x] = 2.0f * xNormalizedDeviceCoordinates - 1.0f;
215  }
216 
217  // Precalc Y values for camera -> ray generation
218  for( unsigned int y = 0; y < (unsigned int)m_windowSize.y + 1 ; ++y )
219  {
220  // Converts 0.0 .. 1.0
221  const float yNormalizedDeviceCoordinates = ( ( (float)y + 0.5f ) /
222  (m_windowSize.y - 0.0f) );
223 
224  // Converts -1.0 .. 1.0
225  m_scr_nY[y] = 2.0f * yNormalizedDeviceCoordinates - 1.0f;
226  }
227 
228  updateFrustum();
229  }
230 }
231 
232 
234 {
235  // Update matrix and vectors
236  m_viewMatrixInverse = glm::inverse( m_viewMatrix );
237 
238  m_right = glm::normalize( SFVEC3F( m_viewMatrixInverse *
239  glm::vec4( SFVEC3F( 1.0, 0.0, 0.0 ), 0.0 ) ) );
240 
241  m_up = glm::normalize( SFVEC3F( m_viewMatrixInverse *
242  glm::vec4( SFVEC3F( 0.0, 1.0, 0.0 ), 0.0 ) ) );
243 
244  m_dir = glm::normalize( SFVEC3F( m_viewMatrixInverse *
245  glm::vec4( SFVEC3F( 0.0, 0.0, 1.0 ), 0.0 ) ) );
246 
247  m_pos = SFVEC3F( m_viewMatrixInverse * glm::vec4( SFVEC3F( 0.0, 0.0, 0.0 ), 1.0 ) );
248 
249 
250  /*
251  * Frustum is a implementation based on a tutorial by
252  * http://www.lighthouse3d.com/tutorials/view-frustum-culling/
253  */
254 
255  // compute the centers of the near and far planes
258 
259  // compute the 4 corners of the frustum on the near plane
264 
265  // compute the 4 corners of the frustum on the far plane
270 
271  if ( (m_windowSize.x > 0) &&
272  (m_windowSize.y > 0) )
273  {
274  // Reserve size for precalc values
275  m_right_nX.resize( m_windowSize.x + 1 );
276  m_up_nY.resize( m_windowSize.y + 1 );
277 
278  // Precalc X values for camera -> ray generation
279  const SFVEC3F right_nw = m_right * m_frustum.nw;
280 
281  for( unsigned int x = 0; x < ((unsigned int)m_windowSize.x + 1); ++x )
282  m_right_nX[x] = right_nw * m_scr_nX[x];
283 
284  // Precalc Y values for camera -> ray generation
285  const SFVEC3F up_nh = m_up * m_frustum.nh;
286 
287  for( unsigned int y = 0; y < ((unsigned int)m_windowSize.y + 1); ++y )
288  m_up_nY[y] = up_nh * m_scr_nY[y];
289  }
290 }
291 
292 
293 void CCAMERA::MakeRay( const SFVEC2I &aWindowPos,
294  SFVEC3F &aOutOrigin,
295  SFVEC3F &aOutDirection ) const
296 {
297  wxASSERT( aWindowPos.x < m_windowSize.x );
298  wxASSERT( aWindowPos.y < m_windowSize.y );
299 
300  const SFVEC3F up_plus_right = m_up_nY[aWindowPos.y] +
301  m_right_nX[aWindowPos.x];
302 
303  switch( m_projectionType )
304  {
305  default:
307  aOutOrigin = up_plus_right + m_frustum.nc;
308  aOutDirection = glm::normalize( aOutOrigin - m_pos );
309  break;
310 
311  case PROJECTION_ORTHO:
312  aOutOrigin = up_plus_right * 0.5f + m_frustum.nc;
313  aOutDirection = -m_dir;
314  break;
315  }
316 }
317 
318 
319 void CCAMERA::MakeRay( const SFVEC2F &aWindowPos, SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection ) const
320 {
321  wxASSERT( aWindowPos.x < (float)m_windowSize.x );
322  wxASSERT( aWindowPos.y < (float)m_windowSize.y );
323 
324  const SFVEC2F floorWinPos_f = glm::floor( aWindowPos );
325  const SFVEC2I floorWinPos_i = (SFVEC2I)floorWinPos_f;
326  const SFVEC2F relativeWinPos = aWindowPos - floorWinPos_f;
327 
328  // Note: size of vectors m_up and m_right are m_windowSize + 1
329  const SFVEC3F up_plus_right = m_up_nY[floorWinPos_i.y] * (1.0f - relativeWinPos.y) +
330  m_up_nY[floorWinPos_i.y + 1] * relativeWinPos.y +
331  m_right_nX[floorWinPos_i.x] * (1.0f - relativeWinPos.x) +
332  m_right_nX[floorWinPos_i.x + 1] * relativeWinPos.x;
333 
334  switch( m_projectionType )
335  {
336  default:
338  aOutOrigin = up_plus_right + m_frustum.nc;
339  aOutDirection = glm::normalize( aOutOrigin - m_pos );
340  break;
341 
342  case PROJECTION_ORTHO:
343  aOutOrigin = up_plus_right * 0.5f + m_frustum.nc;
344  aOutDirection = -m_dir;
345  break;
346  }
347 }
348 
349 
351  SFVEC3F &aOutDirection ) const
352 {
355  aOutOrigin, aOutDirection );
356 }
357 
358 
359 const glm::mat4 &CCAMERA::GetProjectionMatrix() const
360 {
361  return m_projectionMatrix;
362 }
363 
364 
365 const glm::mat4 &CCAMERA::GetProjectionMatrixInv() const
366 {
367  return m_projectionMatrixInv;
368 }
369 
370 
372 {
373  m_parametersChanged = true;
374  m_camera_pos.x = 0.0f;
375  m_camera_pos.y = 0.0f;
376 
378  updateFrustum();
379 }
380 
381 
383 {
384  m_camera_pos_t1.x = 0.0f;
385  m_camera_pos_t1.y = 0.0f;
386 }
387 
388 
389 const glm::mat4 &CCAMERA::GetViewMatrix() const
390 {
391  return m_viewMatrix;
392 }
393 
394 
395 const glm::mat4 &CCAMERA::GetViewMatrix_Inv() const
396 {
397  return m_viewMatrixInverse;
398 }
399 
400 
401 void CCAMERA::SetCurMousePosition( const wxPoint &aNewMousePosition )
402 {
403  m_lastPosition = aNewMousePosition;
404 }
405 
406 
408 {
409  if( m_projectionType != aProjectionType )
410  {
411  m_projectionType = aProjectionType;
413  }
414 }
415 
416 
418 {
421  else
423 
425 }
426 
427 
428 bool CCAMERA::SetCurWindowSize( const wxSize &aSize )
429 {
430  const SFVEC2I newSize = SFVEC2I( aSize.x, aSize.y );
431 
432  if( m_windowSize != newSize )
433  {
434  m_windowSize = newSize;
436 
437  return true;
438  }
439 
440  return false;
441 }
442 
443 
445 {
446  m_zoom = 1.0f;
447 
449 
452 }
453 
454 bool CCAMERA::Zoom( float aFactor )
455 {
456  if ( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) || aFactor == 1 )
457  return false;
458 
459  m_zoom /= aFactor;
460  if( m_zoom <= MIN_ZOOM )
461  m_zoom = MIN_ZOOM;
462  if( m_zoom >= MAX_ZOOM )
463  m_zoom = MAX_ZOOM;
464 
466 
469 
470  return true;
471 }
472 
473 bool CCAMERA::Zoom_T1( float aFactor )
474 {
475  if( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) || aFactor == 1 )
476  return false;
477 
478  m_zoom_t1 = m_zoom / aFactor;
479  if (m_zoom_t1 < MIN_ZOOM )
481  if (m_zoom_t1 > MAX_ZOOM )
483 
485 
486  return true;
487 }
488 
489 
490 float CCAMERA::ZoomGet() const
491 {
492  return m_zoom;
493 }
494 
495 
496 void CCAMERA::RotateX( float aAngleInRadians )
497 {
498  m_rotate_aux.x += aAngleInRadians;
500 }
501 
502 
503 void CCAMERA::RotateY( float aAngleInRadians )
504 {
505  m_rotate_aux.y += aAngleInRadians;
507 }
508 
509 
510 void CCAMERA::RotateZ( float aAngleInRadians )
511 {
512  m_rotate_aux.z += aAngleInRadians;
514 }
515 
516 
517 void CCAMERA::RotateX_T1( float aAngleInRadians )
518 {
519  m_rotate_aux_t1.x += aAngleInRadians;
520 }
521 
522 
523 void CCAMERA::RotateY_T1( float aAngleInRadians )
524 {
525  m_rotate_aux_t1.y += aAngleInRadians;
526 }
527 
528 
529 void CCAMERA::RotateZ_T1( float aAngleInRadians )
530 {
531  m_rotate_aux_t1.z += aAngleInRadians;
532 }
533 
534 
536 {
540  m_zoom_t0 = m_zoom;
541 
545  m_zoom_t1 = m_zoom;
546 }
547 
548 
549 void CCAMERA::Interpolate( float t )
550 {
551  wxASSERT( t >= 0.0f );
552 
553  const float t0 = 1.0f - t;
554 
558  m_zoom = m_zoom_t0 * t0 + m_zoom_t1 * t;
559 
560  m_parametersChanged = true;
561 
564 }
565 
566 
568 {
569  const bool parametersChanged = m_parametersChanged;
570 
571  m_parametersChanged = false;
572 
573  return parametersChanged;
574 }
#define MAX_ZOOM
Definition: ccamera.cpp:43
SFVEC3F fc
Definition: ccamera.h:51
float ZoomGet() const
Definition: ccamera.cpp:490
PROJECTION_TYPE
Definition: ccamera.h:37
void ResetXYpos()
Definition: ccamera.cpp:371
bool m_parametersChanged
Set to true if any of the parameters in the camera was changed.
Definition: ccamera.h:322
SFVEC3F m_dir
Definition: ccamera.h:283
virtual void SetT0_and_T1_current_T()
SetT0_and_T1_current_T - This will set T0 and T1 with the current values.
Definition: ccamera.cpp:535
SFVEC3F ftl
Far Top Left.
Definition: ccamera.h:56
void ResetXYpos_T1()
Definition: ccamera.cpp:382
SFVEC3F ntl
Near Top Left.
Definition: ccamera.h:52
virtual void Reset()
Reset the camera to initial state.
Definition: ccamera.cpp:60
float farD
Definition: ccamera.h:60
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
Definition: ccamera.h:330
SFVEC3F m_board_lookat_pos_init
Default boardlookat position (the board center)
Definition: ccamera.h:296
SFVEC3F m_rotate_aux
Stores the rotation angle auxiliar.
Definition: ccamera.h:298
void ZoomReset()
Definition: ccamera.cpp:444
void RotateY(float aAngleInRadians)
Definition: ccamera.cpp:503
CCAMERA(float aRangeScale)
CCAMERA initialize a camera.
Definition: ccamera.cpp:45
void updateFrustum()
Definition: ccamera.cpp:233
const glm::mat4 & GetViewMatrix_Inv() const
Definition: ccamera.cpp:395
std::vector< SFVEC3F > m_up_nY
Definition: ccamera.h:316
const glm::mat4 & GetProjectionMatrix() const
Definition: ccamera.cpp:359
void SetProjection(PROJECTION_TYPE aProjectionType)
Definition: ccamera.cpp:407
float nearD
Definition: ccamera.h:60
glm::mat4 m_viewMatrixInverse
Definition: ccamera.h:274
float nw
Definition: ccamera.h:61
const glm::mat4 & GetViewMatrix() const
Definition: ccamera.cpp:389
std::vector< float > m_scr_nY
Definition: ccamera.h:309
std::vector< float > m_scr_nX
Precalc values array used to calc ray for each pixel (constant for the same window size) ...
Definition: ccamera.h:308
SFVEC3F fbr
Far Bottom Right.
Definition: ccamera.h:59
Define an abstract camera.
glm::ivec2 SFVEC2I
Definition: xv3d_types.h:42
float tang
Definition: ccamera.h:60
void updateViewMatrix()
Definition: ccamera.cpp:101
wxPoint m_lastPosition
The last mouse position in the screen.
Definition: ccamera.h:269
void SetCurMousePosition(const wxPoint &aPosition)
It updates the current mouse position without make any new recalculations on camera.
Definition: ccamera.cpp:401
bool Zoom(float aFactor)
Definition: ccamera.cpp:454
float fw
Definition: ccamera.h:61
void RotateZ(float aAngleInRadians)
Definition: ccamera.cpp:510
void RotateX(float aAngleInRadians)
Definition: ccamera.cpp:496
SFVEC2F m_focalLen
Definition: ccamera.h:286
SFVEC3F nbr
Near Bottom Right.
Definition: ccamera.h:55
SFVEC3F m_camera_pos_t1
Definition: ccamera.h:291
SFVEC3F fbl
Far Bottom Left.
Definition: ccamera.h:58
float m_zoom_t0
Definition: ccamera.h:258
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
SFVEC3F m_right
Definition: ccamera.h:281
SFVEC3F m_pos
Definition: ccamera.h:284
const glm::mat4 & GetProjectionMatrixInv() const
Definition: ccamera.cpp:365
void ToggleProjection()
Definition: ccamera.cpp:417
float angle
Definition: ccamera.h:60
SFVEC3F m_up
Definition: ccamera.h:282
SFVEC3F m_lookat_pos_t1
Definition: ccamera.h:295
virtual void Interpolate(float t)
Interpolate - It will update the matrix to interpolate between T0 and T1 values.
Definition: ccamera.cpp:549
SFVEC3F nbl
Near Bottom Left.
Definition: ccamera.h:54
float m_range_scale
m_range_scale - the nominal range expected to be used in the camera.
Definition: ccamera.h:252
SFVEC3F m_lookat_pos_t0
Definition: ccamera.h:294
void MakeRay(const SFVEC2I &aWindowPos, SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRay - Make a ray based on a windows screen position.
Definition: ccamera.cpp:293
bool SetCurWindowSize(const wxSize &aSize)
SetCurWindowSize - update the windows size of the camera.
Definition: ccamera.cpp:428
glm::mat4 m_rotationMatrix
Definition: ccamera.h:271
SFVEC3F ntr
Near Top Right.
Definition: ccamera.h:53
FRUSTUM m_frustum
Definition: ccamera.h:279
glm::mat4 m_projectionMatrix
Definition: ccamera.h:275
bool Zoom_T1(float aFactor)
Definition: ccamera.cpp:473
void RotateX_T1(float aAngleInRadians)
Definition: ccamera.cpp:517
virtual void Reset_T1()
Definition: ccamera.cpp:92
float m_zoom
3D zoom value (Min 0.0 ...
Definition: ccamera.h:257
SFVEC3F m_rotate_aux_t1
Definition: ccamera.h:300
void updateRotationMatrix()
Definition: ccamera.cpp:109
SFVEC3F m_camera_pos_init
Definition: ccamera.h:288
SFVEC3F m_camera_pos
Definition: ccamera.h:289
SFVEC3F m_camera_pos_t0
Definition: ccamera.h:290
std::vector< SFVEC3F > m_right_nX
Precalc values array used to calc ray for each pixel, for X and Y axis of each new camera position...
Definition: ccamera.h:315
SFVEC3F nc
Definition: ccamera.h:50
void MakeRayAtCurrrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRayAtCurrrentMousePosition - Make a ray based on the latest mouse position.
Definition: ccamera.cpp:350
void RotateY_T1(float aAngleInRadians)
Definition: ccamera.cpp:523
void rebuildProjection()
Definition: ccamera.cpp:136
#define MIN_ZOOM
Definition: ccamera.cpp:42
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
const glm::mat4 GetRotationMatrix() const
Function GetRotationMatrix Get the rotation matrix to be applied in a transformation camera...
Definition: ccamera.cpp:130
SFVEC2I m_windowSize
The window size that this camera is working.
Definition: ccamera.h:264
SFVEC3F ftr
Far Top Right.
Definition: ccamera.h:57
float m_zoom_t1
Definition: ccamera.h:259
CAMERA_INTERPOLATION m_interpolation_mode
Definition: ccamera.h:302
SFVEC3F m_rotate_aux_t0
Definition: ccamera.h:299
glm::mat4 m_rotationMatrixAux
Definition: ccamera.h:272
void RotateZ_T1(float aAngleInRadians)
Definition: ccamera.cpp:529
float fh
Definition: ccamera.h:61
float nh
Definition: ccamera.h:61
float ratio
Definition: ccamera.h:60
glm::mat4 m_viewMatrix
Definition: ccamera.h:273
glm::mat4 m_projectionMatrixInv
Definition: ccamera.h:276
bool ParametersChanged()
Function ParametersChanged.
Definition: ccamera.cpp:567
SFVEC3F m_lookat_pos
Definition: ccamera.h:293
PROJECTION_TYPE m_projectionType
Definition: ccamera.h:277