Radium Engine  1.5.0
FlightCameraManipulator.cpp
1 #include <Gui/Viewer/FlightCameraManipulator.hpp>
2 
3 #include <Core/Asset/Camera.hpp>
4 #include <Core/Math/Math.hpp>
5 #include <Core/Utils/Log.hpp>
6 #include <Engine/Scene/Light.hpp>
7 #include <Gui/Utils/Keyboard.hpp>
8 
9 #include <Gui/Utils/KeyMappingManager.hpp>
10 
11 #include <Engine/Scene/CameraComponent.hpp>
12 #include <QApplication>
13 #include <QMessageBox>
14 #include <algorithm>
15 #include <functional>
16 #include <iostream>
17 #include <utility>
18 
19 namespace Ra {
20 namespace Gui {
21 
22 using Core::Math::Pi;
23 using namespace Core::Utils;
24 
26 using FlightCameraKeyMapping = Ra::Gui::KeyMappingManageable<FlightCameraManipulator>;
27 
28 #define KMA_VALUE( XX ) Gui::KeyMappingManager::KeyMappingAction Gui::FlightCameraManipulator::XX;
29 KeyMappingFlightManipulator
30 #undef KMA_VALUE
31 
32 void FlightCameraManipulator::configureKeyMapping_impl() {
33 
34  FlightCameraKeyMapping::setContext(
35  Gui::KeyMappingManager::getInstance()->getContext( "FlightManipulatorContext" ) );
36 
37  if ( KeyMapping::getContext().isInvalid() ) {
38  LOG( logWARNING )
39  << "CameraContext not defined (maybe the configuration file do not contains "
40  "it). Add it for default key mapping.";
41  FlightCameraKeyMapping::setContext(
42  Gui::KeyMappingManager::getInstance()->addContext( "FlightManipulatorContext" ) );
43  }
44 
45 #define KMA_VALUE( XX ) \
46  XX = Gui::KeyMappingManager::getInstance()->getAction( FlightCameraKeyMapping::getContext(), \
47  #XX );
48  KeyMappingFlightManipulator
49 #undef KMA_VALUE
50 
51  auto mgr = Gui::KeyMappingManager::getInstance();
52  auto context = FlightCameraKeyMapping::getContext();
53 
54  // use wrapper to have reference in pair
55  using ActionBindingPair = std::pair<std::reference_wrapper<KeyMappingManager::KeyMappingAction>,
56  KeyMappingManager::EventBinding>;
57 
58  // don't use [] since reference don't have a default value. use at and insert instead.
59  std::map<std::string, ActionBindingPair> defaultBinding;
60 
61  defaultBinding.insert(
62  std::make_pair( std::string { "FLIGHTMODECAMERA_PAN" },
63  ActionBindingPair { FLIGHTMODECAMERA_PAN,
64  mgr->createEventBindingFromStrings(
65  "LeftButton", "ShiftModifier" ) } ) );
66 
67  defaultBinding.insert( std::make_pair(
68  std::string { "FLIGHTMODECAMERA_ROTATE" },
69  ActionBindingPair { FLIGHTMODECAMERA_ROTATE,
70  mgr->createEventBindingFromStrings( "LeftButton" ) } ) );
71 
72  defaultBinding.insert(
73  std::make_pair( std::string { "FLIGHTMODECAMERA_ZOOM" },
74  ActionBindingPair { FLIGHTMODECAMERA_ZOOM,
75  mgr->createEventBindingFromStrings(
76  "LeftButton", "ControlModifier" ) } ) );
77 
78  for ( auto& [actionName, actionBinding] : defaultBinding ) {
79  if ( actionBinding.first.get().isInvalid() ) {
80  LOG( logWARNING ) << "FlightManipulator action " << actionName
81  << " not defined in configuration file. Adding default keymapping.";
82  actionBinding.first.get() = mgr->addAction( context, actionBinding.second, actionName );
83  }
84  }
85 }
87 
88 void FlightCameraManipulator::setupKeyMappingCallbacks() {
89 
90  m_keyMappingCallbackManager.addEventCallback( FLIGHTMODECAMERA_PAN,
91  [=]( QEvent* event ) { panCallback( event ); } );
92  m_keyMappingCallbackManager.addEventCallback(
93  FLIGHTMODECAMERA_ROTATE, [=]( QEvent* event ) { rotateCallback( event ); } );
94 
95  m_keyMappingCallbackManager.addEventCallback( FLIGHTMODECAMERA_ZOOM,
96  [=]( QEvent* event ) { zoomCallback( event ); } );
97 }
98 
99 void FlightCameraManipulator::panCallback( QEvent* event ) {
100  if ( event->type() == QEvent::MouseMove ) {
101  auto mouseEvent = reinterpret_cast<QMouseEvent*>( event );
102  auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
103  handleCameraPan( dx, dy );
104  }
105 }
106 
107 void FlightCameraManipulator::rotateCallback( QEvent* event ) {
108  if ( event->type() == QEvent::MouseMove ) {
109  auto mouseEvent = reinterpret_cast<QMouseEvent*>( event );
110  auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
111  handleCameraRotate( dx, dy );
112  }
113 }
114 
115 void FlightCameraManipulator::zoomCallback( QEvent* event ) {
116  if ( event->type() == QEvent::MouseMove ) {
117  auto mouseEvent = reinterpret_cast<QMouseEvent*>( event );
118  auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
119  handleCameraZoom( dx, dy );
120  }
121  if ( event->type() == QEvent::Wheel ) {
122  auto wheelEvent = reinterpret_cast<QWheelEvent*>( event );
123  handleCameraZoom(
124  ( wheelEvent->angleDelta().y() * 0.01_ra + wheelEvent->angleDelta().x() * 0.01_ra ) *
125  m_wheelSpeedModifier );
126  }
127 }
128 
130  return FlightCameraKeyMapping::getContext();
131 }
132 
133 FlightCameraManipulator::FlightCameraManipulator() :
134  CameraManipulator(), m_keyMappingCallbackManager { KeyMapping::getContext() } {
135  resetCamera();
136  setupKeyMappingCallbacks();
137  m_cameraSensitivity = 2_ra;
138 }
139 
141 FlightCameraManipulator::FlightCameraManipulator( const CameraManipulator& other ) :
142  CameraManipulator( other ), m_keyMappingCallbackManager { KeyMapping::getContext() } {
143  m_flightSpeed = ( m_target - m_camera->getPosition() ).norm() / 10_ra;
144  initializeFixedUpVector();
145  setupKeyMappingCallbacks();
146  m_cameraSensitivity = 2_ra;
147 }
149 
151 
153 
154  initializeFixedUpVector();
155 
156  m_target = m_camera->getPosition() + 2_ra * m_camera->getDirection().normalized();
157  m_flightSpeed = 0.2_ra;
158 
159  if ( m_light != nullptr ) {
162  }
163 }
164 
165 void FlightCameraManipulator::resetCamera() {
166  m_camera->setFrame( Core::Transform::Identity() );
167  m_camera->setPosition( Core::Vector3( 0, 0, 1 ) );
168  initializeFixedUpVector();
169 
170  m_target = m_camera->getPosition() + 2_ra * m_camera->getDirection().normalized();
171  m_flightSpeed = 0.2_ra;
172 
173  if ( m_light != nullptr ) {
176  }
177 }
178 
180  const Qt::MouseButtons&,
181  const Qt::KeyboardModifiers&,
182  int key ) {
183  m_lastMouseX = event->pos().x();
184  m_lastMouseY = event->pos().y();
185  bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key );
186  return handled;
187 }
188 
190  const Qt::MouseButtons& /*buttons*/,
191  const Qt::KeyboardModifiers& /*modifiers*/,
192  int key ) {
193 
194  bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key );
195 
196  m_lastMouseX = event->pos().x();
197  m_lastMouseY = event->pos().y();
198 
199  if ( m_light != nullptr ) {
202  }
203 
204  return handled;
205 }
206 
207 bool FlightCameraManipulator::handleMouseReleaseEvent( QMouseEvent* /*event*/ ) {
208  return false;
209 }
210 
212  const Qt::MouseButtons&,
213  const Qt::KeyboardModifiers&,
214  int key ) {
216  bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key, true );
217 
218  if ( m_light != nullptr ) {
221  }
222 
223  return handled;
224 }
225 
227  QKeyEvent* event,
228  const KeyMappingManager::KeyMappingAction& action ) {
229  return m_keyMappingCallbackManager.triggerEventCallback( action, event );
230 }
231 
232 void FlightCameraManipulator::setCameraPosition( const Core::Vector3& position ) {
233  if ( position == m_target ) {
234  QMessageBox::warning( nullptr, "Error", "Position cannot be set to target point" );
235  return;
236  }
237  m_camera->setPosition( position );
238  m_camera->setDirection( ( m_target - position ).normalized() );
239 
240  if ( m_light != nullptr ) {
243  }
244 }
245 
246 void FlightCameraManipulator::setCameraTarget( const Core::Vector3& target ) {
247  if ( m_camera->getPosition() == m_target ) {
248  QMessageBox::warning( nullptr, "Error", "Target cannot be set to current camera position" );
249  return;
250  }
251 
252  m_target = target;
253  m_camera->setDirection( ( target - m_camera->getPosition() ).normalized() );
254 
255  if ( m_light != nullptr ) { m_light->setDirection( m_camera->getDirection() ); }
256 }
257 
258 void FlightCameraManipulator::fitScene( const Core::Aabb& aabb ) {
259  resetCamera();
260 
261  Scalar f = m_camera->getFOV();
262  Scalar a = m_camera->getAspect();
263 
264  const Scalar r = ( aabb.max() - aabb.min() ).norm() / 2_ra;
265  const Scalar x = r / std::sin( f / 2_ra );
266  const Scalar y = r / std::sin( f * a / 2_ra );
267  Scalar d = std::max( std::max( x, y ), 0.001_ra );
268 
270  Core::Vector3( aabb.center().x(), aabb.center().y(), aabb.center().z() + d ) );
271  m_camera->setDirection( Core::Vector3( 0_ra, 0_ra, -1_ra ) );
272  initializeFixedUpVector();
273  m_target = aabb.center();
274 
275  m_flightSpeed = d / 10_ra;
276 
277  Scalar zfar = std::max( d + ( aabb.max().z() - aabb.min().z() ) * 2_ra, m_camera->getZFar() );
278  m_camera->setZFar( zfar );
279 
280  if ( m_light != nullptr ) {
283  }
284 }
285 
286 void FlightCameraManipulator::handleCameraRotate( Scalar dx, Scalar dy ) {
287  Scalar dphi = dx * m_cameraSensitivity * m_quickCameraModifier;
288  Scalar dtheta = -dy * m_cameraSensitivity * m_quickCameraModifier;
289 
290  Core::Transform R( Core::Transform::Identity() );
291  if ( std::abs( dphi ) > std::abs( dtheta ) ) {
292  R = Core::AngleAxis( -dphi, /*m_camera->getUpVector().normalized()*/ m_fixUpVector );
293  }
294  else { R = Core::AngleAxis( -dtheta, -m_camera->getRightVector().normalized() ); }
295 
296  Scalar d = ( m_target - m_camera->getPosition() ).norm();
297 
298  m_camera->applyTransform( R );
300 }
301 
302 void FlightCameraManipulator::handleCameraPan( Scalar dx, Scalar dy ) {
303  Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier;
304  Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier;
305  // Move camera and trackball center, keep the distance to the center
306  Core::Vector3 R = -m_camera->getRightVector();
307  Core::Vector3 U = m_fixUpVector; // m_camera->getUpVector();
308 
309  Core::Transform T( Core::Transform::Identity() );
310  Core::Vector3 t = x * R + y * U;
311  T.translate( t );
312 
313  m_camera->applyTransform( T );
314  m_target += t;
315 }
316 
317 void FlightCameraManipulator::handleCameraZoom( Scalar dx, Scalar dy ) {
318  handleCameraZoom( Ra::Core::Math::sign( dy ) * ( std::abs( dx ) + std::abs( dy ) ) );
319 }
320 
321 void FlightCameraManipulator::handleCameraZoom( Scalar z ) {
322  auto y = m_flightSpeed * z * m_cameraSensitivity * m_quickCameraModifier;
323  Core::Transform T( Core::Transform::Identity() );
324  Core::Vector3 t = y * m_camera->getDirection();
325  T.translate( t );
326  m_camera->applyTransform( T );
327  m_target += t;
328 }
329 
330 void FlightCameraManipulator::initializeFixedUpVector() {
331 #if 0
332  // This is supposed to adapt the up vector to the main up direction but is not really satisfactory.
333  const auto& upVector = m_camera->getUpVector();
334  if ( std::abs(upVector[0]) > std::abs(upVector[1]) )
335  {
336  if ( std::abs(upVector[0]) > std::abs(upVector[2]) ) { m_fixUpVector = Ra::Core::Vector3( 1, 0, 0 ); }
337  else
338  { m_fixUpVector = Ra::Core::Vector3( 0, 0, 1 ); }
339  }
340  else if ( std::abs(upVector[1]) > std::abs(upVector[2]) )
341  { m_fixUpVector = Ra::Core::Vector3( 0, 1, 0 ); }
342  else
343  { m_fixUpVector = Ra::Core::Vector3( 0, 0, 1 ); }
344 #endif
345  m_fixUpVector = Ra::Core::Vector3( 0_ra, 1_ra, 0_ra );
346 }
347 
348 } // namespace Gui
349 } // namespace Ra
Scalar getZFar() const
Return the Z Far plane distance from the camera.
Definition: Camera.hpp:293
void setPosition(const Core::Vector3 &position)
Set the position of the camera to position.
Definition: Camera.hpp:248
void setDirection(const Core::Vector3 &direction)
Definition: Camera.cpp:32
void setZFar(Scalar zFar)
Set the Z Far plane distance to zFar.
Definition: Camera.hpp:297
Core::Vector3 getPosition() const
Return the position.
Definition: Camera.hpp:244
Core::Vector3 getUpVector() const
Return the up vector.
Definition: Camera.hpp:258
void setFrame(const Core::Transform &frame)
Set the frame of the camera to frame.
Definition: Camera.hpp:240
Scalar getFOV() const
Definition: Camera.hpp:272
Scalar getAspect() const
Return the aspect ratio of the viewport.
Definition: Camera.hpp:319
Core::Vector3 getDirection() const
Return the direction the camera is looking at.
Definition: Camera.hpp:254
virtual void setDirection(const Eigen::Matrix< Scalar, 3, 1 > &)
Definition: Light.hpp:69
virtual void setPosition(const Eigen::Matrix< Scalar, 3, 1 > &)
Definition: Light.hpp:75
The CameraManipulator class is the generic class for camera manipulators.
Scalar m_lastMouseX
x-position of the mouse on the screen at the manipulation start.
Scalar m_quickCameraModifier
Additional factor for camera sensitivity.
Core::Asset::Camera * m_camera
The Camera.
Scalar m_lastMouseY
y-position of the mouse on the screen at the manipulation start.
Engine::Scene::Light * m_light
The light attached to the Camera.
Scalar m_cameraSensitivity
the Camera sensitivity to manipulation.
bool handleKeyPressEvent(QKeyEvent *event, const KeyMappingManager::KeyMappingAction &action) override
bool handleWheelEvent(QWheelEvent *event, const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &modifiers, int key) override
virtual ~FlightCameraManipulator()
[Constructor]
bool handleMousePressEvent(QMouseEvent *event, const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &modifiers, int key) override
bool handleMouseReleaseEvent(QMouseEvent *event) override
bool handleMouseMoveEvent(QMouseEvent *event, const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &modifiers, int key) override
KeyMappingManager::Context mappingContext() override
bool triggerEventCallback(QEvent *event, int key, bool wheel=false)
Ra::Core::Utils::Index KeyMappingAction
handle to an action
Ra::Core::Utils::Index Context
handle to a Context
constexpr int sign(const T &val)
Returns the sign of any numeric type as { -1, 0, 1}.
Definition: Math.hpp:106
Definition: Cage.cpp:3