Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
19namespace Ra {
20namespace Gui {
21
22using Core::Math::Pi;
23using namespace Core::Utils;
24
27
28#define KMA_VALUE( XX ) Gui::KeyMappingManager::KeyMappingAction Gui::FlightCameraManipulator::XX;
29KeyMappingFlightManipulator
30#undef KMA_VALUE
31
32void 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
56 KeyMappingManager::EventBinding>;
57
58 // don't use [] since reference don't have a default value. use at and insert instead.
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
88void 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
99void 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
107void 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
115void 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 ) *
126 }
127}
128
130 return FlightCameraKeyMapping::getContext();
131}
132
133FlightCameraManipulator::FlightCameraManipulator() :
134 CameraManipulator(), m_keyMappingCallbackManager { KeyMapping::getContext() } {
135 resetCamera();
136 setupKeyMappingCallbacks();
137 m_cameraSensitivity = 2_ra;
138}
139
141FlightCameraManipulator::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
165void 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
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,
229 return m_keyMappingCallbackManager.triggerEventCallback( action, event );
230}
231
232void 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
246void 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
258void 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
286void 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
302void FlightCameraManipulator::handleCameraPan( Scalar dx, Scalar dy ) {
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
317void FlightCameraManipulator::handleCameraZoom( Scalar dx, Scalar dy ) {
318 handleCameraZoom( Ra::Core::Math::sign( dy ) * ( std::abs( dx ) + std::abs( dy ) ) );
319}
320
321void 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
330void 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:67
virtual void setPosition(const Eigen::Matrix< Scalar, 3, 1 > &)
Definition Light.hpp:73
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.
Scalar m_wheelSpeedModifier
Speed modifier on mouse wheel events.
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
KeyMappingManager::Context mappingContext() override
bool handleMouseMoveEvent(QMouseEvent *event, const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &modifiers, int key) override
bool triggerEventCallback(QEvent *event, int key, bool wheel=false)
void addEventCallback(KeyMappingAction action, Callback callback)
KeyMappingManageable decorator to use as CRTP.
Ra::Core::Utils::Index KeyMappingAction
handle to an action
Ra::Core::Utils::Index Context
handle to a Context
T insert(T... args)
T make_pair(T... args)
T max(T... args)
constexpr int sign(const T &val)
Returns the sign of any numeric type as { -1, 0, 1}.
Definition Math.hpp:106
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T sin(T... args)