2015-12-08 07:31:57 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2016-07-19 17:35:25 +00:00
|
|
|
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
2024-03-03 18:11:42 +00:00
|
|
|
* Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
2015-12-08 07:31:57 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2021-01-03 22:23:00 +00:00
|
|
|
* @file camera.cpp
|
2015-12-08 07:31:57 +00:00
|
|
|
*/
|
|
|
|
|
2023-09-23 23:39:12 +00:00
|
|
|
#include <gal/3d/camera.h>
|
2015-12-08 07:31:57 +00:00
|
|
|
#include <wx/log.h>
|
2021-06-24 08:47:28 +00:00
|
|
|
#include <algorithm>
|
2024-03-03 18:11:42 +00:00
|
|
|
#include <3d_enums.h>
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-01-13 13:30:49 +00:00
|
|
|
// A helper function to normalize aAngle between -2PI and +2PI
|
|
|
|
inline void normalise2PI( float& aAngle )
|
|
|
|
{
|
|
|
|
while( aAngle > 0.0 )
|
2020-10-05 10:41:14 +00:00
|
|
|
aAngle -= static_cast<float>( M_PI * 2.0f );
|
2020-01-13 13:30:49 +00:00
|
|
|
|
|
|
|
while( aAngle < 0.0 )
|
2020-10-05 10:41:14 +00:00
|
|
|
aAngle += static_cast<float>( M_PI * 2.0f );
|
2020-01-13 13:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-12-08 07:31:57 +00:00
|
|
|
/**
|
2020-12-13 23:02:57 +00:00
|
|
|
* @ingroup trace_env_vars
|
2015-12-08 07:31:57 +00:00
|
|
|
*/
|
2021-01-02 21:05:29 +00:00
|
|
|
const wxChar *CAMERA::m_logTrace = wxT( "KI_TRACE_CAMERA" );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2023-01-10 22:30:05 +00:00
|
|
|
const float CAMERA::DEFAULT_MIN_ZOOM = 0.020f;
|
|
|
|
const float CAMERA::DEFAULT_MAX_ZOOM = 2.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-12-13 23:02:57 +00:00
|
|
|
|
2024-03-03 18:11:42 +00:00
|
|
|
CAMERA::CAMERA( float aInitialDistance ) :
|
|
|
|
CAMERA( SFVEC3F( 0.0f, 0.0f, -aInitialDistance ), SFVEC3F( 0.0f ),
|
|
|
|
PROJECTION_TYPE::PERSPECTIVE )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CAMERA::CAMERA( SFVEC3F aInitPos, SFVEC3F aLookat, PROJECTION_TYPE aProjectionType )
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2021-01-02 21:05:29 +00:00
|
|
|
wxLogTrace( m_logTrace, wxT( "CAMERA::CAMERA" ) );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2024-03-03 18:11:42 +00:00
|
|
|
m_camera_pos_init = aInitPos;
|
|
|
|
m_board_lookat_pos_init = aLookat;
|
|
|
|
m_windowSize = SFVEC2I( 0, 0 );
|
|
|
|
m_projectionType = aProjectionType;
|
|
|
|
m_interpolation_mode = CAMERA_INTERPOLATION::BEZIER;
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-10-24 17:30:40 +00:00
|
|
|
m_minZoom = DEFAULT_MIN_ZOOM;
|
|
|
|
m_maxZoom = DEFAULT_MAX_ZOOM;
|
|
|
|
|
2016-07-19 17:35:25 +00:00
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::Reset()
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
2015-12-08 07:31:57 +00:00
|
|
|
m_parametersChanged = true;
|
|
|
|
m_projectionMatrix = glm::mat4( 1.0f );
|
2016-07-19 17:35:25 +00:00
|
|
|
m_projectionMatrixInv = glm::mat4( 1.0f );
|
2015-12-08 07:31:57 +00:00
|
|
|
m_rotationMatrix = glm::mat4( 1.0f );
|
2016-07-19 17:35:25 +00:00
|
|
|
m_rotationMatrixAux = glm::mat4( 1.0f );
|
2015-12-08 07:31:57 +00:00
|
|
|
m_lastPosition = wxPoint( 0, 0 );
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-09-15 22:01:24 +00:00
|
|
|
m_zoom = 1.0f;
|
|
|
|
m_zoom_t0 = 1.0f;
|
|
|
|
m_zoom_t1 = 1.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
m_camera_pos = m_camera_pos_init;
|
2016-07-19 17:35:25 +00:00
|
|
|
m_camera_pos_t0 = m_camera_pos_init;
|
|
|
|
m_camera_pos_t1 = m_camera_pos_init;
|
|
|
|
m_lookat_pos = m_board_lookat_pos_init;
|
|
|
|
m_lookat_pos_t0 = m_board_lookat_pos_init;
|
|
|
|
m_lookat_pos_t1 = m_board_lookat_pos_init;
|
|
|
|
|
|
|
|
m_rotate_aux = SFVEC3F( 0.0f );
|
|
|
|
m_rotate_aux_t0 = SFVEC3F( 0.0f );
|
|
|
|
m_rotate_aux_t1 = SFVEC3F( 0.0f );
|
|
|
|
|
|
|
|
updateRotationMatrix();
|
2015-12-08 07:31:57 +00:00
|
|
|
updateViewMatrix();
|
2016-07-19 17:35:25 +00:00
|
|
|
m_viewMatrixInverse = glm::inverse( m_viewMatrix );
|
2015-12-08 07:31:57 +00:00
|
|
|
m_scr_nX.clear();
|
|
|
|
m_scr_nY.clear();
|
2016-07-19 17:35:25 +00:00
|
|
|
rebuildProjection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-03 18:11:42 +00:00
|
|
|
bool CAMERA::ViewCommand_T1( VIEW3D_TYPE aRequestedView )
|
|
|
|
{
|
|
|
|
switch( aRequestedView )
|
|
|
|
{
|
|
|
|
case VIEW3D_TYPE::VIEW3D_RIGHT:
|
|
|
|
SetT0_and_T1_current_T();
|
|
|
|
Reset_T1();
|
|
|
|
RotateZ_T1( glm::radians( -90.0f ) );
|
|
|
|
RotateX_T1( glm::radians( -90.0f ) );
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_LEFT:
|
|
|
|
Reset_T1();
|
|
|
|
RotateZ_T1( glm::radians( 90.0f ) );
|
|
|
|
RotateX_T1( glm::radians( -90.0f ) );
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_FRONT:
|
|
|
|
Reset_T1();
|
|
|
|
RotateX_T1( glm::radians( -90.0f ) );
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_BACK:
|
|
|
|
Reset_T1();
|
|
|
|
RotateX_T1( glm::radians( -90.0f ) );
|
|
|
|
|
|
|
|
// The rotation angle should be 180.
|
|
|
|
// We use 179.999 (180 - epsilon) to avoid a full 360 deg rotation when
|
|
|
|
// using 180 deg if the previous rotated position was already 180 deg
|
|
|
|
RotateZ_T1( glm::radians( 179.999f ) );
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_TOP:
|
|
|
|
Reset_T1();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_BOTTOM:
|
|
|
|
Reset_T1();
|
|
|
|
RotateY_T1( glm::radians( 179.999f ) ); // Rotation = 180 - epsilon
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case VIEW3D_TYPE::VIEW3D_FLIP:
|
|
|
|
RotateY_T1( glm::radians( 179.999f ) );
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::Reset_T1()
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_camera_pos_t1 = m_camera_pos_init;
|
2021-09-15 22:01:24 +00:00
|
|
|
m_zoom_t1 = 1.0f;
|
2016-07-19 17:35:25 +00:00
|
|
|
m_rotate_aux_t1 = SFVEC3F( 0.0f );
|
|
|
|
m_lookat_pos_t1 = m_board_lookat_pos_init;
|
2020-01-15 18:03:57 +00:00
|
|
|
|
|
|
|
// Since 0 = 2pi, we want to reset the angle to be the closest
|
|
|
|
// one to where we currently are. That ensures that we rotate
|
|
|
|
// the board around the smallest distance getting there.
|
|
|
|
if( m_rotate_aux_t0.x > M_PI )
|
2020-10-05 10:41:14 +00:00
|
|
|
m_rotate_aux_t1.x = static_cast<float>( 2.0f * M_PI );
|
2020-01-15 18:03:57 +00:00
|
|
|
|
|
|
|
if( m_rotate_aux_t0.y > M_PI )
|
2020-10-05 10:41:14 +00:00
|
|
|
m_rotate_aux_t1.y = static_cast<float>( 2.0f * M_PI );
|
2020-01-15 18:03:57 +00:00
|
|
|
|
|
|
|
if( m_rotate_aux_t0.z > M_PI )
|
2020-10-05 10:41:14 +00:00
|
|
|
m_rotate_aux_t1.z = static_cast<float>( 2.0f * M_PI );
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 08:04:36 +00:00
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
void CAMERA::SetBoardLookAtPos( const SFVEC3F& aBoardPos )
|
|
|
|
{
|
|
|
|
if( m_board_lookat_pos_init != aBoardPos )
|
|
|
|
{
|
|
|
|
m_board_lookat_pos_init = aBoardPos;
|
2021-06-11 13:10:36 +00:00
|
|
|
m_lookat_pos = aBoardPos;
|
|
|
|
|
|
|
|
m_parametersChanged = true;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
updateFrustum();
|
2021-06-11 10:31:42 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2021-07-05 08:04:36 +00:00
|
|
|
|
2021-10-24 17:30:40 +00:00
|
|
|
void CAMERA::zoomChanged()
|
|
|
|
{
|
|
|
|
if( m_zoom < m_minZoom )
|
|
|
|
m_zoom = m_minZoom;
|
|
|
|
|
|
|
|
if( m_zoom > m_maxZoom )
|
|
|
|
m_zoom = m_maxZoom;
|
|
|
|
|
|
|
|
m_camera_pos.z = m_camera_pos_init.z * m_zoom;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
rebuildProjection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::updateViewMatrix()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
|
|
|
m_viewMatrix = glm::translate( glm::mat4( 1.0f ), m_camera_pos ) *
|
2016-07-19 17:35:25 +00:00
|
|
|
m_rotationMatrix * m_rotationMatrixAux *
|
|
|
|
glm::translate( glm::mat4( 1.0f ), -m_lookat_pos );
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::updateRotationMatrix()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2021-01-02 21:05:29 +00:00
|
|
|
m_rotationMatrixAux = glm::rotate( glm::mat4( 1.0f ), m_rotate_aux.x,
|
2016-07-19 17:35:25 +00:00
|
|
|
SFVEC3F( 1.0f, 0.0f, 0.0f ) );
|
2020-01-15 18:03:57 +00:00
|
|
|
normalise2PI( m_rotate_aux.x );
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
m_rotationMatrixAux = glm::rotate( m_rotationMatrixAux, m_rotate_aux.y,
|
2016-07-19 17:35:25 +00:00
|
|
|
SFVEC3F( 0.0f, 1.0f, 0.0f ) );
|
2020-01-15 18:03:57 +00:00
|
|
|
normalise2PI( m_rotate_aux.y );
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
m_rotationMatrixAux = glm::rotate( m_rotationMatrixAux, m_rotate_aux.z,
|
2016-07-19 17:35:25 +00:00
|
|
|
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
2020-01-15 18:03:57 +00:00
|
|
|
normalise2PI( m_rotate_aux.z );
|
2016-07-19 17:35:25 +00:00
|
|
|
|
|
|
|
m_parametersChanged = true;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
updateFrustum();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-24 08:47:28 +00:00
|
|
|
glm::mat4 CAMERA::GetRotationMatrix() const
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
return m_rotationMatrix * m_rotationMatrixAux;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 08:04:36 +00:00
|
|
|
|
2021-06-24 08:47:28 +00:00
|
|
|
void CAMERA::SetRotationMatrix( const glm::mat4& aRotation )
|
|
|
|
{
|
|
|
|
m_parametersChanged = true;
|
|
|
|
std::copy_n( glm::value_ptr( aRotation * glm::inverse( m_rotationMatrixAux ) ), 12,
|
|
|
|
glm::value_ptr( m_rotationMatrix ) );
|
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2021-07-05 08:04:36 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::rebuildProjection()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2020-12-13 23:02:57 +00:00
|
|
|
if( ( m_windowSize.x == 0 ) || ( m_windowSize.y == 0 ) )
|
2016-07-19 17:35:25 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_frustum.ratio = (float) m_windowSize.x / (float)m_windowSize.y;
|
2021-10-24 17:30:40 +00:00
|
|
|
m_frustum.farD = glm::length( m_camera_pos_init ) * m_maxZoom * 2.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
switch( m_projectionType )
|
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
default:
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::PERSPECTIVE:
|
2016-07-19 17:35:25 +00:00
|
|
|
|
|
|
|
m_frustum.nearD = 0.10f;
|
|
|
|
|
2021-09-12 19:43:03 +00:00
|
|
|
m_frustum.angle = 45.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
m_projectionMatrix = glm::perspective( glm::radians( m_frustum.angle ), m_frustum.ratio,
|
|
|
|
m_frustum.nearD, m_frustum.farD );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2016-07-19 17:35:25 +00:00
|
|
|
m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-01-05 19:02:54 +00:00
|
|
|
m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
m_focalLen.x = ( (float)m_windowSize.y / (float)m_windowSize.x ) / m_frustum.tang;
|
|
|
|
m_focalLen.y = 1.0f / m_frustum.tang;
|
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
m_frustum.nh = 2.0f * m_frustum.nearD * m_frustum.tang;
|
2015-12-08 07:31:57 +00:00
|
|
|
m_frustum.nw = m_frustum.nh * m_frustum.ratio;
|
2021-06-11 10:31:42 +00:00
|
|
|
m_frustum.fh = 2.0f * m_frustum.farD * m_frustum.tang;
|
2015-12-08 07:31:57 +00:00
|
|
|
m_frustum.fw = m_frustum.fh * m_frustum.ratio;
|
|
|
|
break;
|
|
|
|
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::ORTHO:
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
// Keep the viewed plane at (m_camera_pos_init * m_zoom) the same dimensions in both projections.
|
|
|
|
m_frustum.angle = 45.0f;
|
|
|
|
m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f );
|
|
|
|
|
2016-09-07 05:10:33 +00:00
|
|
|
m_frustum.nearD = -m_frustum.farD; // Use a symmetrical clip plane for ortho projection
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
const float orthoReductionFactor =
|
|
|
|
glm::length( m_camera_pos_init ) * m_zoom * m_frustum.tang;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-12-13 23:02:57 +00:00
|
|
|
// Initialize Projection Matrix for Orthographic View
|
2020-01-05 19:02:54 +00:00
|
|
|
m_projectionMatrix = glm::ortho( -m_frustum.ratio * orthoReductionFactor,
|
|
|
|
m_frustum.ratio * orthoReductionFactor,
|
|
|
|
-orthoReductionFactor,
|
|
|
|
orthoReductionFactor,
|
2016-07-19 17:35:25 +00:00
|
|
|
m_frustum.nearD, m_frustum.farD );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2016-07-19 17:35:25 +00:00
|
|
|
m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-01-05 19:02:54 +00:00
|
|
|
m_frustum.nw = orthoReductionFactor * 2.0f * m_frustum.ratio;
|
|
|
|
m_frustum.nh = orthoReductionFactor * 2.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
m_frustum.fw = m_frustum.nw;
|
|
|
|
m_frustum.fh = m_frustum.nh;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-12-13 23:02:57 +00:00
|
|
|
if( ( m_windowSize.x > 0 ) && ( m_windowSize.y > 0 ) )
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-10-22 22:37:13 +00:00
|
|
|
m_scr_nX.resize( m_windowSize.x + 1 );
|
|
|
|
m_scr_nY.resize( m_windowSize.y + 1 );
|
|
|
|
|
|
|
|
// Precalc X values for camera -> ray generation
|
|
|
|
for( unsigned int x = 0; x < (unsigned int)m_windowSize.x + 1; ++x )
|
|
|
|
{
|
|
|
|
// Converts 0.0 .. 1.0
|
|
|
|
const float xNormalizedDeviceCoordinates = ( ( (float)x + 0.5f ) /
|
|
|
|
(m_windowSize.x - 0.0f) );
|
|
|
|
|
|
|
|
// Converts -1.0 .. 1.0
|
|
|
|
m_scr_nX[x] = 2.0f * xNormalizedDeviceCoordinates - 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Precalc Y values for camera -> ray generation
|
|
|
|
for( unsigned int y = 0; y < (unsigned int)m_windowSize.y + 1 ; ++y )
|
|
|
|
{
|
|
|
|
// Converts 0.0 .. 1.0
|
|
|
|
const float yNormalizedDeviceCoordinates = ( ( (float)y + 0.5f ) /
|
|
|
|
(m_windowSize.y - 0.0f) );
|
|
|
|
|
|
|
|
// Converts -1.0 .. 1.0
|
|
|
|
m_scr_nY[y] = 2.0f * yNormalizedDeviceCoordinates - 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateFrustum();
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::updateFrustum()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
|
|
|
// Update matrix and vectors
|
2016-07-19 17:35:25 +00:00
|
|
|
m_viewMatrixInverse = glm::inverse( m_viewMatrix );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2016-07-19 17:35:25 +00:00
|
|
|
m_right = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
|
|
|
glm::vec4( SFVEC3F( 1.0, 0.0, 0.0 ), 0.0 ) ) );
|
|
|
|
|
|
|
|
m_up = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
|
|
|
glm::vec4( SFVEC3F( 0.0, 1.0, 0.0 ), 0.0 ) ) );
|
|
|
|
|
|
|
|
m_dir = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
|
|
|
glm::vec4( SFVEC3F( 0.0, 0.0, 1.0 ), 0.0 ) ) );
|
|
|
|
|
|
|
|
m_pos = SFVEC3F( m_viewMatrixInverse * glm::vec4( SFVEC3F( 0.0, 0.0, 0.0 ), 1.0 ) );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Frustum is a implementation based on a tutorial by
|
|
|
|
* http://www.lighthouse3d.com/tutorials/view-frustum-culling/
|
|
|
|
*/
|
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
const SFVEC3F half_right_nw = m_right * m_frustum.nw * 0.5f;
|
|
|
|
const SFVEC3F half_right_fw = m_right * m_frustum.fw * 0.5f;
|
|
|
|
const SFVEC3F half_up_nh = m_up * m_frustum.nh * 0.5f;
|
|
|
|
const SFVEC3F half_up_fh = m_up * m_frustum.fh * 0.5f;
|
|
|
|
|
2015-12-08 07:31:57 +00:00
|
|
|
// compute the centers of the near and far planes
|
|
|
|
m_frustum.nc = m_pos - m_dir * m_frustum.nearD;
|
|
|
|
m_frustum.fc = m_pos - m_dir * m_frustum.farD;
|
|
|
|
|
|
|
|
// compute the 4 corners of the frustum on the near plane
|
2021-06-11 10:31:42 +00:00
|
|
|
m_frustum.ntl = m_frustum.nc + half_up_nh - half_right_nw;
|
|
|
|
m_frustum.ntr = m_frustum.nc + half_up_nh + half_right_nw;
|
|
|
|
m_frustum.nbl = m_frustum.nc - half_up_nh - half_right_nw;
|
|
|
|
m_frustum.nbr = m_frustum.nc - half_up_nh + half_right_nw;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
// compute the 4 corners of the frustum on the far plane
|
2021-06-11 10:31:42 +00:00
|
|
|
m_frustum.ftl = m_frustum.fc + half_up_fh - half_right_fw;
|
|
|
|
m_frustum.ftr = m_frustum.fc + half_up_fh + half_right_fw;
|
|
|
|
m_frustum.fbl = m_frustum.fc - half_up_fh - half_right_fw;
|
|
|
|
m_frustum.fbr = m_frustum.fc - half_up_fh + half_right_fw;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2020-12-13 23:02:57 +00:00
|
|
|
if( ( m_windowSize.x > 0 ) && ( m_windowSize.y > 0 ) )
|
2016-10-22 22:37:13 +00:00
|
|
|
{
|
|
|
|
// Reserve size for precalc values
|
|
|
|
m_right_nX.resize( m_windowSize.x + 1 );
|
|
|
|
m_up_nY.resize( m_windowSize.y + 1 );
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2016-10-22 22:37:13 +00:00
|
|
|
// Precalc X values for camera -> ray generation
|
2020-12-13 23:02:57 +00:00
|
|
|
for( unsigned int x = 0; x < ( (unsigned int) m_windowSize.x + 1 ); ++x )
|
2021-06-11 10:31:42 +00:00
|
|
|
m_right_nX[x] = half_right_nw * m_scr_nX[x];
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2016-10-22 22:37:13 +00:00
|
|
|
// Precalc Y values for camera -> ray generation
|
2020-12-13 23:02:57 +00:00
|
|
|
for( unsigned int y = 0; y < ( (unsigned int) m_windowSize.y + 1 ); ++y )
|
2021-06-11 10:31:42 +00:00
|
|
|
m_up_nY[y] = half_up_nh * m_scr_nY[y];
|
2016-10-22 22:37:13 +00:00
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::MakeRay( const SFVEC2I& aWindowPos, SFVEC3F& aOutOrigin,
|
|
|
|
SFVEC3F& aOutDirection ) const
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
wxASSERT( aWindowPos.x < m_windowSize.x );
|
|
|
|
wxASSERT( aWindowPos.y < m_windowSize.y );
|
2016-10-22 22:37:13 +00:00
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
aOutOrigin = m_frustum.nc + m_up_nY[aWindowPos.y] + m_right_nX[aWindowPos.x];
|
2016-10-22 22:37:13 +00:00
|
|
|
|
|
|
|
switch( m_projectionType )
|
|
|
|
{
|
|
|
|
default:
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::PERSPECTIVE:
|
2016-10-22 22:37:13 +00:00
|
|
|
aOutDirection = glm::normalize( aOutOrigin - m_pos );
|
|
|
|
break;
|
|
|
|
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::ORTHO:
|
2019-05-13 21:14:15 +00:00
|
|
|
aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
|
2016-10-22 22:37:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::MakeRay( const SFVEC2F& aWindowPos, SFVEC3F& aOutOrigin,
|
|
|
|
SFVEC3F& aOutDirection ) const
|
2016-10-22 22:37:13 +00:00
|
|
|
{
|
|
|
|
wxASSERT( aWindowPos.x < (float)m_windowSize.x );
|
|
|
|
wxASSERT( aWindowPos.y < (float)m_windowSize.y );
|
|
|
|
|
|
|
|
const SFVEC2F floorWinPos_f = glm::floor( aWindowPos );
|
|
|
|
const SFVEC2I floorWinPos_i = (SFVEC2I)floorWinPos_f;
|
|
|
|
const SFVEC2F relativeWinPos = aWindowPos - floorWinPos_f;
|
|
|
|
|
|
|
|
// Note: size of vectors m_up and m_right are m_windowSize + 1
|
|
|
|
const SFVEC3F up_plus_right = m_up_nY[floorWinPos_i.y] * (1.0f - relativeWinPos.y) +
|
|
|
|
m_up_nY[floorWinPos_i.y + 1] * relativeWinPos.y +
|
|
|
|
m_right_nX[floorWinPos_i.x] * (1.0f - relativeWinPos.x) +
|
|
|
|
m_right_nX[floorWinPos_i.x + 1] * relativeWinPos.x;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2021-06-11 10:31:42 +00:00
|
|
|
aOutOrigin = up_plus_right + m_frustum.nc;
|
|
|
|
|
2016-07-19 17:35:25 +00:00
|
|
|
switch( m_projectionType )
|
|
|
|
{
|
|
|
|
default:
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::PERSPECTIVE:
|
2016-07-19 17:35:25 +00:00
|
|
|
aOutDirection = glm::normalize( aOutOrigin - m_pos );
|
|
|
|
break;
|
|
|
|
|
2019-12-30 13:01:06 +00:00
|
|
|
case PROJECTION_TYPE::ORTHO:
|
2019-05-13 21:14:15 +00:00
|
|
|
aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
|
2016-07-19 17:35:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-11 10:57:15 +00:00
|
|
|
void CAMERA::MakeRayAtCurrentMousePosition( SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2020-12-13 23:02:57 +00:00
|
|
|
const SFVEC2I windowPos = SFVEC2I( m_lastPosition.x, m_windowSize.y - m_lastPosition.y );
|
2020-09-04 00:00:56 +00:00
|
|
|
|
2020-09-30 22:14:10 +00:00
|
|
|
if( ( 0 < windowPos.x ) && ( windowPos.x < m_windowSize.x ) &&
|
|
|
|
( 0 < windowPos.y ) && ( windowPos.y < m_windowSize.y ) )
|
|
|
|
{
|
|
|
|
MakeRay( windowPos, aOutOrigin, aOutDirection );
|
|
|
|
}
|
2016-07-19 17:35:25 +00:00
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
const glm::mat4& CAMERA::GetProjectionMatrix() const
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
return m_projectionMatrix;
|
|
|
|
}
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
const glm::mat4& CAMERA::GetProjectionMatrixInv() const
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
return m_projectionMatrixInv;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-10-24 17:30:40 +00:00
|
|
|
float CAMERA::GetCameraMinDimension() const
|
|
|
|
{
|
|
|
|
return -m_camera_pos_init.z * m_frustum.tang;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::ResetXYpos()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
m_parametersChanged = true;
|
|
|
|
m_camera_pos.x = 0.0f;
|
|
|
|
m_camera_pos.y = 0.0f;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
updateFrustum();
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::ResetXYpos_T1()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
m_camera_pos_t1.x = 0.0f;
|
|
|
|
m_camera_pos_t1.y = 0.0f;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
const glm::mat4& CAMERA::GetViewMatrix() const
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
|
|
|
return m_viewMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-24 08:47:28 +00:00
|
|
|
void CAMERA::SetViewMatrix( glm::mat4 aViewMatrix )
|
|
|
|
{
|
|
|
|
SetRotationMatrix( aViewMatrix );
|
|
|
|
|
|
|
|
// The look at position in the view frame.
|
|
|
|
glm::vec4 lookat = aViewMatrix * glm::vec4( m_lookat_pos, 1.0f );
|
|
|
|
|
|
|
|
wxLogTrace( m_logTrace,
|
|
|
|
wxT( "CAMERA::SetViewMatrix aViewMatrix[3].z =%f, old_zoom=%f, new_zoom=%f, "
|
|
|
|
"m[3].z=%f" ),
|
|
|
|
aViewMatrix[3].z, m_zoom, lookat.z / m_camera_pos_init.z, lookat.z );
|
|
|
|
|
|
|
|
m_zoom = lookat.z / m_camera_pos_init.z;
|
|
|
|
|
|
|
|
if( m_zoom > m_maxZoom )
|
|
|
|
{
|
|
|
|
m_zoom = m_maxZoom;
|
|
|
|
aViewMatrix[3].z += -lookat.z + m_maxZoom * m_camera_pos_init.z;
|
|
|
|
}
|
|
|
|
else if( m_zoom < m_minZoom )
|
|
|
|
{
|
|
|
|
m_zoom = m_minZoom;
|
|
|
|
aViewMatrix[3].z += -lookat.z + m_minZoom * m_camera_pos_init.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_viewMatrix = std::move( aViewMatrix );
|
|
|
|
m_camera_pos = m_viewMatrix
|
|
|
|
* glm::inverse( m_rotationMatrix * m_rotationMatrixAux
|
|
|
|
* glm::translate( glm::mat4( 1.0f ), -m_lookat_pos ) )[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
const glm::mat4& CAMERA::GetViewMatrix_Inv() const
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
return m_viewMatrixInverse;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::SetCurMousePosition( const wxPoint& aNewMousePosition )
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
|
|
|
m_lastPosition = aNewMousePosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::ToggleProjection()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2019-12-30 13:01:06 +00:00
|
|
|
if( m_projectionType == PROJECTION_TYPE::ORTHO )
|
|
|
|
m_projectionType = PROJECTION_TYPE::PERSPECTIVE;
|
2016-07-19 17:35:25 +00:00
|
|
|
else
|
2019-12-30 13:01:06 +00:00
|
|
|
m_projectionType = PROJECTION_TYPE::ORTHO;
|
2016-07-19 17:35:25 +00:00
|
|
|
|
|
|
|
rebuildProjection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
bool CAMERA::SetCurWindowSize( const wxSize& aSize )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
const SFVEC2I newSize = SFVEC2I( aSize.x, aSize.y );
|
|
|
|
|
|
|
|
if( m_windowSize != newSize )
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
m_windowSize = newSize;
|
2015-12-08 07:31:57 +00:00
|
|
|
rebuildProjection();
|
2016-07-19 17:35:25 +00:00
|
|
|
|
|
|
|
return true;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
2016-07-19 17:35:25 +00:00
|
|
|
|
|
|
|
return false;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::ZoomReset()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
|
|
|
m_zoom = 1.0f;
|
|
|
|
|
|
|
|
m_camera_pos.z = m_camera_pos_init.z;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
rebuildProjection();
|
|
|
|
}
|
|
|
|
|
2021-07-05 08:04:36 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
bool CAMERA::Zoom( float aFactor )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
2021-06-24 08:47:28 +00:00
|
|
|
if( ( m_zoom <= m_minZoom && aFactor > 1 ) || ( m_zoom >= m_maxZoom && aFactor < 1 )
|
2021-10-24 17:30:40 +00:00
|
|
|
|| aFactor == 1 )
|
|
|
|
{
|
2017-01-14 14:17:56 +00:00
|
|
|
return false;
|
2021-10-24 17:30:40 +00:00
|
|
|
}
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2021-06-24 08:47:28 +00:00
|
|
|
float zoom = m_zoom;
|
2017-01-14 14:17:56 +00:00
|
|
|
m_zoom /= aFactor;
|
2020-12-13 23:02:57 +00:00
|
|
|
|
2021-06-24 08:47:28 +00:00
|
|
|
if( m_zoom <= m_minZoom && aFactor > 1 )
|
|
|
|
{
|
|
|
|
aFactor = zoom / m_minZoom;
|
|
|
|
m_zoom = m_minZoom;
|
|
|
|
}
|
|
|
|
else if( m_zoom >= m_maxZoom && aFactor < 1 )
|
|
|
|
{
|
|
|
|
aFactor = zoom / m_maxZoom;
|
|
|
|
m_zoom = m_maxZoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_camera_pos.z /= aFactor;
|
|
|
|
|
|
|
|
updateViewMatrix();
|
|
|
|
rebuildProjection();
|
|
|
|
|
2017-01-14 14:17:56 +00:00
|
|
|
return true;
|
2016-07-19 17:35:25 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 23:02:57 +00:00
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
bool CAMERA::Zoom_T1( float aFactor )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
2021-06-24 08:47:28 +00:00
|
|
|
if( ( m_zoom <= m_minZoom && aFactor > 1 ) || ( m_zoom >= m_maxZoom && aFactor < 1 )
|
2021-10-24 17:30:40 +00:00
|
|
|
|| aFactor == 1 )
|
|
|
|
{
|
2017-01-14 14:17:56 +00:00
|
|
|
return false;
|
2021-10-24 17:30:40 +00:00
|
|
|
}
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2017-01-14 14:17:56 +00:00
|
|
|
m_zoom_t1 = m_zoom / aFactor;
|
2020-12-13 23:02:57 +00:00
|
|
|
|
2021-10-24 17:30:40 +00:00
|
|
|
if( m_zoom_t1 < m_minZoom )
|
|
|
|
m_zoom_t1 = m_minZoom;
|
2020-12-13 23:02:57 +00:00
|
|
|
|
2021-10-24 17:30:40 +00:00
|
|
|
if( m_zoom_t1 > m_maxZoom )
|
|
|
|
m_zoom_t1 = m_maxZoom;
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2017-01-14 14:17:56 +00:00
|
|
|
m_camera_pos_t1.z = m_camera_pos_init.z * m_zoom_t1;
|
2016-07-19 17:35:25 +00:00
|
|
|
|
2017-01-14 14:17:56 +00:00
|
|
|
return true;
|
2015-12-08 07:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateX( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux.x += aAngleInRadians;
|
|
|
|
updateRotationMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateY( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux.y += aAngleInRadians;
|
|
|
|
updateRotationMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateZ( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux.z += aAngleInRadians;
|
|
|
|
updateRotationMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateX_T1( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux_t1.x += aAngleInRadians;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateY_T1( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux_t1.y += aAngleInRadians;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::RotateZ_T1( float aAngleInRadians )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_rotate_aux_t1.z += aAngleInRadians;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::SetT0_and_T1_current_T()
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
m_camera_pos_t0 = m_camera_pos;
|
|
|
|
m_lookat_pos_t0 = m_lookat_pos;
|
|
|
|
m_rotate_aux_t0 = m_rotate_aux;
|
|
|
|
m_zoom_t0 = m_zoom;
|
|
|
|
|
|
|
|
m_camera_pos_t1 = m_camera_pos;
|
|
|
|
m_lookat_pos_t1 = m_lookat_pos;
|
|
|
|
m_rotate_aux_t1 = m_rotate_aux;
|
|
|
|
m_zoom_t1 = m_zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
void CAMERA::Interpolate( float t )
|
2016-07-19 17:35:25 +00:00
|
|
|
{
|
|
|
|
wxASSERT( t >= 0.0f );
|
|
|
|
|
|
|
|
const float t0 = 1.0f - t;
|
|
|
|
|
|
|
|
m_camera_pos = m_camera_pos_t0 * t0 + m_camera_pos_t1 * t;
|
|
|
|
m_lookat_pos = m_lookat_pos_t0 * t0 + m_lookat_pos_t1 * t;
|
|
|
|
m_rotate_aux = m_rotate_aux_t0 * t0 + m_rotate_aux_t1 * t;
|
|
|
|
m_zoom = m_zoom_t0 * t0 + m_zoom_t1 * t;
|
|
|
|
|
|
|
|
m_parametersChanged = true;
|
|
|
|
|
|
|
|
updateRotationMatrix();
|
|
|
|
rebuildProjection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 21:05:29 +00:00
|
|
|
bool CAMERA::ParametersChanged()
|
2015-12-08 07:31:57 +00:00
|
|
|
{
|
2016-07-19 17:35:25 +00:00
|
|
|
const bool parametersChanged = m_parametersChanged;
|
2015-12-08 07:31:57 +00:00
|
|
|
|
|
|
|
m_parametersChanged = false;
|
|
|
|
|
|
|
|
return parametersChanged;
|
|
|
|
}
|