From 8df7ce545e33a2b22db2959ce2f42944f8b9427a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 3 Apr 2023 12:15:31 +0400 Subject: [PATCH 1/3] Migrate from GraphicsWindowQt to QOpenGLWidget --- CHANGELOG.md | 1 + CI/before_script.msvc.sh | 6 +- CMakeLists.txt | 4 +- apps/launcher/datafilespage.cpp | 4 - apps/opencs/CMakeLists.txt | 6 +- apps/opencs/main.cpp | 19 + apps/opencs/view/render/scenewidget.cpp | 108 +--- apps/opencs/view/render/scenewidget.hpp | 31 +- apps/opencs/view/render/worldspacewidget.cpp | 12 +- apps/opencs/view/world/table.cpp | 6 - extern/osgQt/CMakeLists.txt | 17 +- extern/osgQt/CompositeOsgRenderer.cpp | 119 ++++ extern/osgQt/CompositeOsgRenderer.hpp | 46 ++ extern/osgQt/GraphicsWindowQt | 155 ----- extern/osgQt/GraphicsWindowQt.cpp | 615 ------------------- extern/osgQt/osgQOpenGLWidget.cpp | 98 +++ extern/osgQt/osgQOpenGLWidget.hpp | 70 +++ 17 files changed, 418 insertions(+), 899 deletions(-) create mode 100644 extern/osgQt/CompositeOsgRenderer.cpp create mode 100644 extern/osgQt/CompositeOsgRenderer.hpp delete mode 100644 extern/osgQt/GraphicsWindowQt delete mode 100644 extern/osgQt/GraphicsWindowQt.cpp create mode 100644 extern/osgQt/osgQOpenGLWidget.cpp create mode 100644 extern/osgQt/osgQOpenGLWidget.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index d20c45e688..d89049aa66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Feature #3537: Shader-based water ripples Feature #5492: Let rain and snow collide with statics Feature #6447: Add LOD support to Object Paging + Feature #6491: Add support for Qt6 Feature #6726: Lua API for creating new objects Feature #6922: Improve launcher appearance Feature #6933: Support high-resolution cursor textures diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 01ef37a8c9..359cb01cd8 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -934,7 +934,11 @@ printf "Qt ${QT_VER}... " else DLLSUFFIX="" fi - add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,Widgets}${DLLSUFFIX}.dll + if [ "${QT_VER:0:1}" -eq "6" ]; then + add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,OpenGLWidgets,Widgets}${DLLSUFFIX}.dll + else + add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,Widgets}${DLLSUFFIX}.dll + fi add_qt_platform_dlls $CONFIGURATION "$(pwd)/plugins/platforms/qwindows${DLLSUFFIX}.dll" add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qwindowsvistastyle${DLLSUFFIX}.dll" done diff --git a/CMakeLists.txt b/CMakeLists.txt index bc964f60d7..8bbd5cace7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,7 +241,7 @@ if (USE_QT) if (QT_VERSION_MAJOR VERSION_EQUAL 5) find_package(Qt5 5.15 COMPONENTS Core Widgets Network OpenGL REQUIRED) else() - find_package(Qt6 COMPONENTS Core Widgets Network OpenGL REQUIRED) + find_package(Qt6 COMPONENTS Core Widgets Network OpenGL OpenGLWidgets REQUIRED) endif() message(STATUS "Using Qt${QT_VERSION}") endif() @@ -627,7 +627,7 @@ endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clan add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) add_subdirectory (extern/Base64) -if ((BUILD_OPENCS OR BUILD_OPENCS_TESTS) AND Qt5_FOUND) +if (BUILD_OPENCS OR BUILD_OPENCS_TESTS) add_subdirectory (extern/osgQt) endif() diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f731571186..d81f6dda58 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -789,12 +789,8 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles) // The following code will run only if there is not another thread currently running it CellNameLoader cellNameLoader; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QSet set = cellNameLoader.getCellNames(selectedFiles); QStringList cellNamesList(set.begin(), set.end()); -#else - QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles)); -#endif std::sort(cellNamesList.begin(), cellNamesList.end()); emit signalLoadedCellsChanged(cellNamesList); } diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 2247d71717..d6fb6691ce 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -243,7 +243,11 @@ target_link_libraries(openmw-cs-lib components_qt ) -target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL) +if (QT_VERSION_MAJOR VERSION_EQUAL 6) + target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets) +else() + target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL) +endif() if (WIN32) target_link_libraries(openmw-cs-lib ${Boost_LOCALE_LIBRARY}) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 28201edf7e..ecab9614a1 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -5,6 +5,9 @@ #include #include +#include + +#include #include #include @@ -46,6 +49,19 @@ public: } }; +void setQSurfaceFormat() +{ + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + QSurfaceFormat format = QSurfaceFormat::defaultFormat(); + format.setVersion(2, 1); + format.setRenderableType(QSurfaceFormat::OpenGL); + format.setDepthBufferSize(24); + format.setSamples(ds->getMultiSamples()); + format.setStencilBufferSize(ds->getMinimumNumStencilBits()); + format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + QSurfaceFormat::setDefaultFormat(format); +} + int runApplication(int argc, char* argv[]) { Platform::init(); @@ -60,6 +76,9 @@ int runApplication(int argc, char* argv[]) qRegisterMetaType("CSMWorld::UniversalId"); qRegisterMetaType("CSMDoc::Message"); + setQSurfaceFormat(); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + Application application(argc, argv); #ifdef Q_OS_MAC diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 8d896f6913..298b67596a 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -13,9 +14,8 @@ #include #include -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -#include -#endif +#include +#include #include #include @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -67,47 +66,34 @@ namespace CSVRender : QWidget(parent, f) , mRootNode(nullptr) { + mView = new osgViewer::View; + updateCameraParameters(width() / static_cast(height())); - osgViewer::CompositeViewer& viewer = CompositeViewer::get(); - - osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); - // ds->setNumMultiSamples(8); - - osg::ref_ptr traits = new osg::GraphicsContext::Traits; - traits->windowName.clear(); - traits->windowDecoration = true; - traits->x = 0; - traits->y = 0; - traits->width = width(); - traits->height = height(); - traits->doubleBuffer = true; - traits->alpha = ds->getMinimumNumAlphaBits(); - traits->stencil = ds->getMinimumNumStencilBits(); - traits->sampleBuffers = ds->getMultiSamples(); - traits->samples = ds->getNumMultiSamples(); - // Doesn't make much sense as we're running on demand updates, and there seems to be a bug with the refresh rate - // when running multiple QGLWidgets - traits->vsync = false; + mWidget = new osgQOpenGLWidget(this); - mView = new osgViewer::View; - updateCameraParameters(traits->width / static_cast(traits->height)); + mRenderer = mWidget->getCompositeViewer(); + osg::ref_ptr window + = new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height()); + mWidget->setGraphicsWindowEmbedded(window); + + int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt(); + mRenderer->setRunMaxFrameRate(frameRateLimit); + mRenderer->setUseConfigureAffinity(false); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(window->getGLWidget()); + layout->addWidget(mWidget); setLayout(layout); mView->getCamera()->setGraphicsContext(window); -#endif - mView->getCamera()->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); lightMgr->setLightingMask(Mask_Lighting); mRootNode = lightMgr; + mView->getCamera()->setViewport(new osg::Viewport(0, 0, width(), height())); + mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); mView->getCamera()->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); osg::ref_ptr defaultMat(new osg::Material); @@ -122,21 +108,21 @@ namespace CSVRender // Add ability to signal osg to show its statistics for debugging purposes mView->addEventHandler(new osgViewer::StatsHandler); - viewer.addView(mView); - viewer.setDone(false); - viewer.realize(); + mRenderer->addView(mView); + mRenderer->setDone(false); } RenderWidget::~RenderWidget() { try { - CompositeViewer::get().removeView(mView); + mRenderer->removeView(mView); } catch (const std::exception& e) { Log(Debug::Error) << "Error in the destructor: " << e.what(); } + delete mWidget; } void RenderWidget::flagAsModified() @@ -163,54 +149,6 @@ namespace CSVRender window->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_S); } - // -------------------------------------------------- - - CompositeViewer::CompositeViewer() - : mSimulationTime(0.0) - { - // TODO: Upgrade osgQt to support osgViewer::ViewerBase::DrawThreadPerContext - // https://gitlab.com/OpenMW/openmw/-/issues/5481 - setThreadingModel(osgViewer::ViewerBase::SingleThreaded); - - setUseConfigureAffinity(false); - - // disable the default setting of viewer.done() by pressing Escape. - setKeyEventSetsDone(0); - - // Only render when the camera position changed, or content flagged dirty - // setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); - setRunFrameScheme(osgViewer::ViewerBase::CONTINUOUS); - - connect(&mTimer, &QTimer::timeout, this, &CompositeViewer::update); - mTimer.start(10); - - int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt(); - setRunMaxFrameRate(frameRateLimit); - } - - CompositeViewer& CompositeViewer::get() - { - static CompositeViewer sThis; - return sThis; - } - - void CompositeViewer::update() - { - double dt = mFrameTimer.time_s(); - mFrameTimer.setStartTick(); - - emit simulationUpdated(dt); - - mSimulationTime += dt; - frame(mSimulationTime); - - double minFrameTime = _runMaxFrameRate > 0.0 ? 1.0 / _runMaxFrameRate : 0.0; - if (dt < minFrameTime) - { - std::this_thread::sleep_for(std::chrono::duration(minFrameTime - dt)); - } - } - // --------------------------------------------------- SceneWidget::SceneWidget(std::shared_ptr resourceSystem, QWidget* parent, @@ -268,7 +206,7 @@ namespace CSVRender CSMPrefs::get()["Tooltips"].update(); } - connect(&CompositeViewer::get(), &CompositeViewer::simulationUpdated, this, &SceneWidget::update); + connect(mRenderer, SIGNAL(simulationUpdated(double)), this, SLOT(update(double))); // Shortcuts CSMPrefs::Shortcut* focusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); @@ -560,7 +498,7 @@ namespace CSVRender } else if (*setting == "Rendering/framerate-limit") { - CompositeViewer::get().setRunMaxFrameRate(setting->toInt()); + mRenderer->setRunMaxFrameRate(setting->toInt()); } else if (*setting == "Rendering/camera-fov" || *setting == "Rendering/camera-ortho" || *setting == "Rendering/camera-ortho-size") diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 0b5c8f2969..a2200c780e 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -22,6 +22,9 @@ class QMouseEvent; class QWheelEvent; +class osgQOpenGLWidget; +class CompositeOsgRenderer; + namespace Resource { class ResourceSystem; @@ -73,13 +76,13 @@ namespace CSVRender osg::Camera* getCamera(); protected: + osgQOpenGLWidget* mWidget; + CompositeOsgRenderer* mRenderer; osg::ref_ptr mView; osg::ref_ptr mRootNode; void updateCameraParameters(double overrideAspect = -1.0); - QTimer mTimer; - protected slots: void toggleRenderStats(); @@ -154,30 +157,6 @@ namespace CSVRender void focusToolbarRequest(); }; - - // There are rendering glitches when using multiple Viewer instances, work around using CompositeViewer with - // multiple views - class CompositeViewer : public QObject, public osgViewer::CompositeViewer - { - Q_OBJECT - public: - CompositeViewer(); - - static CompositeViewer& get(); - - QTimer mTimer; - - private: - osg::Timer mFrameTimer; - double mSimulationTime; - - public slots: - void update(); - - signals: - void simulationUpdated(double dt); - }; - } #endif diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 57e77911c6..3999925bd1 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -6,8 +6,11 @@ #include #include #include +#include #include +#include #include +#include #include #include @@ -381,9 +384,14 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick( const QPoint& localPos, unsigned int interactionMask) const { + // may be okay to just use devicePixelRatio() directly + QScreen* screen = SceneWidget::windowHandle() && SceneWidget::windowHandle()->screen() + ? SceneWidget::windowHandle()->screen() + : QGuiApplication::primaryScreen(); + // (0,0) is considered the lower left corner of an OpenGL window - int x = localPos.x(); - int y = height() - localPos.y(); + int x = localPos.x() * screen->devicePixelRatio(); + int y = height() * screen->devicePixelRatio() - localPos.y() * screen->devicePixelRatio(); // Convert from screen space to world space osg::Matrixd wpvMat; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 80f0c33cec..f5f3fa20ef 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -141,7 +141,6 @@ void CSVWorld::Table::contextMenuEvent(QContextMenuEvent* event) } } -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (selectedRows.size() == 1) { int row = selectedRows.begin()->row(); @@ -173,7 +172,6 @@ void CSVWorld::Table::contextMenuEvent(QContextMenuEvent* event) menu.addAction(mPreviewAction); } } -#endif if (mHelpAction) menu.addAction(mHelpAction); @@ -390,18 +388,14 @@ CSVWorld::Table::Table(const CSMWorld::UniversalId& id, bool createAndDelete, bo mViewAction->setIcon(QIcon(":/cell.png")); addAction(mViewAction); CSMPrefs::Shortcut* viewShortcut = new CSMPrefs::Shortcut("table-view", this); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) viewShortcut->associateAction(mViewAction); -#endif mPreviewAction = new QAction(tr("Preview"), this); connect(mPreviewAction, &QAction::triggered, this, &Table::previewRecord); mPreviewAction->setIcon(QIcon(":edit-preview")); addAction(mPreviewAction); CSMPrefs::Shortcut* previewShortcut = new CSMPrefs::Shortcut("table-preview", this); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) previewShortcut->associateAction(mPreviewAction); -#endif mExtendedDeleteAction = new QAction(tr("Extended Delete Record"), this); connect(mExtendedDeleteAction, &QAction::triggered, this, &Table::executeExtendedDelete); diff --git a/extern/osgQt/CMakeLists.txt b/extern/osgQt/CMakeLists.txt index 724c17e8d0..781305ca47 100644 --- a/extern/osgQt/CMakeLists.txt +++ b/extern/osgQt/CMakeLists.txt @@ -2,13 +2,26 @@ set(OSGQT_LIBRARY "osgQt") # Sources +set(SOURCE_H + osgQOpenGLWidget.hpp + CompositeOsgRenderer.hpp +) + +qt_wrap_cpp(SOURCES_H_MOC ${SOURCE_H} ) + set(OSGQT_SOURCE_FILES - GraphicsWindowQt.cpp + osgQOpenGLWidget.cpp + CompositeOsgRenderer.cpp + ${SOURCES_H_MOC} ) add_library(${OSGQT_LIBRARY} STATIC ${OSGQT_SOURCE_FILES}) -target_link_libraries(${OSGQT_LIBRARY} Qt::Core Qt::OpenGL) +if (QT_VERSION_MAJOR VERSION_EQUAL 6) + target_link_libraries(${OSGQT_LIBRARY} Qt::Core Qt::OpenGL Qt::OpenGLWidgets) +else() + target_link_libraries(${OSGQT_LIBRARY} Qt::Core Qt::OpenGL) +endif() link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/osgQt/CompositeOsgRenderer.cpp b/extern/osgQt/CompositeOsgRenderer.cpp new file mode 100644 index 0000000000..5950293fa5 --- /dev/null +++ b/extern/osgQt/CompositeOsgRenderer.cpp @@ -0,0 +1,119 @@ +#include "CompositeOsgRenderer.hpp" +#include "osgQOpenGLWidget.hpp" + +#include +#include + +#include + +CompositeOsgRenderer::CompositeOsgRenderer(QObject* parent) + : QObject(parent), osgViewer::CompositeViewer(), mSimulationTime(0.0) +{ + _firstFrame = true; +} + +CompositeOsgRenderer::CompositeOsgRenderer(osg::ArgumentParser* arguments, QObject* parent) + : QObject(parent), osgViewer::CompositeViewer(*arguments), mSimulationTime(0.0) +{ + _firstFrame = true; +} + +CompositeOsgRenderer::~CompositeOsgRenderer() +{ +} + +void CompositeOsgRenderer::update() +{ + double dt = mFrameTimer.time_s(); + mFrameTimer.setStartTick(); + + emit simulationUpdated(dt); + + mSimulationTime += dt; + osgQOpenGLWidget* osgWidget = dynamic_cast(parent()); + if (osgWidget) + { + osgWidget->update(); + } + + double minFrameTime = _runMaxFrameRate > 0.0 ? 1.0 / _runMaxFrameRate : 0.0; + if (dt < minFrameTime) + { + std::this_thread::sleep_for(std::chrono::duration(minFrameTime - dt)); + } +} + +void CompositeOsgRenderer::resize(int windowWidth, int windowHeight) +{ + if(!m_osgInitialized) + return; + + for(RefViews::iterator itr = _views.begin(); + itr != _views.end(); + ++itr) + { + osgViewer::View* view = itr->get(); + if(view) + { + m_osgWinEmb->resized(0, 0, windowWidth, windowHeight); + m_osgWinEmb->getEventQueue()->windowResize(0, 0, windowWidth, windowHeight); + } + } + + update(); +} + +void CompositeOsgRenderer::setGraphicsWindowEmbedded(osg::ref_ptr osgWinEmb) +{ + m_osgWinEmb = osgWinEmb; +} + +void CompositeOsgRenderer::setupOSG() +{ + m_osgInitialized = true; + + m_osgWinEmb->getEventQueue()->syncWindowRectangleWithGraphicsContext(); + // disable key event (default is Escape key) that the viewer checks on each + // frame to see + // if the viewer's done flag should be set to signal end of viewers main + // loop. + setKeyEventSetsDone(0); + setReleaseContextAtEndOfFrameHint(false); + setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); + + setRunFrameScheme(osgViewer::ViewerBase::ON_DEMAND); + + connect( &mTimer, SIGNAL(timeout()), this, SLOT(update()) ); + mTimer.start( 10 ); + + osgViewer::CompositeViewer::Windows windows; + getWindows(windows); +} + +// called from ViewerWidget paintGL() method +void CompositeOsgRenderer::frame(double simulationTime) +{ + if(_done) return; + + if(_firstFrame) + { + viewerInit(); + realize(); + _firstFrame = false; + } + + advance(simulationTime); + + eventTraversal(); + updateTraversal(); + renderingTraversals(); +} + +void CompositeOsgRenderer::timerEvent(QTimerEvent* /*event*/) +{ + // ask ViewerWidget to update 3D view + if(getRunFrameScheme() != osgViewer::ViewerBase::ON_DEMAND || checkNeedToDoFrame()) + { + update(); + } +} diff --git a/extern/osgQt/CompositeOsgRenderer.hpp b/extern/osgQt/CompositeOsgRenderer.hpp new file mode 100644 index 0000000000..aefe45f5d8 --- /dev/null +++ b/extern/osgQt/CompositeOsgRenderer.hpp @@ -0,0 +1,46 @@ +#ifndef COMPOSITEOSGRENDERER_H +#define COMPOSITEOSGRENDERER_H + +#include +#include + +#include + +class CompositeOsgRenderer : public QObject, public osgViewer::CompositeViewer +{ + bool m_osgInitialized {false}; + osg::ref_ptr m_osgWinEmb; + + osg::Timer mFrameTimer; + double mSimulationTime; + Q_OBJECT + +public: + + explicit CompositeOsgRenderer(QObject* parent = nullptr); + explicit CompositeOsgRenderer(osg::ArgumentParser* arguments, QObject* parent = nullptr); + + ~CompositeOsgRenderer() override; + + virtual void resize(int windowWidth, int windowHeight); + + void setGraphicsWindowEmbedded(osg::ref_ptr osgWinEmb); + + void setupOSG(); + + // overrided from osgViewer::ViewerBase + void frame(double simulationTime = USE_REFERENCE_TIME) override; + + QTimer mTimer; + +protected: + void timerEvent(QTimerEvent* event) override; + +public slots: + void update(); + +signals: + void simulationUpdated(double dt); +}; + +#endif // COMPOSITEOSGRENDERER_H diff --git a/extern/osgQt/GraphicsWindowQt b/extern/osgQt/GraphicsWindowQt deleted file mode 100644 index 18fcb754f5..0000000000 --- a/extern/osgQt/GraphicsWindowQt +++ /dev/null @@ -1,155 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library 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 - * OpenSceneGraph Public License for more details. -*/ - -#ifndef OSGVIEWER_GRAPHICSWINDOWQT -#define OSGVIEWER_GRAPHICSWINDOWQT - -#include - -#include -#include -#include -#include -#include - -class QInputEvent; -class QGestureEvent; - -namespace osgViewer { - class ViewerBase; -} - -namespace osgQt -{ - -// forward declarations -class GraphicsWindowQt; - -class GLWidget : public QGLWidget -{ - typedef QGLWidget inherited; - -public: - - GLWidget( QWidget* parent = nullptr, const QGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); - GLWidget( QGLContext* context, QWidget* parent = nullptr, const QGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); - GLWidget( const QGLFormat& format, QWidget* parent = nullptr, const QGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); - virtual ~GLWidget(); - - inline void setGraphicsWindow( GraphicsWindowQt* gw ) { _gw = gw; } - inline GraphicsWindowQt* getGraphicsWindow() { return _gw; } - inline const GraphicsWindowQt* getGraphicsWindow() const { return _gw; } - -protected: - - int getNumDeferredEvents() - { - QMutexLocker lock(&_deferredEventQueueMutex); - return _deferredEventQueue.count(); - } - void enqueueDeferredEvent(QEvent::Type eventType, QEvent::Type removeEventType = QEvent::None) - { - QMutexLocker lock(&_deferredEventQueueMutex); - - if (removeEventType != QEvent::None) - { - if (_deferredEventQueue.removeOne(removeEventType)) - _eventCompressor.remove(eventType); - } - - if (_eventCompressor.find(eventType) == _eventCompressor.end()) - { - _deferredEventQueue.enqueue(eventType); - _eventCompressor.insert(eventType); - } - } - void processDeferredEvents(); - - friend class GraphicsWindowQt; - GraphicsWindowQt* _gw; - - QMutex _deferredEventQueueMutex; - QQueue _deferredEventQueue; - QSet _eventCompressor; - - qreal _devicePixelRatio; - - void resizeEvent( QResizeEvent* event ) override; - void moveEvent( QMoveEvent* event ) override; - void glDraw() override; - bool event( QEvent* event ) override; -}; - -class GraphicsWindowQt : public osgViewer::GraphicsWindow -{ -public: - GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent = nullptr, const QGLWidget* shareWidget = nullptr, Qt::WindowFlags f = Qt::WindowFlags() ); - GraphicsWindowQt( GLWidget* widget ); - virtual ~GraphicsWindowQt(); - - inline GLWidget* getGLWidget() { return _widget; } - inline const GLWidget* getGLWidget() const { return _widget; } - - /// deprecated - inline GLWidget* getGraphWidget() { return _widget; } - /// deprecated - inline const GLWidget* getGraphWidget() const { return _widget; } - - struct WindowData : public osg::Referenced - { - WindowData( GLWidget* widget = nullptr, QWidget* parent = nullptr ): _widget(widget), _parent(parent) {} - GLWidget* _widget; - QWidget* _parent; - }; - - bool init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ); - - static QGLFormat traits2qglFormat( const osg::GraphicsContext::Traits* traits ); - static void qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits ); - static osg::GraphicsContext::Traits* createTraits( const QGLWidget* widget ); - - bool setWindowRectangleImplementation( int x, int y, int width, int height ) override; - void getWindowRectangle( int& x, int& y, int& width, int& height ) override; - bool setWindowDecorationImplementation( bool windowDecoration ) override; - bool getWindowDecoration() const override; - void grabFocus() override; - void grabFocusIfPointerInWindow( )override; - void raiseWindow() override; - void setWindowName( const std::string& name ) override; - std::string getWindowName() override; - void useCursor( bool cursorOn ) override; - void setCursor( MouseCursor cursor ) override; - - bool valid() const override; - bool realizeImplementation() override; - bool isRealizedImplementation() const override; - void closeImplementation() override; - bool makeCurrentImplementation() override; - bool releaseContextImplementation() override; - void swapBuffersImplementation() override; - void runOperations() override; - - void requestWarpPointer( float x, float y ) override; - -protected: - - friend class GLWidget; - GLWidget* _widget; - bool _ownsWidget; - QCursor _currentCursor; - bool _realized; -}; - -} - -#endif diff --git a/extern/osgQt/GraphicsWindowQt.cpp b/extern/osgQt/GraphicsWindowQt.cpp deleted file mode 100644 index 4755ad4a8b..0000000000 --- a/extern/osgQt/GraphicsWindowQt.cpp +++ /dev/null @@ -1,615 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library 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 - * OpenSceneGraph Public License for more details. -*/ - -#include "GraphicsWindowQt" - -#include -#include -#include -#include -#include - -using namespace osgQt; - -#define GETDEVICEPIXELRATIO() devicePixelRatio() - -GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) -: QGLWidget(parent, shareWidget, f), _gw( nullptr ) -{ - _devicePixelRatio = GETDEVICEPIXELRATIO(); -} - -GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) -: QGLWidget(context, parent, shareWidget, f), _gw( nullptr ) -{ - _devicePixelRatio = GETDEVICEPIXELRATIO(); -} - -GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) -: QGLWidget(format, parent, shareWidget, f), _gw( nullptr ) -{ - _devicePixelRatio = GETDEVICEPIXELRATIO(); -} - -GLWidget::~GLWidget() -{ - // close GraphicsWindowQt and remove the reference to us - if( _gw ) - { - _gw->close(); - _gw->_widget = nullptr; - _gw = nullptr; - } -} - -void GLWidget::processDeferredEvents() -{ - QQueue deferredEventQueueCopy; - { - QMutexLocker lock(&_deferredEventQueueMutex); - deferredEventQueueCopy = _deferredEventQueue; - _eventCompressor.clear(); - _deferredEventQueue.clear(); - } - - while (!deferredEventQueueCopy.isEmpty()) - { - QEvent event(deferredEventQueueCopy.dequeue()); - QGLWidget::event(&event); - } -} - -bool GLWidget::event( QEvent* event ) -{ - - // QEvent::Hide - // - // workaround "Qt-workaround" that does glFinish before hiding the widget - // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0) - // - // Qt makes the context current, performs glFinish, and releases the context. - // This makes the problem in OSG multithreaded environment as the context - // is active in another thread, thus it can not be made current for the purpose - // of glFinish in this thread. - - // QEvent::ParentChange - // - // Reparenting GLWidget may create a new underlying window and a new GL context. - // Qt will then call doneCurrent on the GL context about to be deleted. The thread - // where old GL context was current has no longer current context to render to and - // we cannot make new GL context current in this thread. - - // We workaround above problems by deferring execution of problematic event requests. - // These events has to be enqueue and executed later in a main GUI thread (GUI operations - // outside the main thread are not allowed) just before makeCurrent is called from the - // right thread. The good place for doing that is right after swap in a swapBuffersImplementation. - - if (event->type() == QEvent::Hide) - { - // enqueue only the last of QEvent::Hide and QEvent::Show - enqueueDeferredEvent(QEvent::Hide, QEvent::Show); - return true; - } - else if (event->type() == QEvent::Show) - { - // enqueue only the last of QEvent::Show or QEvent::Hide - enqueueDeferredEvent(QEvent::Show, QEvent::Hide); - return true; - } - else if (event->type() == QEvent::ParentChange) - { - // enqueue only the last QEvent::ParentChange - enqueueDeferredEvent(QEvent::ParentChange); - return true; - } - else if (event->type() == QEvent::PlatformSurface && static_cast(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) - { - if (_gw) - _gw->close(); - } - - // perform regular event handling - return QGLWidget::event( event ); -} - -void GLWidget::resizeEvent( QResizeEvent* event ) -{ - if (_gw == nullptr || !_gw->valid()) - return; - const QSize& size = event->size(); - - int scaled_width = static_cast(size.width()*_devicePixelRatio); - int scaled_height = static_cast(size.height()*_devicePixelRatio); - _gw->resized( x(), y(), scaled_width, scaled_height); - _gw->getEventQueue()->windowResize( x(), y(), scaled_width, scaled_height ); - _gw->requestRedraw(); -} - -void GLWidget::moveEvent( QMoveEvent* event ) -{ - if (_gw == nullptr || !_gw->valid()) - return; - const QPoint& pos = event->pos(); - int scaled_width = static_cast(width()*_devicePixelRatio); - int scaled_height = static_cast(height()*_devicePixelRatio); - _gw->resized( pos.x(), pos.y(), scaled_width, scaled_height ); - _gw->getEventQueue()->windowResize( pos.x(), pos.y(), scaled_width, scaled_height ); -} - -void GLWidget::glDraw() -{ - _gw->requestRedraw(); -} - -GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ) -: _realized(false) -{ - - _widget = nullptr; - _traits = traits; - init( parent, shareWidget, f ); -} - -GraphicsWindowQt::GraphicsWindowQt( GLWidget* widget ) -: _realized(false) -{ - _widget = widget; - _traits = _widget ? createTraits( _widget ) : new osg::GraphicsContext::Traits; - init( nullptr, nullptr, Qt::WindowFlags() ); -} - -GraphicsWindowQt::~GraphicsWindowQt() -{ - close(); - - // remove reference from GLWidget - if ( _widget ) - _widget->_gw = nullptr; -} - -bool GraphicsWindowQt::init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ) -{ - // update _widget and parent by WindowData - WindowData* windowData = _traits.get() ? dynamic_cast(_traits->inheritedWindowData.get()) : nullptr; - if ( !_widget ) - _widget = windowData ? windowData->_widget : nullptr; - if ( !parent ) - parent = windowData ? windowData->_parent : nullptr; - - // create widget if it does not exist - _ownsWidget = _widget == nullptr; - if ( !_widget ) - { - // shareWidget - if ( !shareWidget ) { - GraphicsWindowQt* sharedContextQt = dynamic_cast(_traits->sharedContext.get()); - if ( sharedContextQt ) - shareWidget = sharedContextQt->getGLWidget(); - } - - // WindowFlags - Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint; - if ( _traits->windowDecoration ) - flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; - - // create widget - _widget = new GLWidget( traits2qglFormat( _traits.get() ), parent, shareWidget, flags ); - } - - // set widget name and position - // (do not set it when we inherited the widget) - if ( _ownsWidget ) - { - _widget->setWindowTitle( _traits->windowName.c_str() ); - _widget->move( _traits->x, _traits->y ); - if ( !_traits->supportsResize ) _widget->setFixedSize( _traits->width, _traits->height ); - else _widget->resize( _traits->width, _traits->height ); - } - - // initialize widget properties - _widget->setAutoBufferSwap( false ); - _widget->setMouseTracking( true ); - _widget->setGraphicsWindow( this ); - useCursor( _traits->useCursor ); - - // initialize State - setState( new osg::State ); - getState()->setGraphicsContext(this); - - // initialize contextID - if ( _traits.valid() && _traits->sharedContext.valid() ) - { - getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); - incrementContextIDUsageCount( getState()->getContextID() ); - } - else - { - getState()->setContextID( osg::GraphicsContext::createNewContextID() ); - } - - // make sure the event queue has the correct window rectangle size and input range - getEventQueue()->syncWindowRectangleWithGraphicsContext(); - - return true; -} - -QGLFormat GraphicsWindowQt::traits2qglFormat( const osg::GraphicsContext::Traits* traits ) -{ - QGLFormat format( QGLFormat::defaultFormat() ); - - format.setAlphaBufferSize( traits->alpha ); - format.setRedBufferSize( traits->red ); - format.setGreenBufferSize( traits->green ); - format.setBlueBufferSize( traits->blue ); - format.setDepthBufferSize( traits->depth ); - format.setStencilBufferSize( traits->stencil ); - format.setSampleBuffers( traits->sampleBuffers ); - format.setSamples( traits->samples ); - - format.setAlpha( traits->alpha>0 ); - format.setDepth( traits->depth>0 ); - format.setStencil( traits->stencil>0 ); - format.setDoubleBuffer( traits->doubleBuffer ); - format.setSwapInterval( traits->vsync ? 1 : 0 ); - format.setStereo( traits->quadBufferStereo ? 1 : 0 ); - - return format; -} - -void GraphicsWindowQt::qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits ) -{ - traits->red = format.redBufferSize(); - traits->green = format.greenBufferSize(); - traits->blue = format.blueBufferSize(); - traits->alpha = format.alpha() ? format.alphaBufferSize() : 0; - traits->depth = format.depth() ? format.depthBufferSize() : 0; - traits->stencil = format.stencil() ? format.stencilBufferSize() : 0; - - traits->sampleBuffers = format.sampleBuffers() ? 1 : 0; - traits->samples = format.samples(); - - traits->quadBufferStereo = format.stereo(); - traits->doubleBuffer = format.doubleBuffer(); - - traits->vsync = format.swapInterval() >= 1; -} - -osg::GraphicsContext::Traits* GraphicsWindowQt::createTraits( const QGLWidget* widget ) -{ - osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits; - - qglFormat2traits( widget->format(), traits ); - - QRect r = widget->geometry(); - traits->x = r.x(); - traits->y = r.y(); - traits->width = r.width(); - traits->height = r.height(); - - traits->windowName = widget->windowTitle().toLocal8Bit().data(); - Qt::WindowFlags f = widget->windowFlags(); - traits->windowDecoration = ( f & Qt::WindowTitleHint ) && - ( f & Qt::WindowMinMaxButtonsHint ) && - ( f & Qt::WindowSystemMenuHint ); - QSizePolicy sp = widget->sizePolicy(); - traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed || - sp.verticalPolicy() != QSizePolicy::Fixed; - - return traits; -} - -bool GraphicsWindowQt::setWindowRectangleImplementation( int x, int y, int width, int height ) -{ - if ( _widget == nullptr ) - return false; - - _widget->setGeometry( x, y, width, height ); - return true; -} - -void GraphicsWindowQt::getWindowRectangle( int& x, int& y, int& width, int& height ) -{ - if ( _widget ) - { - const QRect& geom = _widget->geometry(); - x = geom.x(); - y = geom.y(); - width = geom.width(); - height = geom.height(); - } -} - -bool GraphicsWindowQt::setWindowDecorationImplementation( bool windowDecoration ) -{ - Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint; - if ( windowDecoration ) - flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint; - _traits->windowDecoration = windowDecoration; - - if ( _widget ) - { - _widget->setWindowFlags( flags ); - - return true; - } - - return false; -} - -bool GraphicsWindowQt::getWindowDecoration() const -{ - return _traits->windowDecoration; -} - -void GraphicsWindowQt::grabFocus() -{ - if ( _widget ) - _widget->setFocus( Qt::ActiveWindowFocusReason ); -} - -void GraphicsWindowQt::grabFocusIfPointerInWindow() -{ - if ( _widget->underMouse() ) - _widget->setFocus( Qt::ActiveWindowFocusReason ); -} - -void GraphicsWindowQt::raiseWindow() -{ - if ( _widget ) - _widget->raise(); -} - -void GraphicsWindowQt::setWindowName( const std::string& name ) -{ - if ( _widget ) - _widget->setWindowTitle( name.c_str() ); -} - -std::string GraphicsWindowQt::getWindowName() -{ - return _widget ? _widget->windowTitle().toStdString() : ""; -} - -void GraphicsWindowQt::useCursor( bool cursorOn ) -{ - if ( _widget ) - { - _traits->useCursor = cursorOn; - if ( !cursorOn ) _widget->setCursor( Qt::BlankCursor ); - else _widget->setCursor( _currentCursor ); - } -} - -void GraphicsWindowQt::setCursor( MouseCursor cursor ) -{ - if ( cursor==InheritCursor && _widget ) - { - _widget->unsetCursor(); - } - - switch ( cursor ) - { - case NoCursor: _currentCursor = Qt::BlankCursor; break; - case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break; - case InfoCursor: _currentCursor = Qt::SizeAllCursor; break; - case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break; - case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break; - case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break; - case SprayCursor: _currentCursor = Qt::SizeAllCursor; break; - case WaitCursor: _currentCursor = Qt::WaitCursor; break; - case TextCursor: _currentCursor = Qt::IBeamCursor; break; - case CrosshairCursor: _currentCursor = Qt::CrossCursor; break; - case HandCursor: _currentCursor = Qt::OpenHandCursor; break; - case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break; - case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break; - case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break; - case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break; - case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break; - case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break; - case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break; - case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break; - default: break; - }; - if ( _widget ) _widget->setCursor( _currentCursor ); -} - -bool GraphicsWindowQt::valid() const -{ - return _widget && _widget->isValid(); -} - -bool GraphicsWindowQt::realizeImplementation() -{ - // save the current context - // note: this will save only Qt-based contexts - const QGLContext *savedContext = QGLContext::currentContext(); - - // initialize GL context for the widget - if ( !valid() ) - _widget->glInit(); - - // make current - _realized = true; - bool result = makeCurrent(); - _realized = false; - - // fail if we do not have current context - if ( !result ) - { - if ( savedContext ) - const_cast< QGLContext* >( savedContext )->makeCurrent(); - - OSG_WARN << "Window realize: Can make context current." << std::endl; - return false; - } - - _realized = true; - - // make sure the event queue has the correct window rectangle size and input range - getEventQueue()->syncWindowRectangleWithGraphicsContext(); - - // make this window's context not current - // note: this must be done as we will probably make the context current from another thread - // and it is not allowed to have one context current in two threads - if( !releaseContext() ) - OSG_WARN << "Window realize: Can not release context." << std::endl; - - // restore previous context - if ( savedContext ) - const_cast< QGLContext* >( savedContext )->makeCurrent(); - - return true; -} - -bool GraphicsWindowQt::isRealizedImplementation() const -{ - return _realized; -} - -void GraphicsWindowQt::closeImplementation() -{ - if ( _widget ) - _widget->close(); - _realized = false; -} - -void GraphicsWindowQt::runOperations() -{ - // While in graphics thread this is last chance to do something useful before - // graphics thread will execute its operations. - if (_widget->getNumDeferredEvents() > 0) - _widget->processDeferredEvents(); - - if (QGLContext::currentContext() != _widget->context()) - _widget->makeCurrent(); - - GraphicsWindow::runOperations(); -} - -bool GraphicsWindowQt::makeCurrentImplementation() -{ - if (_widget->getNumDeferredEvents() > 0) - _widget->processDeferredEvents(); - - _widget->makeCurrent(); - - return true; -} - -bool GraphicsWindowQt::releaseContextImplementation() -{ - _widget->doneCurrent(); - return true; -} - -void GraphicsWindowQt::swapBuffersImplementation() -{ - // QOpenGLContext complains if we swap on an non-exposed QWindow - if (!_widget || !_widget->windowHandle()->isExposed()) - return; - - // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but - // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will - // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the - // QGLWidget event handler is an indication of a Qt bug. - if (_widget->getNumDeferredEvents() > 0) - _widget->processDeferredEvents(); - - // We need to call makeCurrent here to restore our previously current context - // which may be changed by the processDeferredEvents function. - _widget->makeCurrent(); - _widget->swapBuffers(); -} - -void GraphicsWindowQt::requestWarpPointer( float x, float y ) -{ - if ( _widget ) - QCursor::setPos( _widget->mapToGlobal(QPoint((int)x,(int)y)) ); -} - - -class QtWindowingSystem : public osg::GraphicsContext::WindowingSystemInterface -{ -public: - - QtWindowingSystem() - { - OSG_INFO << "QtWindowingSystemInterface()" << std::endl; - } - - ~QtWindowingSystem() - { - if (osg::Referenced::getDeleteHandler()) - { - osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); - osg::Referenced::getDeleteHandler()->flushAll(); - } - } - - // Access the Qt windowing system through this singleton class. - static QtWindowingSystem* getInterface() - { - static QtWindowingSystem* qtInterface = new QtWindowingSystem; - return qtInterface; - } - - // Return the number of screens present in the system - unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& /*si*/ ) override - { - OSG_WARN << "osgQt: getNumScreens() not implemented yet." << std::endl; - return 0; - } - - // Return the resolution of specified screen - // (0,0) is returned if screen is unknown - void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, osg::GraphicsContext::ScreenSettings & /*resolution*/ ) override - { - OSG_WARN << "osgQt: getScreenSettings() not implemented yet." << std::endl; - } - - // Set the resolution for given screen - bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, const osg::GraphicsContext::ScreenSettings & /*resolution*/ ) override - { - OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl; - return false; - } - - // Enumerates available resolutions - void enumerateScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/, osg::GraphicsContext::ScreenSettingsList & /*resolution*/ ) override - { - OSG_WARN << "osgQt: enumerateScreenSettings() not implemented yet." << std::endl; - } - - // Create a graphics context with given traits - osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits ) override - { - if (traits->pbuffer) - { - OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl; - return nullptr; - } - else - { - osg::ref_ptr< GraphicsWindowQt > window = new GraphicsWindowQt( traits ); - if (window->valid()) return window.release(); - else return nullptr; - } - } - -private: - - // No implementation for these - QtWindowingSystem( const QtWindowingSystem& ); - QtWindowingSystem& operator=( const QtWindowingSystem& ); -}; - diff --git a/extern/osgQt/osgQOpenGLWidget.cpp b/extern/osgQt/osgQOpenGLWidget.cpp new file mode 100644 index 0000000000..0f2fba71cc --- /dev/null +++ b/extern/osgQt/osgQOpenGLWidget.cpp @@ -0,0 +1,98 @@ +#include "CompositeOsgRenderer.hpp" +#include "osgQOpenGLWidget.hpp" + +#include +#include + +#include +#include +#include + +osgQOpenGLWidget::osgQOpenGLWidget(QWidget* parent) + : QOpenGLWidget(parent) +{ + m_renderer = new CompositeOsgRenderer(this); + setMouseTracking(true); +} + +osgQOpenGLWidget::osgQOpenGLWidget(osg::ArgumentParser* arguments, + QWidget* parent) : + QOpenGLWidget(parent), + _arguments(arguments) +{ + m_renderer = new CompositeOsgRenderer(this); +} + +osgQOpenGLWidget::~osgQOpenGLWidget() +{ + if (m_renderer) delete m_renderer; +} + +osgViewer::View* osgQOpenGLWidget::getOsgView(unsigned i) +{ + if (m_renderer) return m_renderer->getView(i); + else return nullptr; +} + +std::mutex* osgQOpenGLWidget::mutex() +{ + return &_osgMutex; +} + +void osgQOpenGLWidget::initializeGL() +{ + // Initializes OpenGL function resolution for the current context. + initializeOpenGLFunctions(); + createRenderer(); + emit initialized(); +} + +void osgQOpenGLWidget::resizeGL(int w, int h) +{ + Q_ASSERT(m_renderer); + QScreen* screen = windowHandle() + && windowHandle()->screen() ? windowHandle()->screen() : + qApp->screens().front(); + m_renderer->resize(w * screen->devicePixelRatio(), h * screen->devicePixelRatio()); +} + +void osgQOpenGLWidget::paintGL() +{ + std::scoped_lock locker(_osgMutex); + if (_isFirstFrame) + { + _isFirstFrame = false; + for (unsigned int i = 0; i < m_renderer->getNumViews(); ++i) + { + m_renderer->getView(i)->getCamera()->getGraphicsContext()->setDefaultFboId(defaultFramebufferObject()); + } + } + m_renderer->frame(); +} + +void osgQOpenGLWidget::setDefaultDisplaySettings() +{ + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + ds->setNvOptimusEnablement(1); + ds->setStereo(false); +} + +CompositeOsgRenderer* osgQOpenGLWidget::getCompositeViewer() +{ + if (m_renderer) return m_renderer; + return nullptr; +} + +void osgQOpenGLWidget::setGraphicsWindowEmbedded(osg::ref_ptr osgWinEmb) +{ + if (m_renderer) m_renderer->setGraphicsWindowEmbedded(osgWinEmb); +} + +void osgQOpenGLWidget::createRenderer() +{ + // call this before creating a View... + setDefaultDisplaySettings(); + if (!m_renderer) m_renderer = new CompositeOsgRenderer(this); + + m_renderer->setupOSG(); +} diff --git a/extern/osgQt/osgQOpenGLWidget.hpp b/extern/osgQt/osgQOpenGLWidget.hpp new file mode 100644 index 0000000000..07ffc12248 --- /dev/null +++ b/extern/osgQt/osgQOpenGLWidget.hpp @@ -0,0 +1,70 @@ +#ifndef OSGQOPENGLWIDGET_H +#define OSGQOPENGLWIDGET_H + +#include + +#ifdef WIN32 +#include +#endif + +#include + +#include +#include +#include + +class CompositeOsgRenderer; + +namespace osgViewer +{ + class View; + class GraphicsWindowEmbedded; +} + +class osgQOpenGLWidget : public QOpenGLWidget, + protected QOpenGLFunctions +{ + Q_OBJECT + +protected: + CompositeOsgRenderer* m_renderer {nullptr}; + std::mutex _osgMutex; + osg::ArgumentParser* _arguments {nullptr}; + bool _isFirstFrame {true}; + + friend class CompositeOsgRenderer; + +public: + osgQOpenGLWidget(QWidget* parent = nullptr); + osgQOpenGLWidget(osg::ArgumentParser* arguments, QWidget* parent = nullptr); + virtual ~osgQOpenGLWidget(); + + /** Get osgViewer View */ + virtual osgViewer::View* getOsgView(unsigned i); + + //! get mutex + virtual std::mutex* mutex(); + + CompositeOsgRenderer* getCompositeViewer(); + + void setGraphicsWindowEmbedded(osg::ref_ptr osgWinEmb); + +signals: + void initialized(); + +protected: + //! call createRender. If overloaded, this method must send initialized signal at end + void initializeGL() override; + + void resizeGL(int w, int h) override; + + //! lock scene graph and call osgViewer::frame() + void paintGL() override; + + //! called before creating renderer + virtual void setDefaultDisplaySettings(); + + void createRenderer(); +}; + +#endif // OSGQOPENGLWIDGET_H From 3e9cedf3b5b8dc1775de36f45c6bcd23b5f1888a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 6 Apr 2023 08:04:21 +0400 Subject: [PATCH 2/3] Use a compile-time check --- apps/opencs/view/render/scenewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 298b67596a..6961a9d1a5 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -206,7 +206,7 @@ namespace CSVRender CSMPrefs::get()["Tooltips"].update(); } - connect(mRenderer, SIGNAL(simulationUpdated(double)), this, SLOT(update(double))); + connect(mRenderer, &CompositeOsgRenderer::simulationUpdated, this, &SceneWidget::update); // Shortcuts CSMPrefs::Shortcut* focusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this); From 5862f9f284986a56e119cef92fd3dad9beebd031 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 11 Apr 2023 12:18:01 +0400 Subject: [PATCH 3/3] Do not use GL ES wrappers --- extern/osgQt/osgQOpenGLWidget.cpp | 2 -- extern/osgQt/osgQOpenGLWidget.hpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/extern/osgQt/osgQOpenGLWidget.cpp b/extern/osgQt/osgQOpenGLWidget.cpp index 0f2fba71cc..d52f3c02ac 100644 --- a/extern/osgQt/osgQOpenGLWidget.cpp +++ b/extern/osgQt/osgQOpenGLWidget.cpp @@ -41,8 +41,6 @@ std::mutex* osgQOpenGLWidget::mutex() void osgQOpenGLWidget::initializeGL() { - // Initializes OpenGL function resolution for the current context. - initializeOpenGLFunctions(); createRenderer(); emit initialized(); } diff --git a/extern/osgQt/osgQOpenGLWidget.hpp b/extern/osgQt/osgQOpenGLWidget.hpp index 07ffc12248..8677b146f8 100644 --- a/extern/osgQt/osgQOpenGLWidget.hpp +++ b/extern/osgQt/osgQOpenGLWidget.hpp @@ -10,7 +10,6 @@ #include #include -#include #include class CompositeOsgRenderer; @@ -21,8 +20,7 @@ namespace osgViewer class GraphicsWindowEmbedded; } -class osgQOpenGLWidget : public QOpenGLWidget, - protected QOpenGLFunctions +class osgQOpenGLWidget : public QOpenGLWidget { Q_OBJECT