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>
7#include <glbinding/Version.h>
9#include <glbinding/gl/gl.h>
11#include <globjects/globjects.h>
14#include <Gui/Viewer/Viewer.hpp>
18#include <QOpenGLContext>
20#include <QApplication>
25#define STB_IMAGE_WRITE_IMPLEMENTATION
26#include <stb/stb_image_write.h>
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>
55#include <QApplication>
63using namespace Core::Utils;
64using namespace glbinding;
66using ViewerMapping = KeyMappingManageable<Viewer>;
68#define KMA_VALUE( x ) KeyMappingManager::KeyMappingAction Viewer::x;
75 auto keyMappingManager = KeyMappingManager::getInstance();
80 keyMappingManager->addListener(
87 m_keyMappingCallbackManager.
addEventCallback( VIEWER_TOGGLE_WIREFRAME, [
this]( QEvent* event ) {
88 if ( event->type() == QEvent::KeyPress ) m_currentRenderer->
toggleWireframe();
90 m_keyMappingCallbackManager.
addEventCallback( VIEWER_RELOAD_SHADERS, [
this]( QEvent* event ) {
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 );
101 m_keyMappingCallbackManager.
addEventCallback( VIEWER_SWITCH_CAMERA, []( QEvent* event ) {
102 if ( event->type() == QEvent::KeyPress ) {
104 Engine::RadiumEngine::getInstance()->getSystem(
"DefaultCameraManager" ) );
106 if ( cameraManager->count() > 0 ) {
107 idx %= cameraManager->count();
108 cameraManager->activate( idx );
114 m_keyMappingCallbackManager.
addEventCallback( VIEWER_CAMERA_FIT_SCENE, [
this]( QEvent* event ) {
115 if ( event->type() == QEvent::KeyPress ) fitCamera();
117 m_keyMappingCallbackManager.
addEventCallback( VIEWER_HELP, [
this]( QEvent* event ) {
118 if ( event->type() == QEvent::KeyPress ) {
125void Viewer::configureKeyMapping_impl() {
126 auto keyMappingManager = KeyMappingManager::getInstance();
127 ViewerMapping::setContext( keyMappingManager->getContext(
"ViewerContext" ) );
128 if ( ViewerMapping::getContext().isInvalid() ) {
130 <<
"ViewerContext not defined (maybe the configuration file do not contains it)";
131 LOG( Ra::Core::Utils::logERROR ) <<
"ViewerContext all keymapping invalide !";
135#define KMA_VALUE( XX ) XX = keyMappingManager->getAction( ViewerMapping::getContext(), #XX );
142 m_currentRenderer( nullptr ),
143 m_pickingManager( new PickingManager() ),
144 m_isBrushPickingEnabled( false ),
147 m_gizmoManager( nullptr ),
148 m_keyMappingCallbackManager {
ViewerMapping::getContext() } {}
151 if ( m_glInitialized.load() ) {
169void Viewer::resetToDefaultCamera() {
172 Engine::RadiumEngine::getInstance()->getSystem(
"DefaultCameraManager" ) );
181 return m_currentRenderer;
185 return m_currentRenderer;
192 if ( m_glInitialized.load() ) {
195 LOG( logINFO ) <<
"[Viewer] New Renderer (" << e->getRendererName() <<
") added.";
199 LOG( logINFO ) <<
"[Viewer] New Renderer (" << e->getRendererName()
200 <<
") added with deferred init.";
201 m_pendingRenderers.push_back( e );
220 CORE_ASSERT( m_glInitialized.load(),
"OpenGL needs to be initialized before rendering." );
222 CORE_ASSERT( m_currentRenderer !=
nullptr,
"No renderer found." );
228 auto entityManager = Engine::RadiumEngine::getInstance()->getEntityManager();
229 if ( entityManager ) {
235 for (
const auto& entity : entityManager->getEntities() ) {
237 aabb.extend( entity->computeAabb() );
240 if ( !aabb.isEmpty() ) {
m_camera->getCamera()->fitZRange( aabb ); }
243 Engine::RadiumEngine::getInstance()->getSystem(
"DefaultCameraManager" ) );
246 m_camera->setCameraZNear( cameraManager->defaultCamera.getZNear() );
247 m_camera->setCameraZFar( cameraManager->defaultCamera.getZFar() );
253 if ( !m_currentRenderer->
hasLight() ) {
257 LOG( logDEBUG ) <<
"Unable to attach the head light!";
260 m_camera->getCamera()->getViewMatrix(),
m_camera->getCamera()->getProjMatrix(), dt };
261 m_currentRenderer->
render( data );
265 if ( isExposed() ) { m_context->swapBuffers(
this ); }
270 CORE_ASSERT( m_glInitialized.load(),
"OpenGL needs to be initialized before rendering." );
272 CORE_ASSERT( m_currentRenderer !=
nullptr,
"No renderer found." );
276 "There should be one result per query." );
282 if ( query.m_purpose == Engine::Rendering::Renderer::PickingPurpose::MANIPULATION ) {
291 if ( !aabb.isEmpty() ) {
292 CORE_ASSERT(
m_camera !=
nullptr,
"No camera found." );
299 else { LOG( logINFO ) <<
"Unable to fit the camera to the scene : empty Bbox."; }
302void Viewer::fitCamera() {
303 auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
312 if ( renderer ) { ret.
push_back( renderer->getRendererName() ); }
322 auto writtenPixels = m_currentRenderer->
grabFrame( w, h );
324 std::string ext = Core::Utils::getFileExt( filename );
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 ) );
331 LOG( logWARNING ) <<
"Cannot write frame to " << filename <<
" : unsupported extension";
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 ) {
344 if ( i < call.parameters.size() - 1 ) {
std::cerr <<
", "; }
347 if ( call.returnValue ) {
std::cerr <<
" -> " << call.returnValue.get(); }
353 CORE_ASSERT( m_glInitialized.load(),
"OpenGL needs to be initialized reload shaders." );
366 CORE_ASSERT( m_glInitialized.load(),
"OpenGL needs to be initialized to display textures." );
378 if ( m_glInitialized.load() &&
m_renderers[index] ) {
381 if ( m_currentRenderer !=
nullptr ) { m_currentRenderer->
lockRendering(); }
385 auto deviceSize =
toDevice( { width(), height() } );
386 m_currentRenderer->
resize( deviceSize.x(), deviceSize.y() );
391 LOG( logINFO ) <<
"[Viewer] Set active renderer: " << m_currentRenderer->
getRendererName();
394 if (
m_camera ) {
m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() ); }
414 m_backgroundColor = background;
416 renderer->setBackgroundColor( m_backgroundColor );
421void Viewer::onAboutToCompose() {
427void Viewer::onAboutToResize() {
433void Viewer::onResized() {
438void Viewer::onFrameSwapped() {
449 auto deviceSize =
toDevice( { width(), height() } );
453 gl::glViewport( 0, 0, deviceSize.x(), deviceSize.y() );
455 renderer->
initialize( deviceSize.x(), deviceSize.y() );
461 globjects::init( getProcAddress );
463 m_glInitialized =
true;
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 ) );
473 LOG( logINFO ) <<
"*** Radium Engine Viewer ***";
480 auto deviceSize =
toDevice( { width(), height() } );
482 m_camera = std::make_unique<TrackballCameraManipulator>();
483 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
487 Ra::Engine::Scene::SystemEntity::getInstance(),
"headlight" );
488 headlight->setColor( Ra::Core::Utils::Color::Grey( 1.0_ra ) );
494 Engine::RadiumEngine::getInstance()->getSystem(
"DefaultCameraManager" ) );
504 for (
auto& rptr : m_pendingRenderers ) {
507 m_pendingRenderers.clear();
513 emit glInitialized();
518 LOG( logINFO ) <<
"[Viewer] No renderer added, adding default (Forward Renderer)";
526 return m_glInitialized;
532 auto deviceSize =
toDevice( {
event->size().width(),
event->size().height() } );
533 gl::glViewport( 0, 0, deviceSize.x(), deviceSize.y() );
534 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
535 m_currentRenderer->
resize( deviceSize.x(), deviceSize.y() );
542 if ( action == VIEWER_PICKING_VERTEX ) {
546 if ( action == VIEWER_PICKING_EDGE ) {
550 if ( action == VIEWER_PICKING_TRIANGLE ) {
558void Viewer::propagateEventToParent( QEvent* event ) {
560 if ( !isTopLevel() ) { QApplication::sendEvent( parent(), event ); }
563void Viewer::keyPressEvent( QKeyEvent* event ) {
564 keyPressed( event->key() );
565 if ( !m_glInitialized.load() || event->isAutoRepeat() || !handleKeyPressEvent( event ) )
566 propagateEventToParent( event );
571void Viewer::keyReleaseEvent( QKeyEvent* event ) {
572 if ( !m_glInitialized.load() || !handleKeyReleaseEvent( event ) )
573 propagateEventToParent( event );
576 keyReleased( event->key() );
580 if ( !m_glInitialized.load() ) {
581 propagateEventToParent( event );
585 m_currentRenderer->setMousePosition(
toDevice( {
event->pos().x(),
event->pos().y() } ) );
588 auto result = pickAtPosition(
toDevice( {
event->pos().x(), height() -
event->pos().y() } ) );
589 m_depthUnderMouse = result.getDepth();
597 handleMouseReleaseEvent( event );
603 if ( !m_glInitialized.load() ) {
608 m_currentRenderer->setMousePosition(
toDevice( {
event->pos().x(),
event->pos().y() } ) );
610 auto result = pickAtPosition(
toDevice( {
event->pos().x(), height() -
event->pos().y() } ) );
611 m_depthUnderMouse = result.getDepth();
613 handleMouseMoveEvent( event, result );
620 if ( !m_glInitialized.load() ) {
625 handleWheelEvent( event );
630void Viewer::showEvent( QShowEvent* ev ) {
631 WindowQt::showEvent( ev );
632 auto deviceSize =
toDevice( { width(), height() } );
633 m_camera->getCamera()->setViewport( deviceSize.x(), deviceSize.y() );
645Viewer::getComponentActions(
const Qt::MouseButtons& buttons,
646 const Qt::KeyboardModifiers& modifiers,
649 auto keyMap = KeyMappingManager::getInstance();
652 keyMap->getAction( keyMap->getContext(
"CameraContext" ), buttons, modifiers, key, wheel );
654 keyMap->getAction( keyMap->getContext(
"GizmoContext" ), buttons, modifiers, key, wheel );
656 keyMap->getAction( keyMap->getContext(
"ViewerContext" ), buttons, modifiers, key, wheel );
657 return { actionCamera, actionGizmo, actionViewer };
660bool Viewer::handleKeyPressEvent( QKeyEvent* event ) {
661 bool eventCatched =
false;
663 auto [actionCamera, actionGizmo, actionViewer] =
664 getComponentActions( Qt::NoButton, event->modifiers(), activeKey(),
false );
669 if ( actionCamera.isValid() ) {
670 eventCatched =
m_camera->handleKeyPressEvent( event, actionCamera );
672 else if ( actionGizmo.isValid() ) {
677 else if ( actionViewer.isValid() ) {
683bool Viewer::handleKeyReleaseEvent( QKeyEvent* event ) {
684 bool eventCatched =
false;
688 auto [actionCamera, actionGizmo, actionViewer] =
689 getComponentActions( Qt::NoButton, event->modifiers(), activeKey(),
false );
691 if ( actionCamera.isValid() ) {
692 eventCatched =
m_camera->handleKeyReleaseEvent( event, actionCamera );
694 else if ( actionViewer.isValid() ) {
712 m_activeContext.setInvalid();
714 auto keyMap = KeyMappingManager::getInstance();
716 auto buttons =
event->buttons();
717 auto modifiers =
event->modifiers();
718 auto key = activeKey();
721 if ( result.getRoIdx().isInvalid() ) {
722 if (
m_camera->handleMousePressEvent( event, buttons, modifiers, key ) ) {
723 m_activeContext =
m_camera->mappingContext();
727 m_activeContext = KeyMappingManageable::getContext();
735 event, buttons, modifiers, key, *
m_camera->getCamera() ) ) {
736 m_activeContext = GizmoManager::getContext();
738 else if (
m_camera->handleMousePressEvent( event, buttons, modifiers, key ) ) {
739 m_activeContext =
m_camera->mappingContext();
742 m_activeContext = KeyMappingManageable::getContext();
743 auto action = keyMap->getAction( m_activeContext, buttons, modifiers, key );
744 auto pickingMode = getPickingMode( action );
749 toDevice( {
event->x(), height() -
event->y() } ),
750 Engine::Rendering::Renderer::PickingPurpose::MANIPULATION,
758void Viewer::handleMouseReleaseEvent( QMouseEvent* event ) {
759 if ( m_activeContext ==
m_camera->mappingContext() ) {
760 m_camera->handleMouseReleaseEvent( event );
762 if ( m_activeContext == GizmoManager::getContext() ) {
765 m_activeContext.setInvalid();
768void Viewer::handleMouseMoveEvent( QMouseEvent* event,
771 auto keyMap = KeyMappingManager::getInstance();
772 auto buttons =
event->buttons();
773 auto modifiers =
event->modifiers();
774 auto key = activeKey();
778 if ( m_activeContext ==
m_camera->mappingContext() ) {
779 m_camera->handleMouseMoveEvent( event, buttons, modifiers, key );
781 else if ( m_activeContext == GizmoManager::getContext() ) {
783 event, buttons, modifiers, key, *
m_camera->getCamera() );
785 else if ( m_activeContext == KeyMappingManageable::getContext() ) {
786 auto action = keyMap->getAction( m_activeContext, buttons, modifiers, key );
787 auto pickingMode = getPickingMode( action );
789 Engine::Rendering::Renderer::PickingQuery query = {
790 toDevice( {
event->x(), height() -
event->y() } ),
791 Engine::Rendering::Renderer::PickingPurpose::MANIPULATION,
799void Viewer::handleWheelEvent( QWheelEvent* event ) {
801 auto keyMap = KeyMappingManager::getInstance();
802 auto buttons =
event->buttons();
803 auto modifiers =
event->modifiers();
804 auto key = activeKey();
806 keyMap->getAction( KeyMappingManageable::getContext(), buttons, modifiers, key,
true );
808 if ( action == VIEWER_SCALE_BRUSH && m_isBrushPickingEnabled ) {
810 (
event->angleDelta().y() * 0.01 + event->angleDelta().x() * 0.01 ) > 0 ? 5 : -5;
811 m_brushRadius =
std::max( m_brushRadius, Scalar( 5 ) );
812 m_currentRenderer->setBrushRadius( m_brushRadius );
814 else {
m_camera->handleWheelEvent( event, buttons, modifiers, key ); }
821 Engine::Rendering::Renderer::PickingPurpose::SELECTION,
823 {
m_camera->getCamera()->getViewMatrix(),
m_camera->getCamera()->getProjMatrix(), 0. } );
834 auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
843void Viewer::displayHelpDialog() {
844 if ( !m_helpDialog ) { m_helpDialog.
reset(
new RadiumHelpDialog() ); }
845 m_helpDialog->show();
846 m_helpDialog->raise();
847 m_helpDialog->activateWindow();
int attach(Observer observer)
Result of a PickingQuery.
void render(const Data::ViewingParameters &renderData)
Tell the renderer it needs to render. This method does the following steps :
void initialize(uint width, uint height)
Initialize renderer.
PickingResult doPickingNow(const PickingQuery &query, const Data::ViewingParameters &renderData)
virtual void displayTexture(const std::string &texName)
Change the texture that is displayed on screen. Set m_displayedIsDepth to true if depth linearization...
void addPickingRequest(const PickingQuery &query)
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...
void enableDebugDraw(bool enabled)
void enablePostProcess(bool enabled)
bool hasLight() const
Tell if the renderer has an usable light.
virtual void addLight(const Scene::Light *light)
int buildAllRenderTechniques() const
void setBackgroundColor(const Core::Utils::Color &color)
Update the background color (does not trigger a redraw)
virtual void reloadShaders()
virtual std::unique_ptr< uchar[]> grabFrame(size_t &w, size_t &h) const
@ C_VERTEX
Picks all vertices of a mesh within a screen space circle.
@ C_TRIANGLE
Picks all triangles of a mesh within a screen space circle.
@ C_EDGE
Picks all edges of a mesh within a screen space circle.
@ TRIANGLE
Pick a triangle of a mesh.
@ EDGE
Pick an edge of a mesh.
@ VERTEX
Pick a vertex of a mesh.
const std::vector< PickingResult > & getPickingResults() const
const std::vector< PickingQuery > & getPickingQueries() const
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)
static void configureKeyMapping()
Inner class to store event binding.
Ra::Core::Utils::Index KeyMappingAction
handle to an action
virtual bool prepareDisplay()
void resizeGL(QResizeEvent *event) override
Resize the view port and the camera. Called by the resize event.
std::unique_ptr< CameraManipulator > m_camera
Owning pointer to the camera.
void startRendering(const Scalar dt)
Start rendering (potentially asynchronously in a separate thread)
bool initializeGL() override
void initializeRenderer(Engine::Rendering::Renderer *renderer)
Initialize renderer internal state + configure lights.
void enableDebugDraw(int enabled)
Toggle the debug drawing.
void swapBuffers()
Blocks until rendering is finished.
PickingManager * m_pickingManager
Owning Pointer to the feature picking manager.
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.
void onMousePress(QMouseEvent *event)
Event sent after a mouse press event has been processed, but before emitting needUpdate()
void mouseReleaseEvent(QMouseEvent *event) override
virtual void update(const Scalar dt)
Update the internal viewer state to the (application) time dt.
void toggleBrushPicking(bool on)
Emitted when the corresponding key is released (see keyReleaseEvent)
int addRenderer(const std::shared_ptr< Engine::Rendering::Renderer > &e)
PickingManager * getPickingManager()
Access to the feature picking manager.
std::vector< std::shared_ptr< Engine::Rendering::Renderer > > m_renderers
Core::Vector2 toDevice(const Core::Vector2 &logicCoordinates)
void mouseMoveEvent(QMouseEvent *event) override
void reloadShaders()
Tell the renderer to reload all shaders.
std::vector< std::string > getRenderersName() const
Returns the names of the different registred renderers.
void mousePressEvent(QMouseEvent *event) override
KeyMappingManager::KeyMappingAction addCustomAction(const std::string &actionName, const KeyMappingManager::EventBinding &binding, std::function< void(QEvent *)> callback)
Add a custom event callback.
Viewer(QScreen *screen=nullptr)
Constructor.
bool changeRenderer(int index)
Set the renderer.
void displayTexture(const QString &tex)
Set the final display texture.
void setCameraManipulator(CameraManipulator *ci)
Set the current camera interface.
const Engine::Rendering::Renderer * getRenderer() const
Read-only access to renderer.
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.
void grabFrame(const std::string &filename)
Write the current frame as an image. Supports either BMP or PNG file names.
void createGizmoManager()
create gizmos
void fitCameraToScene(const Core::Aabb &sceneAabb)
Moves the camera so that the whole scene is visible.
~Viewer() override
Destructor.
GizmoManager * m_gizmoManager
Owning (QObject child) pointer to gizmo manager.
void rightClickPicking(const Ra::Engine::Rendering::Renderer::PickingResult &result)
Emitted when the rendered is correctly initialized.
GizmoManager * getGizmoManager()
Access to gizmo manager.
void wheelEvent(QWheelEvent *event) override
CameraManipulator * getCameraManipulator()
Access to camera interface.
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
void processPicking()
Emits signals corresponding to picking requests.
virtual void handleMousePressEvent(QMouseEvent *event, Ra::Engine::Rendering::Renderer::PickingResult &result)
Base class for OpenGL widgets, compatble with Qt and globjects/glbindings.
ScopedGLContext activateScopedContext()
QOpenGLContext * context()
hepler function to manage enum as underlying types in VariableSet
the set of viewing parameters extracted from the camera and given to the renderer