Radium Engine  1.5.20
Loading...
Searching...
No Matches
Viewer.cpp
1#include <glbinding-aux/ContextInfo.h>
2#include <glbinding-aux/debug.h>
3#include <glbinding-aux/types_to_string.h>
4#include <glbinding/Binding.h>
5#include <glbinding/glbinding.h>
6
7#include <glbinding/Version.h>
8// Do not import namespace to prevent glbinding/QTOpenGL collision
9#include <glbinding/gl/gl.h>
10
11#include <globjects/globjects.h>
12
13// include radium engine here to prevent glbinding incompatibility with gl.h
14#include <Gui/Viewer/Viewer.hpp>
15
16#include <iostream>
17
18#include <QOpenGLContext>
19
20#include <QApplication>
21#include <QMouseEvent>
22#include <QPainter>
23#include <QTimer>
24
25#define STB_IMAGE_WRITE_IMPLEMENTATION
26#include <stb/stb_image_write.h>
27
28#include <Core/Asset/Camera.hpp>
29#include <Core/Asset/FileData.hpp>
30#include <Core/Containers/MakeShared.hpp>
31#include <Core/Math/Math.hpp>
32#include <Core/Utils/Color.hpp>
33#include <Core/Utils/Log.hpp>
34#include <Core/Utils/StringUtils.hpp>
35#include <Engine/Data/ShaderProgramManager.hpp>
36#include <Engine/Data/ViewingParameters.hpp>
37#include <Engine/Rendering/ForwardRenderer.hpp>
38#include <Engine/Rendering/Renderer.hpp>
39#include <Engine/Scene/CameraComponent.hpp>
40#include <Engine/Scene/CameraManager.hpp>
41#include <Engine/Scene/Component.hpp>
42#include <Engine/Scene/DirLight.hpp>
43#include <Engine/Scene/EntityManager.hpp>
45#include <Gui/AboutDialog/RadiumHelpDialog.hpp>
46#include <Gui/Utils/KeyMappingManager.hpp>
47#include <Gui/Utils/Keyboard.hpp>
48#include <Gui/Utils/PickingManager.hpp>
49#include <Gui/Viewer/FlightCameraManipulator.hpp>
50#include <Gui/Viewer/Gizmo/GizmoManager.hpp>
51#include <Gui/Viewer/RotateAroundCameraManipulator.hpp>
52#include <Gui/Viewer/TrackballCameraManipulator.hpp>
53#include <Gui/Viewer/Viewer.hpp>
54
55#include <QApplication>
56#include <QMouseEvent>
57#include <QPainter>
58#include <QTimer>
59
60namespace Ra {
61namespace Gui {
62
63using namespace Core::Utils; // log
64using namespace glbinding;
65
66using ViewerMapping = KeyMappingManageable<Viewer>;
67
68#define KMA_VALUE( x ) KeyMappingManager::KeyMappingAction Viewer::x;
69KeyMappingViewer
70#undef KMA_VALUE
71
72// Register all keymapings related to the viewer and its managed functionalities (Trackball
73// camera, Gizmo, ..)
75 auto keyMappingManager = KeyMappingManager::getInstance();
76
77 // Add default manipulator listener
78 keyMappingManager->addListener( TrackballCameraManipulator::configureKeyMapping );
79 keyMappingManager->addListener( FlightCameraManipulator::configureKeyMapping );
80 keyMappingManager->addListener(
82 // add viewer related listener
83 keyMappingManager->addListener( GizmoManager::configureKeyMapping );
84 keyMappingManager->addListener( configureKeyMapping );
85
86 m_keyMappingCallbackManager = KeyMappingCallbackManager { ViewerMapping::getContext() };
87 m_keyMappingCallbackManager.addEventCallback( VIEWER_TOGGLE_WIREFRAME, [this]( QEvent* event ) {
88 if ( event->type() == QEvent::KeyPress ) m_currentRenderer->toggleWireframe();
89 } );
90 m_keyMappingCallbackManager.addEventCallback( VIEWER_RELOAD_SHADERS, [this]( QEvent* event ) {
91 if ( event->type() == QEvent::KeyPress ) reloadShaders();
92 } );
93 m_keyMappingCallbackManager.addEventCallback(
94 VIEWER_PICKING_MULTI_CIRCLE, [this]( QEvent* event ) {
95 if ( event->type() == QEvent::KeyPress ) {
96 m_isBrushPickingEnabled = !m_isBrushPickingEnabled;
97 m_currentRenderer->setBrushRadius( m_isBrushPickingEnabled ? m_brushRadius : 0 );
98 emit toggleBrushPicking( m_isBrushPickingEnabled );
99 }
100 } );
101 m_keyMappingCallbackManager.addEventCallback( VIEWER_SWITCH_CAMERA, []( QEvent* event ) {
102 if ( event->type() == QEvent::KeyPress ) {
103 auto cameraManager = static_cast<Ra::Engine::Scene::CameraManager*>(
104 Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) );
105 static int idx = 0;
106 if ( cameraManager->count() > 0 ) {
107 idx %= cameraManager->count();
108 cameraManager->activate( idx );
109 }
110 idx++;
111 }
112 } );
113
114 m_keyMappingCallbackManager.addEventCallback( VIEWER_CAMERA_FIT_SCENE, [this]( QEvent* event ) {
115 if ( event->type() == QEvent::KeyPress ) fitCamera();
116 } );
117 m_keyMappingCallbackManager.addEventCallback( VIEWER_HELP, [this]( QEvent* event ) {
118 if ( event->type() == QEvent::KeyPress ) {
119 displayHelpDialog();
120 requestActivate();
121 }
122 } );
123}
124
125void Viewer::configureKeyMapping_impl() {
126 auto keyMappingManager = KeyMappingManager::getInstance();
127 ViewerMapping::setContext( keyMappingManager->getContext( "ViewerContext" ) );
128 if ( ViewerMapping::getContext().isInvalid() ) {
129 LOG( logINFO )
130 << "ViewerContext not defined (maybe the configuration file do not contains it)";
131 LOG( Ra::Core::Utils::logERROR ) << "ViewerContext all keymapping invalide !";
132 return;
133 }
134
135#define KMA_VALUE( XX ) XX = keyMappingManager->getAction( ViewerMapping::getContext(), #XX );
136 KeyMappingViewer
137#undef KMA_VALUE
138}
139
140Viewer::Viewer( QScreen* screen ) :
141 WindowQt( screen ),
142 m_currentRenderer( nullptr ),
143 m_pickingManager( new PickingManager() ),
144 m_isBrushPickingEnabled( false ),
145 m_brushRadius( 10 ),
146 m_camera( nullptr ),
147 m_gizmoManager( nullptr ),
148 m_keyMappingCallbackManager { ViewerMapping::getContext() } {}
149
151 if ( m_glInitialized.load() ) {
152 makeCurrent();
153 m_renderers.clear();
154
155 delete m_gizmoManager;
156 doneCurrent();
157 }
158 delete m_pickingManager;
159}
160
162 m_camera.reset( ci );
163}
164
168
169void Viewer::resetToDefaultCamera() {
170
171 auto cameraManager = static_cast<Ra::Engine::Scene::CameraManager*>(
172 Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) );
173 cameraManager->resetActiveCamera();
174}
175
179
181 return m_currentRenderer;
182}
183
185 return m_currentRenderer;
186}
187
189 m_renderers.push_back( e );
190
191 // initialize the renderer (deferred if GL is not ready yet)
192 if ( m_glInitialized.load() ) {
193 makeCurrent();
194 initializeRenderer( e.get() );
195 LOG( logINFO ) << "[Viewer] New Renderer (" << e->getRendererName() << ") added.";
196 doneCurrent();
197 }
198 else {
199 LOG( logINFO ) << "[Viewer] New Renderer (" << e->getRendererName()
200 << ") added with deferred init.";
201 m_pendingRenderers.push_back( e );
202 }
203
204 return m_renderers.size() - 1;
205}
206
207PickingManager* Viewer::getPickingManager() {
208 return m_pickingManager;
209}
210
211void Viewer::update( const Scalar dt ) {
212 CORE_UNUSED( dt );
213 if ( m_gizmoManager != nullptr ) { m_gizmoManager->updateValues(); }
214}
215
216// Asynchronous rendering implementation
217
218void Viewer::startRendering( const Scalar dt ) {
219
220 CORE_ASSERT( m_glInitialized.load(), "OpenGL needs to be initialized before rendering." );
221
222 CORE_ASSERT( m_currentRenderer != nullptr, "No renderer found." );
223
224 m_pickingManager->clear();
225 makeCurrent();
226
227 // update znear/zfar to fit the scene ...
228 auto entityManager = Engine::RadiumEngine::getInstance()->getEntityManager();
229 if ( entityManager ) {
230
231 // to fit scene only
232 // auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
233 // to fit also debug and system entity aabb
234 Core::Aabb aabb {};
235 for ( const auto& entity : entityManager->getEntities() ) {
236 // entity aabb is in world space
237 aabb.extend( entity->computeAabb() );
238 }
239
240 if ( !aabb.isEmpty() ) { m_camera->getCamera()->fitZRange( aabb ); }
241 else {
242 auto cameraManager = static_cast<Ra::Engine::Scene::CameraManager*>(
243 Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) );
244
245 // scene is empty, reset to defaults bounds
246 m_camera->setCameraZNear( cameraManager->defaultCamera.getZNear() );
247 m_camera->setCameraZFar( cameraManager->defaultCamera.getZFar() );
248 }
249 }
250
253 if ( !m_currentRenderer->hasLight() ) {
254 if ( m_camera->hasLightAttached() )
255 m_currentRenderer->addLight( m_camera->getLight() );
256 else
257 LOG( logDEBUG ) << "Unable to attach the head light!";
258 }
260 m_camera->getCamera()->getViewMatrix(), m_camera->getCamera()->getProjMatrix(), dt };
261 m_currentRenderer->render( data );
262}
263
265 if ( isExposed() ) { m_context->swapBuffers( this ); }
266 doneCurrent();
267}
268
270 CORE_ASSERT( m_glInitialized.load(), "OpenGL needs to be initialized before rendering." );
271
272 CORE_ASSERT( m_currentRenderer != nullptr, "No renderer found." );
273
274 CORE_ASSERT( m_currentRenderer->getPickingQueries().size() ==
275 m_currentRenderer->getPickingResults().size(),
276 "There should be one result per query." );
277
278 for ( uint i = 0; i < m_currentRenderer->getPickingQueries().size(); ++i ) {
280 m_currentRenderer->getPickingQueries()[i];
281
282 if ( query.m_purpose == Engine::Rendering::Renderer::PickingPurpose::MANIPULATION ) {
283 const auto& result = m_currentRenderer->getPickingResults()[i];
284 m_pickingManager->setCurrent( result );
285 emit rightClickPicking( result );
286 }
287 }
288}
289
290void Viewer::fitCameraToScene( const Core::Aabb& aabb ) {
291 if ( !aabb.isEmpty() ) {
292 CORE_ASSERT( m_camera != nullptr, "No camera found." );
293 m_camera->fitScene( aabb );
294
295 // uncomment to display scene aabb
296 // RA_DISPLAY_AABB( aabb, Color::Blue() );
297 emit needUpdate();
298 }
299 else { LOG( logINFO ) << "Unable to fit the camera to the scene : empty Bbox."; }
300}
301
302void Viewer::fitCamera() {
303 auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
304 if ( aabb.isEmpty() ) { getCameraManipulator()->resetCamera(); }
305 else { fitCameraToScene( aabb ); }
306}
307
310
311 for ( const auto& renderer : m_renderers ) {
312 if ( renderer ) { ret.push_back( renderer->getRendererName() ); }
313 }
314
315 return ret;
316}
317
318void Viewer::grabFrame( const std::string& filename ) {
319 makeCurrent();
320
321 size_t w, h;
322 auto writtenPixels = m_currentRenderer->grabFrame( w, h );
323
324 std::string ext = Core::Utils::getFileExt( filename );
325
326 if ( ext == "bmp" ) { stbi_write_bmp( filename.c_str(), w, h, 4, writtenPixels.get() ); }
327 else if ( ext == "png" ) {
328 stbi_write_png( filename.c_str(), w, h, 4, writtenPixels.get(), w * 4 * sizeof( uchar ) );
329 }
330 else {
331 LOG( logWARNING ) << "Cannot write frame to " << filename << " : unsupported extension";
332 }
333
334 doneCurrent();
335}
336
337void Viewer::enableDebug() {
338 glbinding::setCallbackMask( glbinding::CallbackMask::After |
339 glbinding::CallbackMask::ParametersAndReturnValue );
340 glbinding::setAfterCallback( []( const glbinding::FunctionCall& call ) {
341 std::cerr << call.function->name() << "(";
342 for ( unsigned i = 0; i < call.parameters.size(); ++i ) {
343 std::cerr << call.parameters[i].get();
344 if ( i < call.parameters.size() - 1 ) { std::cerr << ", "; }
345 }
346 std::cerr << ")";
347 if ( call.returnValue ) { std::cerr << " -> " << call.returnValue.get(); }
349 } );
350}
351
353 CORE_ASSERT( m_glInitialized.load(), "OpenGL needs to be initialized reload shaders." );
354
355 makeCurrent();
356 // FIXME : check thread-saefty of this.
357 m_currentRenderer->lockRendering();
358 m_currentRenderer->reloadShaders();
359 m_currentRenderer->unlockRendering();
360 doneCurrent();
361
362 emit needUpdate();
363}
364
365void Viewer::displayTexture( const QString& tex ) {
366 CORE_ASSERT( m_glInitialized.load(), "OpenGL needs to be initialized to display textures." );
367
368 makeCurrent();
369 m_currentRenderer->lockRendering();
370 m_currentRenderer->displayTexture( tex.toStdString() );
371 m_currentRenderer->unlockRendering();
372 doneCurrent();
373
374 emit needUpdate();
375}
376
377bool Viewer::changeRenderer( int index ) {
378 if ( m_glInitialized.load() && m_renderers[index] ) {
379 makeCurrent();
380
381 if ( m_currentRenderer != nullptr ) { m_currentRenderer->lockRendering(); }
382
383 m_currentRenderer = m_renderers[index].get();
384 // renderers in m_renderers are supposed to be locked
385 auto deviceSize = toDevice( { width(), height() } );
386 m_currentRenderer->resize( deviceSize.x(), deviceSize.y() );
387 // Configure the renderObjects for this renderer
388 m_currentRenderer->buildAllRenderTechniques();
389 m_currentRenderer->unlockRendering();
390
391 LOG( logINFO ) << "[Viewer] Set active renderer: " << m_currentRenderer->getRendererName();
392
393 // resize camera viewport since the one in show event might have 0x0
394 if ( m_camera ) { m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() ); }
395
396 doneCurrent();
397 emit rendererReady();
398
399 emit needUpdate();
400 return true;
401 }
402 return false;
403}
404
405void Viewer::enablePostProcess( int enabled ) {
406 m_currentRenderer->enablePostProcess( enabled );
407}
408
409void Viewer::enableDebugDraw( int enabled ) {
410 m_currentRenderer->enableDebugDraw( enabled );
411}
412
413void Viewer::setBackgroundColor( const Core::Utils::Color& background ) {
414 m_backgroundColor = background;
415 for ( const auto& renderer : m_renderers )
416 renderer->setBackgroundColor( m_backgroundColor );
417
418 emit needUpdate();
419}
420
421void Viewer::onAboutToCompose() {
422 // This slot function is called from the main thread as part of the event loop
423 // when the GUI is about to update. We have to wait for the rendering to finish.
424 m_currentRenderer->lockRendering();
425}
426
427void Viewer::onAboutToResize() {
428 // Like swap buffers, resizing is a blocking operation and we have to wait for the rendering
429 // to finish before resizing.
430 m_currentRenderer->lockRendering();
431}
432
433void Viewer::onResized() {
434 m_currentRenderer->unlockRendering();
435 emit needUpdate();
436}
437
438void Viewer::onFrameSwapped() {
439 // This slot is called from the main thread as part of the event loop when the
440 // GUI has finished displaying the rendered image, so we unlock the renderer.
441 m_currentRenderer->unlockRendering();
442}
443
445 if ( m_gizmoManager == nullptr ) { m_gizmoManager = new GizmoManager( this ); }
446}
447
449 auto deviceSize = toDevice( { width(), height() } );
450
451 // see issue #261 Qt Event order and default viewport management (Viewer.cpp)
452 // https://github.com/STORM-IRIT/Radium-Engine/issues/261
453 gl::glViewport( 0, 0, deviceSize.x(), deviceSize.y() );
454
455 renderer->initialize( deviceSize.x(), deviceSize.y() );
456 renderer->setBackgroundColor( m_backgroundColor );
457 renderer->lockRendering();
458}
459
461 globjects::init( getProcAddress );
462 // mark openGL as initialized
463 m_glInitialized = true;
464
465 LOG( logINFO ) << "*** Radium Engine OpenGL context ***";
466 LOG( logINFO ) << "Renderer (glbinding) : " << glbinding::aux::ContextInfo::renderer();
467 LOG( logINFO ) << "Vendor (glbinding) : " << glbinding::aux::ContextInfo::vendor();
468 LOG( logINFO ) << "OpenGL (glbinding) : "
469 << glbinding::aux::ContextInfo::version().toString();
470 LOG( logINFO ) << "GLSL : "
471 << gl::glGetString( gl::GLenum( GL_SHADING_LANGUAGE_VERSION ) );
472
473 LOG( logINFO ) << "*** Radium Engine Viewer ***";
474
475 // emit the signal so that the client will initialize the OpenGL part of the Engine
476 // and custom OpenGL properties
478
479 // Configure the viewer services
480 auto deviceSize = toDevice( { width(), height() } );
481 // create default camera interface : trackball
482 m_camera = std::make_unique<TrackballCameraManipulator>();
483 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
484
486 auto headlight = new Engine::Scene::DirectionalLight(
487 Ra::Engine::Scene::SystemEntity::getInstance(), "headlight" );
488 headlight->setColor( Ra::Core::Utils::Color::Grey( 1.0_ra ) );
489
490 m_camera->attachLight( headlight );
491
492 // Register to the camera manager active camera changes
493 auto cameraManager = static_cast<Ra::Engine::Scene::CameraManager*>(
494 Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) );
495 cameraManager->activeCameraObservers().attach(
496 [this, size = deviceSize]( Core::Utils::Index /*idx*/ ) {
497 m_camera->updateCamera();
498 m_camera->getCamera()->setViewport( size.x(), size.y() );
499 } );
500
501 // Initialize renderers added to the viewer before initializeGL
502 for ( auto& rptr : m_pendingRenderers ) {
503 initializeRenderer( rptr.get() );
504 }
505 m_pendingRenderers.clear();
506
507 // create the gizmo manager (Ui)
509
510 // Signal that OpenGL is initialized
511 emit glInitialized();
512
513 // If no renderer was added before that (either by slots on requestEngineOpenGLInitialization
514 // or on glInitialized), add default forward renderer
515 if ( m_renderers.empty() ) {
516 LOG( logINFO ) << "[Viewer] No renderer added, adding default (Forward Renderer)";
519 addRenderer( e );
520 }
521
522 if ( m_currentRenderer == nullptr ) { changeRenderer( 0 ); }
523
524 return m_glInitialized;
525}
526
527void Viewer::resizeGL( QResizeEvent* event ) {
529
530 auto deviceSize = toDevice( { event->size().width(), event->size().height() } );
531 gl::glViewport( 0, 0, deviceSize.x(), deviceSize.y() );
532 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
533 m_currentRenderer->resize( deviceSize.x(), deviceSize.y() );
534
535 emit needUpdate();
536}
537
539Viewer::getPickingMode( const KeyMappingManager::KeyMappingAction& action ) const {
540 if ( action == VIEWER_PICKING_VERTEX ) {
541 return m_isBrushPickingEnabled ? Engine::Rendering::Renderer::C_VERTEX
543 }
544 if ( action == VIEWER_PICKING_EDGE ) {
545 return m_isBrushPickingEnabled ? Engine::Rendering::Renderer::C_EDGE
547 }
548 if ( action == VIEWER_PICKING_TRIANGLE ) {
549 return m_isBrushPickingEnabled ? Engine::Rendering::Renderer::C_TRIANGLE
551 }
552 if ( action == VIEWER_PICKING ) { return Engine::Rendering::Renderer::RO; }
554}
555
556void Viewer::propagateEventToParent( QEvent* event ) {
557 event->ignore();
558 if ( !isTopLevel() ) { QApplication::sendEvent( parent(), event ); }
559}
560
561void Viewer::keyPressEvent( QKeyEvent* event ) {
562 keyPressed( event->key() );
563 if ( !m_glInitialized.load() || event->isAutoRepeat() || !handleKeyPressEvent( event ) )
564 propagateEventToParent( event );
565 else
566 emit needUpdate();
567}
568
569void Viewer::keyReleaseEvent( QKeyEvent* event ) {
570 if ( !m_glInitialized.load() || !handleKeyReleaseEvent( event ) )
571 propagateEventToParent( event );
572 else
573 emit needUpdate();
574 keyReleased( event->key() );
575}
576
577void Viewer::mousePressEvent( QMouseEvent* event ) {
578 if ( !m_glInitialized.load() ) {
579 propagateEventToParent( event );
580 return;
581 }
582
583 m_currentRenderer->setMousePosition( toDevice( { event->pos().x(), event->pos().y() } ) );
584
585 // get what's under the mouse
586 auto result = pickAtPosition( toDevice( { event->pos().x(), height() - event->pos().y() } ) );
587 m_depthUnderMouse = result.getDepth();
588
589 handleMousePressEvent( event, result );
590 emit onMousePress( event );
591 emit needUpdate();
592}
593
594void Viewer::mouseReleaseEvent( QMouseEvent* event ) {
595 handleMouseReleaseEvent( event );
596 emit onMouseRelease( event );
597 emit needUpdate();
598}
599
600void Viewer::mouseMoveEvent( QMouseEvent* event ) {
601 if ( !m_glInitialized.load() ) {
602 event->ignore();
603 return;
604 }
605
606 m_currentRenderer->setMousePosition( toDevice( { event->pos().x(), event->pos().y() } ) );
607
608 auto result = pickAtPosition( toDevice( { event->pos().x(), height() - event->pos().y() } ) );
609 m_depthUnderMouse = result.getDepth();
610
611 handleMouseMoveEvent( event, result );
612 emit onMouseMove( event );
613 emit needUpdate();
614}
615
616void Viewer::wheelEvent( QWheelEvent* event ) {
617
618 if ( !m_glInitialized.load() ) {
619 event->ignore();
620 return;
621 }
622
623 handleWheelEvent( event );
624
625 emit needUpdate();
626}
627
628void Viewer::showEvent( QShowEvent* ev ) {
629 WindowQt::showEvent( ev );
630 auto deviceSize = toDevice( { width(), height() } );
631 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
632
633 emit needUpdate();
634}
635
636void Viewer::focusOutEvent( QFocusEvent* ) {
637 releaseAllKeys();
638}
639
643Viewer::getComponentActions( const Qt::MouseButtons& buttons,
644 const Qt::KeyboardModifiers& modifiers,
645 int key,
646 bool wheel ) {
647 auto keyMap = KeyMappingManager::getInstance();
648
649 auto actionCamera =
650 keyMap->getAction( keyMap->getContext( "CameraContext" ), buttons, modifiers, key, wheel );
651 auto actionGizmo =
652 keyMap->getAction( keyMap->getContext( "GizmoContext" ), buttons, modifiers, key, wheel );
653 auto actionViewer =
654 keyMap->getAction( keyMap->getContext( "ViewerContext" ), buttons, modifiers, key, wheel );
655 return { actionCamera, actionGizmo, actionViewer };
656}
657
658bool Viewer::handleKeyPressEvent( QKeyEvent* event ) {
659 bool eventCatched = false;
660
661 auto [actionCamera, actionGizmo, actionViewer] =
662 getComponentActions( Qt::NoButton, event->modifiers(), activeKey(), false );
663
664 // Is keymapping something of the viewer only ?
665 // or should be dispatched to all receivers ?
666
667 if ( actionCamera.isValid() ) {
668 eventCatched = m_camera->handleKeyPressEvent( event, actionCamera );
669 }
670 else if ( actionGizmo.isValid() ) {
671 // \todo add gizmo manager handleKeyPressEvent
672 // m_gizmoManager->handleKeyPressEvent( event, action );
673 // eventCatched = true;
674 }
675 else if ( actionViewer.isValid() ) {
676 eventCatched = m_keyMappingCallbackManager.triggerEventCallback( actionViewer, event );
677 }
678 return eventCatched;
679}
680
681bool Viewer::handleKeyReleaseEvent( QKeyEvent* event ) {
682 bool eventCatched = false;
683
684 // Is keymapping something of the viewer only ?
685 // or should be dispatched to all receivers ?
686 auto [actionCamera, actionGizmo, actionViewer] =
687 getComponentActions( Qt::NoButton, event->modifiers(), activeKey(), false );
688
689 if ( actionCamera.isValid() ) {
690 eventCatched = m_camera->handleKeyReleaseEvent( event, actionCamera );
691 }
692 else if ( actionViewer.isValid() ) {
693 eventCatched = m_keyMappingCallbackManager.triggerEventCallback( actionViewer, event );
694 }
695 return eventCatched;
696}
697
698void Viewer::handleMousePressEvent( QMouseEvent* event,
700
708
709 // for now just handle one active context
710 m_activeContext.setInvalid();
711
712 auto keyMap = KeyMappingManager::getInstance();
714 auto buttons = event->buttons();
715 auto modifiers = event->modifiers();
716 auto key = activeKey();
717
718 // nothing under mouse ? juste move the camera ...
719 if ( result.getRoIdx().isInvalid() ) {
720 if ( m_camera->handleMousePressEvent( event, buttons, modifiers, key ) ) {
721 m_activeContext = m_camera->mappingContext();
722 }
723 else {
724 // should not pass here, since viewerContext is only for valid picking ...
725 m_activeContext = KeyMappingManageable::getContext();
726 }
727 }
729 else {
730 // something under the mouse, let's check if it's a gizmo ro
731 getGizmoManager()->handlePickingResult( result.getRoIdx() );
733 event, buttons, modifiers, key, *m_camera->getCamera() ) ) {
734 m_activeContext = GizmoManager::getContext();
735 } // if not, try to do camera stuff
736 else if ( m_camera->handleMousePressEvent( event, buttons, modifiers, key ) ) {
737 m_activeContext = m_camera->mappingContext();
738 }
739 else {
740 m_activeContext = KeyMappingManageable::getContext();
741 auto action = keyMap->getAction( m_activeContext, buttons, modifiers, key );
742 auto pickingMode = getPickingMode( action );
743
744 if ( pickingMode != Ra::Engine::Rendering::Renderer::NONE ) {
745 // Push query, we may also do it here ...
747 toDevice( { event->x(), height() - event->y() } ),
748 Engine::Rendering::Renderer::PickingPurpose::MANIPULATION,
749 pickingMode };
750 m_currentRenderer->addPickingRequest( query );
751 }
752 }
753 }
754}
755
756void Viewer::handleMouseReleaseEvent( QMouseEvent* event ) {
757 if ( m_activeContext == m_camera->mappingContext() ) {
758 m_camera->handleMouseReleaseEvent( event );
759 }
760 if ( m_activeContext == GizmoManager::getContext() ) {
761 m_gizmoManager->handleMouseReleaseEvent( event );
762 }
763 m_activeContext.setInvalid();
764}
765
766void Viewer::handleMouseMoveEvent( QMouseEvent* event,
768
769 auto keyMap = KeyMappingManager::getInstance();
770 auto buttons = event->buttons();
771 auto modifiers = event->modifiers();
772 auto key = activeKey();
773 // if needed can use
774 // auto action = keyMap->getAction( m_activeContext, buttons, modifiers, key );
775
776 if ( m_activeContext == m_camera->mappingContext() ) {
777 m_camera->handleMouseMoveEvent( event, buttons, modifiers, key );
778 }
779 else if ( m_activeContext == GizmoManager::getContext() ) {
781 event, buttons, modifiers, key, *m_camera->getCamera() );
782 }
783 else if ( m_activeContext == KeyMappingManageable::getContext() ) {
784 auto action = keyMap->getAction( m_activeContext, buttons, modifiers, key );
785 auto pickingMode = getPickingMode( action );
786 if ( pickingMode != Ra::Engine::Rendering::Renderer::NONE ) {
787 Engine::Rendering::Renderer::PickingQuery query = {
788 toDevice( { event->x(), height() - event->y() } ),
789 Engine::Rendering::Renderer::PickingPurpose::MANIPULATION,
790 pickingMode };
791 m_currentRenderer->addPickingRequest( query );
792 }
793 }
794 else { getGizmoManager()->handlePickingResult( result.getRoIdx() ); }
795}
796
797void Viewer::handleWheelEvent( QWheelEvent* event ) {
798
799 auto keyMap = KeyMappingManager::getInstance();
800 auto buttons = event->buttons();
801 auto modifiers = event->modifiers();
802 auto key = activeKey();
803 auto action =
804 keyMap->getAction( KeyMappingManageable::getContext(), buttons, modifiers, key, true );
805
806 if ( action == VIEWER_SCALE_BRUSH && m_isBrushPickingEnabled ) {
807 m_brushRadius +=
808 ( event->angleDelta().y() * 0.01 + event->angleDelta().x() * 0.01 ) > 0 ? 5 : -5;
809 m_brushRadius = std::max( m_brushRadius, Scalar( 5 ) );
810 m_currentRenderer->setBrushRadius( m_brushRadius );
811 }
812 else { m_camera->handleWheelEvent( event, buttons, modifiers, key ); }
813}
814
815Ra::Engine::Rendering::Renderer::PickingResult Viewer::pickAtPosition( Core::Vector2 position ) {
816 makeCurrent();
817 auto result = m_currentRenderer->doPickingNow(
818 { position,
819 Engine::Rendering::Renderer::PickingPurpose::SELECTION,
821 { m_camera->getCamera()->getViewMatrix(), m_camera->getCamera()->getProjMatrix(), 0. } );
822
823 doneCurrent();
824 return result;
825}
826
828 auto renderer = getRenderer();
829 if ( renderer ) {
830 makeCurrent();
832 auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
833 if ( aabb.isEmpty() ) { getCameraManipulator()->resetCamera(); }
834 else { fitCameraToScene( aabb ); }
835 doneCurrent();
836 return true;
837 }
838 return false;
839}
840
841void Viewer::displayHelpDialog() {
842 if ( !m_helpDialog ) { m_helpDialog.reset( new RadiumHelpDialog() ); }
843 m_helpDialog->show();
844 m_helpDialog->raise();
845 m_helpDialog->activateWindow();
846}
847
850 const KeyMappingManager::EventBinding& binding,
851 std::function<void( QEvent* )> callback ) {
852
853 return m_keyMappingCallbackManager.addActionAndCallback( actionName, binding, callback );
854}
855
856} // namespace Gui
857} // namespace Ra
T c_str(T... args)
int attach(Observer observer)
void render(const Data::ViewingParameters &renderData)
Tell the renderer it needs to render. This method does the following steps :
Definition Renderer.cpp:315
void initialize(uint width, uint height)
Initialize renderer.
Definition Renderer.cpp:56
PickingResult doPickingNow(const PickingQuery &query, const Data::ViewingParameters &renderData)
Definition Renderer.cpp:191
virtual void displayTexture(const std::string &texName)
Change the texture that is displayed on screen. Set m_displayedIsDepth to true if depth linearization...
Definition Renderer.cpp:696
void addPickingRequest(const PickingQuery &query)
Definition Renderer.hpp:591
virtual std::string getRendererName() const =0
Get the name of the renderer, e.g to be displayed in the UI.
void resize(uint width, uint height)
Resize the viewport and all the screen textures, fbos. This function must be overrided as soon as som...
Definition Renderer.cpp:671
void enableDebugDraw(bool enabled)
Definition Renderer.hpp:583
void enablePostProcess(bool enabled)
Definition Renderer.hpp:587
bool hasLight() const
Tell if the renderer has an usable light.
Definition Renderer.cpp:756
virtual void addLight(const Scene::Light *light)
Definition Renderer.cpp:751
void setBackgroundColor(const Core::Utils::Color &color)
Update the background color (does not trigger a redraw)
Definition Renderer.hpp:612
virtual std::unique_ptr< uchar[]> grabFrame(size_t &w, size_t &h) const
Definition Renderer.cpp:717
@ C_VERTEX
Picks all vertices of a mesh within a screen space circle.
Definition Renderer.hpp:70
@ C_TRIANGLE
Picks all triangles of a mesh within a screen space circle.
Definition Renderer.hpp:72
@ C_EDGE
Picks all edges of a mesh within a screen space circle.
Definition Renderer.hpp:71
@ TRIANGLE
Pick a triangle of a mesh.
Definition Renderer.hpp:69
@ EDGE
Pick an edge of a mesh.
Definition Renderer.hpp:68
@ VERTEX
Pick a vertex of a mesh.
Definition Renderer.hpp:67
const std::vector< PickingResult > & getPickingResults() const
Definition Renderer.hpp:595
const std::vector< PickingQuery > & getPickingQueries() const
Definition Renderer.hpp:599
void resetActiveCamera()
reset the active camera data to default camera
Core::Utils::Observable< Core::Utils::Index > & activeCameraObservers()
get a ref to active camera observers to add/remove an observer
The CameraManipulator class is the generic class for camera manipulators.
virtual void resetCamera()=0
Reset the Camera settings to default values.
void updateValues() override
Retrieve the transform from the editable and update the gizmos.
virtual bool handleMouseMoveEvent(QMouseEvent *event, const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &modifiers, int key, const Core::Asset::Camera &cam)
void handlePickingResult(int drawableId)
Callback when a drawable is picked.
This class manage a collection of binding/callback associated with a context.
bool triggerEventCallback(QEvent *event, int key, bool wheel=false)
void addEventCallback(KeyMappingAction action, Callback callback)
KeyMappingManager::KeyMappingAction addActionAndCallback(const std::string &actionName, const KeyMappingManager::EventBinding &binding, Callback callback)
Inner class to store event binding.
Ra::Core::Utils::Index KeyMappingAction
handle to an action
virtual bool prepareDisplay()
Definition Viewer.cpp:827
void resizeGL(QResizeEvent *event) override
Resize the view port and the camera. Called by the resize event.
Definition Viewer.cpp:527
std::unique_ptr< CameraManipulator > m_camera
Owning pointer to the camera.
Definition Viewer.hpp:311
void startRendering(const Scalar dt)
Start rendering (potentially asynchronously in a separate thread)
Definition Viewer.cpp:218
bool initializeGL() override
Definition Viewer.cpp:460
void initializeRenderer(Engine::Rendering::Renderer *renderer)
Initialize renderer internal state + configure lights.
Definition Viewer.cpp:448
void enableDebugDraw(int enabled)
Toggle the debug drawing.
Definition Viewer.cpp:409
void swapBuffers()
Blocks until rendering is finished.
Definition Viewer.cpp:264
PickingManager * m_pickingManager
Owning Pointer to the feature picking manager.
Definition Viewer.hpp:305
void rendererReady()
Emitted when GL context is ready. We except call to addRenderer here.
void requestEngineOpenGLInitialization()
void enablePostProcess(int enabled)
Toggle the post-process effetcs.
Definition Viewer.cpp:405
void onMousePress(QMouseEvent *event)
Event sent after a mouse press event has been processed, but before emitting needUpdate()
void mouseReleaseEvent(QMouseEvent *event) override
Definition Viewer.cpp:594
virtual void update(const Scalar dt)
Update the internal viewer state to the (application) time dt.
Definition Viewer.cpp:211
void toggleBrushPicking(bool on)
Emitted when the corresponding key is released (see keyReleaseEvent)
int addRenderer(const std::shared_ptr< Engine::Rendering::Renderer > &e)
Definition Viewer.cpp:188
PickingManager * getPickingManager()
Access to the feature picking manager.
Definition Viewer.cpp:207
std::vector< std::shared_ptr< Engine::Rendering::Renderer > > m_renderers
Definition Viewer.hpp:300
Core::Vector2 toDevice(const Core::Vector2 &logicCoordinates)
Definition Viewer.hpp:165
void mouseMoveEvent(QMouseEvent *event) override
Definition Viewer.cpp:600
void reloadShaders()
Tell the renderer to reload all shaders.
Definition Viewer.cpp:352
std::vector< std::string > getRenderersName() const
Returns the names of the different registred renderers.
Definition Viewer.cpp:308
void mousePressEvent(QMouseEvent *event) override
Definition Viewer.cpp:577
KeyMappingManager::KeyMappingAction addCustomAction(const std::string &actionName, const KeyMappingManager::EventBinding &binding, std::function< void(QEvent *)> callback)
Add a custom event callback.
Definition Viewer.cpp:849
Viewer(QScreen *screen=nullptr)
Constructor.
Definition Viewer.cpp:140
bool changeRenderer(int index)
Set the renderer.
Definition Viewer.cpp:377
void displayTexture(const QString &tex)
Set the final display texture.
Definition Viewer.cpp:365
void setCameraManipulator(CameraManipulator *ci)
Set the current camera interface.
Definition Viewer.cpp:161
const Engine::Rendering::Renderer * getRenderer() const
Read-only access to renderer.
Definition Viewer.cpp:180
void onMouseRelease(QMouseEvent *event)
Event sent after a mouse release event has been processed, but before emitting needUpdate()
virtual void setupKeyMappingCallbacks()
add observers to keyMappingManager for gizmo, camera and viewer.
Definition Viewer.cpp:74
void grabFrame(const std::string &filename)
Write the current frame as an image. Supports either BMP or PNG file names.
Definition Viewer.cpp:318
void createGizmoManager()
create gizmos
Definition Viewer.cpp:444
void fitCameraToScene(const Core::Aabb &sceneAabb)
Moves the camera so that the whole scene is visible.
Definition Viewer.cpp:290
~Viewer() override
Destructor.
Definition Viewer.cpp:150
GizmoManager * m_gizmoManager
Owning (QObject child) pointer to gizmo manager.
Definition Viewer.hpp:314
void rightClickPicking(const Ra::Engine::Rendering::Renderer::PickingResult &result)
Emitted when the rendered is correctly initialized.
GizmoManager * getGizmoManager()
Access to gizmo manager.
Definition Viewer.cpp:176
void wheelEvent(QWheelEvent *event) override
Definition Viewer.cpp:616
CameraManipulator * getCameraManipulator()
Access to camera interface.
Definition Viewer.cpp:165
void onMouseMove(QMouseEvent *event)
Event sent after a mouse move event has been processed, but before emitting needUpdate()
void focusOutEvent(QFocusEvent *event) override
reset key pressed, in case a key is pressed when focus lost
Definition Viewer.cpp:636
void processPicking()
Emits signals corresponding to picking requests.
Definition Viewer.cpp:269
virtual void handleMousePressEvent(QMouseEvent *event, Ra::Engine::Rendering::Renderer::PickingResult &result)
Definition Viewer.cpp:698
Base class for OpenGL widgets, compatble with Qt and globjects/glbindings.
Definition WindowQt.hpp:28
ScopedGLContext activateScopedContext()
Definition WindowQt.hpp:154
QOpenGLContext * context()
Definition WindowQt.cpp:76
T endl(T... args)
T max(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T push_back(T... args)
T reset(T... args)
the set of viewing parameters extracted from the camera and given to the renderer