diff options
-rw-r--r-- | src/imports/studio3d/q3dsstudio3ditem.cpp | 11 | ||||
-rw-r--r-- | src/runtime/api/q3dssurfaceviewer.cpp | 8 | ||||
-rw-r--r-- | src/runtime/api/q3dsviewersettings.cpp | 27 | ||||
-rw-r--r-- | src/runtime/api/q3dsviewersettings.h | 4 | ||||
-rw-r--r-- | src/runtime/api/q3dsviewersettings_p.h | 3 | ||||
-rw-r--r-- | src/runtime/api/q3dswidget.cpp | 8 | ||||
-rw-r--r-- | src/runtime/q3dsengine.cpp | 93 | ||||
-rw-r--r-- | src/runtime/q3dsengine_p.h | 6 | ||||
-rw-r--r-- | src/runtime/q3dsinputmanager.cpp | 16 | ||||
-rw-r--r-- | src/runtime/q3dsinputmanager_p.h | 1 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager.cpp | 86 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager_p.h | 22 | ||||
-rw-r--r-- | tools/q3dsviewer/q3dsmainwindow.cpp | 62 |
13 files changed, 303 insertions, 44 deletions
diff --git a/src/imports/studio3d/q3dsstudio3ditem.cpp b/src/imports/studio3d/q3dsstudio3ditem.cpp index 1c16b89..7b4c0eb 100644 --- a/src/imports/studio3d/q3dsstudio3ditem.cpp +++ b/src/imports/studio3d/q3dsstudio3ditem.cpp @@ -242,10 +242,8 @@ void Q3DSStudio3DItem::componentComplete() qWarning("Studio3D: Duplicate ViewerSettings"); } else { m_viewerSettings = viewerSettings; - connect(m_viewerSettings, &Q3DSViewerSettings::showRenderStatsChanged, m_viewerSettings, [this] { - if (m_engine) - m_engine->setProfileUiVisible(m_viewerSettings->isShowingRenderStats()); - }); + if (m_engine) + m_engine->setViewerSettings(m_viewerSettings); } } } @@ -346,11 +344,12 @@ void Q3DSStudio3DItem::createEngine() m_engine->setSurface(w); } + if (m_viewerSettings) + m_engine->setViewerSettings(m_viewerSettings); + qCDebug(lcStudio3D, "created engine %p", m_engine); connect(m_engine, &Q3DSEngine::presentationLoaded, this, [this]() { - if (m_viewerSettings && m_viewerSettings->isShowingRenderStats()) - m_engine->setProfileUiVisible(true); m_presentation->studio3DPresentationLoaded(); if (!m_running) { m_running = true; diff --git a/src/runtime/api/q3dssurfaceviewer.cpp b/src/runtime/api/q3dssurfaceviewer.cpp index bbe6344..8ead5af 100644 --- a/src/runtime/api/q3dssurfaceviewer.cpp +++ b/src/runtime/api/q3dssurfaceviewer.cpp @@ -469,11 +469,6 @@ Q3DSSurfaceViewerPrivate::Q3DSSurfaceViewerPrivate() viewerSettings(new Q3DSViewerSettings) { Q3DSPresentationPrivate::get(presentation)->setController(this); - - QObject::connect(viewerSettings, &Q3DSViewerSettings::showRenderStatsChanged, viewerSettings, [this] { - if (engine) - engine->setProfileUiVisible(viewerSettings->isShowingRenderStats()); - }); } Q3DSSurfaceViewerPrivate::~Q3DSSurfaceViewerPrivate() @@ -511,6 +506,7 @@ bool Q3DSSurfaceViewerPrivate::createEngine() return false; } engine->setSurface(windowOrOffscreenSurface); + engine->setViewerSettings(viewerSettings); qCDebug(lc3DSSurface, "Created engine %p", engine); @@ -528,8 +524,6 @@ bool Q3DSSurfaceViewerPrivate::createEngine() QObject::connect(engine, &Q3DSEngine::presentationLoaded, engine, [this] { Q_Q(Q3DSSurfaceViewer); - if (viewerSettings->isShowingRenderStats()) - engine->setProfileUiVisible(true); emit q->presentationLoaded(); }); diff --git a/src/runtime/api/q3dsviewersettings.cpp b/src/runtime/api/q3dsviewersettings.cpp index c6c65fd..26844b4 100644 --- a/src/runtime/api/q3dsviewersettings.cpp +++ b/src/runtime/api/q3dsviewersettings.cpp @@ -92,6 +92,19 @@ Q3DSViewerSettings::~Q3DSViewerSettings() \note This property is currently ignored. */ + +/*! + \property Q3DSViewerSettings::matteEnabled + + \note This property is currently ignored. + */ + +bool Q3DSViewerSettings::matteEnabled() const +{ + Q_D(const Q3DSViewerSettings); + return d->matteEnabled; +} + QColor Q3DSViewerSettings::matteColor() const { Q_D(const Q3DSViewerSettings); @@ -128,8 +141,6 @@ Q3DSViewerSettings::ShadeMode Q3DSViewerSettings::shadeMode() const /*! \property Q3DSViewerSettings::scaleMode - - \note This property is currently ignored. */ Q3DSViewerSettings::ScaleMode Q3DSViewerSettings::scaleMode() const { @@ -137,11 +148,20 @@ Q3DSViewerSettings::ScaleMode Q3DSViewerSettings::scaleMode() const return d->scaleMode; } + +void Q3DSViewerSettings::setMatteEnabled(bool isEnabled) +{ + Q_D(Q3DSViewerSettings); + if (d->matteEnabled != isEnabled) { + d->matteEnabled = isEnabled; + emit matteEnabledChanged(); + } +} + void Q3DSViewerSettings::setMatteColor(const QColor &color) { Q_D(Q3DSViewerSettings); if (d->matteColor != color) { - qWarning() << Q_FUNC_INFO << "not implemented"; d->matteColor = color; emit matteColorChanged(); } @@ -170,7 +190,6 @@ void Q3DSViewerSettings::setScaleMode(Q3DSViewerSettings::ScaleMode mode) { Q_D(Q3DSViewerSettings); if (d->scaleMode != mode) { - qWarning() << Q_FUNC_INFO << "not implemented"; d->scaleMode = mode; emit scaleModeChanged(); } diff --git a/src/runtime/api/q3dsviewersettings.h b/src/runtime/api/q3dsviewersettings.h index de64393..044c436 100644 --- a/src/runtime/api/q3dsviewersettings.h +++ b/src/runtime/api/q3dsviewersettings.h @@ -46,6 +46,7 @@ class Q3DSViewerSettingsPrivate; class Q3DSV_EXPORT Q3DSViewerSettings : public QObject { Q_OBJECT + Q_PROPERTY(bool matteEnabled READ matteEnabled WRITE setMatteEnabled NOTIFY matteEnabledChanged) Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged) Q_PROPERTY(bool showRenderStats READ isShowingRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged) Q_PROPERTY(ShadeMode shadeMode READ shadeMode WRITE setShadeMode NOTIFY shadeModeChanged) @@ -68,6 +69,7 @@ public: explicit Q3DSViewerSettings(QObject *parent = nullptr); ~Q3DSViewerSettings(); + bool matteEnabled() const; QColor matteColor() const; bool isShowingRenderStats() const; ShadeMode shadeMode() const; @@ -81,12 +83,14 @@ public: const QString &application = QString()); public Q_SLOTS: + void setMatteEnabled(bool isEnabled); void setMatteColor(const QColor &color); void setShowRenderStats(bool show); void setShadeMode(ShadeMode mode); void setScaleMode(ScaleMode mode); Q_SIGNALS: + void matteEnabledChanged(); void matteColorChanged(); void showRenderStatsChanged(); void shadeModeChanged(); diff --git a/src/runtime/api/q3dsviewersettings_p.h b/src/runtime/api/q3dsviewersettings_p.h index a4464cf..9255d35 100644 --- a/src/runtime/api/q3dsviewersettings_p.h +++ b/src/runtime/api/q3dsviewersettings_p.h @@ -54,7 +54,8 @@ class Q3DSV_PRIVATE_EXPORT Q3DSViewerSettingsPrivate : public QObjectPrivate public: static Q3DSViewerSettingsPrivate *get(Q3DSViewerSettings *p) { return p->d_func(); } - QColor matteColor = Qt::black; + bool matteEnabled = false; + QColor matteColor = QColor(51, 51, 51); bool showRenderStats = false; Q3DSViewerSettings::ShadeMode shadeMode = Q3DSViewerSettings::ShadeModeShaded; Q3DSViewerSettings::ScaleMode scaleMode = Q3DSViewerSettings::ScaleModeFill; diff --git a/src/runtime/api/q3dswidget.cpp b/src/runtime/api/q3dswidget.cpp index 56d65d5..7381ce5 100644 --- a/src/runtime/api/q3dswidget.cpp +++ b/src/runtime/api/q3dswidget.cpp @@ -325,11 +325,6 @@ Q3DSWidgetPrivate::Q3DSWidgetPrivate(Q3DSWidget *q) { Q3DSPresentationPrivate::get(presentation)->setController(this); - QObject::connect(viewerSettings, &Q3DSViewerSettings::showRenderStatsChanged, viewerSettings, [this] { - if (engine) - engine->setProfileUiVisible(viewerSettings->isShowingRenderStats()); - }); - typedef void (QWidget::*QWidgetVoidSlot)(); QObject::connect(&updateTimer, &QTimer::timeout, q, static_cast<QWidgetVoidSlot>(&QWidget::update)); updateTimer.setInterval(updateInterval); @@ -355,6 +350,7 @@ void Q3DSWidgetPrivate::createEngine() engine->setAutoToggleProfileUi(false); // up to the app to control this via the API instead engine->setSurface(q_ptr->window()->windowHandle()); + engine->setViewerSettings(viewerSettings); qCDebug(lc3DSWidget, "Created engine %p", engine); initializePresentationController(engine, presentation); @@ -366,8 +362,6 @@ void Q3DSWidgetPrivate::createEngine() engine->resize(sz); QObject::connect(engine, &Q3DSEngine::presentationLoaded, engine, [this] { - if (viewerSettings->isShowingRenderStats()) - engine->setProfileUiVisible(true); emit q_ptr->presentationLoaded(); }); diff --git a/src/runtime/q3dsengine.cpp b/src/runtime/q3dsengine.cpp index 20d9b0e..b58140b 100644 --- a/src/runtime/q3dsengine.cpp +++ b/src/runtime/q3dsengine.cpp @@ -34,12 +34,14 @@ #include "q3dslogging_p.h" #include "q3dsinputmanager_p.h" #include "q3dsinlineqmlsubpresentation_p.h" +#include "q3dsviewersettings.h" #include <QLoggingCategory> #include <QKeyEvent> #include <QMouseEvent> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcontext.h> +#include <QtMath> #include <QOpenGLContext> #include <QOpenGLFunctions> @@ -158,6 +160,7 @@ Q3DSEngine::Q3DSEngine() const bool logValueChanges = qEnvironmentVariableIntValue("Q3DS_DEBUG") >= 1; const_cast<QLoggingCategory &>(lcUipProp()).setEnabled(QtDebugMsg, logValueChanges); } + setViewerSettings(new Q3DSViewerSettings(this)); } Q3DSEngine::~Q3DSEngine() @@ -752,6 +755,7 @@ bool Q3DSEngine::buildUipPresentationScene(UipPresentation *pres) params.outputDpr = effectiveDpr; params.surface = m_surface; params.engine = this; + params.viewport = calculateViewport(effectiveSize, m_implicitSize); QScopedPointer<Q3DSSceneManager> sceneManager(new Q3DSSceneManager); pres->q3dscene = sceneManager->buildScene(pres->presentation, params); @@ -775,7 +779,11 @@ bool Q3DSEngine::buildUipPresentationScene(UipPresentation *pres) // Generate a resize to make sure everything size-related gets updated. // (avoids issues with camera upon loading new scenes) - pres->sceneManager->updateSizes(effectiveSize, effectiveDpr); + pres->sceneManager->updateSizes(effectiveSize, effectiveDpr, params.viewport); + + // Set matte preferences + pres->sceneManager->setMatteEnabled(m_viewerSettings->matteEnabled()); + pres->sceneManager->setMatteColor(m_viewerSettings->matteColor()); // Expose update signal connect(pres->q3dscene.frameAction, &Qt3DLogic::QFrameAction::triggered, this, [this](float dt) { @@ -1109,7 +1117,6 @@ void Q3DSEngine::destroy() // wish I knew why this is needed. Qt 3D tends not to shut down its threads correctly on exit otherwise. if (m_aspectEngine) Qt3DCore::QAspectEnginePrivate::get(m_aspectEngine.data())->exitSimulationLoop(); - m_aspectEngine.reset(); } @@ -1188,6 +1195,36 @@ Qt3DCore::QEntity *Q3DSEngine::rootEntity() const return m_uipPresentations.isEmpty() ? nullptr : m_uipPresentations[0].q3dscene.rootEntity; } +Q3DSViewerSettings *Q3DSEngine::viewerSettings() const +{ + return m_viewerSettings; +} + +void Q3DSEngine::setViewerSettings(Q3DSViewerSettings *viewerSettings) +{ + if (m_viewerSettings == viewerSettings) + return; + + m_viewerSettings = viewerSettings; + connect(m_viewerSettings, &Q3DSViewerSettings::showRenderStatsChanged, [this] { + setProfileUiVisible(m_viewerSettings->isShowingRenderStats()); + }); + connect(m_viewerSettings, &Q3DSViewerSettings::scaleModeChanged, [this] { + // Force a resize + resize(m_size, m_dpr); + }); + connect(m_viewerSettings, &Q3DSViewerSettings::matteEnabledChanged, [this] { + if (!m_uipPresentations.isEmpty()) { + m_uipPresentations[0].sceneManager->setMatteEnabled(m_viewerSettings->matteEnabled()); + } + }); + connect(m_viewerSettings, &Q3DSViewerSettings::matteColorChanged, [this] { + if (!m_uipPresentations.isEmpty()) { + m_uipPresentations[0].sceneManager->setMatteColor(m_viewerSettings->matteColor()); + } + }); +} + void Q3DSEngine::setOnDemandRendering(bool enabled) { if (m_onDemandRendering == enabled) @@ -1228,8 +1265,13 @@ void Q3DSEngine::resize(const QSize &size, qreal dpr, bool forceSynchronous) { m_size = size; m_dpr = dpr; - if (!m_uipPresentations.isEmpty()) - m_uipPresentations[0].sceneManager->updateSizes(m_size, m_dpr, forceSynchronous); + + if (!m_uipPresentations.isEmpty()) { + const QSize presentationSize(m_uipPresentations[0].presentation->presentationWidth(), + m_uipPresentations[0].presentation->presentationHeight()); + const QRect viewport = calculateViewport(m_size, presentationSize); + m_uipPresentations[0].sceneManager->updateSizes(m_size, m_dpr, viewport, forceSynchronous); + } } void Q3DSEngine::setAutoStart(bool autoStart) @@ -1644,6 +1686,49 @@ void Q3DSEngine::behaviorFrameUpdate(float dt) } } +QRect Q3DSEngine::calculateViewport(const QSize &surfaceSize, const QSize &presentationSize) const +{ + // The top level persentations viewport depends on the scale mode of + // the Q3DSViewerSettings. The method returns the viewport rect based + // on the current surface size and scale mode. + + // We need to have the presentation size + if (presentationSize.isNull()) + return QRect(); + + QRect viewportRect; + if (m_viewerSettings->scaleMode() == Q3DSViewerSettings::ScaleModeFill) { + // the presentation is always rendered to fill the viewport + viewportRect = QRect(0, 0, surfaceSize.width(), surfaceSize.height()); + } else if (m_viewerSettings->scaleMode() == Q3DSViewerSettings::ScaleModeCenter) { + // the presentation is rendered at the size specified in Studio. Additional content is cropped, + // additional space is letterboxed. + const qreal presHorizontalCenter = presentationSize.width() * 0.5; + const qreal presVerticalCenter = presentationSize.height() * 0.5; + const qreal surfaceHorizontalCenter = surfaceSize.width() * 0.5; + const qreal surfaceVerticalCenter = surfaceSize.height() * 0.5; + const qreal x = surfaceHorizontalCenter - presHorizontalCenter; + const qreal y = surfaceVerticalCenter - presVerticalCenter; + viewportRect = QRect(qFloor(x), qFloor(y), presentationSize.width(), presentationSize.height()); + } else if (m_viewerSettings->scaleMode() == Q3DSViewerSettings::ScaleModeFit) { + // the aspect ratio of the presentation is preserved, letterboxing as needed. + const qreal presentationAspectRatio = qreal(presentationSize.width()) / qreal(presentationSize.height()); + const qreal surfaceAspectRatio = qreal(surfaceSize.width()) / qreal(surfaceSize.height()); + int width = surfaceSize.width(); + int height = surfaceSize.height(); + if (presentationAspectRatio > surfaceAspectRatio) + height = int(surfaceSize.width() / presentationAspectRatio); + else + width = int(surfaceSize.height() * presentationAspectRatio); + viewportRect = QRect((surfaceSize.width() - width) / 2, + (surfaceSize.height() - height) / 2, + width, + height); + } + + return viewportRect; +} + // Object reference format used by behaviors and some public API: // // (presentationName:)?(parent|this|(Scene|Slide)(\..)*|(.)*) diff --git a/src/runtime/q3dsengine_p.h b/src/runtime/q3dsengine_p.h index 841e5e1..2a602b9 100644 --- a/src/runtime/q3dsengine_p.h +++ b/src/runtime/q3dsengine_p.h @@ -61,6 +61,7 @@ class QTabletEvent; class QQmlEngine; class QQmlComponent; class Q3DSInlineQmlSubPresentation; +class Q3DSViewerSettings; namespace Qt3DRender { class QRenderCapture; @@ -134,6 +135,9 @@ public: Qt3DCore::QAspectEngine *aspectEngine() const; Qt3DCore::QEntity *rootEntity() const; + Q3DSViewerSettings *viewerSettings() const; + void setViewerSettings(Q3DSViewerSettings *viewerSettings); + void setOnDemandRendering(bool enabled); QSize implicitSize() const; @@ -244,6 +248,7 @@ private: void loadBehaviors(); void destroyBehaviorHandle(const Q3DSBehaviorHandle &h); void behaviorFrameUpdate(float dt); + QRect calculateViewport(const QSize &surfaceSize, const QSize &presentationSize) const; QObject *m_surface = nullptr; QSize m_implicitSize; @@ -279,6 +284,7 @@ private: BehaviorMap m_behaviorHandles; bool m_onDemandRendering = false; + Q3DSViewerSettings *m_viewerSettings = nullptr; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSEngine::Flags) diff --git a/src/runtime/q3dsinputmanager.cpp b/src/runtime/q3dsinputmanager.cpp index 774ad14..315b27c 100644 --- a/src/runtime/q3dsinputmanager.cpp +++ b/src/runtime/q3dsinputmanager.cpp @@ -47,14 +47,14 @@ Q3DSInputManager::Q3DSInputManager(Q3DSSceneManager *sceneManager, QObject *pare void Q3DSInputManager::handleMousePressEvent(QMouseEvent *e) { m_currentState.mousePressed = true; - PickRequest req(e->pos() * m_sceneManager->m_guiData.outputDpr, m_currentState); + PickRequest req(convertToViewportSpace(e->pos()), m_currentState); m_pickRequests.append(req); } void Q3DSInputManager::handleMouseReleaseEvent(QMouseEvent *e) { m_currentState.mousePressed = false; - PickRequest req(e->pos() * m_sceneManager->m_guiData.outputDpr, m_currentState); + PickRequest req(convertToViewportSpace(e->pos()), m_currentState); m_pickRequests.append(req); } @@ -63,7 +63,7 @@ void Q3DSInputManager::handleMouseMoveEvent(QMouseEvent *e) if (!m_isHoverEnabled && !m_currentState.mousePressed) return; - PickRequest req(e->pos() * m_sceneManager->m_guiData.outputDpr, m_currentState); + PickRequest req(convertToViewportSpace(e->pos()), m_currentState); m_pickRequests.append(req); } @@ -224,6 +224,16 @@ Q3DSGraphObject *Q3DSInputManager::getNodeForEntity(Q3DSLayerNode *layer, Qt3DCo return nullptr; } +QPoint Q3DSInputManager::convertToViewportSpace(const QPoint &point) const +{ + QPoint convertedPoint; + convertedPoint.setX(point.x() - m_sceneManager->m_viewportData.viewportRect.x()); + convertedPoint.setY(point.y() - m_sceneManager->m_viewportData.viewportRect.y()); + + // adjust point for device pixel ratio + return convertedPoint * m_sceneManager->m_viewportData.viewportDpr; +} + void Q3DSInputManager::pick(const QPoint &point, const InputState &inputState) { // Get a list of layers in this scene (in order) diff --git a/src/runtime/q3dsinputmanager_p.h b/src/runtime/q3dsinputmanager_p.h index 13199f9..b3b8b26 100644 --- a/src/runtime/q3dsinputmanager_p.h +++ b/src/runtime/q3dsinputmanager_p.h @@ -85,6 +85,7 @@ private: void castRayIntoLayer(Q3DSLayerNode *layer, const QPointF &pos, const InputState &inputState, int eventId); void sendMouseEvent(Q3DSGraphObject *target, const Qt3DRender::QRayCasterHit &hit, const InputState &inputState); Q3DSGraphObject *getNodeForEntity(Q3DSLayerNode *layer, Qt3DCore::QEntity *entity); + QPoint convertToViewportSpace(const QPoint &point) const; Q3DSSceneManager *m_sceneManager = nullptr; bool m_isHoverEnabled = false; diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp index 6008af5..22b51b2 100644 --- a/src/runtime/q3dsscenemanager.cpp +++ b/src/runtime/q3dsscenemanager.cpp @@ -74,6 +74,7 @@ #include <Qt3DRender/QGraphicsApiFilter> #include <Qt3DRender/QRenderPass> #include <Qt3DRender/QRenderPassFilter> +#include <Qt3DRender/QRenderStateSet> #include <Qt3DRender/QFilterKey> #include <Qt3DRender/QNoDraw> #include <Qt3DRender/QFrontFace> @@ -90,6 +91,7 @@ #include <Qt3DRender/QStencilMask> #include <Qt3DRender/QStencilOperation> #include <Qt3DRender/QStencilOperationArguments> +#include <Qt3DRender/QScissorTest> #include <Qt3DRender/QRayCaster> #include <Qt3DAnimation/QClipAnimator> @@ -466,20 +468,44 @@ Q3DSSceneManager::~Q3DSSceneManager() delete m_inputManager; } -void Q3DSSceneManager::updateSizes(const QSize &size, qreal dpr, bool forceSynchronous) +void Q3DSSceneManager::updateSizes(const QSize &size, qreal dpr, const QRect &viewport, bool forceSynchronous) { if (!m_scene) return; - qCDebug(lcScene) << "Resize to" << size << "device pixel ratio" << dpr; + // Setup the matte and scene viewport + QRectF normalizedViewport; + if (viewport.isNull()) + normalizedViewport = QRectF(0, 0, 1, 1); + else + normalizedViewport = QRectF(viewport.x() / qreal(size.width()), + viewport.y() / qreal(size.height()), + viewport.width() / qreal(size.width()), + viewport.height() / qreal(size.height())); + + if (m_viewportData.viewport) + m_viewportData.viewport->setNormalizedRect(normalizedViewport); + + m_viewportData.viewportRect = viewport; + m_viewportData.viewportDpr = dpr; + if (m_viewportData.matteScissorTest) { + m_viewportData.matteScissorTest->setBottom(qFloor(-(viewport.height() + viewport.y() - size.height()) * dpr)); + m_viewportData.matteScissorTest->setLeft(qFloor(viewport.x() * dpr)); + m_viewportData.matteScissorTest->setWidth(qFloor(viewport.width() * dpr)); + m_viewportData.matteScissorTest->setHeight(qFloor(viewport.height() * dpr)); + } + + qCDebug(lcScene) << "Resize to" << size << "with viewport" << viewport << "device pixel ratio" << dpr; + + m_outputPixelSize = viewport.size() * dpr; - m_outputPixelSize = size * dpr; + // m_guiData uses the full surface size (not viewport) m_guiData.outputSize = size; m_guiData.outputDpr = dpr; if (m_guiData.camera) { - m_guiData.camera->setRight(m_outputPixelSize.width()); - m_guiData.camera->setBottom(m_outputPixelSize.height()); + m_guiData.camera->setRight(size.width() * float(dpr)); + m_guiData.camera->setBottom(size.height() * float(dpr)); } for (auto callback : m_compositorOutputSizeChangeCallbacks) @@ -682,8 +708,10 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen subPresFrameGraphRoot = nullptr; Q_ASSERT(frameGraphRoot); } - - m_outputPixelSize = params.outputSize * params.outputDpr; + if (params.viewport.isNull()) + m_outputPixelSize = params.outputSize * params.outputDpr; + else + m_outputPixelSize = params.viewport.size() * params.outputDpr; m_guiData.outputSize = params.outputSize; m_guiData.outputDpr = params.outputDpr; @@ -3269,8 +3297,18 @@ void Q3DSSceneManager::buildCompositor(Qt3DRender::QFrameGraphNode *parent, Qt3D // ... // With standard blend modes only this is simplified to a single LayerFilter and QLayer tag. - Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(parent); - viewport->setNormalizedRect(QRectF(0, 0, 1, 1)); + // If Matte is enabled in the ViewerSettings, then we need clear with the matte color first + // then later restrict the scene clear color to the vieport rect with a scissor test + m_viewportData.drawMatteNode = new Qt3DRender::QFrameGraphNode(parent); + new Qt3DRender::QNoDraw(m_viewportData.drawMatteNode); + m_viewportData.dummyMatteRoot = new Qt3DCore::QNode(m_rootEntity); + m_viewportData.matteClearBuffers = new Qt3DRender::QClearBuffers(m_viewportData.dummyMatteRoot); + m_viewportData.matteClearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthStencilBuffer); + m_viewportData.matteClearBuffers->setClearColor(Qt::black); + new Qt3DRender::QNoDraw(m_viewportData.matteClearBuffers); + + m_viewportData.viewport = new Qt3DRender::QViewport(parent); + m_viewportData.viewport->setNormalizedRect(QRectF(0, 0, 1, 1)); Qt3DRender::QCamera *camera = new Qt3DRender::QCamera; camera->setObjectName(QLatin1String("compositor camera")); @@ -3282,10 +3320,15 @@ void Q3DSSceneManager::buildCompositor(Qt3DRender::QFrameGraphNode *parent, Qt3D camera->setPosition(QVector3D(0, 0, 1)); camera->setViewCenter(QVector3D(0, 0, 0)); - Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport); + Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(m_viewportData.viewport); cameraSelector->setCamera(camera); - Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(cameraSelector); + m_viewportData.matteRenderState = new Qt3DRender::QRenderStateSet(cameraSelector); + m_viewportData.matteRenderState->setEnabled(false); + m_viewportData.matteScissorTest = new Qt3DRender::QScissorTest(m_viewportData.matteRenderState); + m_viewportData.matteRenderState->addRenderState(m_viewportData.matteScissorTest); + + Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(m_viewportData.matteRenderState); clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthStencilBuffer); QColor clearColor = Qt::transparent; if (m_scene->useClearColor()) { @@ -7172,6 +7215,27 @@ void Q3DSSceneManager::configureProfileUi(float scale) #endif } +void Q3DSSceneManager::setMatteEnabled(bool isEnabled) +{ + if (!m_viewportData.drawMatteNode) + return; + + if (isEnabled) { + // Attached the matteClearBuffers to the drawMatteNode placeholder + m_viewportData.matteClearBuffers->setParent(m_viewportData.drawMatteNode); + m_viewportData.matteRenderState->setEnabled(true); + } else { + m_viewportData.matteClearBuffers->setParent(m_viewportData.dummyMatteRoot); + m_viewportData.matteRenderState->setEnabled(false); + } +} + +void Q3DSSceneManager::setMatteColor(const QColor &color) +{ + if (m_viewportData.matteClearBuffers) + m_viewportData.matteClearBuffers->setClearColor(color); +} + void Q3DSSceneManager::addLog(const QString &msg) { #if QT_CONFIG(q3ds_profileui) diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h index 1faf985..fd565b9 100644 --- a/src/runtime/q3dsscenemanager_p.h +++ b/src/runtime/q3dsscenemanager_p.h @@ -96,6 +96,9 @@ class QTechnique; class QFilterKey; class QRenderState; class QRayCaster; +class QViewport; +class QScissorTest; +class QRenderStateSet; } namespace Qt3DExtras { @@ -611,6 +614,18 @@ struct Q3DSGuiData qreal outputDpr = 1; }; +struct Q3DSViewportData +{ + Qt3DRender::QFrameGraphNode *drawMatteNode = nullptr; + Qt3DRender::QClearBuffers *matteClearBuffers = nullptr; + Qt3DRender::QRenderStateSet *matteRenderState = nullptr; + Qt3DRender::QScissorTest *matteScissorTest = nullptr; + Qt3DCore::QNode *dummyMatteRoot = nullptr; + Qt3DRender::QViewport *viewport = nullptr; + qreal viewportDpr = 1; + QRect viewportRect; +}; + class Q3DSV_PRIVATE_EXPORT Q3DSSceneManager { public: @@ -628,6 +643,7 @@ public: QObject *surface = nullptr; // null for subpresentations that go into a texture Qt3DRender::QFrameGraphNode *frameGraphRoot = nullptr; // when !window Q3DSEngine *engine = nullptr; + QRect viewport; }; struct Scene { @@ -643,7 +659,7 @@ public: Scene buildScene(Q3DSUipPresentation *presentation, const SceneBuilderParams ¶ms); void finalizeMainScene(const QVector<Q3DSSubPresentation> &subPresentations); - void updateSizes(const QSize &size, qreal dpr, bool forceSynchronous = false); + void updateSizes(const QSize &size, qreal dpr, const QRect &viewport = QRect(), bool forceSynchronous = false); void prepareEngineReset(); static void prepareEngineResetGlobal(); @@ -700,6 +716,9 @@ public: void setProfileUiInputEventSource(QObject *obj); void configureProfileUi(float scale); + void setMatteEnabled(bool isEnabled); + void setMatteColor(const QColor &color); + Q3DSInputManager *inputManager() { return m_inputManager; } // for testing from the viewer - to be moved private later @@ -873,6 +892,7 @@ private: bool m_layerCaching = true; bool m_layerUncachePending = false; QSet<Q3DSSceneManager *> m_layerCacheDeps; + Q3DSViewportData m_viewportData; friend class Q3DSFrameUpdater; friend class Q3DSProfiler; diff --git a/tools/q3dsviewer/q3dsmainwindow.cpp b/tools/q3dsviewer/q3dsmainwindow.cpp index e89c7b8..e91f59d 100644 --- a/tools/q3dsviewer/q3dsmainwindow.cpp +++ b/tools/q3dsviewer/q3dsmainwindow.cpp @@ -33,6 +33,7 @@ #include <private/q3dsengine_p.h> #include <private/q3dsutils_p.h> #include <private/q3dsslideplayer_p.h> +#include <Qt3DStudioRuntime2/Q3DSViewerSettings> #include <QApplication> #include <QMenuBar> #include <QMenu> @@ -106,7 +107,68 @@ Q3DStudioMainWindow::Q3DStudioMainWindow(Q3DSWindow *view, Q3DSRemoteDeploymentM } }); } + QAction *showMatte = viewMenu->addAction(tr("Show Matte")); + showMatte->setCheckable(true); + showMatte->setChecked(false); + showMatte->setShortcut(QKeySequence(tr("Ctrl+D"))); + connect(showMatte, &QAction::toggled, [=]() { + view->engine()->viewerSettings()->setMatteEnabled(showMatte->isChecked()); + }); + QAction *scaleModeAction = new QAction(tr("Scale Mode")); + scaleModeAction->setShortcut(QKeySequence(tr("Ctrl+Shift+S"))); + QMenu *scaleModeMenu = new QMenu(); + scaleModeAction->setMenu(scaleModeMenu); + QAction *scaleModeCenter = new QAction(tr("Center")); + scaleModeCenter->setCheckable(true); + scaleModeCenter->setChecked(false); + scaleModeMenu->addAction(scaleModeCenter); + + QAction *scaleModeFit = new QAction(tr("Scale to Fit")); + scaleModeFit->setCheckable(true); + scaleModeFit->setChecked(false); + scaleModeMenu->addAction(scaleModeFit); + + QAction *scaleModeFill = new QAction(tr("Scale to Fill")); + scaleModeFill->setCheckable(true); + scaleModeFill->setChecked(true); + scaleModeMenu->addAction(scaleModeFill); + + connect(scaleModeFit, &QAction::triggered, [=]() { + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeFit); + scaleModeCenter->setChecked(false); + scaleModeFill->setChecked(false); + scaleModeFit->setChecked(true); + }); + connect(scaleModeCenter, &QAction::triggered, [=]() { + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeCenter); + scaleModeCenter->setChecked(true); + scaleModeFill->setChecked(false); + scaleModeFit->setChecked(false); + }); + connect(scaleModeFill, &QAction::triggered, [=]() { + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill); + scaleModeCenter->setChecked(false); + scaleModeFill->setChecked(true); + scaleModeFit->setChecked(false); + }); + connect(scaleModeAction, &QAction::triggered, [=]() { + // toggle between the 3 scale modes + if (scaleModeCenter->isChecked()) { + scaleModeCenter->setChecked(false); + scaleModeFit->setChecked(true); + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeFit); + } else if (scaleModeFit->isChecked()) { + scaleModeFit->setChecked(false); + scaleModeFill->setChecked(true); + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill); + } else { + scaleModeFill->setChecked(false); + scaleModeCenter->setChecked(true); + view->engine()->viewerSettings()->setScaleMode(Q3DSViewerSettings::ScaleModeCenter); + } + }); + viewMenu->addMenu(scaleModeMenu); viewMenu->addAction(tr("Toggle Full Scree&n"), this, [this] { Qt::WindowStates s = windowState(); s.setFlag(Qt::WindowFullScreen, !s.testFlag(Qt::WindowFullScreen)); |