summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--examples/qt3d/qt3d.pro3
-rw-r--r--examples/qt3d/scene3dview/AnimatedEntity.qml143
-rw-r--r--examples/qt3d/scene3dview/doc/images/scene3dview.pngbin0 -> 28772 bytes
-rw-r--r--examples/qt3d/scene3dview/doc/src/scene3dview.qdoc62
-rw-r--r--examples/qt3d/scene3dview/main.cpp66
-rw-r--r--examples/qt3d/scene3dview/main.qml142
-rw-r--r--examples/qt3d/scene3dview/scene3dview.pro15
-rw-r--r--examples/qt3d/scene3dview/scene3dview.qrc6
-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
18 files changed, 1049 insertions, 17 deletions
diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro
index 2f8d624af..91163a0d1 100644
--- a/examples/qt3d/qt3d.pro
+++ b/examples/qt3d/qt3d.pro
@@ -21,7 +21,8 @@ SUBDIRS += \
scene2d \
phong-cubes \
pbr-materials \
- controlsunderlay
+ controlsunderlay \
+ scene3dview
qtHaveModule(multimedia): SUBDIRS += audio-visualizer-qml
diff --git a/examples/qt3d/scene3dview/AnimatedEntity.qml b/examples/qt3d/scene3dview/AnimatedEntity.qml
new file mode 100644
index 000000000..12575b314
--- /dev/null
+++ b/examples/qt3d/scene3dview/AnimatedEntity.qml
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+import QtQuick 2.0 as QQ2
+
+
+Entity {
+ id: sceneRoot
+ property color sceneColor
+ property bool clearColor: true
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, 40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ FirstPersonCameraController { camera: camera }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ camera: camera
+ clearColor: "transparent"
+ clearBuffers: sceneRoot.clearColor ? ClearBuffers.ColorDepthBuffer : ClearBuffers.DepthBuffer
+ }
+ },
+ InputSettings { }
+ ]
+
+ PhongMaterial {
+ id: material
+ diffuse: sceneColor
+ }
+
+ TorusMesh {
+ id: torusMesh
+ radius: 5
+ minorRadius: 1
+ rings: 100
+ slices: 20
+ }
+
+ Transform {
+ id: torusTransform
+ scale3D: Qt.vector3d(1.5, 1, 0.5)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, material, torusTransform ]
+ }
+
+ SphereMesh {
+ id: sphereMesh
+ radius: 3
+ }
+
+ Transform {
+ id: sphereTransform
+ property real userAngle: 0.0
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.rotate(userAngle, Qt.vector3d(0, 1, 0))
+ m.translate(Qt.vector3d(20, 0, 0));
+ return m;
+ }
+ }
+
+ QQ2.NumberAnimation {
+ target: sphereTransform
+ property: "userAngle"
+ duration: 10000
+ from: 0
+ to: 360
+
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+
+ Entity {
+ id: sphereEntity
+ components: [ sphereMesh, material, sphereTransform ]
+ }
+}
diff --git a/examples/qt3d/scene3dview/doc/images/scene3dview.png b/examples/qt3d/scene3dview/doc/images/scene3dview.png
new file mode 100644
index 000000000..d697d1850
--- /dev/null
+++ b/examples/qt3d/scene3dview/doc/images/scene3dview.png
Binary files differ
diff --git a/examples/qt3d/scene3dview/doc/src/scene3dview.qdoc b/examples/qt3d/scene3dview/doc/src/scene3dview.qdoc
new file mode 100644
index 000000000..721929350
--- /dev/null
+++ b/examples/qt3d/scene3dview/doc/src/scene3dview.qdoc
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scene3dview
+ \title Qt 3D: Scene3DView QML Example
+ \ingroup qt3d-examples-qml
+ \brief A QML application that demonstrates visualizing multiple 3D scenes
+ using Scene3D and Scene3DView.
+
+ \image scene3dview.png
+
+ This example demonstrates visualizing multiple 3D scenes from a Qt Quick
+ application usinc Scene3D and Scene3DView. Each 3D scene contains a single
+ active camera and a single active light source. Visualized data is assumed
+ to be at a fixed location.
+
+ \include examples-run.qdocinc
+
+ \section1 Visualizing 3D Scenes
+
+ First we set up a Scene3D instance that will be required for our
+ Scene3DView instanced.
+
+ \snippet scene3dview/main.qml 0
+
+ Then we instanciate our Scene3DView instances and make them reference the
+ Scene3D. We also provide a root Entity for each Scene3DView with a \e
+ scene3dview/AnimatedEntity.qml.
+
+ \snippet scene3dview/main.qml 1
+
+ Care has to be taken that only the first Scene3DView clears the color
+ buffer. We don't want each Scene3DView to clear the screen as that would
+ erase content for all but the last Scene3DView.
+
+ \snippet scene3dview/main.qml 1.1
+*/
diff --git a/examples/qt3d/scene3dview/main.cpp b/examples/qt3d/scene3dview/main.cpp
new file mode 100644
index 000000000..8886263f4
--- /dev/null
+++ b/examples/qt3d/scene3dview/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQuickView>
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView view;
+
+ view.resize(500, 500);
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/qt3d/scene3dview/main.qml b/examples/qt3d/scene3dview/main.qml
new file mode 100644
index 000000000..d2a3fc3e0
--- /dev/null
+++ b/examples/qt3d/scene3dview/main.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Scene3D 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+
+Item {
+
+ //! [0]
+ Scene3D {
+ id: scene3dInstance
+ anchors.fill: parent
+ focus: true
+ aspects: ["input", "logic"]
+ cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
+ multisample: true
+ }
+ //! [0]
+
+ ColumnLayout {
+ anchors.fill: parent
+ Grid {
+ id: grid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ columns: 2
+ rows: 2
+ spacing: 50
+
+ readonly property int cellWidth: (width - spacing ) * 0.5
+ readonly property int cellHeight: (height -spacing) * 0.5
+ readonly property var colors: ["green", "gray", "orange", "blue"]
+ readonly property int maxInstances: grid.rows * grid.columns
+
+ Repeater {
+ id: gridRepeater
+ model: grid.rows * grid.columns
+
+ //! [1]
+ Rectangle {
+ width: grid.cellWidth
+ height: grid.cellHeight
+ color: "darkRed"
+ scale: ma.pressed || ma.containsMouse ? 0.8 : 1
+ Behavior on scale { NumberAnimation { duration: 750 } }
+
+ Scene3DView {
+ onXChanged: console.log(("X (%1): %2").arg(model.index).arg(x))
+ scene3D: scene3dInstance
+ anchors.fill: parent
+ AnimatedEntity {
+ sceneColor: grid.colors[model.index]
+ //! [1.1]
+ // Only clear the color for the first Scene3DView
+ clearColor: model.index === 0
+ //! [1.1]
+ }
+ }
+ Text {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ bottom: parent.bottom
+ }
+
+ color: "white"
+ font.bold: true
+ text: "Scene3DView " + (model.index + 1)
+ }
+
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+ }
+ //! [1]
+ }
+ }
+
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter
+ Button {
+ text: "-"
+ onClicked: gridRepeater.model = Math.max(1, gridRepeater.count - 1);
+ }
+ Text { text: "Instances (%1/%2)".arg(gridRepeater.count).arg(grid.maxInstances) }
+ Button {
+ text: "+"
+ onClicked: gridRepeater.model = Math.min(grid.maxInstances, gridRepeater.count + 1);
+ }
+ }
+ }
+}
diff --git a/examples/qt3d/scene3dview/scene3dview.pro b/examples/qt3d/scene3dview/scene3dview.pro
new file mode 100644
index 000000000..4e1052b7b
--- /dev/null
+++ b/examples/qt3d/scene3dview/scene3dview.pro
@@ -0,0 +1,15 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+QT += qml quick 3dinput
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ AnimatedEntity.qml \
+ main.qml
+
+RESOURCES += \
+ scene3dview.qrc
diff --git a/examples/qt3d/scene3dview/scene3dview.qrc b/examples/qt3d/scene3dview/scene3dview.qrc
new file mode 100644
index 000000000..dff72ed5a
--- /dev/null
+++ b/examples/qt3d/scene3dview/scene3dview.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>AnimatedEntity.qml</file>
+ <file>main.qml</file>
+ </qresource>
+</RCC>
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