summaryrefslogtreecommitdiffstats
path: root/src/imports/studio3d/q3dsstudio3ditem.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2018-08-06 13:29:32 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2018-08-14 19:51:45 +0000
commitf2dac6a0b0c4be1a95dca352a72844f649b934e4 (patch)
tree8ee864015c4f1112cb4173c602b693b9ca4701e8 /src/imports/studio3d/q3dsstudio3ditem.cpp
parentf9facdf889dd4d040aa2a48d177c728c626813b8 (diff)
Add an optional separated engine-view mode to Studio3D
Adding View3D items to the Qt Quick scene allows turning off layer composition in the main presentation, and instead accessing each layer's texture as an individual visual QQuickItem. This way the 3D layers can be placed anywhere and be blended freely in the 2D scene, while avoiding all the trouble multiple Studio3D items would cause. This also moves composition into the Qt Quick domain, providing a more sensible story for creating 2D-3D UIs. While post-processing effects are still active even in separated views mode, it is now possible to use ShaderEffect instead. MSAA and SSAA layers are not handled currently and are left as a future exercise for those who like mind-boggling complexity. Task-number: QT3DS-2032 Change-Id: I08128b65d0344c609f8dea15f9562ccfd19140a6 Reviewed-by: Christian Stromme <christian.stromme@qt.io>
Diffstat (limited to 'src/imports/studio3d/q3dsstudio3ditem.cpp')
-rw-r--r--src/imports/studio3d/q3dsstudio3ditem.cpp139
1 files changed, 135 insertions, 4 deletions
diff --git a/src/imports/studio3d/q3dsstudio3ditem.cpp b/src/imports/studio3d/q3dsstudio3ditem.cpp
index c339c51..162f1fa 100644
--- a/src/imports/studio3d/q3dsstudio3ditem.cpp
+++ b/src/imports/studio3d/q3dsstudio3ditem.cpp
@@ -30,6 +30,7 @@
#include "q3dsstudio3ditem_p.h"
#include "q3dsstudio3drenderer_p.h"
#include "q3dsstudio3dnode_p.h"
+#include "q3dsstudio3dview_p.h"
#include "q3dspresentationitem_p.h"
#include <QSGNode>
#include <QLoggingCategory>
@@ -232,6 +233,25 @@ void Q3DSStudio3DItem::setIgnoredEvents(EventIgnoreFlags flags)
emit ignoredEventsChanged();
}
+void Q3DSStudio3DItem::setupSeparateViews()
+{
+ if (m_engine && window()) {
+ m_separateViewSetupPending = false;
+
+ m_engine->setMainLayerComposition(m_views.isEmpty());
+
+ const qreal dpr = window()->effectiveDevicePixelRatio();
+ for (Q3DSStudio3DView *view : m_views) {
+ handleViewGeometryChange(view, view->size().toSize() * dpr);
+ view->update();
+ }
+
+ update();
+ } else {
+ m_separateViewSetupPending = true;
+ }
+}
+
void Q3DSStudio3DItem::updateEventMasks()
{
if (m_eventIgnoreFlags.testFlag(IgnoreMouseEvents)) {
@@ -379,6 +399,16 @@ void Q3DSStudio3DItem::createEngine()
}
emit frameUpdate();
});
+
+ connect(m_engine, &Q3DSEngine::layerResized, this, [this](Q3DSLayerNode *) {
+ m_pendingViewSend = true;
+ update();
+ });
+
+ connect(m_engine, &Q3DSEngine::layerTextureNodeChanged, this, [this](Q3DSLayerNode *) {
+ m_pendingViewSend = true;
+ update();
+ });
}
m_needsPresReadySignal = true;
@@ -417,19 +447,67 @@ QSGNode *Q3DSStudio3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePain
// this on the render thread; the engine lives on the gui thread and should
// be ready at this point - unless there's no source set yet (or it failed)
- if (!m_engine || !m_sourceLoaded) {
+ if (!m_engine || !m_sourceLoaded || (size().isEmpty() && m_views.isEmpty())) {
delete node;
return nullptr;
}
Q3DSStudio3DNode *n = static_cast<Q3DSStudio3DNode *>(node);
- if (!n)
+ if (!n && m_views.isEmpty()) {
n = new Q3DSStudio3DNode;
+ // could be that m_views got changed from non-empty to empty, communicate the new node then
+ if (m_renderer)
+ m_renderer->setNode(n);
+ }
- n->setRect(boundingRect());
+ if (n)
+ n->setRect(QRectF(0, 0, width(), height()));
- if (!m_renderer)
+ if (!m_renderer) {
m_renderer = new Q3DSStudio3DRenderer(this, n, m_engine->aspectEngine());
+ m_pendingViewSend = true; // force pushing the view-layer pairs to the instance
+ }
+
+ if (!m_views.isEmpty()) {
+ if (m_pendingViewSend) {
+ m_pendingViewSend = false;
+ QVector<Q3DSStudio3DViewDesc> viewDesc;
+ // Gather the layer names (or ids) that need to be exposed.
+ for (Q3DSStudio3DView *view : m_views) {
+ QString objRef = view->source();
+ if (objRef.isEmpty())
+ continue;
+ // engine lives on the main thread but is safe here since that is blocked
+ Q3DSGraphObject *obj = m_engine->findObjectByHashIdOrNameOrPath(nullptr, m_engine->presentation(0), objRef);
+ if (obj && obj->type() == Q3DSGraphObject::Layer) {
+ Q3DSLayerNode *layer3DS = static_cast<Q3DSLayerNode *>(obj);
+ Qt3DCore::QNodeId nodeId = m_engine->layerTextureNodeId(layer3DS);
+ if (!nodeId.isNull()) {
+ Q3DSStudio3DViewDesc vd;
+ vd.view = view;
+ vd.textureNodeId = nodeId;
+ vd.layerSize = layer3DS->attached<Q3DSLayerAttached>()->layerSize;
+ vd.viewSize = view->size().toSize() * window()->effectiveDevicePixelRatio();
+ viewDesc.append(vd);
+ } else {
+ qWarning("No QNodeId for layer %s texture?", layer3DS->id().constData());
+ }
+ } else {
+ qWarning("%s is not a Layer", qPrintable(objRef));
+ }
+ }
+ m_renderer->setViewDescriptions(viewDesc);
+ }
+
+ // With separate views we are still technically a visual item and run
+ // the 3D rendering underneath, but there is no SG node and therefore
+ // the Studio3D item itself will not display anything.
+ if (n) {
+ m_renderer->setNode(nullptr);
+ delete n;
+ }
+ return nullptr;
+ }
return n;
}
@@ -453,6 +531,9 @@ void Q3DSStudio3DItem::itemChange(QQuickItem::ItemChange change,
if (!m_source.isEmpty() && !m_engine)
createEngine();
+
+ if (m_engine && m_separateViewSetupPending)
+ setupSeparateViews();
}
}
}
@@ -651,4 +732,54 @@ void Q3DSStudio3DItem::touchEvent(QTouchEvent *event)
m_engine->handleTouchEvent(event);
}
+void Q3DSStudio3DItem::registerView(Q3DSStudio3DView *view)
+{
+ const bool wasEmpty = m_views.isEmpty();
+ m_views.append(view);
+ m_pendingViewSend = true;
+ if (wasEmpty)
+ setupSeparateViews();
+}
+
+void Q3DSStudio3DItem::unregisterView(Q3DSStudio3DView *view)
+{
+ m_views.removeOne(view);
+ m_pendingViewSend = true;
+ if (m_views.isEmpty())
+ setupSeparateViews();
+}
+
+void Q3DSStudio3DItem::handleViewGeometryChange(Q3DSStudio3DView *view, const QSize &size)
+{
+ if (!m_engine)
+ return;
+
+ QString objRef = view->source();
+ if (objRef.isEmpty())
+ return;
+
+ Q3DSGraphObject *obj = m_engine->findObjectByHashIdOrNameOrPath(nullptr, m_engine->presentation(0), objRef);
+ if (!obj || obj->type() != Q3DSGraphObject::Layer)
+ return;
+
+ Q3DSLayerNode *layer3DS = static_cast<Q3DSLayerNode *>(obj);
+ if (!m_views.isEmpty() && view->sizeLayerToView()) {
+ if (!layer3DS->hasExplicitSize() || layer3DS->explicitSize() != size) {
+ qCDebug(lcScene, "Explicit size for layer %s is %dx%d", layer3DS->id().constData(), size.width(), size.height());
+ // Set the desired size and generate a property change. The
+ // property name may be something bogus but that's enough to get
+ // the scenemanager to recalculate size-related things in the
+ // layer. Eventually it will lead to emitting
+ // Q3DSEngine::layerResized. Note that this is all asynchronous and
+ // may only happen on the next frame action.
+ layer3DS->notifyPropertyChanges({ layer3DS->setExplicitSize(true, size) });
+ }
+ } else {
+ if (layer3DS->hasExplicitSize()) {
+ qCDebug(lcScene, "Layer %s is no longer explicitly sized", layer3DS->id().constData());
+ layer3DS->notifyPropertyChanges({ layer3DS->setExplicitSize(false) });
+ }
+ }
+}
+
QT_END_NAMESPACE