summaryrefslogtreecommitdiffstats
path: root/src/quick3d
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-08-08 14:45:29 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-08-27 17:08:23 +0200
commit91dc1e1a61651a82a0ee5ce6ad3b24e82f526be6 (patch)
treef54c30c337a9bae1e0b5d9c8622dd599344f46bf /src/quick3d
parentf9306d34bde648975b2a3e24eea01aaa4b6bd679 (diff)
Introduce Scene3DView
Allows to render several 3D scenes using a single Scene3D. To be used when you need multiple Scene3D instances. [ChangeLog] Introduce Scene3DView to render multiple distinct 3D scenes Change-Id: I5d51c5935218cc84c15d57def3703aa0d92040ba Reviewed-by: Mike Krus <mike.krus@kdab.com>
Diffstat (limited to 'src/quick3d')
-rw-r--r--src/quick3d/imports/scene3d/importsscene3d.pro6
-rw-r--r--src/quick3d/imports/scene3d/qtquickscene3dplugin.cpp2
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp117
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem_p.h9
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp26
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer_p.h5
-rw-r--r--src/quick3d/imports/scene3d/scene3dsgnode.cpp7
-rw-r--r--src/quick3d/imports/scene3d/scene3dsgnode_p.h2
-rw-r--r--src/quick3d/imports/scene3d/scene3dview.cpp318
-rw-r--r--src/quick3d/imports/scene3d/scene3dview_p.h137
10 files changed, 613 insertions, 16 deletions
diff --git a/src/quick3d/imports/scene3d/importsscene3d.pro b/src/quick3d/imports/scene3d/importsscene3d.pro
index a97dac09a..e29f7b831 100644
--- a/src/quick3d/imports/scene3d/importsscene3d.pro
+++ b/src/quick3d/imports/scene3d/importsscene3d.pro
@@ -17,7 +17,8 @@ HEADERS += \
scene3drenderer_p.h \
scene3dsgnode_p.h \
scene3dsgmaterialshader_p.h \
- scene3dsgmaterial_p.h
+ scene3dsgmaterial_p.h \
+ scene3dview_p.h
SOURCES += \
qtquickscene3dplugin.cpp \
@@ -27,7 +28,8 @@ SOURCES += \
scene3drenderer.cpp \
scene3dsgnode.cpp \
scene3dsgmaterialshader.cpp \
- scene3dsgmaterial.cpp
+ scene3dsgmaterial.cpp \
+ scene3dview.cpp
OTHER_FILES += qmldir
diff --git a/src/quick3d/imports/scene3d/qtquickscene3dplugin.cpp b/src/quick3d/imports/scene3d/qtquickscene3dplugin.cpp
index f93a8fdd1..00f24070e 100644
--- a/src/quick3d/imports/scene3d/qtquickscene3dplugin.cpp
+++ b/src/quick3d/imports/scene3d/qtquickscene3dplugin.cpp
@@ -42,6 +42,7 @@
#include <QtQml>
#include <scene3ditem_p.h>
+#include <scene3dview_p.h>
QT_BEGIN_NAMESPACE
@@ -49,6 +50,7 @@ void QtQuickScene3DPlugin::registerTypes(const char *uri)
{
qmlRegisterType<Qt3DRender::Scene3DItem>(uri, 2, 0, "Scene3D");
qmlRegisterType<Qt3DRender::Scene3DItem, 14>(uri, 2, 14, "Scene3D");
+ qmlRegisterType<Qt3DRender::Scene3DView>(uri, 2, 14, "Scene3DView");
// Auto-increment the import to stay in sync with ALL future Qt minor versions
qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index 8f3d0b9a6..098cab032 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -72,6 +72,7 @@
#include <scene3dlogging_p.h>
#include <scene3drenderer_p.h>
#include <scene3dsgnode_p.h>
+#include <scene3dview_p.h>
#include <Qt3DCore/private/qaspectengine_p.h>
#include <Qt3DCore/private/qaspectmanager_p.h>
@@ -122,16 +123,33 @@ namespace Qt3DRender {
\endqml
to that material.
+
+ It is not recommended to instantiate more than a single Scene3D instance
+ per application. The reason for this is that a Scene3D instance
+ instantiates the entire Qt 3D engine (memory managers, thread pool, render
+ ...) under the scene. You should instead look into using \l Scene3DView
+ instances in conjunction with a single Scene3D instance.
+
+ When using Scene3D with Scene3DViews the following conditions are expected:
+ \list
+ \li The compositingMode is set to FBO
+ \li The Scene3D is sized to occupy the full window size
+ \li The Scene3D instance is instantiated prior to any Scene3DView
+ \li The Scene3D entity property is left unset
+ \endlist
*/
Scene3DItem::Scene3DItem(QQuickItem *parent)
: QQuickItem(parent)
, m_entity(nullptr)
+ , m_viewHolderEntity(nullptr)
+ , m_viewHolderFG(nullptr)
, m_aspectEngine(new Qt3DCore::QAspectEngine())
, m_renderAspect(nullptr)
, m_renderer(nullptr)
, m_rendererCleaner(new Scene3DCleaner())
, m_multisample(true)
, m_dirty(true)
+ , m_dirtyViews(false)
, m_clearsWindowByDefault(true)
, m_disableClearWindow(false)
, m_cameraAspectRatioMode(AutomaticAspectRatio)
@@ -186,7 +204,7 @@ Qt3DCore::QEntity *Scene3DItem::entity() const
void Scene3DItem::setAspects(const QStringList &aspects)
{
if (!m_aspects.isEmpty()) {
- qWarning() << "Aspects already set on the Scene3D, ignoring";
+ qCWarning(Scene3D) << "Aspects already set on the Scene3D, ignoring";
return;
}
@@ -312,6 +330,66 @@ Scene3DItem::CompositingMode Scene3DItem::compositingMode() const
return m_compositingMode;
}
+// MainThread called by Scene3DView
+void Scene3DItem::addView(Scene3DView *view)
+{
+ if (m_views.contains(view))
+ return;
+
+ Qt3DRender::QFrameGraphNode *viewFG = view->viewFrameGraph();
+ Qt3DCore::QEntity *subtreeRoot = view->viewSubtree();
+
+ if (m_viewHolderEntity == nullptr) {
+ m_viewHolderEntity = new Qt3DCore::QEntity;
+
+ if (m_entity != nullptr) {
+ qCWarning(Scene3D) << "Scene3DView is not supported if the Scene3D entity property has been set";
+ }
+
+ Qt3DRender::QRenderSettings *settings = new Qt3DRender::QRenderSettings();
+ Qt3DRender::QRenderSurfaceSelector *surfaceSelector = new Qt3DRender::QRenderSurfaceSelector();
+ m_viewHolderFG = surfaceSelector;
+ surfaceSelector->setSurface(window());
+
+ // Copy setting properties from first View
+ QVector<Qt3DRender::QRenderSettings *> viewRenderSettings = subtreeRoot->componentsOfType<Qt3DRender::QRenderSettings>();
+ if (viewRenderSettings.size() > 0) {
+ Qt3DRender::QRenderSettings *viewRenderSetting = viewRenderSettings.first();
+ settings->setRenderPolicy(viewRenderSetting->renderPolicy());
+ settings->pickingSettings()->setPickMethod(viewRenderSetting->pickingSettings()->pickMethod());
+ settings->pickingSettings()->setPickResultMode(viewRenderSetting->pickingSettings()->pickResultMode());
+ }
+ settings->setActiveFrameGraph(m_viewHolderFG);
+ m_viewHolderEntity->addComponent(settings);
+
+ setEntity(m_viewHolderEntity);
+ }
+
+ // Parent FG and Subtree
+ viewFG->setParent(m_viewHolderFG);
+ subtreeRoot->setParent(m_viewHolderEntity);
+
+ m_views.push_back(view);
+ m_dirtyViews |= true;
+}
+
+// MainThread called by Scene3DView
+void Scene3DItem::removeView(Scene3DView *view)
+{
+ if (!m_views.contains(view))
+ return;
+
+ Qt3DRender::QFrameGraphNode *viewFG = view->viewFrameGraph();
+ Qt3DCore::QEntity *subtreeRoot = view->viewSubtree();
+
+ // Unparent FG and Subtree
+ viewFG->setParent(Q_NODE_NULLPTR);
+ subtreeRoot->setParent(Q_NODE_NULLPTR);
+
+ m_views.removeOne(view);
+ m_dirtyViews |= true;
+}
+
void Scene3DItem::applyRootEntityChange()
{
if (m_aspectEngine->rootEntity() != m_entity) {
@@ -391,6 +469,20 @@ void Scene3DItem::onBeforeSync()
m_renderer->setCompositingMode(m_compositingMode);
const bool usesFBO = m_compositingMode == FBO;
+ // Make renderer aware of any Scene3DView we are dealing with
+ if (m_dirtyViews) {
+ // Scene3DViews checks
+ if (m_entity != m_viewHolderEntity) {
+ qCWarning(Scene3D) << "Scene3DView is not supported if the Scene3D entity property has been set";
+ }
+ if (!usesFBO) {
+ qCWarning(Scene3D) << "Scene3DView is only supported when Scene3D compositingMode is set to FBO";
+ }
+ // The Scene3DRender will take care of providing the texture containing the 3D scene
+ m_renderer->setScene3DViews(m_views);
+ m_dirtyViews = false;
+ }
+
Q_ASSERT(m_aspectEngine->runMode() == Qt3DCore::QAspectEngine::Manual);
m_aspectEngine->processFrame();
// The above essentially sets the number of RV for the RenderQueue and
@@ -412,10 +504,13 @@ void Scene3DItem::onBeforeSync()
// When using the FBO mode, only the QQuickItem needs to be updated
// When using the Underlay mode, the whole windows needs updating
- if (usesFBO)
+ if (usesFBO) {
QQuickItem::update();
- else
+ for (Scene3DView *view : m_views)
+ view->update();
+ } else {
window()->update();
+ }
}
void Scene3DItem::setWindowSurface(QObject *rootObject)
@@ -539,21 +634,17 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
m_renderer->setCleanerHelper(m_rendererCleaner);
}
const bool usesFBO = m_compositingMode == FBO;
+ const bool hasScene3DViews = !m_views.empty();
Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node);
// When usin Scene3DViews or Scene3D in Underlay mode
// we shouldn't be managing a Scene3DSGNode
- if (!usesFBO) {
+ if (!usesFBO || hasScene3DViews) {
if (fboNode != nullptr) {
delete fboNode;
fboNode = nullptr;
m_renderer->setSGNode(fboNode);
}
- // Record clearBeforeRendering value before we force it to false
- m_clearsWindowByDefault = window()->clearBeforeRendering();
- m_disableClearWindow = true;
- if (m_clearsWindowByDefault)
- window()->setClearBeforeRendering(false);
} else {
// Regular Scene3D only case
// Create SGNode if using FBO and no Scene3DViews
@@ -562,11 +653,19 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
m_renderer->setSGNode(fboNode);
}
fboNode->setRect(boundingRect());
+ }
+ if (usesFBO) {
// Reset clear flag if we've set it to false it's still set to that
if (m_disableClearWindow && !window()->clearBeforeRendering())
window()->setClearBeforeRendering(m_clearsWindowByDefault);
m_disableClearWindow = false;
+ } else {
+ // Record clearBeforeRendering value before we force it to false
+ m_clearsWindowByDefault = window()->clearBeforeRendering();
+ m_disableClearWindow = true;
+ if (m_clearsWindowByDefault)
+ window()->setClearBeforeRendering(false);
}
return fboNode;
diff --git a/src/quick3d/imports/scene3d/scene3ditem_p.h b/src/quick3d/imports/scene3d/scene3ditem_p.h
index ae7a4600e..4a2fc7f44 100644
--- a/src/quick3d/imports/scene3d/scene3ditem_p.h
+++ b/src/quick3d/imports/scene3d/scene3ditem_p.h
@@ -69,6 +69,8 @@ class QCamera;
class QRenderAspect;
class Scene3DRenderer;
class Scene3DCleaner;
+class Scene3DView;
+class QFrameGraphNode;
class Scene3DItem : public QQuickItem
{
@@ -106,6 +108,9 @@ public:
Q_ENUM(CompositingMode) // LCOV_EXCL_LINE
CompositingMode compositingMode() const;
+ void addView(Scene3DView *view);
+ void removeView(Scene3DView *view);
+
public Q_SLOTS:
void setAspects(const QStringList &aspects);
void setEntity(Qt3DCore::QEntity *entity);
@@ -135,6 +140,8 @@ private:
QStringList m_aspects;
Qt3DCore::QEntity *m_entity;
+ Qt3DCore::QEntity *m_viewHolderEntity;
+ Qt3DRender::QFrameGraphNode *m_viewHolderFG;
Qt3DCore::QAspectEngine *m_aspectEngine;
QRenderAspect *m_renderAspect;
@@ -143,6 +150,7 @@ private:
bool m_multisample;
bool m_dirty;
+ bool m_dirtyViews;
bool m_clearsWindowByDefault;
bool m_disableClearWindow;
@@ -150,6 +158,7 @@ private:
CameraAspectRatioMode m_cameraAspectRatioMode;
CompositingMode m_compositingMode;
QOffscreenSurface *m_dummySurface;
+ QVector<Scene3DView *> m_views;
};
} // Qt3DRender
diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp
index bc75e0861..bc4dbd362 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer.cpp
+++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp
@@ -57,6 +57,7 @@
#include <scene3ditem_p.h>
#include <scene3dlogging_p.h>
#include <scene3dsgnode_p.h>
+#include <scene3dview_p.h>
QT_BEGIN_NAMESPACE
@@ -159,6 +160,7 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp
, m_needsShutdown(true)
, m_forceRecreate(false)
, m_shouldRender(false)
+ , m_dirtyViews(false)
, m_allowRendering(0)
{
Q_CHECK_PTR(m_item);
@@ -313,9 +315,23 @@ void Scene3DRenderer::beforeSynchronize()
m_texture.reset(m_window->createTextureFromId(m_finalFBO->texture(), m_finalFBO->size(), QQuickWindow::TextureHasAlphaChannel));
}
+ // We can render either the Scene3D or the Scene3DView but not both
+ // at the same time
+ Q_ASSERT((m_node == nullptr || m_views.empty()) ||
+ (m_node != nullptr && m_views.empty()) ||
+ (m_node == nullptr && !m_views.empty()));
+
// Set texture on node
if (m_node && (!m_node->texture() || generateNewTexture))
m_node->setTexture(m_texture.data());
+
+ // Set textures on Scene3DView
+ if (m_dirtyViews || generateNewTexture) {
+ for (Scene3DView *view : qAsConst(m_views))
+ if (!view->texture() || generateNewTexture)
+ view->setTexture(m_texture.data());
+ m_dirtyViews = false;
+ }
}
if (m_aspectEngine->rootEntity() != m_item->entity()) {
@@ -326,6 +342,9 @@ void Scene3DRenderer::beforeSynchronize()
if (m_node)
m_node->markDirty(QSGNode::DirtyMaterial);
+ for (Scene3DView *view : qAsConst(m_views))
+ view->markSGNodeDirty();
+
m_item->update();
}
}
@@ -340,6 +359,13 @@ void Scene3DRenderer::setCompositingMode(Scene3DItem::CompositingMode mode)
m_compositingMode = mode;
}
+// Main Thread, Render Thread locked
+void Scene3DRenderer::setScene3DViews(const QVector<Scene3DView *> views)
+{
+ m_views = views;
+ m_dirtyViews = true;
+}
+
void Scene3DRenderer::setSGNode(Scene3DSGNode *node)
{
m_node = node;
diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h
index 11dfef77d..4f3651cd3 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer_p.h
+++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h
@@ -72,6 +72,7 @@ namespace Qt3DRender {
class QRenderAspect;
class Scene3DCleaner;
class Scene3DSGNode;
+class Scene3DViews;
class Scene3DRenderer : public QObject
{
@@ -87,6 +88,8 @@ public:
void allowRender();
void setCompositingMode(Scene3DItem::CompositingMode mode);
+ void setScene3DViews(const QVector<Scene3DView *> views);
+
public Q_SLOTS:
void render();
void shutdown();
@@ -115,8 +118,10 @@ private:
bool m_needsShutdown;
bool m_forceRecreate;
bool m_shouldRender;
+ bool m_dirtyViews;
QSemaphore m_allowRendering;
Scene3DItem::CompositingMode m_compositingMode;
+ QVector<Scene3DView *> m_views;
friend class Scene3DCleaner;
};
diff --git a/src/quick3d/imports/scene3d/scene3dsgnode.cpp b/src/quick3d/imports/scene3d/scene3dsgnode.cpp
index 8806b59a9..c38e9ffeb 100644
--- a/src/quick3d/imports/scene3d/scene3dsgnode.cpp
+++ b/src/quick3d/imports/scene3d/scene3dsgnode.cpp
@@ -74,13 +74,12 @@ Scene3DSGNode::~Scene3DSGNode()
// is terminated.
}
-void Scene3DSGNode::setRect(const QRectF &rect)
+void Scene3DSGNode::setRect(const QRectF &rect, const QRectF textureRect)
{
if (rect != m_rect) {
m_rect = rect;
- // Map the item's bounding rect to normalized texture coordinates
- const QRectF sourceRect(0.0f, 1.0f, 1.0f, -1.0f);
- QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, sourceRect);
+ // By default, map the item's bounding rect to normalized texture coordinates
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, textureRect);
markDirty(DirtyGeometry);
}
}
diff --git a/src/quick3d/imports/scene3d/scene3dsgnode_p.h b/src/quick3d/imports/scene3d/scene3dsgnode_p.h
index 68b68eea5..388c8a605 100644
--- a/src/quick3d/imports/scene3d/scene3dsgnode_p.h
+++ b/src/quick3d/imports/scene3d/scene3dsgnode_p.h
@@ -75,7 +75,7 @@ public:
}
QSGTexture *texture() const Q_DECL_NOTHROW { return m_material.texture(); }
- void setRect(const QRectF &rect);
+ void setRect(const QRectF &rect, const QRectF textureRect = QRectF(0.0f, 1.0f, 1.0f, -1.0f));
QRectF rect() const Q_DECL_NOTHROW { return m_rect; }
private:
diff --git a/src/quick3d/imports/scene3d/scene3dview.cpp b/src/quick3d/imports/scene3d/scene3dview.cpp
new file mode 100644
index 000000000..9d298b435
--- /dev/null
+++ b/src/quick3d/imports/scene3d/scene3dview.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "scene3dview_p.h"
+#include <Qt3DCore/QEntity>
+#include <Qt3DRender/QRenderSettings>
+#include <Qt3DRender/QFrameGraphNode>
+#include <Qt3DRender/QLayer>
+#include <Qt3DRender/QLayerFilter>
+#include <Qt3DRender/QViewport>
+#include <scene3dsgnode_p.h>
+#include <scene3ditem_p.h>
+#include <QQuickWindow>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+/*!
+ \qmltype Scene3DView
+ \inherits Item
+ \inqmlmodule QtQuick.Scene3D
+ \since 5.14
+
+ \preliminary
+
+ \brief The Scene3DView type is used to integrate a Qt 3D sub scene into a
+ QtQuick 2 scene using Scene3D. Whereas you should only use a single Scene3D
+ instance per application, you can have multiple Scene3DView instances.
+
+ Essentially, if you need to render multiple scenes each in a separate view,
+ you should use a single Scene3D instance and as many Scene3DView items as
+ you have scenes to render.
+
+ Typical usage looks like:
+ \qml
+ Scene3D {
+ id: mainScene3D
+ anchors.fill: parent
+ }
+
+ Scene3DView {
+ id: view1
+ scene3D: mainScene3D
+ width: 200
+ height: 200
+ Entity {
+ ...
+ }
+ }
+
+ Scene3DView {
+ id: view2
+ scene3D: mainScene3D
+ width: 200
+ height: 200
+ x: 200
+ Entity {
+ ...
+ }
+ }
+ \endqml
+
+ There are a few limitations when using Scene3DView:
+ \list
+ \li The Scene3D compositingMode has to be set to FBO
+ \li The Scene3D is sized to occupy the full window size (at the very least
+ it must be sized as wide as the area occupied by all Scene3DViews)
+ \li The Scene3D instance is instantiated prior to any Scene3DView
+ \li The Scene3D entity property is left unset
+ \endlist
+
+ Scene3D behaves likes a texture atlas from which all Scene3DView instances.
+ For this reason, care should be taken that only the first Scene3DView
+ declared in the scene clears the color/depth. Additionally overlapping
+ Scene3DView instances is discouraged as this might not produce the expected
+ output.
+
+ It is expected that a Scene3DView's Entity provide a RenderSettings with a
+ valid SceneGraph. Please note that only the RenderSettings of the first
+ Scene3DView instantiated will be taken into account.
+
+ There are no restriction on the sharing of elements between different scenes
+ in different Scene3DView instances.
+ */
+
+namespace {
+
+Qt3DRender::QFrameGraphNode *frameGraphFromEntity(Qt3DCore::QEntity *entity)
+{
+ const auto renderSettingsComponents = entity->componentsOfType<Qt3DRender::QRenderSettings>();
+
+ if (renderSettingsComponents.size() > 0) {
+ Qt3DRender::QRenderSettings *renderSettings = renderSettingsComponents.first();
+ return renderSettings->activeFrameGraph();
+ }
+ return nullptr;
+}
+
+}
+
+Scene3DView::Scene3DView(QQuickItem *parent)
+ : QQuickItem(parent)
+ , m_scene3D(nullptr)
+ , m_entity(nullptr)
+ , m_previousFGParent(nullptr)
+ , m_holderEntity(new Qt3DCore::QEntity())
+ , m_holderLayer(new Qt3DRender::QLayer())
+ , m_holderLayerFilter(new Qt3DRender::QLayerFilter())
+ , m_holderViewport(new Qt3DRender::QViewport())
+ , m_dirtyFlags(DirtyNode|DirtyTexture)
+ , m_texture(nullptr)
+{
+ setFlag(QQuickItem::ItemHasContents, true);\
+
+ m_holderLayer->setRecursive(true);
+ m_holderEntity->addComponent(m_holderLayer);
+ m_holderLayerFilter->setParent(m_holderViewport);
+ m_holderLayerFilter->addLayer(m_holderLayer);
+}
+
+Scene3DView::~Scene3DView()
+{
+ if (m_entity)
+ abandonSubtree(m_entity);
+
+ if (m_scene3D)
+ m_scene3D->removeView(this);
+}
+
+Qt3DCore::QEntity *Scene3DView::entity() const
+{
+ return m_entity;
+}
+
+Scene3DItem *Scene3DView::scene3D() const
+{
+ return m_scene3D;
+}
+
+Qt3DCore::QEntity *Scene3DView::viewSubtree() const
+{
+ return m_holderEntity;
+}
+
+QFrameGraphNode *Scene3DView::viewFrameGraph() const
+{
+ return m_holderViewport;
+}
+
+// Called by Scene3DRender::beforeSynchronizing in RenderThread
+void Scene3DView::setTexture(QSGTexture *texture)
+{
+ m_dirtyFlags |= DirtyTexture;
+ m_texture = texture;
+ QQuickItem::update();
+}
+
+QSGTexture *Scene3DView::texture() const
+{
+ return m_texture;
+}
+
+// Called by Scene3DRender::beforeSynchronizing in RenderThread
+void Scene3DView::markSGNodeDirty()
+{
+ m_dirtyFlags |= DirtyNode;
+ QQuickItem::update();
+}
+
+// Main Thread
+void Scene3DView::setEntity(Qt3DCore::QEntity *entity)
+{
+ if (m_entity == entity)
+ return;
+
+ if (m_entity)
+ abandonSubtree(m_entity);
+
+ m_entity = entity;
+ emit entityChanged();
+
+ if (m_entity)
+ adoptSubtree(m_entity);
+}
+
+// Main Thread
+void Scene3DView::setScene3D(Scene3DItem *scene3D)
+{
+ if (m_scene3D == scene3D)
+ return;
+
+ if (m_scene3D) {
+ m_scene3D->removeView(this);
+ QObject::disconnect(m_scene3DDestroyedConnection);
+ }
+
+ setTexture(nullptr);
+ m_scene3D = scene3D;
+ emit scene3DChanged();
+
+
+ if (m_scene3D) {
+ m_scene3DDestroyedConnection = QObject::connect(m_scene3D,
+ &Scene3DItem::destroyed,
+ this,
+ [this] {
+ m_scene3D = nullptr;
+ });
+ m_scene3D->addView(this);
+ }
+}
+
+// Render Thread
+QSGNode *Scene3DView::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
+{
+ Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node);
+ if (fboNode == nullptr)
+ fboNode = new Scene3DSGNode();
+
+ // We only need to draw a sub part of the texture based
+ // on our size, Scene3D essentially acts as a TextureAtlas
+ const QRectF itemRect(mapRectToScene(boundingRect()));
+ const QSize winSize = window() ? window()->size() : QSize();
+ const QRectF normalizedViewportRect(itemRect.x() / winSize.width(),
+ itemRect.y() / winSize.height(),
+ itemRect.width() / winSize.width(),
+ itemRect.height() / winSize.height());
+ // Swap Y axis to match GL coordinates
+ const QRectF textureRect(itemRect.x() / winSize.width(),
+ 1.0f - (itemRect.y() / winSize.height()),
+ itemRect.width() / winSize.width(),
+ -(itemRect.height() / winSize.height()));
+
+ // TO DO: Should be done from main thread
+ // updateViewport
+ m_holderViewport->setNormalizedRect(normalizedViewportRect);
+
+ // update node rect and texture coordinates
+ fboNode->setRect(boundingRect(), textureRect);
+
+ if (m_dirtyFlags & DirtyTexture) {
+ fboNode->setTexture(m_texture);
+ m_dirtyFlags.setFlag(DirtyTexture, false);
+ }
+ if (m_dirtyFlags & DirtyNode) {
+ fboNode->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyFlags.setFlag(DirtyNode, false);
+ }
+
+ return fboNode;
+}
+
+// Main Thread
+void Scene3DView::adoptSubtree(Qt3DCore::QEntity *subtree)
+{
+ // Reparent FrameGraph
+ Qt3DRender::QFrameGraphNode *fgNode = frameGraphFromEntity(subtree);
+ if (fgNode) {
+ m_previousFGParent = fgNode->parentNode();
+ fgNode->setParent(m_holderLayerFilter);
+ }
+
+ // Insert Entity Subtree
+ subtree->setParent(m_holderEntity);
+}
+
+// Main Thread
+void Scene3DView::abandonSubtree(Qt3DCore::QEntity *subtree)
+{
+ // Remove FrameGraph part
+ Qt3DRender::QFrameGraphNode *fgNode = frameGraphFromEntity(subtree);
+ if (fgNode)
+ fgNode->setParent(m_previousFGParent);
+
+ // Remove Entity Subtree
+ subtree->setParent(Q_NODE_NULLPTR);
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/imports/scene3d/scene3dview_p.h b/src/quick3d/imports/scene3d/scene3dview_p.h
new file mode 100644
index 000000000..ffb80f93b
--- /dev/null
+++ b/src/quick3d/imports/scene3d/scene3dview_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCENE3DVIEW_P_H
+#define SCENE3DVIEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/QQuickItem>
+#include <QtCore/QFlags>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTexture;
+
+namespace Qt3DCore {
+class QEntity;
+class QNode;
+}
+
+namespace Qt3DRender {
+
+class QLayer;
+class QLayerFilter;
+class Scene3DItem;
+class QFrameGraphNode;
+class QViewport;
+
+class Scene3DView : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QEntity* entity READ entity WRITE setEntity NOTIFY entityChanged)
+ Q_PROPERTY(Qt3DRender::Scene3DItem *scene3D READ scene3D WRITE setScene3D NOTIFY scene3DChanged)
+ Q_CLASSINFO("DefaultProperty", "entity")
+
+public:
+ enum DirtyFlag {
+ DirtyNode = 1 << 0,
+ DirtyTexture = 1 << 1
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ explicit Scene3DView(QQuickItem *parent = nullptr);
+ ~Scene3DView();
+
+ Qt3DCore::QEntity *entity() const;
+ Scene3DItem *scene3D() const;
+
+ Qt3DCore::QEntity *viewSubtree() const;
+ Qt3DRender::QFrameGraphNode *viewFrameGraph() const;
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const;
+
+ void markSGNodeDirty();
+
+public Q_SLOTS:
+ void setEntity(Qt3DCore::QEntity *entity);
+ void setScene3D(Scene3DItem *scene3D);
+
+Q_SIGNALS:
+ void entityChanged();
+ void scene3DChanged();
+
+private:
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *nodeData) override;
+ void adoptSubtree(Qt3DCore::QEntity *subtree);
+ void abandonSubtree(Qt3DCore::QEntity *subtree);
+
+ Scene3DItem *m_scene3D;
+ Qt3DCore::QEntity *m_entity;
+ Qt3DCore::QNode *m_previousFGParent;
+
+ Qt3DCore::QEntity *m_holderEntity;
+ Qt3DRender::QLayer *m_holderLayer;
+ Qt3DRender::QLayerFilter *m_holderLayerFilter;
+ Qt3DRender::QViewport *m_holderViewport;
+
+ QMetaObject::Connection m_scene3DDestroyedConnection;
+
+ DirtyFlags m_dirtyFlags;
+ QSGTexture *m_texture;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Scene3DView::DirtyFlags)
+
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // SCENE3DVIEW_P_H