summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/qt3d/assimp/assimp.pro3
-rw-r--r--examples/qt3d/assimp/main.qml62
-rw-r--r--examples/qt3d/bigmodel-qml/main.qml19
-rw-r--r--examples/qt3d/dynamicscene-cpp/examplescene.cpp24
-rw-r--r--examples/qt3d/planets-qml/ShadowMapFrameGraph.qml103
-rw-r--r--examples/qt3d/planets-qml/doc/src/planets-qml.qdoc10
-rw-r--r--examples/qt3d/planets-qml/shaders/planetD.frag105
-rw-r--r--examples/qt3d/planets-qml/shaders/planetD.vert71
-rw-r--r--examples/qt3d/planets-qml/shaders/planetDB.frag107
-rw-r--r--examples/qt3d/planets-qml/shaders/planetDB.vert96
-rw-r--r--examples/qt3d/planets-qml/shaders/planetDS.frag104
-rw-r--r--examples/qt3d/planets-qml/shaders/planetDSB.frag110
-rw-r--r--examples/qt3d/planets-qml/shaders/shadowmap.frag41
-rw-r--r--examples/qt3d/planets-qml/shaders/shadowmap.vert46
-rw-r--r--examples/qt3d/tessellation-modes/tessellatedquadmesh.cpp5
-rw-r--r--examples/qt3d/tessellation-modes/tessellatedquadmesh.h1
-rw-r--r--src/core/aspects/qaspectengine.cpp43
-rw-r--r--src/core/aspects/qaspectengine.h2
-rw-r--r--src/core/aspects/qaspectengine_p.h5
-rw-r--r--src/core/aspects/qaspectthread.cpp13
-rw-r--r--src/core/aspects/qaspectthread.h7
-rw-r--r--src/core/core-components/qcamera.cpp16
-rw-r--r--src/core/core-components/qcamera.h6
-rw-r--r--src/core/core-components/qcameralens.cpp5
-rw-r--r--src/core/core-components/qcameralens.h1
-rw-r--r--src/core/nodes/qcomponent.cpp15
-rw-r--r--src/core/nodes/qentity.cpp46
-rw-r--r--src/core/nodes/qentity.h1
-rw-r--r--src/core/nodes/qentity_p.h1
-rw-r--r--src/core/nodes/qnode.cpp245
-rw-r--r--src/core/nodes/qnode.h26
-rw-r--r--src/core/nodes/qnode_p.h10
-rw-r--r--src/core/nodes/qnodevisitor.cpp6
-rw-r--r--src/core/nodes/qnodevisitor.h48
-rw-r--r--src/core/transforms/qtransform.cpp1
-rw-r--r--src/input/qinputaspect.cpp4
-rw-r--r--src/input/qkeyboardcontroller.cpp6
-rw-r--r--src/input/qkeyboardcontroller.h1
-rw-r--r--src/input/qkeyboardinput.cpp5
-rw-r--r--src/input/qkeyboardinput.h1
-rw-r--r--src/plugins/sceneparsers/assimp/assimp.pro4
-rw-r--r--src/plugins/sceneparsers/assimp/assimpparser.cpp16
-rw-r--r--src/quick3d/imports/render/defaults/qml/PhongMaterial.qml18
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp361
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.h8
-rw-r--r--src/quick3d/quick3d/items/quick3dentityloader.cpp7
-rw-r--r--src/quick3d/quick3d/items/quick3dentityloader.h1
-rw-r--r--src/quick3d/quick3d/items/quick3dnode.cpp12
-rw-r--r--src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp3
-rw-r--r--src/quick3d/quick3d/items/quick3dtransform.cpp1
-rw-r--r--src/quick3d/quick3d/items/quick3dtransform.h5
-rw-r--r--src/quick3d/quick3drenderer/items/quick3dshaderdataarray.cpp5
-rw-r--r--src/quick3d/quick3drenderer/items/quick3dshaderdataarray.h1
-rw-r--r--src/render/backend/qgraphicscontext.cpp46
-rw-r--r--src/render/backend/qgraphicscontext_p.h13
-rw-r--r--src/render/backend/qgraphicshelperes2.cpp43
-rw-r--r--src/render/backend/qgraphicshelpergl2.cpp45
-rw-r--r--src/render/backend/qgraphicshelpergl3.cpp31
-rw-r--r--src/render/backend/qrenderaspect.cpp4
-rw-r--r--src/render/backend/renderentity.cpp9
-rw-r--r--src/render/backend/renderer.cpp14
-rw-r--r--src/render/backend/renderer_p.h2
-rw-r--r--src/render/backend/rendershader.cpp20
-rw-r--r--src/render/backend/rendershader_p.h3
-rw-r--r--src/render/backend/rendertexture.cpp3
-rw-r--r--src/render/backend/renderthread.cpp17
-rw-r--r--src/render/backend/renderthread_p.h6
-rw-r--r--src/render/backend/scenemanager.cpp9
-rw-r--r--src/render/defaults/qskyboxentity.cpp1
-rw-r--r--src/render/frontend/framegraph-components/qcameraselector.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qcameraselector.h1
-rw-r--r--src/render/frontend/framegraph-components/qclearbuffer.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qclearbuffer.h1
-rw-r--r--src/render/frontend/framegraph-components/qframegraph.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qframegraph.h3
-rw-r--r--src/render/frontend/framegraph-components/qframegraphnode.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qframegraphnode.h1
-rw-r--r--src/render/frontend/framegraph-components/qframegraphselector.cpp1
-rw-r--r--src/render/frontend/framegraph-components/qlayerfilter.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qlayerfilter.h1
-rw-r--r--src/render/frontend/framegraph-components/qnodraw.cpp1
-rw-r--r--src/render/frontend/framegraph-components/qrenderpassfilter.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qrenderpassfilter.h1
-rw-r--r--src/render/frontend/framegraph-components/qrendertargetselector.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qrendertargetselector.h1
-rw-r--r--src/render/frontend/framegraph-components/qsortcriterion.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qsortcriterion.h1
-rw-r--r--src/render/frontend/framegraph-components/qsortmethod.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qsortmethod.h1
-rw-r--r--src/render/frontend/framegraph-components/qstateset.cpp1
-rw-r--r--src/render/frontend/framegraph-components/qtechniquefilter.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qtechniquefilter.h1
-rw-r--r--src/render/frontend/framegraph-components/qviewport.cpp5
-rw-r--r--src/render/frontend/framegraph-components/qviewport.h1
-rw-r--r--src/render/frontend/qabstractmesh.cpp5
-rw-r--r--src/render/frontend/qabstractmesh.h3
-rw-r--r--src/render/frontend/qabstractsceneloader.cpp5
-rw-r--r--src/render/frontend/qabstractsceneloader.h1
-rw-r--r--src/render/frontend/qabstracttextureimage.cpp1
-rw-r--r--src/render/frontend/qabstracttextureprovider.cpp3
-rw-r--r--src/render/frontend/qabstracttextureprovider.h1
-rw-r--r--src/render/frontend/qalphacoverage.cpp5
-rw-r--r--src/render/frontend/qalphacoverage.h1
-rw-r--r--src/render/frontend/qalphatest.cpp5
-rw-r--r--src/render/frontend/qalphatest.h1
-rw-r--r--src/render/frontend/qannotation.cpp5
-rw-r--r--src/render/frontend/qannotation.h1
-rw-r--r--src/render/frontend/qblendequation.cpp5
-rw-r--r--src/render/frontend/qblendequation.h1
-rw-r--r--src/render/frontend/qblendstate.cpp5
-rw-r--r--src/render/frontend/qblendstate.h1
-rw-r--r--src/render/frontend/qcolormask.cpp1
-rw-r--r--src/render/frontend/qcuboidmesh.cpp5
-rw-r--r--src/render/frontend/qcuboidmesh.h3
-rw-r--r--src/render/frontend/qcullface.cpp5
-rw-r--r--src/render/frontend/qcullface.h1
-rw-r--r--src/render/frontend/qcylindermesh.cpp4
-rw-r--r--src/render/frontend/qcylindermesh.h3
-rw-r--r--src/render/frontend/qdepthmask.cpp5
-rw-r--r--src/render/frontend/qdepthmask.h1
-rw-r--r--src/render/frontend/qdepthtest.cpp5
-rw-r--r--src/render/frontend/qdepthtest.h1
-rw-r--r--src/render/frontend/qdithering.cpp5
-rw-r--r--src/render/frontend/qdithering.h1
-rw-r--r--src/render/frontend/qeffect.cpp5
-rw-r--r--src/render/frontend/qeffect.h1
-rw-r--r--src/render/frontend/qfrontface.cpp5
-rw-r--r--src/render/frontend/qfrontface.h1
-rw-r--r--src/render/frontend/qlayer.cpp5
-rw-r--r--src/render/frontend/qlayer.h1
-rw-r--r--src/render/frontend/qmaterial.cpp5
-rw-r--r--src/render/frontend/qmaterial.h1
-rw-r--r--src/render/frontend/qmesh.cpp5
-rw-r--r--src/render/frontend/qmesh.h1
-rw-r--r--src/render/frontend/qparameter.cpp5
-rw-r--r--src/render/frontend/qparameter.h1
-rw-r--r--src/render/frontend/qparametermapping.cpp5
-rw-r--r--src/render/frontend/qparametermapping.h1
-rw-r--r--src/render/frontend/qplanemesh.cpp5
-rw-r--r--src/render/frontend/qplanemesh.h3
-rw-r--r--src/render/frontend/qpolygonoffset.cpp5
-rw-r--r--src/render/frontend/qpolygonoffset.h1
-rw-r--r--src/render/frontend/qrenderattachment.cpp5
-rw-r--r--src/render/frontend/qrenderattachment.h1
-rw-r--r--src/render/frontend/qrenderpass.cpp5
-rw-r--r--src/render/frontend/qrenderpass.h1
-rw-r--r--src/render/frontend/qrenderstate.cpp5
-rw-r--r--src/render/frontend/qrenderstate.h4
-rw-r--r--src/render/frontend/qrendertarget.cpp5
-rw-r--r--src/render/frontend/qrendertarget.h1
-rw-r--r--src/render/frontend/qsceneloader.cpp5
-rw-r--r--src/render/frontend/qsceneloader.h1
-rw-r--r--src/render/frontend/qscissortest.cpp5
-rw-r--r--src/render/frontend/qscissortest.h1
-rw-r--r--src/render/frontend/qshaderdata.cpp5
-rw-r--r--src/render/frontend/qshaderdata.h1
-rw-r--r--src/render/frontend/qshaderprogram.cpp5
-rw-r--r--src/render/frontend/qshaderprogram.h1
-rw-r--r--src/render/frontend/qspheremesh.cpp5
-rw-r--r--src/render/frontend/qspheremesh.h3
-rw-r--r--src/render/frontend/qstenciltest.cpp5
-rw-r--r--src/render/frontend/qstenciltest.h1
-rw-r--r--src/render/frontend/qtechnique.cpp5
-rw-r--r--src/render/frontend/qtechnique.h1
-rw-r--r--src/render/frontend/qtextureimage.cpp1
-rw-r--r--src/render/frontend/qtextureproviders.cpp23
-rw-r--r--src/render/frontend/qtorusmesh.cpp6
-rw-r--r--src/render/frontend/qtorusmesh.h3
-rw-r--r--src/render/frontend/qwrapmode.cpp6
-rw-r--r--src/render/frontend/qwrapmode.h2
-rw-r--r--src/render/io/gltfparser.cpp4
-rw-r--r--tests/auto/core/cloning/tst_cloning.cpp16
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp765
-rw-r--r--tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp2
-rw-r--r--tests/auto/core/qentity/tst_qentity.cpp538
-rw-r--r--tests/auto/core/qscene/tst_qscene.cpp57
176 files changed, 3237 insertions, 602 deletions
diff --git a/examples/qt3d/assimp/assimp.pro b/examples/qt3d/assimp/assimp.pro
index 6742e213a..65dd19d11 100644
--- a/examples/qt3d/assimp/assimp.pro
+++ b/examples/qt3d/assimp/assimp.pro
@@ -13,4 +13,5 @@ SOURCES += \
RESOURCES += \
assimp.qrc \
- ../exampleresources/test_scene.qrc
+ ../exampleresources/test_scene.qrc \
+ ../exampleresources/chest.qrc
diff --git a/examples/qt3d/assimp/main.qml b/examples/qt3d/assimp/main.qml
index 6ebbe8afd..ae6431476 100644
--- a/examples/qt3d/assimp/main.qml
+++ b/examples/qt3d/assimp/main.qml
@@ -40,39 +40,28 @@ import Qt3D.Renderer 2.0
Entity
{
components: FrameGraph {
- activeFrameGraph: Viewport {
- rect: Qt.rect(0, 0, 1, 1)
- ClearBuffer {
- buffers : ClearBuffer.ColorDepthBuffer
- CameraSelector {
- camera: Entity {
- id : camera
- components : [
- Transform {
- LookAt {
- position: Qt.vector3d( 0.0, 0.0, -20.0 )
- upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
- viewCenter: Qt.vector3d( 0.0, 0.0, 10.0 )
- }
- Rotate {
- angle : -30
- axis : Qt.vector3d(0, 1, 0)
- }
- },
- CameraLens {
- projectionType: CameraLens.PerspectiveProjection
- fieldOfView: 60
- aspectRatio: 16/9
- nearPlane : 0.01
- farPlane : 1000.0
- }
- ]
- }
- }
- }
+ activeFrameGraph: ForwardRenderer {
+ clearColor: Qt.rgba(0, 0.5, 1, 1)
+ camera: camera
}
}
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ 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 )
+ }
+
+ Configuration {
+ controlledCamera: camera
+ }
+
Entity {
components : [
Transform {
@@ -80,8 +69,19 @@ Entity
},
SceneLoader
{
- id: scene
source: "qrc:/assets/test_scene.dae"
}]
}
+
+ Entity {
+ components : [
+ Transform {
+ Scale { scale: 0.2 }
+ Translate { dy: -15 }
+ },
+ SceneLoader
+ {
+ source: "qrc:/assets/chest/Chest.obj"
+ }]
+ }
}
diff --git a/examples/qt3d/bigmodel-qml/main.qml b/examples/qt3d/bigmodel-qml/main.qml
index 704d17872..2d5cdf536 100644
--- a/examples/qt3d/bigmodel-qml/main.qml
+++ b/examples/qt3d/bigmodel-qml/main.qml
@@ -59,22 +59,35 @@ Entity {
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
}
+ QQ2.ListModel {
+ id: entityModel
+ QQ2.ListElement { emptyRole: 0 }
+ }
+
NodeInstantiator {
id: collection
- property int count: 64
+ property int _count: 0
property real spacing: 5
property int cols: 8
property int _rows: count / cols
- model: count
+ model: entityModel
delegate: MyEntity {
id: myEntity
property real _lightness: 0.2 + 0.7 / collection._rows * Math.floor(index / collection.cols)
property real _hue: (index % collection.cols) / collection.cols
-
x: collection.spacing * (index % collection.cols - 0.5 * (collection.cols - 1))
z: collection.spacing * (Math.floor(index / collection.cols) - 0.5 * collection._rows)
diffuse: Qt.hsla( _hue, 0.5, _lightness, 1.0 )
}
}
+
+ QQ2.Timer {
+ interval: 1000
+ repeat: true
+ running: true
+ onTriggered: {
+ entityModel.append({});
+ }
+ }
}
diff --git a/examples/qt3d/dynamicscene-cpp/examplescene.cpp b/examples/qt3d/dynamicscene-cpp/examplescene.cpp
index ca15b1a9f..7bfb98f33 100644
--- a/examples/qt3d/dynamicscene-cpp/examplescene.cpp
+++ b/examples/qt3d/dynamicscene-cpp/examplescene.cpp
@@ -45,10 +45,8 @@ ExampleScene::ExampleScene(Qt3D::QNode *parent)
, m_timer(new QTimer(this))
, m_even(true)
{
- buildScene();
-
QObject::connect(m_timer, SIGNAL(timeout()), SLOT(updateScene()));
- m_timer->setInterval(500);
+ m_timer->setInterval(1200);
m_timer->start();
}
@@ -59,15 +57,19 @@ ExampleScene::~ExampleScene()
void ExampleScene::updateScene()
{
- int i = 0;
- Q_FOREACH (BoxEntity *entity, m_entities) {
- if (i % 2 == 0)
- entity->setParent(m_even ? Q_NULLPTR : this);
- else
- entity->setParent(m_even ? this : Q_NULLPTR);
- ++i;
+ if (m_entities.isEmpty()) {
+ buildScene();
+ } else {
+ int i = 0;
+ Q_FOREACH (BoxEntity *entity, m_entities) {
+ if (i % 2 == 0)
+ entity->setParent(m_even ? Q_NULLPTR : this);
+ else
+ entity->setParent(m_even ? this : Q_NULLPTR);
+ ++i;
+ }
+ m_even = !m_even;
}
- m_even = !m_even;
}
void ExampleScene::buildScene()
diff --git a/examples/qt3d/planets-qml/ShadowMapFrameGraph.qml b/examples/qt3d/planets-qml/ShadowMapFrameGraph.qml
new file mode 100644
index 000000000..5020d13c0
--- /dev/null
+++ b/examples/qt3d/planets-qml/ShadowMapFrameGraph.qml
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D 2.0
+import Qt3D.Renderer 2.0
+import QtQuick 2.2 as QQ2
+
+FrameGraph {
+ id: root
+
+ property alias viewCamera: viewCameraSelector.camera
+ property alias lightCamera: lightCameraSelector.camera
+ readonly property Texture2D shadowTexture: depthTexture
+
+ activeFrameGraph: Viewport {
+ rect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+ clearColor: Qt.rgba(0.0, 0.0, 0.0, 1.0)
+
+ RenderPassFilter {
+ includes: [ Annotation { name: "pass"; value: "shadowmap" } ]
+
+ RenderTargetSelector {
+ target: RenderTarget {
+ attachments: [
+ RenderAttachment {
+ name: "depth"
+ type: RenderAttachment.DepthAttachment
+ texture: Texture2D {
+ id: depthTexture
+ width: mainview.width
+ height: mainview.height
+ format: Texture.DepthFormat
+ generateMipMaps: false
+ magnificationFilter: Texture.Linear
+ minificationFilter: Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ comparisonFunction: Texture.CompareLessEqual
+ comparisonMode: Texture.CompareRefToTexture
+ }
+ }
+ ]
+ }
+
+ ClearBuffer {
+ buffers: ClearBuffer.DepthBuffer
+
+ CameraSelector {
+ id: lightCameraSelector
+ }
+ }
+ }
+ }
+
+ RenderPassFilter {
+ includes: [ Annotation { name: "pass"; value: "forward" } ]
+
+ ClearBuffer {
+ buffers: ClearBuffer.ColorDepthBuffer
+
+ CameraSelector {
+ id: viewCameraSelector
+ }
+ }
+ }
+ }
+}
diff --git a/examples/qt3d/planets-qml/doc/src/planets-qml.qdoc b/examples/qt3d/planets-qml/doc/src/planets-qml.qdoc
index d68a21b2d..f50a84fec 100644
--- a/examples/qt3d/planets-qml/doc/src/planets-qml.qdoc
+++ b/examples/qt3d/planets-qml/doc/src/planets-qml.qdoc
@@ -40,12 +40,12 @@
\ingroup qt3d-examples-qml
\brief Demonstrates combining Qt 3D rendering and Qt Quick 2 elements.
- The Planets example demonstrates how to implement an application that combines the use of
+ \image planets-qml-example.jpg
+
+ \e Planets demonstrates how to implement an application that combines the use of
Qt 3D rendering with Qt Quick 2D elements. The example shows the eight planets of our Solar
System with the Sun.
- \image planets-qml-example.jpg
-
Planet texture maps are Copyright (c) by James Hastings-Trew
\l{http://planetpixelemporium.com/planets.html}{http://planetpixelemporium.com/planets.html}
used with permission.
@@ -55,6 +55,8 @@
\l {http://www.stjarnhimlen.se/comp/ppcomp.html}{http://www.stjarnhimlen.se/comp/ppcomp.html}
and \l {http://www.davidcolarusso.com/astro/}{http://www.davidcolarusso.com/astro/}.
+ \include examples-run.qdocinc
+
\section1 Qt Quick 2D Implementation
The Qt Quick Implementation \l{planets-qml/PlanetsMain.qml}{PlanetsMain.qml} of the
@@ -99,7 +101,7 @@
constructed with JavaScript in \l{planets-qml/planets.js}{planets.js} by calling
\c{loadPlanetData()} as the component completes. Other initializations, such as inserting the
planets into an array for easier handling, calculating the ring radii for Saturn and Uranus
- rings, and setting the default scale, speed and camera offset, are done as well:
+ rings, and setting the default scale, speed, and camera offset, are done as well:
\snippet planets-qml/SolarSystem.qml 2
diff --git a/examples/qt3d/planets-qml/shaders/planetD.frag b/examples/qt3d/planets-qml/shaders/planetD.frag
new file mode 100644
index 000000000..62d941d25
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetD.frag
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform vec3 ks; // Specular reflectivity
+uniform float shininess; // Specular shininess factor
+uniform float opacity; // Alpha channel
+
+uniform sampler2D diffuseTexture;
+
+uniform sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 position;
+in vec3 normal;
+in vec2 texCoord;
+
+out vec4 fragColor;
+
+vec3 dModel(const in vec2 flipYTexCoord)
+{
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize(vec3(viewMatrix * vec4(lightPosition, 1.0)) - position);
+
+ // Calculate the vector from the fragment to the eye position
+ // (origin since this is in "eye" or "camera" space)
+ vec3 v = normalize(-position);
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect(-s, normal);
+
+ // Calculate the diffuse component
+ float diffuse = max(dot(s, normal), 0.0);
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if (dot(s, normal) > 0.0)
+ specular = (shininess / (8.0 * 3.14)) * pow(max(dot(r, v), 0.0), shininess);
+
+ // Lookup diffuse and specular factors
+ vec3 diffuseColor = texture(diffuseTexture, flipYTexCoord).rgb;
+
+ // Combine the ambient, diffuse and specular contributions
+ return lightIntensity * ((ka + diffuse) * diffuseColor + specular * ks);
+}
+
+void main()
+{
+ vec2 flipYTexCoord = texCoord;
+ flipYTexCoord.y = 1.0 - texCoord.y;
+
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ vec3 ambient = lightIntensity * ka * texture(diffuseTexture, flipYTexCoord).rgb;
+
+ vec3 result = ambient;
+ if (shadowMapSample > 0)
+ result = dModel(flipYTexCoord);
+
+ float alpha = opacity * texture(diffuseTexture, flipYTexCoord).a;
+
+ fragColor = vec4(result, alpha);
+}
diff --git a/examples/qt3d/planets-qml/shaders/planetD.vert b/examples/qt3d/planets-qml/shaders/planetD.vert
new file mode 100644
index 000000000..41a1db6e4
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetD.vert
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec2 vertexTexCoord;
+
+out vec4 positionInLightSpace;
+out vec3 position;
+out vec3 normal;
+out vec2 texCoord;
+
+uniform mat4 lightViewProjection;
+uniform mat4 modelMatrix;
+uniform mat4 modelView;
+uniform mat3 modelViewNormal;
+uniform mat4 mvp;
+
+uniform float texCoordScale;
+
+void main()
+{
+ const mat4 shadowMatrix = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+ positionInLightSpace = shadowMatrix * lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+
+ texCoord = vertexTexCoord * texCoordScale;
+ normal = normalize(modelViewNormal * vertexNormal);
+ position = vec3(modelView * vec4(vertexPosition, 1.0));
+
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/examples/qt3d/planets-qml/shaders/planetDB.frag b/examples/qt3d/planets-qml/shaders/planetDB.frag
new file mode 100644
index 000000000..bf53a127b
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetDB.frag
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform vec3 ks; // Specular reflectivity
+uniform float shininess; // Specular shininess factor
+uniform float opacity; // Alpha channel
+
+uniform sampler2D diffuseTexture;
+uniform sampler2D normalTexture;
+
+uniform sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 lightDir;
+in vec3 viewDir;
+in vec2 texCoord;
+
+out vec4 fragColor;
+
+void dbModel(const in vec3 norm, const in vec2 flipYTexCoord, out vec3 ambientAndDiff, out vec3 spec)
+{
+ // Reflection of light direction about normal
+ vec3 r = reflect(-lightDir, norm);
+
+ vec3 diffuseColor = texture(diffuseTexture, flipYTexCoord).rgb;
+
+ // Calculate the ambient contribution
+ vec3 ambient = lightIntensity * ka * diffuseColor;
+
+ // Calculate the diffuse contribution
+ float sDotN = max(dot(lightDir, norm), 0.0);
+ vec3 diffuse = lightIntensity * diffuseColor * sDotN;
+
+ // Sum the ambient and diffuse contributions
+ ambientAndDiff = ambient + diffuse;
+
+ // Calculate the specular highlight contribution
+ spec = vec3(0.0);
+ if (sDotN > 0.0)
+ spec = (lightIntensity * ks) * pow(max(dot(r, viewDir), 0.0), shininess);
+}
+
+void main()
+{
+ vec2 flipYTexCoord = texCoord;
+ flipYTexCoord.y = 1.0 - texCoord.y;
+
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ // Sample the textures at the interpolated texCoords
+ vec4 normal = 2.0 * texture(normalTexture, flipYTexCoord) - vec4(1.0);
+
+ vec3 result = lightIntensity * ka * texture(diffuseTexture, flipYTexCoord).rgb;
+
+ // Calculate the lighting model, keeping the specular component separate
+ vec3 ambientAndDiff, spec;
+ if (shadowMapSample > 0) {
+ dbModel(normalize(normal.xyz), flipYTexCoord, ambientAndDiff, spec);
+ result = ambientAndDiff + spec;
+ }
+
+ // Combine spec with ambient+diffuse for final fragment color
+ fragColor = vec4(result, opacity);
+}
diff --git a/examples/qt3d/planets-qml/shaders/planetDB.vert b/examples/qt3d/planets-qml/shaders/planetDB.vert
new file mode 100644
index 000000000..e30394aa3
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetDB.vert
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec2 vertexTexCoord;
+in vec4 vertexTangent;
+
+out vec4 positionInLightSpace;
+out vec3 lightDir;
+out vec3 viewDir;
+out vec2 texCoord;
+
+uniform mat4 viewMatrix;
+uniform mat4 lightViewProjection;
+uniform mat4 modelMatrix;
+uniform mat4 modelView;
+uniform mat3 modelViewNormal;
+uniform mat4 mvp;
+
+uniform float texCoordScale;
+
+uniform vec3 lightPosition;
+
+void main()
+{
+ const mat4 shadowMatrix = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+ positionInLightSpace = shadowMatrix * lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+
+ // Pass through texture coordinates
+ texCoord = vertexTexCoord * texCoordScale;
+
+ // Transform position, normal, and tangent to eye coords
+ vec3 normal = normalize(modelViewNormal * vertexNormal);
+ vec3 tangent = normalize(modelViewNormal * vertexTangent.xyz);
+ vec3 position = vec3(modelView * vec4(vertexPosition, 1.0));
+
+ // Calculate binormal vector
+ vec3 binormal = normalize(cross(normal, tangent));
+
+ // Construct matrix to transform from eye coords to tangent space
+ mat3 tangentMatrix = mat3 (
+ tangent.x, binormal.x, normal.x,
+ tangent.y, binormal.y, normal.y,
+ tangent.z, binormal.z, normal.z);
+
+ // Transform light direction and view direction to tangent space
+ vec3 s = lightPosition - position;
+ lightDir = normalize(tangentMatrix * vec3(viewMatrix * vec4(s, 1.0)));
+
+ vec3 v = -position;
+ viewDir = normalize(tangentMatrix * v);
+
+ // Calculate vertex position in clip coordinates
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/examples/qt3d/planets-qml/shaders/planetDS.frag b/examples/qt3d/planets-qml/shaders/planetDS.frag
new file mode 100644
index 000000000..2a1b78bfa
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetDS.frag
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform float shininess; // Specular shininess factor
+uniform float opacity; // Alpha channel
+
+uniform sampler2D diffuseTexture;
+uniform sampler2D specularTexture;
+
+uniform sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 position;
+in vec3 normal;
+in vec2 texCoord;
+
+out vec4 fragColor;
+
+vec3 dsModel(const in vec2 flipYTexCoord)
+{
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize(vec3(viewMatrix * vec4(lightPosition, 1.0)) - position);
+
+ // Calculate the vector from the fragment to the eye position
+ // (origin since this is in "eye" or "camera" space)
+ vec3 v = normalize(-position);
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect(-s, normal);
+
+ // Calculate the diffuse component
+ float diffuse = max(dot(s, normal), 0.0);
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if (dot(s, normal) > 0.0)
+ specular = (shininess / (8.0 * 3.14)) * pow(max(dot(r, v), 0.0), shininess);
+
+ // Lookup diffuse and specular factors
+ vec3 diffuseColor = texture(diffuseTexture, flipYTexCoord).rgb;
+ vec3 specularColor = texture(specularTexture, flipYTexCoord).rgb;
+
+ // Combine the ambient, diffuse and specular contributions
+ return lightIntensity * ((ka + diffuse) * diffuseColor + specular * specularColor);
+}
+
+void main()
+{
+ vec2 flipYTexCoord = texCoord;
+ flipYTexCoord.y = 1.0 - texCoord.y;
+
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ vec3 ambient = lightIntensity * ka * texture(diffuseTexture, flipYTexCoord).rgb;
+
+ vec3 result = ambient;
+ if (shadowMapSample > 0)
+ result = dsModel(flipYTexCoord);
+
+ fragColor = vec4(result, opacity * texture(diffuseTexture, flipYTexCoord).a);
+}
diff --git a/examples/qt3d/planets-qml/shaders/planetDSB.frag b/examples/qt3d/planets-qml/shaders/planetDSB.frag
new file mode 100644
index 000000000..deb9565d4
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/planetDSB.frag
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform float shininess; // Specular shininess factor
+uniform float opacity; // Alpha channel
+
+uniform sampler2D diffuseTexture;
+uniform sampler2D specularTexture;
+uniform sampler2D normalTexture;
+
+uniform sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 lightDir;
+in vec3 viewDir;
+in vec2 texCoord;
+
+out vec4 fragColor;
+
+void dsbModel(const in vec3 norm, const in vec2 flipYTexCoord, out vec3 ambientAndDiff, out vec3 spec)
+{
+ // Reflection of light direction about normal
+ vec3 r = reflect(-lightDir, norm);
+
+ vec3 diffuseColor = texture(diffuseTexture, flipYTexCoord).rgb;
+ vec3 specularColor = texture(specularTexture, flipYTexCoord).rgb;
+
+ // Calculate the ambient contribution
+ vec3 ambient = lightIntensity * ka * diffuseColor;
+
+ // Calculate the diffuse contribution
+ float sDotN = max(dot(lightDir, norm), 0.0);
+ vec3 diffuse = lightIntensity * diffuseColor * sDotN;
+
+ // Sum the ambient and diffuse contributions
+ ambientAndDiff = ambient + diffuse;
+
+ // Calculate the specular highlight contribution
+ spec = vec3(0.0);
+ if (sDotN > 0.0)
+ spec = (lightIntensity * (shininess / (8.0 * 3.14))) * pow(max(dot(r, viewDir), 0.0), shininess);
+
+ spec *= specularColor;
+}
+
+void main()
+{
+ vec2 flipYTexCoord = texCoord;
+ flipYTexCoord.y = 1.0 - texCoord.y;
+
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ // Sample the textures at the interpolated texCoords
+ vec4 normal = 2.0 * texture(normalTexture, flipYTexCoord) - vec4(1.0);
+
+ vec3 result = lightIntensity * ka * texture(diffuseTexture, flipYTexCoord).rgb;
+
+ // Calculate the lighting model, keeping the specular component separate
+ vec3 ambientAndDiff, spec;
+ if (shadowMapSample > 0) {
+ dsbModel(normalize(normal.xyz), flipYTexCoord, ambientAndDiff, spec);
+ result = ambientAndDiff + spec;
+ }
+
+ // Combine spec with ambient+diffuse for final fragment color
+ fragColor = vec4(result, opacity);
+}
diff --git a/examples/qt3d/planets-qml/shaders/shadowmap.frag b/examples/qt3d/planets-qml/shaders/shadowmap.frag
new file mode 100644
index 000000000..63f203da6
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/shadowmap.frag
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+void main()
+{
+}
diff --git a/examples/qt3d/planets-qml/shaders/shadowmap.vert b/examples/qt3d/planets-qml/shaders/shadowmap.vert
new file mode 100644
index 000000000..ca93360c6
--- /dev/null
+++ b/examples/qt3d/planets-qml/shaders/shadowmap.vert
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#version 150 core
+
+in vec3 vertexPosition;
+
+uniform mat4 mvp;
+
+void main()
+{
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/examples/qt3d/tessellation-modes/tessellatedquadmesh.cpp b/examples/qt3d/tessellation-modes/tessellatedquadmesh.cpp
index 6b04e5da3..08a3f54b3 100644
--- a/examples/qt3d/tessellation-modes/tessellatedquadmesh.cpp
+++ b/examples/qt3d/tessellation-modes/tessellatedquadmesh.cpp
@@ -45,6 +45,11 @@ TessellatedQuadMesh::TessellatedQuadMesh(Qt3D::QNode *parent)
{
}
+TessellatedQuadMesh::~TessellatedQuadMesh()
+{
+ QNode::cleanup();
+}
+
class TessellatedQuadMeshFunctor : public Qt3D::QAbstractMeshFunctor
{
public:
diff --git a/examples/qt3d/tessellation-modes/tessellatedquadmesh.h b/examples/qt3d/tessellation-modes/tessellatedquadmesh.h
index 76b00ae01..0bb6459ef 100644
--- a/examples/qt3d/tessellation-modes/tessellatedquadmesh.h
+++ b/examples/qt3d/tessellation-modes/tessellatedquadmesh.h
@@ -44,6 +44,7 @@ class TessellatedQuadMesh : public Qt3D::QAbstractMesh
Q_OBJECT
public:
explicit TessellatedQuadMesh(Qt3D::QNode *parent = 0);
+ ~TessellatedQuadMesh();
Qt3D::QAbstractMeshFunctorPtr meshFunctor() const Q_DECL_OVERRIDE;
diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp
index 1ef1d803a..8b4a76a84 100644
--- a/src/core/aspects/qaspectengine.cpp
+++ b/src/core/aspects/qaspectengine.cpp
@@ -50,6 +50,7 @@
#include <private/qnode_p.h>
#include "qentity.h"
#include "qcomponent.h"
+#include "qnodevisitor.h"
QT_BEGIN_NAMESPACE
@@ -70,6 +71,26 @@ QAspectEnginePrivate::QAspectEnginePrivate()
qRegisterMetaType<Qt3D::QSceneInterface *>();
}
+/*!
+ Used to init the scene tree when the Qt3D aspect is first started. Basically
+ sets the scene/change arbiter on the items and store the entity - component
+ pairs in the scene
+ */
+void QAspectEnginePrivate::initNode(QNode *node)
+{
+ QNodePrivate::get(node)->setScene(m_scene);
+ m_scene->addObservable(node);
+}
+
+void QAspectEnginePrivate::initEntity(QEntity *entity)
+{
+ Q_FOREACH (QComponent *comp, entity->components()) {
+ if (!comp->shareable() && !m_scene->entitiesForComponent(comp->id()).isEmpty())
+ qWarning() << "Trying to assign a non shareable component to more than one Entity";
+ m_scene->addEntityForComponent(comp->id(), entity->id());
+ }
+}
+
QAspectEngine::QAspectEngine(QObject *parent)
: QObject(*new QAspectEnginePrivate, parent)
{
@@ -107,24 +128,10 @@ QAspectEngine::~QAspectEngine()
delete d->m_scene;
}
-void QAspectEngine::initNodeTree(QNode *node) const
+void QAspectEngine::initNodeTree(QNode *node)
{
- Q_D(const QAspectEngine);
- node->d_func()->setScene(d->m_scene);
- d->m_scene->addObservable(node);
- QEntity *entity = qobject_cast<QEntity *>(node);
- if (entity != Q_NULLPTR)
- Q_FOREACH (QComponent *comp, entity->components()) {
- if (!comp->shareable() && !d->m_scene->entitiesForComponent(comp->id()).isEmpty())
- qWarning() << "Trying to assign a non shareable component to more than one Entity";
- d->m_scene->addEntityForComponent(comp->id(), entity->id());
- }
-
- Q_FOREACH (QObject *c, node->children()) {
- QNode *childNode = qobject_cast<QNode *>(c);
- if (childNode != Q_NULLPTR)
- initNodeTree(childNode);
- }
+ QNodeVisitor visitor;
+ visitor.traverse(node, d_func(), &QAspectEnginePrivate::initNode, &QAspectEnginePrivate::initEntity);
}
void QAspectEngine::initialize()
@@ -218,7 +225,7 @@ void QAspectEngine::setRootEntity(QEntity *root)
// The aspect engine takes ownership of the scene root. We also set the
// parent of the scene root to be the engine
- d->m_root->setParent(this);
+ static_cast<QObject *>(d->m_root.data())->setParent(this);
// Prepare the frontend tree for use by giving each node a pointer to the
// scene object and adding each node to the scene
diff --git a/src/core/aspects/qaspectengine.h b/src/core/aspects/qaspectengine.h
index c93fcb653..cdbb01a30 100644
--- a/src/core/aspects/qaspectengine.h
+++ b/src/core/aspects/qaspectengine.h
@@ -78,7 +78,7 @@ protected:
QAspectEngine(QAspectEnginePrivate &dd, QObject *parent = 0);
private:
- void initNodeTree(QNode *node) const;
+ void initNodeTree(QNode *node);
};
} // namespace Qt3D
diff --git a/src/core/aspects/qaspectengine_p.h b/src/core/aspects/qaspectengine_p.h
index d2f2da88e..4cafaf6a7 100644
--- a/src/core/aspects/qaspectengine_p.h
+++ b/src/core/aspects/qaspectengine_p.h
@@ -65,12 +65,13 @@ public:
QSceneInterface *m_scene;
QSharedPointer<QEntity> m_root;
QList<QAbstractAspect*> m_aspects;
+
+ void initNode(QNode *node);
+ void initEntity(QEntity *entity);
};
} // Qt3D
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QWaitCondition *)
-
#endif // QT3D_QASPECTENGINE_P_H
diff --git a/src/core/aspects/qaspectthread.cpp b/src/core/aspects/qaspectthread.cpp
index 7ddcd4519..e0f948923 100644
--- a/src/core/aspects/qaspectthread.cpp
+++ b/src/core/aspects/qaspectthread.cpp
@@ -46,8 +46,9 @@ QT_BEGIN_NAMESPACE
namespace Qt3D {
QAspectThread::QAspectThread(QObject *parent)
- : QThread(parent)
- , m_aspectManager(0)
+ : QThread(parent),
+ m_aspectManager(Q_NULLPTR),
+ m_semaphore(0)
{
qCDebug(Aspects) << Q_FUNC_INFO;
}
@@ -55,9 +56,8 @@ QAspectThread::QAspectThread(QObject *parent)
void QAspectThread::waitForStart(Priority priority)
{
qCDebug(Aspects) << "Starting QAspectThread and going to sleep until it is ready for us...";
- m_mutex.lock();
start(priority);
- m_waitCondition.wait(&m_mutex);
+ m_semaphore.acquire();
qCDebug(Aspects) << "QAspectThead is now ready & calling thread is now awake again";
}
@@ -65,8 +65,6 @@ void QAspectThread::run()
{
qCDebug(Aspects) << "Entering void QAspectThread::run()";
- // Lock mutex and create worker objects
- QMutexLocker locker(&m_mutex);
m_aspectManager = new QAspectManager;
// Load and initialize the aspects and any other core services
@@ -75,8 +73,7 @@ void QAspectThread::run()
m_aspectManager->initialize();
// Wake up the calling thread now that our worker objects are ready for action
- m_waitCondition.wakeOne();
- m_mutex.unlock();
+ m_semaphore.release();
// Enter the main loop
m_aspectManager->exec();
diff --git a/src/core/aspects/qaspectthread.h b/src/core/aspects/qaspectthread.h
index 989406766..8d32e28bd 100644
--- a/src/core/aspects/qaspectthread.h
+++ b/src/core/aspects/qaspectthread.h
@@ -38,10 +38,10 @@
#define QT3D_QASPECTTHREAD_H
#include <QThread>
-#include <QMutex>
-#include <QWaitCondition>
#include <Qt3DCore/qt3dcore_global.h>
+#include <QtCore/QSemaphore>
+
QT_BEGIN_NAMESPACE
namespace Qt3D {
@@ -63,8 +63,7 @@ protected:
private:
QAspectManager *m_aspectManager;
- QMutex m_mutex;
- QWaitCondition m_waitCondition;
+ QSemaphore m_semaphore;
};
} // namespace Qt3D
diff --git a/src/core/core-components/qcamera.cpp b/src/core/core-components/qcamera.cpp
index 76d208cc9..9450ccf5b 100644
--- a/src/core/core-components/qcamera.cpp
+++ b/src/core/core-components/qcamera.cpp
@@ -77,11 +77,17 @@ QCamera::QCamera(QNode *parent) :
QObject::connect(d_func()->m_lookAt, SIGNAL(positionChanged()), this, SIGNAL(positionChanged()));
QObject::connect(d_func()->m_lookAt, SIGNAL(upVectorChanged()), this, SIGNAL(upVectorChanged()));
QObject::connect(d_func()->m_lookAt, SIGNAL(viewCenterChanged()), this, SIGNAL(viewCenterChanged()));
+ QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(matrixChanged()));
d_func()->m_transform->addTransform(d_func()->m_lookAt);
addComponent(d_func()->m_lens);
addComponent(d_func()->m_transform);
}
+QCamera::~QCamera()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QCamera::QCamera(QCameraPrivate &dd, QNode *parent)
: QEntity(dd, parent)
@@ -99,6 +105,7 @@ QCamera::QCamera(QCameraPrivate &dd, QNode *parent)
QObject::connect(d_func()->m_lookAt, SIGNAL(positionChanged()), this, SIGNAL(positionChanged()));
QObject::connect(d_func()->m_lookAt, SIGNAL(upVectorChanged()), this, SIGNAL(upVectorChanged()));
QObject::connect(d_func()->m_lookAt, SIGNAL(viewCenterChanged()), this, SIGNAL(viewCenterChanged()));
+ QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(matrixChanged()));
d_func()->m_transform->addTransform(d_func()->m_lookAt);
addComponent(d_func()->m_lens);
addComponent(d_func()->m_transform);
@@ -451,6 +458,15 @@ QVector3D QCamera::viewCenter() const
return d->m_lookAt->viewCenter();
}
+/*!
+ \qmlproperty matrix4x4 Qt3D::Camera::matrix
+*/
+QMatrix4x4 QCamera::matrix() const
+{
+ Q_D(const QCamera);
+ return d->m_transform->matrix();
+}
+
} // Qt3D
QT_END_NAMESPACE
diff --git a/src/core/core-components/qcamera.h b/src/core/core-components/qcamera.h
index 9c3ac338f..4bf25534a 100644
--- a/src/core/core-components/qcamera.h
+++ b/src/core/core-components/qcamera.h
@@ -69,10 +69,11 @@ class QT3DCORESHARED_EXPORT QCamera : public QEntity
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY upVectorChanged)
Q_PROPERTY(QVector3D viewCenter READ viewCenter WRITE setViewCenter NOTIFY viewCenterChanged)
+ Q_PROPERTY(QMatrix4x4 matrix READ matrix NOTIFY matrixChanged)
public:
explicit QCamera(QNode *parent = 0);
-
+ ~QCamera();
enum CameraTranslationOption {
TranslateViewCenter,
@@ -142,6 +143,8 @@ public:
void setViewCenter(const QVector3D &viewCenter);
QVector3D viewCenter() const;
+ QMatrix4x4 matrix() const;
+
Q_SIGNALS:
void projectionTypeChanged();
void nearPlaneChanged();
@@ -156,6 +159,7 @@ Q_SIGNALS:
void positionChanged();
void upVectorChanged();
void viewCenterChanged();
+ void matrixChanged();
protected:
Q_DECLARE_PRIVATE(QCamera)
diff --git a/src/core/core-components/qcameralens.cpp b/src/core/core-components/qcameralens.cpp
index 5fc43e5c3..35f9fdd7a 100644
--- a/src/core/core-components/qcameralens.cpp
+++ b/src/core/core-components/qcameralens.cpp
@@ -66,6 +66,11 @@ QCameraLens::QCameraLens(QNode *parent)
d->updateProjectionMatrix();
}
+QCameraLens::~QCameraLens()
+{
+ QNode::cleanup();
+}
+
void QCameraLens::copy(const QNode *ref)
{
QComponent::copy(ref);
diff --git a/src/core/core-components/qcameralens.h b/src/core/core-components/qcameralens.h
index 0e871cc6b..7ec77adf7 100644
--- a/src/core/core-components/qcameralens.h
+++ b/src/core/core-components/qcameralens.h
@@ -66,6 +66,7 @@ class QT3DCORESHARED_EXPORT QCameraLens : public QComponent
public:
explicit QCameraLens(QNode *parent = 0);
+ ~QCameraLens();
enum ProjectionType {
OrthogonalProjection,
diff --git a/src/core/nodes/qcomponent.cpp b/src/core/nodes/qcomponent.cpp
index 43ebfa768..9f2cdbd66 100644
--- a/src/core/nodes/qcomponent.cpp
+++ b/src/core/nodes/qcomponent.cpp
@@ -38,7 +38,7 @@
#include "qcomponent_p.h"
#include "qentity.h"
#include "qentity_p.h"
-
+#include "qsceneinterface.h"
#include <Qt3DCore/qscenepropertychange.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +60,12 @@ void QComponentPrivate::addEntity(QEntity *entity)
{
m_entities.append(entity);
+ if (m_scene != Q_NULLPTR) {
+ if (!m_shareable && !m_scene->entitiesForComponent(m_id).isEmpty())
+ qWarning() << "Trying to assign a non shareable component to more than one Entity";
+ m_scene->addEntityForComponent(m_id, entity->id());
+ }
+
// We notify only if we have a QChangeArbiter
if (m_changeArbiter != Q_NULLPTR) {
Q_Q(QComponent);
@@ -81,6 +87,9 @@ void QComponentPrivate::removeEntity(QEntity *entity)
notifyObservers(e);
}
+ if (m_scene != Q_NULLPTR)
+ m_scene->removeEntityForComponent(m_id, entity->id());
+
m_entities.removeAll(entity);
}
@@ -116,6 +125,8 @@ QComponent::QComponent(QNode *parent)
QComponent::~QComponent()
{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QComponent subclass didn't call QNode::cleanup in its destructor");
+
Q_FOREACH (QEntity *entity, entities()) {
QEntityPrivate *entityPimpl = dynamic_cast<QEntityPrivate *>(QEntityPrivate::get(entity));
if (entityPimpl)
@@ -133,7 +144,7 @@ bool QComponent::shareable() const
}
/*!
- \returns whether the QComponent is enabled or not.
+ Returns whether the QComponent is enabled or not.
*/
bool QComponent::isEnabled() const
{
diff --git a/src/core/nodes/qentity.cpp b/src/core/nodes/qentity.cpp
index e0aff9466..8f9df993e 100644
--- a/src/core/nodes/qentity.cpp
+++ b/src/core/nodes/qentity.cpp
@@ -58,6 +58,7 @@ namespace Qt3D {
QEntityPrivate::QEntityPrivate()
: QNodePrivate()
, m_enabled(true)
+ , m_parentEntityId()
{}
/*!
@@ -89,12 +90,13 @@ QEntity::QEntity(QNode *parent)
QEntity::~QEntity()
{
+ // remove all component aggregations
+ removeAllComponents();
+
+ QNode::cleanup();
// If all children are removed
// That includes the components that are parented by this entity
- // We need to call removeAllComponent only for real Entities (not clone)
- if (d_func()->m_changeArbiter)
- removeAllComponents();
}
/*! \internal */
@@ -113,6 +115,7 @@ void QEntity::copy(const QNode *ref)
const QEntity *entity = static_cast<const QEntity*>(ref);
d_func()->m_enabled = entity->d_func()->m_enabled;
d_func()->m_visible = entity->d_func()->m_visible;
+ d_func()->m_parentEntityId = entity->parentEntityId();
Q_FOREACH (QComponent *c, entity->d_func()->m_components) {
QNode *ccclone = QNode::clone(c);
@@ -140,19 +143,17 @@ void QEntity::addComponent(QComponent *comp)
Q_D(QEntity);
Q_CHECK_PTR( comp );
qCDebug(Nodes) << Q_FUNC_INFO << comp;
- Q_ASSERT(d->m_components.count(comp) == 0);
+
+ // A Component can only be aggregated once
+ if (d->m_components.count(comp) != 0)
+ return ;
+
d->m_components.append(comp);
// We only set the Entity as the Component's parent when it has no parent
// This will be the case mostly on C++ but rarely in QML
if (!comp->parent())
comp->setParent(this);
- if (d->m_scene != Q_NULLPTR) {
- if (!comp->shareable() && !d->m_scene->entitiesForComponent(comp->id()).isEmpty())
- qWarning() << "Trying to assign a non shareable component to more than one Entity";
- d->m_scene->addEntityForComponent(comp->id(), d->m_id);
- }
-
if (d->m_changeArbiter != Q_NULLPTR) {
// Sending a full fledged component in the notification as we'll need
// to know which type of component it was and its properties to create
@@ -186,9 +187,6 @@ void QEntity::removeComponent(QComponent *comp)
d->notifyObservers(propertyChange);
}
- if (d->m_scene != Q_NULLPTR)
- d->m_scene->removeEntityForComponent(comp->id(), d->m_id);
-
d->m_components.removeOne(comp);
}
@@ -210,6 +208,7 @@ void QEntity::removeAllComponents()
*/
QEntity *QEntity::parentEntity() const
{
+ Q_D(const QEntity);
QNode *parentNode = QNode::parentNode();
QEntity *parentEntity = qobject_cast<QEntity *>(parentNode);
@@ -217,9 +216,30 @@ QEntity *QEntity::parentEntity() const
parentNode = parentNode->parentNode();
parentEntity = qobject_cast<QEntity*>(parentNode);
}
+ if (!parentEntity) {
+ if (!d->m_parentEntityId.isNull())
+ d->m_parentEntityId = QNodeId();
+ } else {
+ if (d->m_parentEntityId != parentEntity->id())
+ d->m_parentEntityId = parentEntity->id();
+ }
return parentEntity;
}
+/*!
+ Returns the Qt3D::QNodeId id of the parent Qt3D::QEntity instance of the
+ current Qt3D::QEntity object. The QNodeId isNull method will return true if
+ there is no Qt3D::QEntity parent of the current Qt3D::QEntity in the scene
+ hierarchy.
+ */
+QNodeId QEntity::parentEntityId() const
+{
+ Q_D(const QEntity);
+ if (d->m_parentEntityId.isNull())
+ parentEntity();
+ return d->m_parentEntityId;
+}
+
} // namespace Qt3D
QT_END_NAMESPACE
diff --git a/src/core/nodes/qentity.h b/src/core/nodes/qentity.h
index 17a0107ec..786fde05f 100644
--- a/src/core/nodes/qentity.h
+++ b/src/core/nodes/qentity.h
@@ -66,6 +66,7 @@ public:
void removeAllComponents();
QEntity *parentEntity() const;
+ QNodeId parentEntityId() const;
protected:
QEntity(QEntityPrivate &dd, QNode *parent = 0);
diff --git a/src/core/nodes/qentity_p.h b/src/core/nodes/qentity_p.h
index b28d0c391..4dc851103 100644
--- a/src/core/nodes/qentity_p.h
+++ b/src/core/nodes/qentity_p.h
@@ -58,6 +58,7 @@ public :
// TODO: Is a bool enough here or do we need additional states for entities?
// Perhaps aboutToBeDeleted would be useful?
bool m_enabled;
+ mutable QNodeId m_parentEntityId;
};
}
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index d6472cfd6..a8061a9cd 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -47,6 +47,7 @@
#include <QMetaProperty>
#include <Qt3DCore/QComponent>
#include <Qt3DCore/private/corelogging_p.h>
+#include <Qt3DCore/qnodevisitor.h>
QT_BEGIN_NAMESPACE
@@ -64,24 +65,29 @@ QNodePrivate::QNodePrivate()
, m_scene(Q_NULLPTR)
, m_id(QNodeId::createId())
, m_blockNotifications(false)
+ , m_wasCleanedUp(false)
, m_propertyChangesSetup(false)
, m_signals(this)
{
}
-// Called by QEvent::childAdded (main thread)
-void QNodePrivate::addChild(QNode *childNode)
+// Called by QNodePrivate::ctor or setParent (main thread)
+void QNodePrivate::_q_addChild(QNode *childNode)
{
Q_ASSERT(childNode);
if (childNode == q_func())
return ;
- // Set the scene
- childNode->d_func()->setScene(m_scene);
+ // If the scene is null it means that the current node is part of a subtree
+ // that has been pre-prepared. Therefore the node shouldn't be added by
+ // itself but only when the root of the said subtree is inserted into an
+ // existing node whose m_scene member is valid
+ if (m_scene == Q_NULLPTR)
+ return;
- // addObservable set the QChangeArbiter
- if (m_scene != Q_NULLPTR)
- m_scene->addObservable(childNode);
+ QNodeVisitor visitor;
+ // Recursively set scene and change arbiter for the node subtree
+ visitor.traverse(childNode, this, &QNodePrivate::setSceneHelper);
// We notify only if we have a QChangeArbiter
if (m_changeArbiter != Q_NULLPTR) {
@@ -100,10 +106,13 @@ void QNodePrivate::addChild(QNode *childNode)
e->setValue(QVariant::fromValue(QNodePtr(childClone, &QNodePrivate::nodePtrDeleter)));
notifyObservers(e);
}
+
+ // Handle Entity - Components
+ visitor.traverse(childNode, this, &QNodePrivate::addEntityComponentToScene);
}
-// Called by QEvent::childRemoved (main thread)
-void QNodePrivate::removeChild(QNode *childNode)
+// Called by setParent or cleanup (main thread) (could be other thread if created on the backend in a job)
+void QNodePrivate::_q_removeChild(QNode *childNode)
{
Q_ASSERT(childNode);
if (childNode->parent() != q_func())
@@ -134,18 +143,9 @@ void QNodePrivate::removeChild(QNode *childNode)
notifyObservers(e);
}
- if (m_scene != Q_NULLPTR)
- m_scene->removeObservable(childNode);
- childNode->d_func()->setScene(Q_NULLPTR);
-}
-
-void QNodePrivate::removeAllChildren()
-{
- Q_FOREACH (QObject *child, q_func()->children()) {
- QNode *childNode = qobject_cast<QNode *>(child);
- if (childNode != Q_NULLPTR)
- removeChild(childNode);
- }
+ // Recursively unset the scene on all children
+ QNodeVisitor visitor;
+ visitor.traverse(childNode, this, &QNodePrivate::unsetSceneHelper);
}
void QNodePrivate::registerNotifiedProperties()
@@ -198,6 +198,64 @@ void QNodePrivate::propertyChanged(int propertyIndex)
}
}
+/*!
+ \internal
+ Recursively sets and adds the nodes in the subtree of base node \a root to the scene.
+ Also takes care of connecting Components and Entities together in the scene.
+ */
+void QNodePrivate::setSceneHelper(QNode *root)
+{
+ // Sets the scene
+ root->d_func()->setScene(m_scene);
+ // addObservable sets the QChangeArbiter
+ m_scene->addObservable(root);
+
+ // We also need to handle QEntity <-> QComponent relationships
+ if (QComponent *c = qobject_cast<QComponent *>(root)) {
+ const QVector<QEntity *> entities = c->entities();
+ Q_FOREACH (QEntity *entity, entities) {
+ if (!c->shareable() && !m_scene->entitiesForComponent(c->id()).isEmpty())
+ qWarning() << "Trying to assign a non shareable component to more than one Entity";
+ m_scene->addEntityForComponent(c->id(), entity->id());
+ }
+ }
+}
+
+/*!
+ \internal
+
+ Recursively unsets and remove nodes in the subtree of base node \a root from
+ the scene. Also takes care of removing Components and Entities connections.
+ */
+void QNodePrivate::unsetSceneHelper(QNode *root)
+{
+ // We also need to handle QEntity <-> QComponent relationships removal
+ if (QComponent *c = qobject_cast<QComponent *>(root)) {
+ const QVector<QEntity *> entities = c->entities();
+ Q_FOREACH (QEntity *entity, entities) {
+ m_scene->removeEntityForComponent(c->id(), entity->id());
+ }
+ }
+
+ if (m_scene != Q_NULLPTR)
+ m_scene->removeObservable(root);
+ root->d_func()->setScene(Q_NULLPTR);
+}
+
+/*!
+ \internal
+ */
+void QNodePrivate::addEntityComponentToScene(QNode *root)
+{
+ if (QEntity *e = qobject_cast<QEntity *>(root)) {
+ Q_FOREACH (QComponent *c, e->components())
+ m_scene->addEntityForComponent(c->id(), e->id());
+ }
+}
+
+/*!
+ \internal
+ */
// Called in the main thread by QScene -> following QEvent::childAdded / addChild
void QNodePrivate::setArbiter(QLockableObserverInterface *arbiter)
{
@@ -221,17 +279,26 @@ void QNode::sceneChangeEvent(const QSceneChangePtr &change)
qWarning() << Q_FUNC_INFO << "sceneChangeEvent should have been subclassed";
}
+/*!
+ \internal
+ */
void QNodePrivate::setScene(QSceneInterface *scene)
{
if (m_scene != scene)
m_scene = scene;
}
+/*!
+ \internal
+ */
QSceneInterface *QNodePrivate::scene() const
{
return m_scene;
}
+/*!
+ \internal
+ */
void QNodePrivate::notifyPropertyChange(const char *name, const QVariant &value)
{
// Bail out early if we can to avoid operator new
@@ -244,6 +311,9 @@ void QNodePrivate::notifyPropertyChange(const char *name, const QVariant &value)
notifyObservers(e);
}
+/*!
+ \internal
+ */
// Called by the main thread
void QNodePrivate::notifyObservers(const QSceneChangePtr &change)
{
@@ -264,6 +334,9 @@ void QNodePrivate::notifyObservers(const QSceneChangePtr &change)
// QNode *subtree;
// QNodePrivate::get(root)->insertTree(subtree);
+/*!
+ \internal
+ */
void QNodePrivate::insertTree(QNode *treeRoot, int depth)
{
if (m_scene != Q_NULLPTR) {
@@ -281,11 +354,17 @@ void QNodePrivate::insertTree(QNode *treeRoot, int depth)
treeRoot->setParent(q_func());
}
+/*!
+ \internal
+ */
QNodePrivate *QNodePrivate::get(QNode *q)
{
return q->d_func();
}
+/*!
+ \internal
+ */
void QNodePrivate::nodePtrDeleter(QNode *q)
{
QObject *p = q->parent();
@@ -310,6 +389,9 @@ void QNodePrivate::nodePtrDeleter(QNode *q)
and no particular meaning, it is there as a way of building a node based tree
structure.
+ The parent of a Qt3D::QNode instance can only be another Qt3D::QNode
+ instance.
+
Each Qt3D::QNode instance has a unique id that allows it to be recognizable
from other instances.
@@ -317,24 +399,46 @@ void QNodePrivate::nodePtrDeleter(QNode *q)
will automatically generate notifications that the Qt3D backend aspects will
receive.
+ When subclassing Qt3D::QNode make sure to call QNode::cleanup() from your
+ subclass's destructor to ensure proper notification to backend aspects.
+ Faiure to do so will result in crashes when one of your Qt3D::QNode
+ subclass instance is eventually destroyed.
+
\sa Qt3D::QEntity, Qt3D::QComponent
*/
/*!
Creates a new Qt3D::QNode instance with parent \a parent.
+
+ \note The backend aspects will be notified that a Qt3D::QNode instance is
+ part of the scene only if it has a parent; unless this is the root node of
+ the Qt3D scene.
+
+ \sa setParent(Qt3D::QNode *)
*/
QNode::QNode(QNode *parent)
: QObject(*new QNodePrivate, parent)
{
- // We rely on QEvent::childAdded to be triggered on the parent
- // So we don't actually need to invoke a method or anything
- // to add ourselve with the parent
+ qRegisterMetaType<QNode *>("QNode*");
+ // We need to add ourselves with the parent if it is valid
+ // This will notify the backend about the new child
+ if (parent) {
+ // This needs to be invoked only after the QNode has been fully
+ QMetaObject::invokeMethod(parent, "_q_addChild", Qt::QueuedConnection, Q_ARG(QNode*, this));
+ }
}
/*! \internal */
QNode::QNode(QNodePrivate &dd, QNode *parent)
: QObject(dd, parent)
{
+ qRegisterMetaType<QNode *>("QNode*");
+ // We need to add ourselves with the parent if it is valid
+ // This will notify the backend about the new child
+ if (parent) {
+ // This needs to be invoked only after the QNode has been fully
+ QMetaObject::invokeMethod(parent, "_q_addChild", Qt::QueuedConnection, Q_ARG(QNode*, this));
+ }
}
/*!
@@ -352,6 +456,7 @@ void QNode::copy(const QNode *ref)
QNode::~QNode()
{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QNode subclass didn't call QNode::cleanup in its destructor");
}
/*!
@@ -403,6 +508,42 @@ bool QNode::blockNotifications(bool block)
}
/*!
+ * Sets the parent node of the current Qt3D::QNode instance to \a parent.
+ * Setting the parent will notify the backend aspects about current Qt3D::QNode
+ * instance's parent change.
+ *
+ * \note if \a parent happens to be null, this will actually notify that the
+ * current Qt3D::QNode instance was removed from the scene.
+ */
+void QNode::setParent(QNode *parent)
+{
+ if (parentNode())
+ QNodePrivate::get(parentNode())->_q_removeChild(this);
+ QObject::setParent(parent);
+ if (parentNode())
+ QNodePrivate::get(parentNode())->_q_addChild(this);
+ emit parentChanged();
+}
+
+/*!
+ * Returns a list filled with the Qt3D::QNode children of the current
+ * Qt3D::QNode instance.
+ */
+QNodeList QNode::childrenNodes() const
+{
+ QNodeList nodeChildrenList;
+ const QObjectList objectChildrenList = QObject::children();
+ nodeChildrenList.reserve(objectChildrenList.size());
+
+ Q_FOREACH (QObject *c, objectChildrenList) {
+ if (QNode *n = qobject_cast<QNode *>(c))
+ nodeChildrenList.push_back(n);
+ }
+
+ return nodeChildrenList;
+}
+
+/*!
Returns a clone of \a node. All the children of \a node are cloned as well.
\note This is the only way to create two nodes with the same id.
@@ -426,47 +567,19 @@ QNode *QNode::clone(QNode *node)
QNode *childNode = qobject_cast<QNode *>(c);
if (childNode != Q_NULLPTR) {
QNode *cclone = QNode::clone(childNode);
+ // We use QObject::setParent instead of QNode::setParent to avoid the
+ // whole overhead generated by the latter as we are only dealing with clones
if (cclone != Q_NULLPTR)
- cclone->setParent(clonedNode);
+ static_cast<QObject *>(cclone)->setParent(clonedNode);
}
}
- if (--clearLock == 0)
+ if (--clearLock == 0) // Cloning done
QNodePrivate::m_clonesLookupTable.clear();
return clonedNode;
}
-bool QNode::event(QEvent *e)
-{
- Q_D(QNode);
-
- switch (e->type()) {
-
- case QEvent::ChildAdded: {
- QNode *childNode = qobject_cast<QNode *>(static_cast<QChildEvent *>(e)->child());
- if (childNode != Q_NULLPTR) {
- d->addChild(childNode);
- }
- break;
- }
-
- case QEvent::ChildRemoved: {
- QNode *childNode = qobject_cast<QNode *>(static_cast<QChildEvent *>(e)->child());
- if (childNode != Q_NULLPTR) {
- d->removeChild(childNode);
- }
- break;
- }
-
- default:
- break;
-
- } // switch
-
- return QObject::event(e);
-}
-
/*!
Returns a pointer to the Qt3D::QNode instance's scene.
*/
@@ -476,6 +589,26 @@ QSceneInterface *QNode::scene() const
return d->m_scene;
}
+/*!
+ * This methods can only be called once and takes care of notyfing the backend
+ * aspects that the current Qt3D::QNode instance is about to be destroyed.
+ *
+ * \note It must be called by the destructor of every class subclassing
+ * Qt3D::QNode that is clonable (using the QT3D_CLONEABLE macro).
+ */
+void QNode::cleanup()
+{
+ Q_D(QNode);
+ if (!d->m_wasCleanedUp) {
+ d->m_wasCleanedUp = true;
+ qCDebug(Nodes) << Q_FUNC_INFO << this;
+ if (parentNode())
+ QNodePrivate::get(parentNode())->_q_removeChild(this);
+ // Root element has no parent and therefore we cannot
+ // call parent->_q_removeChild();
+ }
+}
+
} // namespace Qt3D
diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h
index 5d9f04283..040942d81 100644
--- a/src/core/nodes/qnode.h
+++ b/src/core/nodes/qnode.h
@@ -42,6 +42,8 @@
#include <Qt3DCore/qnodeid.h>
#include <Qt3DCore/qscenechange.h>
+#define Q_NODE_NULLPTR static_cast<Qt3D::QNode *>(Q_NULLPTR)
+
QT_BEGIN_NAMESPACE
namespace Qt3D {
@@ -62,12 +64,18 @@ typedef QSharedPointer<QNode> QNodePtr;
return clone_; \
}
+
+// Each QNode subclass should call QNode::cleanup in it dtor
+// QNode::cleanup checks that a flags wasn't set to true,
+// sets it to true and sends a clone to the backend
+
class QT3DCORESHARED_EXPORT QNode : public QObject
{
Q_OBJECT
+ Q_PROPERTY(Qt3D::QNode *parent READ parentNode WRITE setParent NOTIFY parentChanged)
public:
explicit QNode(QNode *parent = 0);
- ~QNode();
+ virtual ~QNode();
const QNodeId id() const;
QNode *parentNode() const;
@@ -75,6 +83,9 @@ public:
bool notificationsBlocked() const;
bool blockNotifications(bool block);
+ virtual void setParent(QNode *parent);
+ QNodeList childrenNodes() const;
+
protected:
// Clone should only be made in the main thread
static QNode *clone(QNode *node);
@@ -82,16 +93,27 @@ protected:
QNode(QNodePrivate &dd, QNode *parent = 0);
virtual void copy(const QNode *ref);
virtual void sceneChangeEvent(const QSceneChangePtr &change);
- bool event(QEvent *e) Q_DECL_OVERRIDE;
QSceneInterface *scene() const;
+ void cleanup();
+
private:
Q_DECLARE_PRIVATE(QNode)
virtual QNode *doClone() const = 0;
+ // We only want setParent(QNode *) to be callable
+ // when dealing with QNode objects
+ void setParent(QObject *) Q_DECL_EQ_DELETE;
+
+ Q_PRIVATE_SLOT(d_func(), void _q_addChild(QNode *))
+ Q_PRIVATE_SLOT(d_func(), void _q_removeChild(QNode *))
+
friend class QAspectEngine;
friend class QPostman;
friend class QScene;
+
+Q_SIGNALS:
+ void parentChanged();
};
} // namespace Qt3D
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index 7e654bf7a..11f64be9c 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -74,18 +74,22 @@ public:
QSceneInterface *m_scene;
mutable QNodeId m_id;
bool m_blockNotifications;
+ bool m_wasCleanedUp;
static QNodePrivate *get(QNode *q);
static void nodePtrDeleter(QNode *q);
private:
- void addChild(QNode *childNode);
- void removeChild(QNode *childNode);
- void removeAllChildren();
+ void _q_addChild(QNode *childNode);
+ void _q_removeChild(QNode *childNode);
void registerNotifiedProperties();
void unregisterNotifiedProperties();
void propertyChanged(int propertyIndex);
+ void setSceneHelper(QNode *root);
+ void unsetSceneHelper(QNode *root);
+ void addEntityComponentToScene(QNode *root);
+
friend class PropertyChangeHandler<QNodePrivate>;
bool m_propertyChangesSetup;
PropertyChangeHandler<QNodePrivate> m_signals;
diff --git a/src/core/nodes/qnodevisitor.cpp b/src/core/nodes/qnodevisitor.cpp
index f7acac132..ec10cbb73 100644
--- a/src/core/nodes/qnodevisitor.cpp
+++ b/src/core/nodes/qnodevisitor.cpp
@@ -41,7 +41,6 @@ QT_BEGIN_NAMESPACE
namespace Qt3D {
QNodeVisitor::QNodeVisitor()
- : m_traverseDisabled(false)
{
}
@@ -64,11 +63,6 @@ QNodeList QNodeVisitor::path() const
return m_path;
}
-void QNodeVisitor::setTraverseDisabled(bool on)
-{
- m_traverseDisabled = on;
-}
-
} // namespace Qt3D
QT_END_NAMESPACE
diff --git a/src/core/nodes/qnodevisitor.h b/src/core/nodes/qnodevisitor.h
index fdc728809..e903dc665 100644
--- a/src/core/nodes/qnodevisitor.h
+++ b/src/core/nodes/qnodevisitor.h
@@ -52,6 +52,18 @@ public:
QNodeVisitor();
virtual ~QNodeVisitor();
+ template<typename NodeVisitorFunc>
+ void traverse(QNode *rootNode_, NodeVisitorFunc fN)
+ {
+ startTraversing(rootNode_, createFunctor(fN));
+ }
+
+ template<typename Obj, typename NodeVisitorFunc>
+ void traverse(QNode *rootNode_, Obj *instance, NodeVisitorFunc fN)
+ {
+ startTraversing(rootNode_, createFunctor(instance, fN));
+ }
+
template<typename NodeVisitorFunc, typename EntityVisitorFunc>
void traverse(QNode *rootNode_, NodeVisitorFunc fN, EntityVisitorFunc fE)
{
@@ -67,11 +79,16 @@ public:
QNode *rootNode() const;
QNode *currentNode() const;
QNodeList path() const;
- void setTraverseDisabled(bool on);
private:
QNodeList m_path;
- bool m_traverseDisabled;
+
+ template<typename NodeVisitorFunctor>
+ void startTraversing(QNode *rootNode_, NodeVisitorFunctor fN)
+ {
+ m_path = QNodeList() << rootNode_;
+ visitNode(rootNode_, fN);
+ }
template<typename NodeVisitorFunctor, typename EntityVisitorFunctor>
void startTraversing(QNode *rootNode_, NodeVisitorFunctor fN, EntityVisitorFunctor fE)
@@ -85,6 +102,13 @@ private:
visitNode(rootNode_, fN, fE);
}
+ template<typename NodeVisitorFunctor>
+ void visitNode(QNode *nd, NodeVisitorFunctor &fN)
+ {
+ fN(nd);
+ traverseChildren(fN);
+ }
+
template<typename NodeVisitorFunctor, typename EntityVisitorFunctor>
void visitNode(QNode *nd, NodeVisitorFunctor &fN, EntityVisitorFunctor &fE)
{
@@ -109,6 +133,16 @@ private:
} // of children iteration
}
+ template<typename NodeVisitorFunctor>
+ void traverseChildren(NodeVisitorFunctor &fN)
+ {
+ Q_FOREACH (QObject *n, currentNode()->children()) {
+ QNode *node = qobject_cast<QNode *>(n);
+ if (node != Q_NULLPTR)
+ outerVisitNode(node, fN);
+ } // of children iteration
+ }
+
template<typename NodeVisitorFunctor, typename EntityVisitorFunctor>
void outerVisitNode(QNode *n, NodeVisitorFunctor &fN, EntityVisitorFunctor &fE)
{
@@ -116,10 +150,18 @@ private:
QEntity* e = qobject_cast<QEntity *>(n);
if (e) {
visitEntity(e, fN, fE);
- m_path.pop_back();
} else {
visitNode(n, fN, fE);
}
+ m_path.pop_back();
+ }
+
+ template<typename NodeVisitorFunctor>
+ void outerVisitNode(QNode *n, NodeVisitorFunctor &fN)
+ {
+ m_path.append(n);
+ visitNode(n, fN);
+ m_path.pop_back();
}
template <typename NodeType>
diff --git a/src/core/transforms/qtransform.cpp b/src/core/transforms/qtransform.cpp
index f9700b60f..48bee2094 100644
--- a/src/core/transforms/qtransform.cpp
+++ b/src/core/transforms/qtransform.cpp
@@ -105,6 +105,7 @@ QTransform::QTransform(QTransformPrivate &dd, QNode *parent)
QTransform::~QTransform()
{
+ QNode::cleanup();
Q_D(QTransform);
// boost destruction by avoiding _q_update()-s
d->m_transforms.clear();
diff --git a/src/input/qinputaspect.cpp b/src/input/qinputaspect.cpp
index c16f06dc3..901152bd4 100644
--- a/src/input/qinputaspect.cpp
+++ b/src/input/qinputaspect.cpp
@@ -105,7 +105,7 @@ void QInputAspect::sceneNodeAdded(QSceneChangePtr &e)
QNodePtr nodePtr = propertyChange->value().value<QNodePtr>();
QNode *n = nodePtr.data();
QNodeVisitor visitor;
- visitor.traverse(n, this, &QInputAspect::visitNode, &QInputAspect::visitNode);
+ visitor.traverse(n, this, &QInputAspect::visitNode);
}
void QInputAspect::sceneNodeRemoved(QSceneChangePtr &e)
@@ -119,7 +119,7 @@ void QInputAspect::sceneNodeRemoved(QSceneChangePtr &e)
void QInputAspect::setRootEntity(QEntity *rootObject)
{
QNodeVisitor visitor;
- visitor.traverse(rootObject, this, &QInputAspect::visitNode, &QInputAspect::visitNode);
+ visitor.traverse(rootObject, this, &QInputAspect::visitNode);
}
void QInputAspect::onInitialize(const QVariantMap &data)
diff --git a/src/input/qkeyboardcontroller.cpp b/src/input/qkeyboardcontroller.cpp
index 25b9b30ed..c8b97971c 100644
--- a/src/input/qkeyboardcontroller.cpp
+++ b/src/input/qkeyboardcontroller.cpp
@@ -72,11 +72,15 @@ QKeyboardController::QKeyboardController(QNode *parent)
{
}
+QKeyboardController::~QKeyboardController()
+{
+ QNode::cleanup();
+}
+
/*!
\qmlproperty KeyboardInput Qt3D.Input::KeyboardController::activeInput
\readonly
*/
-
QKeyboardInput *QKeyboardController::activeInput() const
{
Q_D(const QKeyboardController);
diff --git a/src/input/qkeyboardcontroller.h b/src/input/qkeyboardcontroller.h
index e30b8722b..d447ba3dc 100644
--- a/src/input/qkeyboardcontroller.h
+++ b/src/input/qkeyboardcontroller.h
@@ -54,6 +54,7 @@ class QT3DINPUTSHARED_EXPORT QKeyboardController : public QNode
public:
explicit QKeyboardController(QNode *parent = 0);
+ ~QKeyboardController();
QKeyboardInput *activeInput() const;
diff --git a/src/input/qkeyboardinput.cpp b/src/input/qkeyboardinput.cpp
index 1ad9342f4..d83891018 100644
--- a/src/input/qkeyboardinput.cpp
+++ b/src/input/qkeyboardinput.cpp
@@ -77,6 +77,11 @@ QKeyboardInput::QKeyboardInput(QNode *parent)
{
}
+QKeyboardInput::~QKeyboardInput()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QKeyboardInput::QKeyboardInput(QKeyboardInputPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/input/qkeyboardinput.h b/src/input/qkeyboardinput.h
index d94d7b6f5..683a4c38b 100644
--- a/src/input/qkeyboardinput.h
+++ b/src/input/qkeyboardinput.h
@@ -55,6 +55,7 @@ class QT3DINPUTSHARED_EXPORT QKeyboardInput : public QComponent
Q_PROPERTY(bool focus READ focus WRITE setFocus NOTIFY focusChanged)
public:
explicit QKeyboardInput(QNode *parent = 0);
+ ~QKeyboardInput();
void setController(QKeyboardController *controller);
QKeyboardController *controller() const;
diff --git a/src/plugins/sceneparsers/assimp/assimp.pro b/src/plugins/sceneparsers/assimp/assimp.pro
index a9385ad02..30277be13 100644
--- a/src/plugins/sceneparsers/assimp/assimp.pro
+++ b/src/plugins/sceneparsers/assimp/assimp.pro
@@ -7,9 +7,7 @@ load(qt_plugin)
include(assimp.pri)
-LIBS += -lassimp
-
unix {
CONFIG += link_pkgconfig
- PKGCONFIG += assimp
+ PKGCONFIG_PRIVATE += assimp
}
diff --git a/src/plugins/sceneparsers/assimp/assimpparser.cpp b/src/plugins/sceneparsers/assimp/assimpparser.cpp
index 5f16f977a..272cc533a 100644
--- a/src/plugins/sceneparsers/assimp/assimpparser.cpp
+++ b/src/plugins/sceneparsers/assimp/assimpparser.cpp
@@ -257,6 +257,7 @@ class AssimpMesh : public QAbstractMesh
Q_OBJECT
public :
explicit AssimpMesh(QNode *parent = 0);
+ ~AssimpMesh();
void copy(const QNode *ref) Q_DECL_OVERRIDE;
QAbstractMeshFunctorPtr meshFunctor() const Q_DECL_OVERRIDE;
@@ -751,7 +752,7 @@ void AssimpParser::loadCamera(uint cameraIndex)
// OPTIONAL
void AssimpParser::loadAnimation(uint animationIndex)
{
- Q_UNUSED(animationIndex)
+ Q_UNUSED(animationIndex);
}
/*!
@@ -802,8 +803,8 @@ void AssimpParser::copyMaterialBoolProperties(QMaterial *material, aiMaterial *a
void AssimpParser::copyMaterialShadingModel(QMaterial *material, aiMaterial *assimpMaterial)
{
- Q_UNUSED(material)
- Q_UNUSED(assimpMaterial)
+ Q_UNUSED(material);
+ Q_UNUSED(assimpMaterial);
// TODO
// Match each shading function with a default shader
@@ -813,8 +814,8 @@ void AssimpParser::copyMaterialShadingModel(QMaterial *material, aiMaterial *ass
void AssimpParser::copyMaterialBlendingFunction(QMaterial *material, aiMaterial *assimpMaterial)
{
- Q_UNUSED(material)
- Q_UNUSED(assimpMaterial)
+ Q_UNUSED(material);
+ Q_UNUSED(assimpMaterial);
// TO DO
}
@@ -891,6 +892,11 @@ AssimpMesh::AssimpMesh(QNode *parent)
{
}
+AssimpMesh::~AssimpMesh()
+{
+ QNode::cleanup();
+}
+
void AssimpMesh::copy(const QNode *ref)
{
QAbstractMesh::copy(ref);
diff --git a/src/quick3d/imports/render/defaults/qml/PhongMaterial.qml b/src/quick3d/imports/render/defaults/qml/PhongMaterial.qml
index 2d2ed2d3a..de71040b8 100644
--- a/src/quick3d/imports/render/defaults/qml/PhongMaterial.qml
+++ b/src/quick3d/imports/render/defaults/qml/PhongMaterial.qml
@@ -44,14 +44,6 @@ Material {
property color specular: Qt.rgba( 0.95, 0.95, 0.95, 1.0 )
property real shininess: 150.0
- parameters: [
- Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) },
- Parameter { name: "kd"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) },
- Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) },
- Parameter { name: "shininess"; value: root.shininess },
- Parameter { name: "lightPosition"; value: Qt.vector4d(1.0, 1.0, 0.0, 1.0) },
- Parameter { name: "lightIntensity"; value: Qt.vector3d(1.0, 1.0, 1.0) }
- ]
ShaderProgram {
id: gl3PhongShader
@@ -66,6 +58,16 @@ Material {
}
effect: Effect {
+
+ parameters: [
+ Parameter { name: "ka"; value: Qt.vector3d(root.ambient.r, root.ambient.g, root.ambient.b) },
+ Parameter { name: "kd"; value: Qt.vector3d(root.diffuse.r, root.diffuse.g, root.diffuse.b) },
+ Parameter { name: "ks"; value: Qt.vector3d(root.specular.r, root.specular.g, root.specular.b) },
+ Parameter { name: "shininess"; value: root.shininess },
+ Parameter { name: "lightPosition"; value: Qt.vector4d(1.0, 1.0, 0.0, 1.0) },
+ Parameter { name: "lightIntensity"; value: Qt.vector3d(1.0, 1.0, 1.0) }
+ ]
+
techniques: [
// GL 3 Technique
Technique {
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index ce21e7283..96f482909 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -46,7 +46,10 @@
#include <QSurface>
#include <QQuickWindow>
-#include <QSGSimpleTextureNode>
+#include <QSGTexture>
+#include <QSGMaterial>
+#include <QSGNode>
+#include <QOpenGLFunctions>
QT_BEGIN_NAMESPACE
@@ -73,16 +76,34 @@ private:
QSurface * const m_surface;
};
-class FrameBufferObjectRenderer : public QQuickFramebufferObject::Renderer
+class Scene3DSGNode;
+
+/*!
+ \class Qt3D::Scene3DRenderer
+ \internal
+
+ \brief The Qt3D::Scene3DRenderer class takes care of rendering a Qt3D scene
+ within a Framebuffer object to be used by the QtQuick 2 renderer.
+
+ The Qt3D::Scene3DRenderer class renders a Qt3D scene as provided by a Qt3D::Scene3DItem
+ */
+class Scene3DRenderer : public QObject
{
+ Q_OBJECT
public:
- FrameBufferObjectRenderer(Scene3DItem *item,
- Qt3D::QAspectEngine *aspectEngine,
- Qt3D::QRenderAspect *renderAspect)
- : m_item(item),
- m_aspectEngine(aspectEngine),
- m_renderAspect(renderAspect)
+ Scene3DRenderer(Scene3DItem *item,
+ Qt3D::QAspectEngine *aspectEngine,
+ Qt3D::QRenderAspect *renderAspect)
+ : QObject()
+ , m_item(item)
+ , m_aspectEngine(aspectEngine)
+ , m_renderAspect(renderAspect)
+ , m_multisampledFBO(Q_NULLPTR)
+ , m_finalFBO(Q_NULLPTR)
+ , m_texture(Q_NULLPTR)
{
+ Q_CHECK_PTR(m_item);
+ QObject::connect(m_item->window(), SIGNAL(beforeRendering()), this, SLOT(render()));
ContextSaver saver;
QVariantMap data;
@@ -94,27 +115,14 @@ public:
scheduleRootEntityChange();
}
- void render() Q_DECL_OVERRIDE
+ ~Scene3DRenderer()
{
- if (m_aspectEngine->rootEntity() != m_item->entity())
- scheduleRootEntityChange();
-
- ContextSaver saver;
- Q_UNUSED(saver)
-
- m_renderAspect->renderSynchronous();
-
- // We may have called doneCurrent() so restore the context.
- saver.context()->makeCurrent(saver.surface());
-
- // Reset the state used by the Qt Quick scenegraph to avoid any
- // interference when rendering the rest of the UI.
- m_item->window()->resetOpenGLState();
-
- update();
+ delete m_multisampledFBO;
+ delete m_finalFBO;
+ delete m_texture;
}
- QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) Q_DECL_OVERRIDE
+ QOpenGLFramebufferObject *createMultisampledFramebufferObject(const QSize &size)
{
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
@@ -122,21 +130,203 @@ public:
return new QOpenGLFramebufferObject(size, format);
}
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size)
+ {
+ QOpenGLFramebufferObjectFormat format;
+ format.setAttachment(QOpenGLFramebufferObject::Depth);
+ return new QOpenGLFramebufferObject(size, format);
+ }
+
void scheduleRootEntityChange()
{
QMetaObject::invokeMethod(m_item, "applyRootEntityChange", Qt::QueuedConnection);
}
+ void setSGNode(Scene3DSGNode *node) Q_DECL_NOEXCEPT;
+
+public Q_SLOTS:
+ void render();
+
+private:
Scene3DItem *m_item;
Qt3D::QAspectEngine *m_aspectEngine;
Qt3D::QRenderAspect *m_renderAspect;
+ QOpenGLFramebufferObject *m_multisampledFBO;
+ QOpenGLFramebufferObject *m_finalFBO;
+ QSGTexture *m_texture;
+ Scene3DSGNode *m_node;
+};
+
+/*!
+ \class Qt3D::SCene3DMaterialShader
+ \internal
+
+ \brief The Qt3D::Scene3DSGMaterialShader class is a custom
+ QSGMaterialShader subclass instantiated by a Qt3D::Scene3DSGMateria1
+
+ The Qt3D::Scene3DSGMaterialShader provides a shader that renders a texture
+ using premultiplied alpha.
+ */
+class Scene3DSGMaterialShader : public QSGMaterialShader
+{
+public:
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) Q_DECL_FINAL;
+
+ const char * const *attributeNames() const Q_DECL_FINAL
+ {
+ static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
+ return attr;
+ }
+
+ static QSGMaterialType type;
+
+protected:
+ const char *vertexShader() const Q_DECL_FINAL
+ {
+ return ""
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const Q_DECL_FINAL
+ {
+ return ""
+ "uniform highp sampler2D source; \n"
+ "uniform highp float qt_Opacity; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " highp vec4 p = texture2D(source, qt_TexCoord); \n"
+ " gl_FragColor = vec4(p.rgb * p.a, p.a) * qt_Opacity; \n"
+ "}";
+ }
+
+ void initialize() Q_DECL_FINAL
+ {
+ m_matrixId = program()->uniformLocation("qt_Matrix");
+ m_opacityId = program()->uniformLocation("qt_Opacity");
+ }
+
+private:
+ int m_matrixId;
+ int m_opacityId;
};
+QSGMaterialType Scene3DSGMaterialShader::type;
+
+/*!
+ \class Qt3D::Scene3DSGMaterial
+ \internal
+ \inherit QSGMaterial
+
+ \brief The Qt3D::Scene3DSGMaterial class is a custom QSGMaterial subclass used to
+ render a Qt3D::Scene3DSGNode
+
+ The Qt3D::Scene3DSGMaterial class renders a texture using premultiplied
+ alpha unlike the QSGSimpleTextureMaterial.
+
+ This is needed to properly integrate alpha blending from a Qt3D scene
+ within a QtQuick 2 scene.
+ */
+class Scene3DSGMaterial : public QSGMaterial
+{
+public:
+ Scene3DSGMaterial()
+ : QSGMaterial()
+ , m_texture(Q_NULLPTR)
+ {}
+
+ void setTexture(QSGTexture *texture) Q_DECL_NOEXCEPT
+ {
+ m_texture = texture;
+ setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false);
+ }
+
+ QSGTexture *texture() const Q_DECL_NOEXCEPT { return m_texture; }
+ QSGMaterialType *type() const Q_DECL_FINAL { return &Scene3DSGMaterialShader::type; }
+ QSGMaterialShader *createShader() const Q_DECL_FINAL { return new Scene3DSGMaterialShader(); }
+
+private:
+ QSGTexture *m_texture;
+};
+
+/*!
+ \class Qt3D::Scene3DSGNode
+ \internal
+
+ \brief The Qt3D::Scene3DSGNode class is a simple QSGeometryNode subclass that
+ uses a Qt3D::Scene3DMaterial
+
+ The Qt3D::Scene3DSGNode allows to render a simple rect texture with
+ premultiplied alpha.
+ */
+class Scene3DSGNode : public QSGGeometryNode
+{
+public:
+ Scene3DSGNode()
+ : QSGGeometryNode()
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_renderer(Q_NULLPTR)
+ {
+ setMaterial(&m_material);
+ setOpaqueMaterial(&m_opaqueMaterial);
+ setGeometry(&m_geometry);
+ }
+
+ void setTexture(QSGTexture *texture) Q_DECL_NOEXCEPT
+ {
+ m_material.setTexture(texture);
+ m_opaqueMaterial.setTexture(texture);
+ markDirty(DirtyMaterial);
+ }
+
+ QSGTexture *texture() const Q_DECL_NOEXCEPT { return m_material.texture(); }
+
+ void setRect(const QRectF &rect)
+ {
+ if (rect != m_rect) {
+ m_rect = rect;
+ // Map the item's bounding rect to normalized texture coordinates
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, QRectF(0.0f, 0.0f, 1.0f, 1.0f));
+ markDirty(DirtyGeometry);
+ }
+ }
+
+ QRectF rect() const Q_DECL_NOEXCEPT { return m_rect; }
+
+private:
+ Scene3DSGMaterial m_material;
+ Scene3DSGMaterial m_opaqueMaterial;
+ QSGGeometry m_geometry;
+ Scene3DRenderer *m_renderer;
+ QRectF m_rect;
+};
+
+
+/*!
+ \class Qt3D::Scene3DItem
+ \internal
+
+ \brief The Qt3D::Scene3DItem class is a QQuickItem subclass used to integrate
+ a Qt3D scene into a QtQuick 2 scene.
+
+ The Qt3D::Scene3DItem class renders a Qt3D scene, provided by a Qt3D::QEntity
+ into a multisampled Framebuffer object that is later blitted into a non
+ multisampled Framebuffer object to be then renderer through the use of a
+ Qt3D::Scene3DSGNode with premultiplied alpha.
+ */
+
Scene3DItem::Scene3DItem(QQuickItem *parent)
- : QQuickFramebufferObject(parent),
+ : QQuickItem(parent),
m_entity(Q_NULLPTR),
m_aspectEngine(new Qt3D::QAspectEngine(this)),
- m_renderAspect(new Qt3D::QRenderAspect(Qt3D::QRenderAspect::Synchronous))
+ m_renderAspect(new Qt3D::QRenderAspect(Qt3D::QRenderAspect::Synchronous)),
+ m_renderer(Q_NULLPTR)
{
setFlag(QQuickItem::ItemHasContents, true);
setAcceptedMouseButtons(Qt::MouseButtonMask);
@@ -199,22 +389,115 @@ void Scene3DItem::applyRootEntityChange()
m_aspectEngine->setRootEntity(m_entity);
}
-QQuickFramebufferObject::Renderer *Scene3DItem::createRenderer() const
+QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
{
- Scene3DItem *self = const_cast<Scene3DItem*>(this);
- return new FrameBufferObjectRenderer(self, m_aspectEngine, m_renderAspect);
+ // If the node already exists
+ // we delete it and recreate it
+ // as we need to resize the FBO
+ if (node) {
+ delete node;
+ node = Q_NULLPTR;
+ }
+
+ if (!m_renderer) {
+ m_renderer = new Scene3DRenderer(this, m_aspectEngine, m_renderAspect);
+ }
+
+ Scene3DSGNode *fboNode = new Scene3DSGNode();
+ fboNode->setRect(boundingRect());
+ m_renderer->setSGNode(fboNode);
+ return fboNode;
}
-QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData)
+void Scene3DRenderer::setSGNode(Scene3DSGNode *node) Q_DECL_NOEXCEPT
{
- if (!node) {
- node = QQuickFramebufferObject::updatePaintNode(node, nodeData);
- QSGSimpleTextureNode *textureNode = static_cast<QSGSimpleTextureNode *>(node);
- if (textureNode)
- textureNode->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
- return node;
+ m_node = node;
+ if (m_texture)
+ node->setTexture(m_texture);
+}
+
+void Scene3DRenderer::render()
+{
+ if (!m_item || !m_item->window())
+ return ;
+
+ if (m_aspectEngine->rootEntity() != m_item->entity())
+ scheduleRootEntityChange();
+
+ ContextSaver saver;
+
+ if (!m_multisampledFBO)
+ m_multisampledFBO = createMultisampledFramebufferObject(m_item->boundingRect().size().toSize());
+
+ if (!m_finalFBO) {
+ m_finalFBO = createFramebufferObject(m_item->boundingRect().size().toSize());
+ m_texture = m_item->window()->createTextureFromId(m_finalFBO->texture(), m_finalFBO->size());
+ m_node->setTexture(m_texture);
+ }
+
+ // Bind FBO
+ m_multisampledFBO->bind();
+ // Render Qt3D Scene
+ m_renderAspect->renderSynchronous();
+
+ // We may have called doneCurrent() so restore the context.
+ saver.context()->makeCurrent(saver.surface());
+
+ // Blit multisampled FBO with non multisampled FBO with texture attachment
+ QOpenGLFramebufferObject::blitFramebuffer(m_finalFBO, m_multisampledFBO);
+
+ // Restore QtQuick FBO
+ m_multisampledFBO->bindDefault();
+
+ // Reset the state used by the Qt Quick scenegraph to avoid any
+ // interference when rendering the rest of the UI.
+ m_item->window()->resetOpenGLState();
+
+ // Mark material as dirty to request a new frame
+ m_node->markDirty(QSGNode::DirtyMaterial);
+
+ // Request next frame
+ m_item->window()->update();
+}
+
+inline static bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
+void Scene3DSGMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ Scene3DSGMaterial *tx = static_cast<Scene3DSGMaterial *>(newEffect);
+ Scene3DSGMaterial *oldTx = static_cast<Scene3DSGMaterial *>(oldEffect);
+
+ QSGTexture *t = tx->texture();
+
+ bool npotSupported = const_cast<QOpenGLContext *>(state.context())
+ ->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
+ if (!npotSupported) {
+ QSize size = t->textureSize();
+ const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ if (isNpot) {
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ }
}
- return QQuickFramebufferObject::updatePaintNode(node, nodeData);
+
+ if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
+ t->bind();
+ else
+ t->updateBindOptions();
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrixId, state.combinedMatrix());
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_opacityId, state.opacity());
}
+
QT_END_NAMESPACE
+
+#include "scene3ditem.moc"
diff --git a/src/quick3d/imports/scene3d/scene3ditem.h b/src/quick3d/imports/scene3d/scene3ditem.h
index 95c54ac25..7506892c9 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.h
+++ b/src/quick3d/imports/scene3d/scene3ditem.h
@@ -37,7 +37,7 @@
#ifndef SCENE3DITEM_H
#define SCENE3DITEM_H
-#include <QQuickFramebufferObject>
+#include <QQuickItem>
QT_BEGIN_NAMESPACE
@@ -48,7 +48,9 @@ namespace Qt3D
class QRenderAspect;
}
-class Scene3DItem : public QQuickFramebufferObject
+class Scene3DRenderer;
+
+class Scene3DItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(Qt3D::QEntity* entity READ entity WRITE setEntity NOTIFY entityChanged)
@@ -73,7 +75,6 @@ private Q_SLOTS:
void applyRootEntityChange();
private:
- Renderer *createRenderer() const Q_DECL_OVERRIDE;
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *nodeData) Q_DECL_OVERRIDE;
QStringList m_aspects;
@@ -81,6 +82,7 @@ private:
Qt3D::QAspectEngine *m_aspectEngine;
Qt3D::QRenderAspect *m_renderAspect;
+ Scene3DRenderer *m_renderer;
};
QT_END_NAMESPACE
diff --git a/src/quick3d/quick3d/items/quick3dentityloader.cpp b/src/quick3d/quick3d/items/quick3dentityloader.cpp
index 224c6e6d2..639451861 100644
--- a/src/quick3d/quick3d/items/quick3dentityloader.cpp
+++ b/src/quick3d/quick3d/items/quick3dentityloader.cpp
@@ -85,6 +85,11 @@ Quick3DEntityLoader::Quick3DEntityLoader(QNode *parent)
{
}
+Quick3DEntityLoader::~Quick3DEntityLoader()
+{
+ QNode::cleanup();
+}
+
/*!
\qmlproperty QtQml::QtObject Qt3D::EntityLoader::entity
\readonly
@@ -148,7 +153,7 @@ void Quick3DEntityLoaderPrivate::clear()
}
if (m_entity) {
- m_entity->setParent(Q_NULLPTR);
+ m_entity->setParent(Q_NODE_NULLPTR);
delete m_entity;
m_entity = Q_NULLPTR;
}
diff --git a/src/quick3d/quick3d/items/quick3dentityloader.h b/src/quick3d/quick3d/items/quick3dentityloader.h
index 66fa31644..0280ca3aa 100644
--- a/src/quick3d/quick3d/items/quick3dentityloader.h
+++ b/src/quick3d/quick3d/items/quick3dentityloader.h
@@ -62,6 +62,7 @@ class QT3DQUICKSHARED_EXPORT Quick3DEntityLoader : public QEntity
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
public:
explicit Quick3DEntityLoader(QNode *parent = 0);
+ ~Quick3DEntityLoader();
QObject *entity() const;
diff --git a/src/quick3d/quick3d/items/quick3dnode.cpp b/src/quick3d/quick3d/items/quick3dnode.cpp
index 3a93e0211..c230df447 100644
--- a/src/quick3d/quick3d/items/quick3dnode.cpp
+++ b/src/quick3d/quick3d/items/quick3dnode.cpp
@@ -149,14 +149,18 @@ void Quick3DNode::childAppended(int, QObject *obj)
if (obj->parent() == parentNode)
obj->setParent(0);
// Set after otherwise addChild might not work
- obj->setParent(parentNode);
+ if (QNode *n = qobject_cast<QNode *>(obj))
+ n->setParent(parentNode);
+ else
+ obj->setParent(parentNode);
}
void Quick3DNode::childRemoved(int, QObject *obj)
{
- QNode *node = qobject_cast<Qt3D::QNode *>(obj);
- if (node)
- node->setParent(Q_NULLPTR);
+ if (QNode *n = qobject_cast<QNode *>(obj))
+ n->setParent(Q_NODE_NULLPTR);
+ else
+ obj->setParent(Q_NULLPTR);
}
} // Quick
diff --git a/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp b/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
index 43c5b0f9e..c6257ec58 100644
--- a/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
+++ b/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
@@ -119,7 +119,7 @@ void Quick3DNodeInstantiatorPrivate::_q_createdItem(int idx, QObject *item)
Q_Q(Quick3DNodeInstantiator);
if (m_objects.contains(item)) //Case when it was created synchronously in regenerate
return;
- item->setParent(q);
+ static_cast<QNode *>(item)->setParent(q);
m_objects.insert(idx, item);
if (m_objects.count() == 1)
q->objectChanged();
@@ -218,6 +218,7 @@ Quick3DNodeInstantiator::Quick3DNodeInstantiator(QNode *parent)
Quick3DNodeInstantiator::~Quick3DNodeInstantiator()
{
+ QNode::cleanup();
}
/*!
diff --git a/src/quick3d/quick3d/items/quick3dtransform.cpp b/src/quick3d/quick3d/items/quick3dtransform.cpp
index 56556d491..3386a2c8a 100644
--- a/src/quick3d/quick3d/items/quick3dtransform.cpp
+++ b/src/quick3d/quick3d/items/quick3dtransform.cpp
@@ -52,7 +52,6 @@ Quick3DTransform::Quick3DTransform(QObject *parent)
: QObject(parent)
{
Q_ASSERT(qobject_cast<Qt3D::QTransform *>(parent) != Q_NULLPTR);
- QObject::connect(parent, SIGNAL(transformsChanged()), this, SIGNAL(transformsChanged()));
}
/*!
diff --git a/src/quick3d/quick3d/items/quick3dtransform.h b/src/quick3d/quick3d/items/quick3dtransform.h
index 57d350203..2d7f9aa10 100644
--- a/src/quick3d/quick3d/items/quick3dtransform.h
+++ b/src/quick3d/quick3d/items/quick3dtransform.h
@@ -53,7 +53,7 @@ namespace Quick {
class QT3DQUICKSHARED_EXPORT Quick3DTransform : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQmlListProperty<Qt3D::QAbstractTransform> transforms READ transformList NOTIFY transformsChanged)
+ Q_PROPERTY(QQmlListProperty<Qt3D::QAbstractTransform> transforms READ transformList)
Q_CLASSINFO("DefaultProperty", "transforms")
public:
explicit Quick3DTransform(QObject *parent = 0);
@@ -61,9 +61,6 @@ public:
inline QTransform *parentTransform() const { return qobject_cast<Qt3D::QTransform *>(parent()); }
-Q_SIGNALS:
- void transformsChanged();
-
private:
static void qmlAppendTransform(QQmlListProperty<Qt3D::QAbstractTransform> *list, Qt3D::QAbstractTransform *bar);
static QAbstractTransform* transformAt(QQmlListProperty<Qt3D::QAbstractTransform> *list, int index);
diff --git a/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.cpp b/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.cpp
index 2b636a319..b5f0bc8de 100644
--- a/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.cpp
+++ b/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.cpp
@@ -60,6 +60,11 @@ Quick3DShaderDataArray::Quick3DShaderDataArray(QNode *parent)
{
}
+Quick3DShaderDataArray::~Quick3DShaderDataArray()
+{
+ QNode::cleanup();
+}
+
QQmlListProperty<QShaderData> Quick3DShaderDataArray::valuesList()
{
return QQmlListProperty<QShaderData>(this, 0,
diff --git a/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.h b/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.h
index 7e663fbb9..c9fa3d58d 100644
--- a/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.h
+++ b/src/quick3d/quick3drenderer/items/quick3dshaderdataarray.h
@@ -62,6 +62,7 @@ class QT3DQUICKRENDERERSHARED_EXPORT Quick3DShaderDataArray : public QNode
Q_CLASSINFO("DefaultProperty", "values")
public:
explicit Quick3DShaderDataArray(QNode *parent = 0);
+ ~Quick3DShaderDataArray();
QQmlListProperty<QShaderData> valuesList();
QList<QShaderData *> values() const;
diff --git a/src/render/backend/qgraphicscontext.cpp b/src/render/backend/qgraphicscontext.cpp
index 01487eb57..f811ab6b8 100644
--- a/src/render/backend/qgraphicscontext.cpp
+++ b/src/render/backend/qgraphicscontext.cpp
@@ -90,6 +90,8 @@ QGraphicsContext::QGraphicsContext()
, m_glHelper(Q_NULLPTR)
, m_activeShader(Q_NULLPTR)
, m_material(Q_NULLPTR)
+ , m_activeFBO(0)
+ , m_defaultFBO(0)
, m_stateSet(Q_NULLPTR)
, m_renderer(Q_NULLPTR)
, m_contextInfo(new QOpenGLFilter())
@@ -129,6 +131,8 @@ void QGraphicsContext::initialize()
|| extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
|| extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
}
+
+ m_defaultFBO = m_gl->defaultFramebufferObject();
qCDebug(Backend) << "VAO support = " << m_supportsVAO;
}
@@ -195,7 +199,7 @@ void QGraphicsContext::setViewport(const QRectF &viewport)
{
m_viewport = viewport;
QSize renderTargetSize;
- if (m_activeFBO != 0) {
+ if (m_activeFBO != m_defaultFBO) {
// For external FBOs we may not have an m_renderTargets entry. Do not call glViewport in that case.
if (m_renderTargetsSize.contains(m_activeFBO))
renderTargetSize = m_renderTargetsSize[m_activeFBO];
@@ -270,16 +274,21 @@ void QGraphicsContext::activateShader(RenderShader *shader)
}
// If RenderShader has no QOpenGLShaderProgram or !shader->isLoaded (shader sources have changed)
- if (!m_shaderHash.contains(shader->dna()) || !shader->isLoaded()) {
+ if (!m_renderShaderHash.contains(shader->dna())) {
QOpenGLShaderProgram *prog = shader->getOrCreateProgram(this);
Q_ASSERT(prog);
- m_shaderHash.insert(shader->dna(), prog);
- qCDebug(Backend) << Q_FUNC_INFO << "shader count =" << m_shaderHash.count();
+ m_renderShaderHash.insert(shader->dna(), shader);
+ qCDebug(Backend) << Q_FUNC_INFO << "shader count =" << m_renderShaderHash.count();
shader->initializeUniforms(m_glHelper->programUniformsAndLocations(prog->programId()));
shader->initializeAttributes(m_glHelper->programAttributesAndLocations(prog->programId()));
if (m_glHelper->supportsFeature(QGraphicsHelperInterface::UniformBufferObject))
shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(prog->programId()));
m_activeShader = Q_NULLPTR;
+ } else if (!shader->isLoaded()) {
+ // Shader program is already in the m_shaderHash but we still need to
+ // ensure that the RenderShader has full knowledge of attributes, uniforms,
+ // and uniform blocks.
+ shader->initialize(*m_renderShaderHash.value(shader->dna()));
}
if (m_activeShader != Q_NULLPTR && m_activeShader->dna() == shader->dna()) {
@@ -287,21 +296,38 @@ void QGraphicsContext::activateShader(RenderShader *shader)
// no op
} else {
m_activeShader = shader;
- QOpenGLShaderProgram* prog = m_shaderHash[shader->dna()];
+ QOpenGLShaderProgram* prog = m_renderShaderHash[shader->dna()]->getOrCreateProgram(this);
prog->bind();
// ensure material uniforms are re-applied
m_material = Q_NULLPTR;
}
}
+/*!
+ * \internal
+ * Returns the QOpenGLShaderProgram matching the ProgramDNA \a dna. If no match
+ * is found, Q_NULLPTR is returned.
+ */
+QOpenGLShaderProgram *QGraphicsContext::containsProgram(const ProgramDNA &dna)
+{
+ RenderShader *renderShader = m_renderShaderHash.value(dna, Q_NULLPTR);
+ if (renderShader)
+ return renderShader->getOrCreateProgram(this);
+ return Q_NULLPTR;
+}
+
void QGraphicsContext::activateRenderTarget(RenderTarget *renderTarget, const AttachmentPack &attachments, GLuint defaultFboId)
{
GLuint fboId = defaultFboId; // Default FBO
if (renderTarget != Q_NULLPTR) {
// New RenderTarget
if (!m_renderTargets.contains(renderTarget->peerUuid())) {
- // The FBO is created and its attachments are set once
- if ((fboId = m_glHelper->createFrameBufferObject()) != 0) {
+ if (m_defaultFBO && fboId == m_defaultFBO) {
+ // this is the default fbo that some platforms create (iOS), we just register it
+ // Insert FBO into hash
+ m_renderTargets.insert(renderTarget->peerUuid(), fboId);
+ } else if ((fboId = m_glHelper->createFrameBufferObject()) != 0) {
+ // The FBO is created and its attachments are set once
// Insert FBO into hash
m_renderTargets.insert(renderTarget->peerUuid(), fboId);
// Bind FBO
@@ -657,7 +683,7 @@ void QGraphicsContext::clearColor(const QColor &color)
/*!
\internal
- \returns a texture unit for a texture, -1 if all texture units are assigned.
+ Returns a texture unit for a texture, -1 if all texture units are assigned.
Tries to use the texture unit with the texture that hasn't been used for the longest time
if the texture happens not to be already pinned on a texture unit.
*/
@@ -707,7 +733,7 @@ void QGraphicsContext::decayTextureScores()
QOpenGLShaderProgram* QGraphicsContext::activeShader()
{
Q_ASSERT(m_activeShader);
- return m_shaderHash[m_activeShader->dna()];
+ return m_activeShader->getOrCreateProgram(this);
}
void QGraphicsContext::setRenderer(Renderer *renderer)
@@ -750,7 +776,7 @@ void QGraphicsContext::setUniforms(QUniformPack &uniforms)
UniformBuffer *ubo = m_renderer->uboManager()->lookupResource(ShaderDataShaderUboKey(blockToUbos[i].m_shaderDataID,
m_activeShader->peerUuid()));
// bind Uniform Block of index ubos[i].m_index to binding point i
- bindUniformBlock(m_shaderHash.value(m_activeShader->dna())->programId(), block.m_index, i);
+ bindUniformBlock(m_activeShader->getOrCreateProgram(this)->programId(), block.m_index, i);
// bind the UBO to the binding point i
// Specs specify that there are at least 14 binding points
diff --git a/src/render/backend/qgraphicscontext_p.h b/src/render/backend/qgraphicscontext_p.h
index 33eaff7a3..e94848b96 100644
--- a/src/render/backend/qgraphicscontext_p.h
+++ b/src/render/backend/qgraphicscontext_p.h
@@ -108,15 +108,13 @@ public:
void doneCurrent();
void activateShader(RenderShader* shader);
- QOpenGLShaderProgram *containsProgram(const ProgramDNA &dna) const
- {
- return m_shaderHash.value(dna, Q_NULLPTR);
- }
+ QOpenGLShaderProgram *containsProgram(const ProgramDNA &dna);
+ GLuint activeFBO() const { return m_activeFBO; }
+ GLuint defaultFBO() const { return m_defaultFBO; }
void activateRenderTarget(RenderTarget *renderTarget, const AttachmentPack &attachments, GLuint defaultFboId);
- RenderMaterial* activeMaterial() const
- { return m_material; }
+ RenderMaterial* activeMaterial() const { return m_material; }
void setActiveMaterial(RenderMaterial* rmat);
@@ -207,7 +205,7 @@ private:
QGraphicsHelperInterface *m_glHelper;
RenderShader *m_activeShader;
- QHash<ProgramDNA, QOpenGLShaderProgram *> m_shaderHash;
+ QHash<ProgramDNA, RenderShader *> m_renderShaderHash;
QHash<BufferPtr, QOpenGLBuffer> m_bufferHash;
QHash<QNodeId, GLuint> m_renderTargets;
QHash<GLuint, QSize> m_renderTargetsSize;
@@ -224,6 +222,7 @@ private:
RenderMaterial* m_material;
QRectF m_viewport;
GLuint m_activeFBO;
+ GLuint m_defaultFBO;
RenderStateSet* m_stateSet;
diff --git a/src/render/backend/qgraphicshelperes2.cpp b/src/render/backend/qgraphicshelperes2.cpp
index 37cac786d..ed327b345 100644
--- a/src/render/backend/qgraphicshelperes2.cpp
+++ b/src/render/backend/qgraphicshelperes2.cpp
@@ -140,15 +140,18 @@ QVector<ShaderUniform> QGraphicsHelperES2::programUniformsAndLocations(GLuint pr
GLint nbrActiveUniforms = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
- uniforms.resize(nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
for (GLint i = 0; i < nbrActiveUniforms; i++) {
ShaderUniform uniform;
- QByteArray uniformName(256, '\0');
+ GLsizei uniformNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveUniform(programId, i, 256, NULL, &uniform.m_size, &uniform.m_type , uniformName.data());
- uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName.constData());
- uniform.m_name = QString::fromUtf8(uniformName);
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
uniforms.append(uniform);
}
return uniforms;
@@ -159,14 +162,18 @@ QVector<ShaderAttribute> QGraphicsHelperES2::programAttributesAndLocations(GLuin
QVector<ShaderAttribute> attributes;
GLint nbrActiveAttributes = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
for (GLint i = 0; i < nbrActiveAttributes; i++) {
ShaderAttribute attribute;
- QByteArray attributeName(256, '\0');
+ GLsizei attributeNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveAttrib(programId, i, 256, NULL, &attribute.m_size, &attribute.m_type , attributeName.data());
- attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName.constData());
- attribute.m_name = QString::fromUtf8(attributeName);
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
attributes.append(attribute);
}
return attributes;
@@ -174,7 +181,7 @@ QVector<ShaderAttribute> QGraphicsHelperES2::programAttributesAndLocations(GLuin
QVector<ShaderUniformBlock> QGraphicsHelperES2::programUniformBlocks(GLuint programId)
{
- Q_UNUSED(programId)
+ Q_UNUSED(programId);
QVector<ShaderUniformBlock> blocks;
qWarning() << "UBO are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
return blocks;
@@ -182,8 +189,8 @@ QVector<ShaderUniformBlock> QGraphicsHelperES2::programUniformBlocks(GLuint prog
void QGraphicsHelperES2::vertexAttribDivisor(GLuint index, GLuint divisor)
{
- Q_UNUSED(index)
- Q_UNUSED(divisor)
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
}
void QGraphicsHelperES2::blendEquation(GLenum mode)
@@ -413,9 +420,9 @@ void QGraphicsHelperES2::bindFragDataLocation(GLuint , const QHash<QString, int>
void QGraphicsHelperES2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
- Q_UNUSED(programId)
- Q_UNUSED(uniformBlockIndex)
- Q_UNUSED(uniformBlockBinding)
+ Q_UNUSED(programId);
+ Q_UNUSED(uniformBlockIndex);
+ Q_UNUSED(uniformBlockBinding);
qWarning() << "UBO are not supported by ES 2.0 (since ES 3.0)";
}
@@ -429,9 +436,9 @@ void QGraphicsHelperES2::bindBufferBase(GLenum target, GLuint index, GLuint buff
void QGraphicsHelperES2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
{
- Q_UNUSED(v)
- Q_UNUSED(description)
- Q_UNUSED(buffer)
+ Q_UNUSED(v);
+ Q_UNUSED(description);
+ Q_UNUSED(buffer);
qWarning() << "UBO are not supported by ES 2.0 (since ES 3.0)";
}
diff --git a/src/render/backend/qgraphicshelpergl2.cpp b/src/render/backend/qgraphicshelpergl2.cpp
index e047e14a7..511f81972 100644
--- a/src/render/backend/qgraphicshelpergl2.cpp
+++ b/src/render/backend/qgraphicshelpergl2.cpp
@@ -57,7 +57,7 @@ QGraphicsHelperGL2::QGraphicsHelperGL2()
void QGraphicsHelperGL2::initializeHelper(QOpenGLContext *context,
QAbstractOpenGLFunctions *functions)
{
- Q_UNUSED(context)
+ Q_UNUSED(context);
m_funcs = static_cast<QOpenGLFunctions_2_0*>(functions);
const bool ok = m_funcs->initializeOpenGLFunctions();
Q_ASSERT(ok);
@@ -133,15 +133,18 @@ QVector<ShaderUniform> QGraphicsHelperGL2::programUniformsAndLocations(GLuint pr
GLint nbrActiveUniforms = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
- uniforms.resize(nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
for (GLint i = 0; i < nbrActiveUniforms; i++) {
ShaderUniform uniform;
- QByteArray uniformName(256, '\0');
+ GLsizei uniformNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveUniform(programId, i, 256, NULL, &uniform.m_size, &uniform.m_type , uniformName.data());
- uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName.constData());
- uniform.m_name = QString::fromUtf8(uniformName);
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
uniforms.append(uniform);
}
return uniforms;
@@ -152,14 +155,18 @@ QVector<ShaderAttribute> QGraphicsHelperGL2::programAttributesAndLocations(GLuin
QVector<ShaderAttribute> attributes;
GLint nbrActiveAttributes = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
for (GLint i = 0; i < nbrActiveAttributes; i++) {
ShaderAttribute attribute;
- QByteArray attributeName(256, '\0');
+ GLsizei attributeNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveAttrib(programId, i, 256, NULL, &attribute.m_size, &attribute.m_type , attributeName.data());
- attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName.constData());
- attribute.m_name = QString::fromUtf8(attributeName);
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
attributes.append(attribute);
}
return attributes;
@@ -167,7 +174,7 @@ QVector<ShaderAttribute> QGraphicsHelperGL2::programAttributesAndLocations(GLuin
QVector<ShaderUniformBlock> QGraphicsHelperGL2::programUniformBlocks(GLuint programId)
{
- Q_UNUSED(programId)
+ Q_UNUSED(programId);
QVector<ShaderUniformBlock> blocks;
qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
return blocks;
@@ -176,8 +183,8 @@ QVector<ShaderUniformBlock> QGraphicsHelperGL2::programUniformBlocks(GLuint prog
void QGraphicsHelperGL2::vertexAttribDivisor(GLuint index,
GLuint divisor)
{
- Q_UNUSED(index)
- Q_UNUSED(divisor)
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
}
void QGraphicsHelperGL2::blendEquation(GLenum mode)
@@ -416,9 +423,9 @@ GLuint QGraphicsHelperGL2::boundFrameBufferObject()
void QGraphicsHelperGL2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
- Q_UNUSED(programId)
- Q_UNUSED(uniformBlockIndex)
- Q_UNUSED(uniformBlockBinding)
+ Q_UNUSED(programId);
+ Q_UNUSED(uniformBlockIndex);
+ Q_UNUSED(uniformBlockBinding);
qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
}
@@ -432,9 +439,9 @@ void QGraphicsHelperGL2::bindBufferBase(GLenum target, GLuint index, GLuint buff
void QGraphicsHelperGL2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
{
- Q_UNUSED(v)
- Q_UNUSED(description)
- Q_UNUSED(buffer)
+ Q_UNUSED(v);
+ Q_UNUSED(description);
+ Q_UNUSED(buffer);
qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
}
diff --git a/src/render/backend/qgraphicshelpergl3.cpp b/src/render/backend/qgraphicshelpergl3.cpp
index 1b0fde66f..3fce36261 100644
--- a/src/render/backend/qgraphicshelpergl3.cpp
+++ b/src/render/backend/qgraphicshelpergl3.cpp
@@ -57,7 +57,7 @@ QGraphicsHelperGL3::QGraphicsHelperGL3()
void QGraphicsHelperGL3::initializeHelper(QOpenGLContext *context,
QAbstractOpenGLFunctions *functions)
{
- Q_UNUSED(context)
+ Q_UNUSED(context);
m_funcs = static_cast<QOpenGLFunctions_3_2_Core*>(functions);
const bool ok = m_funcs->initializeOpenGLFunctions();
Q_ASSERT(ok);
@@ -141,15 +141,18 @@ QVector<ShaderUniform> QGraphicsHelperGL3::programUniformsAndLocations(GLuint pr
GLint nbrActiveUniforms = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
- uniforms.resize(nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
for (GLint i = 0; i < nbrActiveUniforms; i++) {
ShaderUniform uniform;
- QByteArray uniformName(256, '\0');
+ GLsizei uniformNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveUniform(programId, i, 256, NULL, &uniform.m_size, &uniform.m_type , uniformName.data());
- uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName.constData());
- uniform.m_name = QString::fromUtf8(uniformName);
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
@@ -169,14 +172,18 @@ QVector<ShaderAttribute> QGraphicsHelperGL3::programAttributesAndLocations(GLuin
QVector<ShaderAttribute> attributes;
GLint nbrActiveAttributes = 0;
m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
for (GLint i = 0; i < nbrActiveAttributes; i++) {
ShaderAttribute attribute;
- QByteArray attributeName(256, '\0');
+ GLsizei attributeNameLength = 0;
// Size is 1 for scalar and more for struct or arrays
// Type is the GL Type
- m_funcs->glGetActiveAttrib(programId, i, 256, NULL, &attribute.m_size, &attribute.m_type , attributeName.data());
- attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName.constData());
- attribute.m_name = QString::fromUtf8(attributeName);
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
attributes.append(attribute);
}
return attributes;
@@ -204,8 +211,8 @@ QVector<ShaderUniformBlock> QGraphicsHelperGL3::programUniformBlocks(GLuint prog
void QGraphicsHelperGL3::vertexAttribDivisor(GLuint index, GLuint divisor)
{
- Q_UNUSED(index)
- Q_UNUSED(divisor)
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
}
void QGraphicsHelperGL3::blendEquation(GLenum mode)
diff --git a/src/render/backend/qrenderaspect.cpp b/src/render/backend/qrenderaspect.cpp
index 3a98ccc07..536c612ef 100644
--- a/src/render/backend/qrenderaspect.cpp
+++ b/src/render/backend/qrenderaspect.cpp
@@ -313,7 +313,7 @@ void QRenderAspect::sceneNodeAdded(QSceneChangePtr &e)
QNodePtr nodePtr = propertyChange->value().value<QNodePtr>();
QNode *n = nodePtr.data();
QNodeVisitor visitor;
- visitor.traverse(n, this, &QRenderAspect::visitNode, &QRenderAspect::visitNode);
+ visitor.traverse(n, this, &QRenderAspect::visitNode);
}
void QRenderAspect::sceneNodeRemoved(QSceneChangePtr &e)
@@ -335,7 +335,7 @@ void QRenderAspect::setRootEntity(QEntity *rootObject)
// setSceneGraphRoot is synchronized using the Renderer's mutex
Q_D(QRenderAspect);
QNodeVisitor visitor;
- visitor.traverse(rootObject, this, &QRenderAspect::visitNode, &QRenderAspect::visitNode);
+ visitor.traverse(rootObject, this, &QRenderAspect::visitNode);
d->m_renderer->setSceneGraphRoot(d->m_renderer->renderNodesManager()->lookupResource(rootObject->id()));
}
diff --git a/src/render/backend/renderentity.cpp b/src/render/backend/renderentity.cpp
index dbc39c40f..ffe78efb9 100644
--- a/src/render/backend/renderentity.cpp
+++ b/src/render/backend/renderentity.cpp
@@ -131,7 +131,7 @@ void RenderEntity::setHandle(HEntity handle)
void RenderEntity::updateFromPeer(QNode *peer)
{
QEntity *entity = static_cast<QEntity *>(peer);
- QEntity *parentEntity = entity->parentEntity();
+ const QNodeId parentEntityId = entity->parentEntityId();
m_objectName = peer->objectName();
m_worldTransform = m_renderer->worldMatrixManager()->getOrAcquireHandle(peerUuid());
@@ -147,8 +147,11 @@ void RenderEntity::updateFromPeer(QNode *peer)
Q_FOREACH (QComponent *comp, entity->components())
addComponent(comp);
- if (parentEntity != Q_NULLPTR)
- setParentHandle(m_renderer->renderNodesManager()->lookupHandle(parentEntity->id()));
+ if (!parentEntityId.isNull()) {
+ setParentHandle(m_renderer->renderNodesManager()->lookupHandle(parentEntityId));
+ } else {
+ qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "No parent entity found for Entity" << peerUuid();
+ }
}
void RenderEntity::sceneChangeEvent(const QSceneChangePtr &e)
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 7a889910c..8ff541286 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -570,8 +570,8 @@ void Renderer::submitRenderViews(int maxFrameCount)
timer.start();
// We might not want to render on the default FBO
- bool defaultFboIdValid = false;
- GLuint defaultFboId = 0;
+ bool boundFboIdValid = false;
+ GLuint boundFboId = 0;
while (m_renderQueues->queuedFrames() > 0)
{
@@ -604,9 +604,9 @@ void Renderer::submitRenderViews(int maxFrameCount)
break;
}
- if (!defaultFboIdValid) {
- defaultFboIdValid = true;
- defaultFboId = m_graphicsContext->boundFrameBufferObject();
+ if (!boundFboIdValid) {
+ boundFboIdValid = true;
+ boundFboId = m_graphicsContext->boundFrameBufferObject();
}
// Reset state to the default state
@@ -622,7 +622,7 @@ void Renderer::submitRenderViews(int maxFrameCount)
// Set RenderTarget ...
// Activate RenderTarget
m_graphicsContext->activateRenderTarget(m_renderTargetManager->data(renderViews[i]->renderTargetHandle()),
- renderViews[i]->attachmentPack(), defaultFboId);
+ renderViews[i]->attachmentPack(), boundFboId);
// Set clear color if different
if (previousClearColor != renderViews[i]->clearColor()) {
@@ -643,7 +643,7 @@ void Renderer::submitRenderViews(int maxFrameCount)
frameElapsed = timer.elapsed();
}
- m_graphicsContext->endDrawing(defaultFboId == 0);
+ m_graphicsContext->endDrawing(boundFboId == m_graphicsContext->defaultFBO());
// Let the Aspect Thread get a look in if it needs to change the surface
locker.unlock();
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 75256a4f7..9f7df1e70 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -258,8 +258,6 @@ private:
UBOManager *m_uboManager;
TextureImageManager *m_textureImageManager;
- QTimer *m_frameTimer;
-
RenderQueues *m_renderQueues;
QScopedPointer<RenderThread> m_renderThread;
diff --git a/src/render/backend/rendershader.cpp b/src/render/backend/rendershader.cpp
index b8c01f334..43d4a0ccf 100644
--- a/src/render/backend/rendershader.cpp
+++ b/src/render/backend/rendershader.cpp
@@ -375,6 +375,26 @@ void RenderShader::initializeUniformBlocks(const QVector<ShaderUniformBlock> &un
}
}
+/*!
+ \internal
+ Initializes this RenderShader's state relating to attributes, global block uniforms and
+ and named uniform blocks by copying these details from \a other.
+*/
+void RenderShader::initialize(const RenderShader &other)
+{
+ Q_ASSERT(m_dna == other.m_dna);
+ m_program = other.m_program;
+ m_uniformsNames = other.m_uniformsNames;
+ m_uniforms = other.m_uniforms;
+ m_attributesNames = other.m_attributesNames;
+ m_attributes = other.m_attributes;
+ m_uniformBlockNames = other.m_uniformBlockNames;
+ m_uniformBlocks = other.m_uniformBlocks;
+ m_blockIndexToShaderUniforms = other.m_blockIndexToShaderUniforms;
+ m_fragOutputs = other.m_fragOutputs;
+ m_isLoaded = other.m_isLoaded;
+}
+
} // namespace Render
} // namespace Qt3D
diff --git a/src/render/backend/rendershader_p.h b/src/render/backend/rendershader_p.h
index 18bd6b232..becbb1317 100644
--- a/src/render/backend/rendershader_p.h
+++ b/src/render/backend/rendershader_p.h
@@ -117,6 +117,9 @@ private:
void initializeUniforms(const QVector<ShaderUniform> &uniformsDescription);
void initializeAttributes(const QVector<ShaderAttribute> &attributesDescription);
void initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformBlockDescription);
+
+ void initialize(const RenderShader &other);
+
QOpenGLShaderProgram *getOrCreateProgram(QGraphicsContext *ctx);
friend class QGraphicsContext;
};
diff --git a/src/render/backend/rendertexture.cpp b/src/render/backend/rendertexture.cpp
index 92a1960d9..27719e562 100644
--- a/src/render/backend/rendertexture.cpp
+++ b/src/render/backend/rendertexture.cpp
@@ -241,6 +241,9 @@ QOpenGLTexture *RenderTexture::buildGLTexture()
case QOpenGLTexture::RGB8_UNorm:
format = QAbstractTextureProvider::RGBFormat;
break;
+ case QOpenGLTexture::DepthFormat:
+ format = QAbstractTextureProvider::DepthFormat;
+ break;
default:
qWarning() << Q_FUNC_INFO << "could not find a matching OpenGL ES 2.0 unsized texture format";
break;
diff --git a/src/render/backend/renderthread.cpp b/src/render/backend/renderthread.cpp
index 625f6190e..a75e3bc68 100644
--- a/src/render/backend/renderthread.cpp
+++ b/src/render/backend/renderthread.cpp
@@ -50,8 +50,9 @@ namespace Qt3D {
namespace Render {
RenderThread::RenderThread(Renderer *renderer)
- : QThread()
- , m_renderer(renderer)
+ : QThread(),
+ m_renderer(renderer),
+ m_semaphore(0)
{
}
@@ -59,19 +60,16 @@ RenderThread::RenderThread(Renderer *renderer)
void RenderThread::waitForStart( Priority priority )
{
qCDebug(Render::Backend) << "Starting Render thread and then going to sleep until it is ready for us...";
- QMutexLocker lock(&m_mutex);
start( priority );
- m_waitCondition.wait( &m_mutex );
+ m_semaphore.acquire();
qCDebug(Render::Backend) << "Render thread is now ready & calling thread is now awake again";
}
// RenderThread context
void RenderThread::run()
{
- m_mutex.lock();
-
- // We lock the renderer's mutex here before unlocking the render thread mutex
- // and returning control to the calling thread (the Aspect Thread). This is
+ // We lock the renderer's mutex here before returning control to the calling
+ // thread (the Aspect Thread). This is
// to ensure that the Renderer's initialize() waitCondition is reached before
// other threads try to wake it up. This is guaranteed by having the
// Renderer::setSurface() function try to lock the renderer's mutex too.
@@ -81,8 +79,7 @@ void RenderThread::run()
// Now we have ensured we will reach the wait condition as described above,
// return control to the aspect thread that created us.
- m_waitCondition.wakeOne();
- m_mutex.unlock();
+ m_semaphore.release();
// This call to Renderer::initialize() waits for a surface to be set on the
// renderer in the context of the Aspect Thread
diff --git a/src/render/backend/renderthread_p.h b/src/render/backend/renderthread_p.h
index 171a817bb..c704881b9 100644
--- a/src/render/backend/renderthread_p.h
+++ b/src/render/backend/renderthread_p.h
@@ -39,8 +39,7 @@
#include <QThread>
-#include <QMutex>
-#include <QWaitCondition>
+#include <QtCore/QSemaphore>
QT_BEGIN_NAMESPACE
@@ -64,9 +63,8 @@ protected:
void run();
private:
- QMutex m_mutex;
- QWaitCondition m_waitCondition;
Renderer* m_renderer;
+ QSemaphore m_semaphore;
};
} // Render
diff --git a/src/render/backend/scenemanager.cpp b/src/render/backend/scenemanager.cpp
index 32611c4d0..fb49a2410 100644
--- a/src/render/backend/scenemanager.cpp
+++ b/src/render/backend/scenemanager.cpp
@@ -52,7 +52,14 @@ SceneManager::SceneManager() : QResourceManager<RenderScene,
void SceneManager::addSceneData(const QUrl &source, const QNodeId &sceneUuid)
{
- m_pendingJobs.append(LoadSceneJobPtr(new LoadSceneJob(source, sceneUuid)));
+ LoadSceneJobPtr newJob(new LoadSceneJob(source, sceneUuid));
+
+ // We cannot run two jobs that use the same scene loader plugin
+ // in two different threads at the same time
+ if (!m_pendingJobs.isEmpty())
+ newJob->addDependency(m_pendingJobs.last());
+
+ m_pendingJobs.append(newJob);
}
QVector<LoadSceneJobPtr> SceneManager::pendingSceneLoaderJobs()
diff --git a/src/render/defaults/qskyboxentity.cpp b/src/render/defaults/qskyboxentity.cpp
index 457fa746a..a2a1e0eaf 100644
--- a/src/render/defaults/qskyboxentity.cpp
+++ b/src/render/defaults/qskyboxentity.cpp
@@ -212,6 +212,7 @@ QSkyboxEntity::QSkyboxEntity(QNode *parent)
QSkyboxEntity::~QSkyboxEntity()
{
+ QNode::cleanup();
}
/*!
diff --git a/src/render/frontend/framegraph-components/qcameraselector.cpp b/src/render/frontend/framegraph-components/qcameraselector.cpp
index b4dc83727..5085adf45 100644
--- a/src/render/frontend/framegraph-components/qcameraselector.cpp
+++ b/src/render/frontend/framegraph-components/qcameraselector.cpp
@@ -76,6 +76,11 @@ QCameraSelector::QCameraSelector(Qt3D::QNode *parent)
: QFrameGraphNode(*new QCameraSelectorPrivate, parent)
{}
+QCameraSelector::~QCameraSelector()
+{
+ QNode::cleanup();
+}
+
void QCameraSelector::setCamera(QEntity *camera)
{
Q_D(QCameraSelector);
diff --git a/src/render/frontend/framegraph-components/qcameraselector.h b/src/render/frontend/framegraph-components/qcameraselector.h
index 023f5f13a..4811d7a96 100644
--- a/src/render/frontend/framegraph-components/qcameraselector.h
+++ b/src/render/frontend/framegraph-components/qcameraselector.h
@@ -54,6 +54,7 @@ class QT3DRENDERERSHARED_EXPORT QCameraSelector : public QFrameGraphNode
public:
explicit QCameraSelector(QNode *parent = 0);
+ ~QCameraSelector();
void setCamera(QEntity *camera);
QEntity *camera() const;
diff --git a/src/render/frontend/framegraph-components/qclearbuffer.cpp b/src/render/frontend/framegraph-components/qclearbuffer.cpp
index e6fc20a84..f40a80883 100644
--- a/src/render/frontend/framegraph-components/qclearbuffer.cpp
+++ b/src/render/frontend/framegraph-components/qclearbuffer.cpp
@@ -64,6 +64,11 @@ QClearBuffer::QClearBuffer(QNode *parent)
{
}
+QClearBuffer::~QClearBuffer()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QClearBuffer::QClearBuffer(QClearBufferPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qclearbuffer.h b/src/render/frontend/framegraph-components/qclearbuffer.h
index 1559511d3..782ec6ef4 100644
--- a/src/render/frontend/framegraph-components/qclearbuffer.h
+++ b/src/render/frontend/framegraph-components/qclearbuffer.h
@@ -51,6 +51,7 @@ class QT3DRENDERERSHARED_EXPORT QClearBuffer : public QFrameGraphNode
Q_PROPERTY(BufferType buffers READ buffers WRITE setBuffers NOTIFY buffersChanged)
public:
explicit QClearBuffer(QNode *parent = 0);
+ ~QClearBuffer();
enum BufferType {
None = 0,
diff --git a/src/render/frontend/framegraph-components/qframegraph.cpp b/src/render/frontend/framegraph-components/qframegraph.cpp
index 08636cc0f..2bb0712ce 100644
--- a/src/render/frontend/framegraph-components/qframegraph.cpp
+++ b/src/render/frontend/framegraph-components/qframegraph.cpp
@@ -98,6 +98,11 @@ QFrameGraph::QFrameGraph(QNode *parent)
{
}
+QFrameGraph::~QFrameGraph()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QFrameGraph::QFrameGraph(QFrameGraphPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qframegraph.h b/src/render/frontend/framegraph-components/qframegraph.h
index c8a88996b..9dc3fbc76 100644
--- a/src/render/frontend/framegraph-components/qframegraph.h
+++ b/src/render/frontend/framegraph-components/qframegraph.h
@@ -47,7 +47,7 @@ namespace Qt3D {
class QFrameGraphPrivate;
class QFrameGraphNode;
-class QT3DRENDERERSHARED_EXPORT QFrameGraph : public Qt3D::QComponent
+class QT3DRENDERERSHARED_EXPORT QFrameGraph : public QComponent
{
Q_OBJECT
// Note : The full namespace has to be used to define the property
@@ -57,6 +57,7 @@ class QT3DRENDERERSHARED_EXPORT QFrameGraph : public Qt3D::QComponent
public:
explicit QFrameGraph(QNode *parent = 0);
+ ~QFrameGraph();
QFrameGraphNode *activeFrameGraph() const;
void setActiveFrameGraph(QFrameGraphNode *activeFrameGraph);
diff --git a/src/render/frontend/framegraph-components/qframegraphnode.cpp b/src/render/frontend/framegraph-components/qframegraphnode.cpp
index 56232a40a..78d50782a 100644
--- a/src/render/frontend/framegraph-components/qframegraphnode.cpp
+++ b/src/render/frontend/framegraph-components/qframegraphnode.cpp
@@ -80,6 +80,11 @@ QFrameGraphNode::QFrameGraphNode(QNode *parent)
{
}
+QFrameGraphNode::~QFrameGraphNode()
+{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QFrameGraphNode subclass didn't call QNode::cleanup in its destructor");
+}
+
/*!
Returns a pointer to the parent.
*/
diff --git a/src/render/frontend/framegraph-components/qframegraphnode.h b/src/render/frontend/framegraph-components/qframegraphnode.h
index 7fb5e4dfa..b13fd6eb6 100644
--- a/src/render/frontend/framegraph-components/qframegraphnode.h
+++ b/src/render/frontend/framegraph-components/qframegraphnode.h
@@ -53,6 +53,7 @@ class QT3DRENDERERSHARED_EXPORT QFrameGraphNode : public QNode
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
public:
explicit QFrameGraphNode(QNode *parent = 0);
+ ~QFrameGraphNode();
QFrameGraphNode *parentFrameGraphNode() const;
diff --git a/src/render/frontend/framegraph-components/qframegraphselector.cpp b/src/render/frontend/framegraph-components/qframegraphselector.cpp
index 20fba808c..6b912f974 100644
--- a/src/render/frontend/framegraph-components/qframegraphselector.cpp
+++ b/src/render/frontend/framegraph-components/qframegraphselector.cpp
@@ -71,6 +71,7 @@ QFrameGraphSelector::QFrameGraphSelector(QNode *parent)
QFrameGraphSelector::~QFrameGraphSelector()
{
+ QNode::cleanup();
}
/*!
diff --git a/src/render/frontend/framegraph-components/qlayerfilter.cpp b/src/render/frontend/framegraph-components/qlayerfilter.cpp
index fd51419ca..b15147f28 100644
--- a/src/render/frontend/framegraph-components/qlayerfilter.cpp
+++ b/src/render/frontend/framegraph-components/qlayerfilter.cpp
@@ -86,6 +86,11 @@ QLayerFilter::QLayerFilter(QNode *parent)
{
}
+QLayerFilter::~QLayerFilter()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QLayerFilter::QLayerFilter(QLayerFilterPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qlayerfilter.h b/src/render/frontend/framegraph-components/qlayerfilter.h
index 817e01bd6..83b97b1e0 100644
--- a/src/render/frontend/framegraph-components/qlayerfilter.h
+++ b/src/render/frontend/framegraph-components/qlayerfilter.h
@@ -52,6 +52,7 @@ class QT3DRENDERERSHARED_EXPORT QLayerFilter : public QFrameGraphNode
Q_PROPERTY(QStringList layers READ layers WRITE setLayers NOTIFY layersChanged)
public:
explicit QLayerFilter(QNode *parent = 0);
+ ~QLayerFilter();
void setLayers(const QStringList &layers);
QStringList layers() const;
diff --git a/src/render/frontend/framegraph-components/qnodraw.cpp b/src/render/frontend/framegraph-components/qnodraw.cpp
index 0c11f5b34..ed695145d 100644
--- a/src/render/frontend/framegraph-components/qnodraw.cpp
+++ b/src/render/frontend/framegraph-components/qnodraw.cpp
@@ -62,6 +62,7 @@ QNoDraw::QNoDraw(QNode *parent)
QNoDraw::~QNoDraw()
{
+ QNode::cleanup();
}
} // Qt3D
diff --git a/src/render/frontend/framegraph-components/qrenderpassfilter.cpp b/src/render/frontend/framegraph-components/qrenderpassfilter.cpp
index 85fddc7b6..a0c845b00 100644
--- a/src/render/frontend/framegraph-components/qrenderpassfilter.cpp
+++ b/src/render/frontend/framegraph-components/qrenderpassfilter.cpp
@@ -54,6 +54,11 @@ QRenderPassFilter::QRenderPassFilter(QNode *parent)
: QFrameGraphNode(*new QRenderPassFilterPrivate, parent)
{}
+QRenderPassFilter::~QRenderPassFilter()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QRenderPassFilter::QRenderPassFilter(QRenderPassFilterPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qrenderpassfilter.h b/src/render/frontend/framegraph-components/qrenderpassfilter.h
index 27848d19f..e0f71a78b 100644
--- a/src/render/frontend/framegraph-components/qrenderpassfilter.h
+++ b/src/render/frontend/framegraph-components/qrenderpassfilter.h
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QRenderPassFilter : public QFrameGraphNode
public:
explicit QRenderPassFilter(QNode *parent = 0);
+ ~QRenderPassFilter();
QList<QAnnotation *> includes() const;
void addInclude(QAnnotation *criterion);
diff --git a/src/render/frontend/framegraph-components/qrendertargetselector.cpp b/src/render/frontend/framegraph-components/qrendertargetselector.cpp
index fd5a58640..069252766 100644
--- a/src/render/frontend/framegraph-components/qrendertargetselector.cpp
+++ b/src/render/frontend/framegraph-components/qrendertargetselector.cpp
@@ -69,6 +69,11 @@ QRenderTargetSelector::QRenderTargetSelector(QNode *parent)
{
}
+QRenderTargetSelector::~QRenderTargetSelector()
+{
+ QNode::cleanup();
+}
+
void QRenderTargetSelector::setTarget(QRenderTarget *target)
{
Q_D(QRenderTargetSelector);
diff --git a/src/render/frontend/framegraph-components/qrendertargetselector.h b/src/render/frontend/framegraph-components/qrendertargetselector.h
index f98f05f8f..33529d4d9 100644
--- a/src/render/frontend/framegraph-components/qrendertargetselector.h
+++ b/src/render/frontend/framegraph-components/qrendertargetselector.h
@@ -55,6 +55,7 @@ class QT3DRENDERERSHARED_EXPORT QRenderTargetSelector : public QFrameGraphNode
Q_PROPERTY(Qt3D::QRenderTarget *target READ target WRITE setTarget NOTIFY targetChanged)
public:
explicit QRenderTargetSelector(QNode *parent = 0);
+ ~QRenderTargetSelector();
void setTarget(QRenderTarget *target);
QRenderTarget *target() const;
diff --git a/src/render/frontend/framegraph-components/qsortcriterion.cpp b/src/render/frontend/framegraph-components/qsortcriterion.cpp
index 85b5cd9fa..a85608df9 100644
--- a/src/render/frontend/framegraph-components/qsortcriterion.cpp
+++ b/src/render/frontend/framegraph-components/qsortcriterion.cpp
@@ -64,6 +64,11 @@ QSortCriterion::QSortCriterion(QNode *parent)
{
}
+QSortCriterion::~QSortCriterion()
+{
+ QNode::cleanup();
+}
+
QSortCriterion::SortType QSortCriterion::sort() const
{
Q_D(const QSortCriterion);
diff --git a/src/render/frontend/framegraph-components/qsortcriterion.h b/src/render/frontend/framegraph-components/qsortcriterion.h
index 2e24c0ee4..81371aa7e 100644
--- a/src/render/frontend/framegraph-components/qsortcriterion.h
+++ b/src/render/frontend/framegraph-components/qsortcriterion.h
@@ -52,6 +52,7 @@ class QT3DRENDERERSHARED_EXPORT QSortCriterion : public QNode
Q_PROPERTY(Qt3D::QSortCriterion::SortType sort READ sort WRITE setSort NOTIFY sortChanged)
public:
explicit QSortCriterion(QNode *parent = 0);
+ ~QSortCriterion();
enum SortType {
StateChangeCost = (1 << 0),
diff --git a/src/render/frontend/framegraph-components/qsortmethod.cpp b/src/render/frontend/framegraph-components/qsortmethod.cpp
index 4f70dd7cd..824c8d198 100644
--- a/src/render/frontend/framegraph-components/qsortmethod.cpp
+++ b/src/render/frontend/framegraph-components/qsortmethod.cpp
@@ -66,6 +66,11 @@ QSortMethod::QSortMethod(QNode *parent)
{
}
+QSortMethod::~QSortMethod()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QSortMethod::QSortMethod(QSortMethodPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qsortmethod.h b/src/render/frontend/framegraph-components/qsortmethod.h
index 5cb37c9dc..c0f17fdd4 100644
--- a/src/render/frontend/framegraph-components/qsortmethod.h
+++ b/src/render/frontend/framegraph-components/qsortmethod.h
@@ -52,6 +52,7 @@ class QT3DRENDERERSHARED_EXPORT QSortMethod : public QFrameGraphNode
public:
explicit QSortMethod(QNode *parent = 0);
+ ~QSortMethod();
void addCriterion(QSortCriterion *criterion);
void removeCriterion(QSortCriterion *criterion);
diff --git a/src/render/frontend/framegraph-components/qstateset.cpp b/src/render/frontend/framegraph-components/qstateset.cpp
index 6f5149b87..602876d5d 100644
--- a/src/render/frontend/framegraph-components/qstateset.cpp
+++ b/src/render/frontend/framegraph-components/qstateset.cpp
@@ -79,6 +79,7 @@ QStateSet::QStateSet(QStateSetPrivate &dd, QNode *parent)
QStateSet::~QStateSet()
{
+ QNode::cleanup();
}
void QStateSet::copy(const QNode *ref)
diff --git a/src/render/frontend/framegraph-components/qtechniquefilter.cpp b/src/render/frontend/framegraph-components/qtechniquefilter.cpp
index 7d93b40be..1a1efc553 100644
--- a/src/render/frontend/framegraph-components/qtechniquefilter.cpp
+++ b/src/render/frontend/framegraph-components/qtechniquefilter.cpp
@@ -68,6 +68,11 @@ QTechniqueFilter::QTechniqueFilter(QNode *parent)
{
}
+QTechniqueFilter::~QTechniqueFilter()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QTechniqueFilter::QTechniqueFilter(QTechniqueFilterPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qtechniquefilter.h b/src/render/frontend/framegraph-components/qtechniquefilter.h
index b7ddcb9b4..eae99d231 100644
--- a/src/render/frontend/framegraph-components/qtechniquefilter.h
+++ b/src/render/frontend/framegraph-components/qtechniquefilter.h
@@ -53,6 +53,7 @@ class QT3DRENDERERSHARED_EXPORT QTechniqueFilter : public QFrameGraphNode
Q_OBJECT
public:
explicit QTechniqueFilter(QNode *parent = 0);
+ ~QTechniqueFilter();
QList<QAnnotation *> criteria() const;
void addRequirement(QAnnotation *criterion);
diff --git a/src/render/frontend/framegraph-components/qviewport.cpp b/src/render/frontend/framegraph-components/qviewport.cpp
index 49ae81231..6197dcd52 100644
--- a/src/render/frontend/framegraph-components/qviewport.cpp
+++ b/src/render/frontend/framegraph-components/qviewport.cpp
@@ -65,6 +65,11 @@ QViewport::QViewport(QNode *parent)
{
}
+QViewport::~QViewport()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QViewport::QViewport(QViewportPrivate &dd, QNode *parent)
: QFrameGraphNode(dd, parent)
diff --git a/src/render/frontend/framegraph-components/qviewport.h b/src/render/frontend/framegraph-components/qviewport.h
index 73e3c5f1a..7390e85ae 100644
--- a/src/render/frontend/framegraph-components/qviewport.h
+++ b/src/render/frontend/framegraph-components/qviewport.h
@@ -55,6 +55,7 @@ class QT3DRENDERERSHARED_EXPORT QViewport : public QFrameGraphNode
public:
explicit QViewport(QNode *parent = 0);
+ ~QViewport();
QRectF rect() const;
void setRect(const QRectF& rect);
diff --git a/src/render/frontend/qabstractmesh.cpp b/src/render/frontend/qabstractmesh.cpp
index a4d6a163e..c81f5aa8f 100644
--- a/src/render/frontend/qabstractmesh.cpp
+++ b/src/render/frontend/qabstractmesh.cpp
@@ -76,6 +76,11 @@ QAbstractMesh::QAbstractMesh(QNode *parent)
{
}
+QAbstractMesh::~QAbstractMesh()
+{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QAbstractMesh subclass didn't call QNode::cleanup in its destructor");
+}
+
/*! \internal */
QAbstractMesh::QAbstractMesh(QAbstractMeshPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/render/frontend/qabstractmesh.h b/src/render/frontend/qabstractmesh.h
index 1be436846..f90e05dff 100644
--- a/src/render/frontend/qabstractmesh.h
+++ b/src/render/frontend/qabstractmesh.h
@@ -65,7 +65,8 @@ class QT3DRENDERERSHARED_EXPORT QAbstractMesh : public QComponent
Q_OBJECT
public:
- QAbstractMesh(QNode *parent = 0);
+ explicit QAbstractMesh(QNode *parent = 0);
+ ~QAbstractMesh();
void update();
diff --git a/src/render/frontend/qabstractsceneloader.cpp b/src/render/frontend/qabstractsceneloader.cpp
index f919a489e..4108b81e5 100644
--- a/src/render/frontend/qabstractsceneloader.cpp
+++ b/src/render/frontend/qabstractsceneloader.cpp
@@ -69,6 +69,11 @@ QAbstractSceneLoader::QAbstractSceneLoader(QNode *parent)
{
}
+QAbstractSceneLoader::~QAbstractSceneLoader()
+{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QAbstractSceneLoader subclass didn't call QNode::cleanup in its destructor");
+}
+
void QAbstractSceneLoader::copy(const QNode *ref)
{
const QAbstractSceneLoader *s = static_cast<const QAbstractSceneLoader*>(ref);
diff --git a/src/render/frontend/qabstractsceneloader.h b/src/render/frontend/qabstractsceneloader.h
index 14aa02e2a..368eb4bc6 100644
--- a/src/render/frontend/qabstractsceneloader.h
+++ b/src/render/frontend/qabstractsceneloader.h
@@ -57,6 +57,7 @@ class QT3DRENDERERSHARED_EXPORT QAbstractSceneLoader : public QComponent
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
explicit QAbstractSceneLoader(QNode *parent = 0);
+ ~QAbstractSceneLoader();
enum Status {
Loading = 0,
diff --git a/src/render/frontend/qabstracttextureimage.cpp b/src/render/frontend/qabstracttextureimage.cpp
index 451b275b0..f02cf1002 100644
--- a/src/render/frontend/qabstracttextureimage.cpp
+++ b/src/render/frontend/qabstracttextureimage.cpp
@@ -89,6 +89,7 @@ QAbstractTextureImage::QAbstractTextureImage(QNode *parent)
*/
QAbstractTextureImage::~QAbstractTextureImage()
{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QAbstractTextureImage subclass didn't call QNode::cleanup in its destructor");
}
diff --git a/src/render/frontend/qabstracttextureprovider.cpp b/src/render/frontend/qabstracttextureprovider.cpp
index 75ea92f03..8aaa302b2 100644
--- a/src/render/frontend/qabstracttextureprovider.cpp
+++ b/src/render/frontend/qabstracttextureprovider.cpp
@@ -120,6 +120,9 @@ QAbstractTextureProvider::QAbstractTextureProvider(QAbstractTextureProviderPriva
QAbstractTextureProvider::~QAbstractTextureProvider()
{
+ // The subclasses of QAbstractTextureProvider are only there to set the type on a QTextureProvider
+ // QNode::cleanup needs to be handled here and not in the subclasses.
+ QNode::cleanup();
}
/*!
diff --git a/src/render/frontend/qabstracttextureprovider.h b/src/render/frontend/qabstracttextureprovider.h
index dd82bd776..4121e01c4 100644
--- a/src/render/frontend/qabstracttextureprovider.h
+++ b/src/render/frontend/qabstracttextureprovider.h
@@ -250,7 +250,6 @@ public:
~QAbstractTextureProvider();
-
Target target() const;
void setFormat(TextureFormat format);
diff --git a/src/render/frontend/qalphacoverage.cpp b/src/render/frontend/qalphacoverage.cpp
index c96980d90..2075b2704 100644
--- a/src/render/frontend/qalphacoverage.cpp
+++ b/src/render/frontend/qalphacoverage.cpp
@@ -57,6 +57,11 @@ QAlphaCoverage::QAlphaCoverage(QNode *parent)
{
}
+QAlphaCoverage::~QAlphaCoverage()
+{
+ QNode::cleanup();
+}
+
} // Qt3D
QT_END_NAMESPACE
diff --git a/src/render/frontend/qalphacoverage.h b/src/render/frontend/qalphacoverage.h
index 9f92bd15d..7ac1c7765 100644
--- a/src/render/frontend/qalphacoverage.h
+++ b/src/render/frontend/qalphacoverage.h
@@ -51,6 +51,7 @@ class QT3DRENDERERSHARED_EXPORT QAlphaCoverage : public QRenderState
Q_OBJECT
public:
explicit QAlphaCoverage(QNode *parent = 0);
+ ~QAlphaCoverage();
private:
Q_DECLARE_PRIVATE(QAlphaCoverage)
diff --git a/src/render/frontend/qalphatest.cpp b/src/render/frontend/qalphatest.cpp
index 1b0498392..1fb92db3a 100644
--- a/src/render/frontend/qalphatest.cpp
+++ b/src/render/frontend/qalphatest.cpp
@@ -64,6 +64,11 @@ QAlphaTest::QAlphaTest(QNode *parent)
{
}
+QAlphaTest::~QAlphaTest()
+{
+ QNode::cleanup();
+}
+
void QAlphaTest::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qalphatest.h b/src/render/frontend/qalphatest.h
index 645677762..4e8e86ca6 100644
--- a/src/render/frontend/qalphatest.h
+++ b/src/render/frontend/qalphatest.h
@@ -66,6 +66,7 @@ public:
Q_ENUM(AlphaFunc)
explicit QAlphaTest(QNode *parent = 0);
+ ~QAlphaTest();
AlphaFunc func() const;
void setFunc(AlphaFunc func);
diff --git a/src/render/frontend/qannotation.cpp b/src/render/frontend/qannotation.cpp
index 567447a47..1c0a2c583 100644
--- a/src/render/frontend/qannotation.cpp
+++ b/src/render/frontend/qannotation.cpp
@@ -88,6 +88,11 @@ QAnnotation::QAnnotation(QNode *parent)
{
}
+QAnnotation::~QAnnotation()
+{
+ QNode::cleanup();
+}
+
void QAnnotation::setValue(const QVariant &value)
{
Q_D(QAnnotation);
diff --git a/src/render/frontend/qannotation.h b/src/render/frontend/qannotation.h
index 47c82d418..f38402fb3 100644
--- a/src/render/frontend/qannotation.h
+++ b/src/render/frontend/qannotation.h
@@ -54,6 +54,7 @@ class QT3DRENDERERSHARED_EXPORT QAnnotation : public QNode
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
explicit QAnnotation(QNode *parent = 0);
+ ~QAnnotation();
void setValue(const QVariant &value);
void setName(const QString &customType);
diff --git a/src/render/frontend/qblendequation.cpp b/src/render/frontend/qblendequation.cpp
index 9960bb2b8..1631a74dd 100644
--- a/src/render/frontend/qblendequation.cpp
+++ b/src/render/frontend/qblendequation.cpp
@@ -68,6 +68,11 @@ QBlendEquation::QBlendEquation(QNode *parent)
{
}
+QBlendEquation::~QBlendEquation()
+{
+ QNode::cleanup();
+}
+
QBlendEquation::BlendMode QBlendEquation::mode() const
{
Q_D(const QBlendEquation);
diff --git a/src/render/frontend/qblendequation.h b/src/render/frontend/qblendequation.h
index 280df3155..78df85183 100644
--- a/src/render/frontend/qblendequation.h
+++ b/src/render/frontend/qblendequation.h
@@ -63,6 +63,7 @@ public:
Q_ENUM(BlendMode)
explicit QBlendEquation(QNode *parent = 0);
+ ~QBlendEquation();
BlendMode mode() const;
void setMode(BlendMode mode);
diff --git a/src/render/frontend/qblendstate.cpp b/src/render/frontend/qblendstate.cpp
index 479249fb0..e3344c0cc 100644
--- a/src/render/frontend/qblendstate.cpp
+++ b/src/render/frontend/qblendstate.cpp
@@ -88,6 +88,11 @@ QBlendState::QBlendState(QNode *parent)
{
}
+QBlendState::~QBlendState()
+{
+ QNode::cleanup();
+}
+
/*! \fn void QBlendState::copy(const QNode *ref)
\internal
Copies \a ref into this object.
diff --git a/src/render/frontend/qblendstate.h b/src/render/frontend/qblendstate.h
index 2217944f3..7f3901f22 100644
--- a/src/render/frontend/qblendstate.h
+++ b/src/render/frontend/qblendstate.h
@@ -81,6 +81,7 @@ public:
Q_ENUM(Blending)
explicit QBlendState(QNode *parent = 0);
+ ~QBlendState();
Blending srcRGB() const;
void setSrcRGB(Blending srcRGB);
diff --git a/src/render/frontend/qcolormask.cpp b/src/render/frontend/qcolormask.cpp
index 923f16b4d..7d7c79481 100644
--- a/src/render/frontend/qcolormask.cpp
+++ b/src/render/frontend/qcolormask.cpp
@@ -83,6 +83,7 @@ QColorMask::QColorMask(QNode *parent)
QColorMask::~QColorMask()
{
+ QNode::cleanup();
}
bool QColorMask::isRed() const
diff --git a/src/render/frontend/qcuboidmesh.cpp b/src/render/frontend/qcuboidmesh.cpp
index 26238f8b6..665eafd7a 100644
--- a/src/render/frontend/qcuboidmesh.cpp
+++ b/src/render/frontend/qcuboidmesh.cpp
@@ -81,6 +81,11 @@ QCuboidMesh::QCuboidMesh(QNode *parent)
update();
}
+QCuboidMesh::~QCuboidMesh()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QCuboidMesh::QCuboidMesh(QCuboidMeshPrivate &dd, QNode *parent)
: QAbstractMesh(dd, parent)
diff --git a/src/render/frontend/qcuboidmesh.h b/src/render/frontend/qcuboidmesh.h
index 46fdad0e0..4568ddf3a 100644
--- a/src/render/frontend/qcuboidmesh.h
+++ b/src/render/frontend/qcuboidmesh.h
@@ -47,7 +47,7 @@ namespace Qt3D {
class QCuboidMeshPrivate;
-class QT3DRENDERERSHARED_EXPORT QCuboidMesh : public Qt3D::QAbstractMesh
+class QT3DRENDERERSHARED_EXPORT QCuboidMesh : public QAbstractMesh
{
Q_OBJECT
@@ -60,6 +60,7 @@ class QT3DRENDERERSHARED_EXPORT QCuboidMesh : public Qt3D::QAbstractMesh
public:
explicit QCuboidMesh(QNode *parent = 0);
+ ~QCuboidMesh();
void setXExtent(float xExtent);
float xExtent() const;
diff --git a/src/render/frontend/qcullface.cpp b/src/render/frontend/qcullface.cpp
index cf2303ee6..4bd885c34 100644
--- a/src/render/frontend/qcullface.cpp
+++ b/src/render/frontend/qcullface.cpp
@@ -62,6 +62,11 @@ QCullFace::QCullFace(QNode *parent)
{
}
+QCullFace::~QCullFace()
+{
+ QNode::cleanup();
+}
+
void QCullFace::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qcullface.h b/src/render/frontend/qcullface.h
index 3321e0cd0..646df0811 100644
--- a/src/render/frontend/qcullface.h
+++ b/src/render/frontend/qcullface.h
@@ -63,6 +63,7 @@ public:
Q_ENUM(CullingMode)
explicit QCullFace(QNode *parent = 0);
+ ~QCullFace();
CullingMode mode() const;
void setMode(CullingMode mode);
diff --git a/src/render/frontend/qcylindermesh.cpp b/src/render/frontend/qcylindermesh.cpp
index f7fe495c9..c45e68a74 100644
--- a/src/render/frontend/qcylindermesh.cpp
+++ b/src/render/frontend/qcylindermesh.cpp
@@ -99,6 +99,10 @@ QCylinderMesh::QCylinderMesh(QNode *parent)
update();
}
+QCylinderMesh::~QCylinderMesh()
+{
+ QNode::cleanup();
+}
void QCylinderMesh::setRings(int rings)
{
diff --git a/src/render/frontend/qcylindermesh.h b/src/render/frontend/qcylindermesh.h
index e33c835e6..13fc0f864 100644
--- a/src/render/frontend/qcylindermesh.h
+++ b/src/render/frontend/qcylindermesh.h
@@ -47,7 +47,7 @@ namespace Qt3D {
class QCylinderMeshPrivate;
-class QT3DRENDERERSHARED_EXPORT QCylinderMesh : public Qt3D::QAbstractMesh
+class QT3DRENDERERSHARED_EXPORT QCylinderMesh : public QAbstractMesh
{
Q_OBJECT
Q_PROPERTY(int rings READ rings WRITE setRings NOTIFY ringsChanged)
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QCylinderMesh : public Qt3D::QAbstractMesh
Q_PROPERTY(float length READ length WRITE setLength NOTIFY lengthChanged)
public:
explicit QCylinderMesh(QNode *parent = 0);
+ ~QCylinderMesh();
void setRings(int rings);
void setSlices(int slices);
diff --git a/src/render/frontend/qdepthmask.cpp b/src/render/frontend/qdepthmask.cpp
index d3cb3d047..df95b08d7 100644
--- a/src/render/frontend/qdepthmask.cpp
+++ b/src/render/frontend/qdepthmask.cpp
@@ -62,6 +62,11 @@ QDepthMask::QDepthMask(QNode *parent)
{
}
+QDepthMask::~QDepthMask()
+{
+ QNode::cleanup();
+}
+
void QDepthMask::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qdepthmask.h b/src/render/frontend/qdepthmask.h
index af28d6fac..d8f33d651 100644
--- a/src/render/frontend/qdepthmask.h
+++ b/src/render/frontend/qdepthmask.h
@@ -52,6 +52,7 @@ class QT3DRENDERERSHARED_EXPORT QDepthMask : public QRenderState
Q_PROPERTY (bool mask READ mask WRITE setMask NOTIFY maskChanged)
public:
explicit QDepthMask(QNode *parent = 0);
+ ~QDepthMask();
bool mask() const;
void setMask(bool mask);
diff --git a/src/render/frontend/qdepthtest.cpp b/src/render/frontend/qdepthtest.cpp
index 331a5be8d..716544dac 100644
--- a/src/render/frontend/qdepthtest.cpp
+++ b/src/render/frontend/qdepthtest.cpp
@@ -71,6 +71,11 @@ QDepthTest::QDepthTest(QNode *parent)
{
}
+QDepthTest::~QDepthTest()
+{
+ QNode::cleanup();
+}
+
QDepthTest::DepthFunc QDepthTest::func() const
{
Q_D(const QDepthTest);
diff --git a/src/render/frontend/qdepthtest.h b/src/render/frontend/qdepthtest.h
index 07579a4e9..e58dc25e7 100644
--- a/src/render/frontend/qdepthtest.h
+++ b/src/render/frontend/qdepthtest.h
@@ -65,6 +65,7 @@ public:
Q_ENUM(DepthFunc)
explicit QDepthTest(QNode *parent = 0);
+ ~QDepthTest();
DepthFunc func() const;
void setFunc(DepthFunc func);
diff --git a/src/render/frontend/qdithering.cpp b/src/render/frontend/qdithering.cpp
index 6d8bb5fdf..c82272644 100644
--- a/src/render/frontend/qdithering.cpp
+++ b/src/render/frontend/qdithering.cpp
@@ -59,6 +59,11 @@ QDithering::QDithering(QNode *parent)
{
}
+QDithering::~QDithering()
+{
+ QNode::cleanup();
+}
+
} // Qt3D
QT_END_NAMESPACE
diff --git a/src/render/frontend/qdithering.h b/src/render/frontend/qdithering.h
index bd15ee570..5f41dc3d6 100644
--- a/src/render/frontend/qdithering.h
+++ b/src/render/frontend/qdithering.h
@@ -51,6 +51,7 @@ class QT3DRENDERERSHARED_EXPORT QDithering : public QRenderState
Q_OBJECT
public:
explicit QDithering(QNode *parent = 0);
+ ~QDithering();
private:
Q_DECLARE_PRIVATE(QDithering)
diff --git a/src/render/frontend/qeffect.cpp b/src/render/frontend/qeffect.cpp
index 70590ec58..2dc5a5def 100644
--- a/src/render/frontend/qeffect.cpp
+++ b/src/render/frontend/qeffect.cpp
@@ -59,6 +59,11 @@ QEffect::QEffect(QNode *parent)
{
}
+QEffect::~QEffect()
+{
+ QNode::cleanup();
+}
+
void QEffect::copy(const QNode* ref)
{
QNode::copy(ref);
diff --git a/src/render/frontend/qeffect.h b/src/render/frontend/qeffect.h
index 5a395e083..59a34f238 100644
--- a/src/render/frontend/qeffect.h
+++ b/src/render/frontend/qeffect.h
@@ -54,6 +54,7 @@ class QT3DRENDERERSHARED_EXPORT QEffect
Q_OBJECT
public:
explicit QEffect(QNode *parent = 0);
+ ~QEffect();
void addParameter(QParameter *parameter);
void removeParameter(QParameter *parameter);
diff --git a/src/render/frontend/qfrontface.cpp b/src/render/frontend/qfrontface.cpp
index add4f2bab..b56cce619 100644
--- a/src/render/frontend/qfrontface.cpp
+++ b/src/render/frontend/qfrontface.cpp
@@ -62,6 +62,11 @@ QFrontFace::QFrontFace(QNode *parent)
{
}
+QFrontFace::~QFrontFace()
+{
+ QNode::cleanup();
+}
+
void QFrontFace::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qfrontface.h b/src/render/frontend/qfrontface.h
index b1d6eb904..ad52685c4 100644
--- a/src/render/frontend/qfrontface.h
+++ b/src/render/frontend/qfrontface.h
@@ -60,6 +60,7 @@ public:
Q_ENUM(FaceDir)
explicit QFrontFace(QNode *parent = 0);
+ ~QFrontFace();
FaceDir direction() const;
void setDirection(FaceDir direction);
diff --git a/src/render/frontend/qlayer.cpp b/src/render/frontend/qlayer.cpp
index 3540d9351..76a83f992 100644
--- a/src/render/frontend/qlayer.cpp
+++ b/src/render/frontend/qlayer.cpp
@@ -86,6 +86,11 @@ QLayer::QLayer(QNode *parent)
{
}
+QLayer::~QLayer()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QLayer::QLayer(QLayerPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/render/frontend/qlayer.h b/src/render/frontend/qlayer.h
index 1ebf6e8e6..7075eb592 100644
--- a/src/render/frontend/qlayer.h
+++ b/src/render/frontend/qlayer.h
@@ -53,6 +53,7 @@ class QT3DRENDERERSHARED_EXPORT QLayer : public QComponent
Q_PROPERTY(QStringList names READ names WRITE setNames NOTIFY namesChanged)
public:
explicit QLayer(QNode *parent = 0);
+ ~QLayer();
QStringList names() const;
void setNames(const QStringList &names);
diff --git a/src/render/frontend/qmaterial.cpp b/src/render/frontend/qmaterial.cpp
index 54efb6709..d54961de3 100644
--- a/src/render/frontend/qmaterial.cpp
+++ b/src/render/frontend/qmaterial.cpp
@@ -89,6 +89,11 @@ QMaterial::QMaterial(QNode *parent)
{
}
+QMaterial::~QMaterial()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QMaterial::QMaterial(QMaterialPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/render/frontend/qmaterial.h b/src/render/frontend/qmaterial.h
index 24206569b..c8cc89ab5 100644
--- a/src/render/frontend/qmaterial.h
+++ b/src/render/frontend/qmaterial.h
@@ -59,6 +59,7 @@ class QT3DRENDERERSHARED_EXPORT QMaterial : public QComponent
public:
explicit QMaterial(QNode *parent = 0);
+ ~QMaterial();
void setEffect(QEffect *effect);
QEffect *effect() const;
diff --git a/src/render/frontend/qmesh.cpp b/src/render/frontend/qmesh.cpp
index 660fd26e5..882fdb2a1 100644
--- a/src/render/frontend/qmesh.cpp
+++ b/src/render/frontend/qmesh.cpp
@@ -82,6 +82,11 @@ QMesh::QMesh(QNode *parent)
{
}
+QMesh::~QMesh()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QMesh::QMesh(QMeshPrivate &dd, QNode *parent)
: QAbstractMesh(dd, parent)
diff --git a/src/render/frontend/qmesh.h b/src/render/frontend/qmesh.h
index 770fda9e0..d087945e8 100644
--- a/src/render/frontend/qmesh.h
+++ b/src/render/frontend/qmesh.h
@@ -61,6 +61,7 @@ class QT3DRENDERERSHARED_EXPORT QMesh : public QAbstractMesh
public:
explicit QMesh(QNode *parent = 0);
+ ~QMesh();
void setSource(const QUrl &source);
QUrl source() const;
diff --git a/src/render/frontend/qparameter.cpp b/src/render/frontend/qparameter.cpp
index 92cb0d4d8..95d35d5c2 100644
--- a/src/render/frontend/qparameter.cpp
+++ b/src/render/frontend/qparameter.cpp
@@ -78,6 +78,11 @@ QParameter::QParameter(QNode *parent)
{
}
+QParameter::~QParameter()
+{
+ QNode::cleanup();
+}
+
QParameter::QParameter(const QString &name, const QVariant &value, QNode *parent)
: QNode(*new QParameterPrivate, parent)
{
diff --git a/src/render/frontend/qparameter.h b/src/render/frontend/qparameter.h
index 6cb363e21..4ef6f22c4 100644
--- a/src/render/frontend/qparameter.h
+++ b/src/render/frontend/qparameter.h
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QParameter : public QNode
public:
explicit QParameter(QNode *parent = 0);
+ ~QParameter();
QParameter(const QString& name, const QVariant& value, QNode* parent = 0);
QParameter(const QString &name, QAbstractTextureProvider *texture, QNode *parent = 0);
diff --git a/src/render/frontend/qparametermapping.cpp b/src/render/frontend/qparametermapping.cpp
index eff5b93db..057ea0bdd 100644
--- a/src/render/frontend/qparametermapping.cpp
+++ b/src/render/frontend/qparametermapping.cpp
@@ -115,6 +115,11 @@ QParameterMapping::QParameterMapping(const QString &parameterName, const QString
d->m_bindingType = bindingType;
}
+QParameterMapping::~QParameterMapping()
+{
+ QNode::cleanup();
+}
+
/*!
\property Qt3D::QParameterMapping::parameterName
diff --git a/src/render/frontend/qparametermapping.h b/src/render/frontend/qparametermapping.h
index 024b5796a..25fcfc809 100644
--- a/src/render/frontend/qparametermapping.h
+++ b/src/render/frontend/qparametermapping.h
@@ -64,6 +64,7 @@ public:
explicit QParameterMapping(QNode *parent = 0);
QParameterMapping(const QString &parameterName, const QString &shaderParameterName, QParameterMapping::Binding bindingType, QNode *parent = 0);
+ ~QParameterMapping();
void setParameterName(const QString &name);
void setShaderVariableName(const QString &name);
diff --git a/src/render/frontend/qplanemesh.cpp b/src/render/frontend/qplanemesh.cpp
index 6aca02247..1bb06d79d 100644
--- a/src/render/frontend/qplanemesh.cpp
+++ b/src/render/frontend/qplanemesh.cpp
@@ -66,6 +66,11 @@ QPlaneMesh::QPlaneMesh(QNode *parent)
update();
}
+QPlaneMesh::~QPlaneMesh()
+{
+ QNode::cleanup();
+}
+
void QPlaneMesh::copy(const QNode *ref)
{
QAbstractMesh::copy(ref);
diff --git a/src/render/frontend/qplanemesh.h b/src/render/frontend/qplanemesh.h
index 47a3c79bf..c2346a1de 100644
--- a/src/render/frontend/qplanemesh.h
+++ b/src/render/frontend/qplanemesh.h
@@ -47,7 +47,7 @@ namespace Qt3D {
class QPlaneMeshPrivate;
-class QT3DRENDERERSHARED_EXPORT QPlaneMesh : public Qt3D::QAbstractMesh
+class QT3DRENDERERSHARED_EXPORT QPlaneMesh : public QAbstractMesh
{
Q_OBJECT
@@ -57,6 +57,7 @@ class QT3DRENDERERSHARED_EXPORT QPlaneMesh : public Qt3D::QAbstractMesh
public:
explicit QPlaneMesh(QNode *parent = 0);
+ ~QPlaneMesh();
void setWidth(float width);
float width() const;
diff --git a/src/render/frontend/qpolygonoffset.cpp b/src/render/frontend/qpolygonoffset.cpp
index 192e1ef02..d252d4893 100644
--- a/src/render/frontend/qpolygonoffset.cpp
+++ b/src/render/frontend/qpolygonoffset.cpp
@@ -62,6 +62,11 @@ QPolygonOffset::QPolygonOffset(QNode *parent)
{
}
+QPolygonOffset::~QPolygonOffset()
+{
+ QNode::cleanup();
+}
+
float QPolygonOffset::factor() const
{
Q_D(const QPolygonOffset);
diff --git a/src/render/frontend/qpolygonoffset.h b/src/render/frontend/qpolygonoffset.h
index 446febf4f..339437ae1 100644
--- a/src/render/frontend/qpolygonoffset.h
+++ b/src/render/frontend/qpolygonoffset.h
@@ -53,6 +53,7 @@ class QT3DRENDERERSHARED_EXPORT QPolygonOffset : public QRenderState
Q_PROPERTY(float units READ units WRITE setUnits NOTIFY unitsChanged)
public:
explicit QPolygonOffset(QNode *parent = Q_NULLPTR);
+ ~QPolygonOffset();
float factor() const;
void setFactor(float factor);
diff --git a/src/render/frontend/qrenderattachment.cpp b/src/render/frontend/qrenderattachment.cpp
index 8e3fd30af..35db47cc7 100644
--- a/src/render/frontend/qrenderattachment.cpp
+++ b/src/render/frontend/qrenderattachment.cpp
@@ -69,6 +69,11 @@ QRenderAttachment::QRenderAttachment(QNode *parent)
{
}
+QRenderAttachment::~QRenderAttachment()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QRenderAttachment::QRenderAttachment(QRenderAttachmentPrivate &dd, QNode *parent)
: QNode(dd, parent)
diff --git a/src/render/frontend/qrenderattachment.h b/src/render/frontend/qrenderattachment.h
index 5cdd8113b..15706fb1d 100644
--- a/src/render/frontend/qrenderattachment.h
+++ b/src/render/frontend/qrenderattachment.h
@@ -92,6 +92,7 @@ public:
Q_ENUM(CubeMapFace)
explicit QRenderAttachment(QNode *parent = 0);
+ ~QRenderAttachment();
void setType(RenderAttachmentType type);
RenderAttachmentType type() const;
diff --git a/src/render/frontend/qrenderpass.cpp b/src/render/frontend/qrenderpass.cpp
index b6b16dbd6..f6feba36a 100644
--- a/src/render/frontend/qrenderpass.cpp
+++ b/src/render/frontend/qrenderpass.cpp
@@ -77,6 +77,11 @@ QRenderPass::QRenderPass(QNode *parent)
{
}
+QRenderPass::~QRenderPass()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QRenderPass::QRenderPass(QRenderPassPrivate &dd, QNode *parent)
: QNode(dd, parent)
diff --git a/src/render/frontend/qrenderpass.h b/src/render/frontend/qrenderpass.h
index 4b0fe79a9..0a30a90e6 100644
--- a/src/render/frontend/qrenderpass.h
+++ b/src/render/frontend/qrenderpass.h
@@ -65,6 +65,7 @@ class QT3DRENDERERSHARED_EXPORT QRenderPass : public QNode
public:
explicit QRenderPass(QNode *parent = 0);
+ ~QRenderPass();
QString glslNameForParameter(QString paramName) const;
diff --git a/src/render/frontend/qrenderstate.cpp b/src/render/frontend/qrenderstate.cpp
index 1b13b5d03..a572b5e06 100644
--- a/src/render/frontend/qrenderstate.cpp
+++ b/src/render/frontend/qrenderstate.cpp
@@ -52,6 +52,11 @@ QRenderStatePrivate::QRenderStatePrivate(QRenderState::Type type)
{
}
+QRenderState::~QRenderState()
+{
+ Q_ASSERT_X(QNodePrivate::get(this)->m_wasCleanedUp, Q_FUNC_INFO, "QNode::cleanup should have been called by now. A Qt3D::QRenderState subclass didn't call QNode::cleanup in its destructor");
+}
+
QRenderState::Type QRenderState::type() const
{
Q_D(const QRenderState);
diff --git a/src/render/frontend/qrenderstate.h b/src/render/frontend/qrenderstate.h
index 7f428b426..90290f8dc 100644
--- a/src/render/frontend/qrenderstate.h
+++ b/src/render/frontend/qrenderstate.h
@@ -70,10 +70,12 @@ public:
};
Q_ENUM(Type)
+ ~QRenderState();
+
Type type() const;
protected:
- QRenderState(QRenderStatePrivate &dd, QNode *parent = 0);
+ QRenderState(QRenderStatePrivate &dd, QNode *parent = Q_NULLPTR);
private:
Q_DECLARE_PRIVATE(QRenderState)
diff --git a/src/render/frontend/qrendertarget.cpp b/src/render/frontend/qrendertarget.cpp
index 532a803c8..d6297d7de 100644
--- a/src/render/frontend/qrendertarget.cpp
+++ b/src/render/frontend/qrendertarget.cpp
@@ -65,6 +65,11 @@ QRenderTarget::QRenderTarget(QNode *parent)
{
}
+QRenderTarget::~QRenderTarget()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QRenderTarget::QRenderTarget(QRenderTargetPrivate &dd, QNode *parent)
: QComponent(dd, parent)
diff --git a/src/render/frontend/qrendertarget.h b/src/render/frontend/qrendertarget.h
index 169f7c882..8b2860bca 100644
--- a/src/render/frontend/qrendertarget.h
+++ b/src/render/frontend/qrendertarget.h
@@ -52,6 +52,7 @@ class QT3DRENDERERSHARED_EXPORT QRenderTarget : public QComponent
Q_OBJECT
public:
explicit QRenderTarget(QNode *parent = 0);
+ ~QRenderTarget();
void addAttachment(QRenderAttachment *attachment);
void removeAttachment(QRenderAttachment *attachment);
diff --git a/src/render/frontend/qsceneloader.cpp b/src/render/frontend/qsceneloader.cpp
index a5662a694..cc0a25afa 100644
--- a/src/render/frontend/qsceneloader.cpp
+++ b/src/render/frontend/qsceneloader.cpp
@@ -51,6 +51,11 @@ QSceneLoader::QSceneLoader(QNode *parent)
{
}
+QSceneLoader::~QSceneLoader()
+{
+ QNode::cleanup();
+}
+
// Called in main thread
void QSceneLoader::sceneChangeEvent(const QSceneChangePtr &change)
{
diff --git a/src/render/frontend/qsceneloader.h b/src/render/frontend/qsceneloader.h
index 2c3914811..8c0092beb 100644
--- a/src/render/frontend/qsceneloader.h
+++ b/src/render/frontend/qsceneloader.h
@@ -48,6 +48,7 @@ class QT3DRENDERERSHARED_EXPORT QSceneLoader : public Render::QAbstractSceneLoad
Q_OBJECT
public:
explicit QSceneLoader(QNode *parent = 0);
+ ~QSceneLoader();
void sceneChangeEvent(const QSceneChangePtr &change) Q_DECL_OVERRIDE;
protected:
diff --git a/src/render/frontend/qscissortest.cpp b/src/render/frontend/qscissortest.cpp
index 5c8922d5f..79ddd61bd 100644
--- a/src/render/frontend/qscissortest.cpp
+++ b/src/render/frontend/qscissortest.cpp
@@ -69,6 +69,11 @@ QScissorTest::QScissorTest(QNode *parent)
{
}
+QScissorTest::~QScissorTest()
+{
+ QNode::cleanup();
+}
+
void QScissorTest::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qscissortest.h b/src/render/frontend/qscissortest.h
index 136d06807..aae531cd3 100644
--- a/src/render/frontend/qscissortest.h
+++ b/src/render/frontend/qscissortest.h
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QScissorTest : public QRenderState
public:
explicit QScissorTest(QNode *parent = 0);
+ ~QScissorTest();
int left() const;
void setLeft(int left);
diff --git a/src/render/frontend/qshaderdata.cpp b/src/render/frontend/qshaderdata.cpp
index 6caf7e5b1..3ce956750 100644
--- a/src/render/frontend/qshaderdata.cpp
+++ b/src/render/frontend/qshaderdata.cpp
@@ -79,6 +79,11 @@ QShaderData::QShaderData(QNode *parent)
{
}
+QShaderData::~QShaderData()
+{
+ QNode::cleanup();
+}
+
PropertyReaderInterfacePtr QShaderData::propertyReader() const
{
Q_D(const QShaderData);
diff --git a/src/render/frontend/qshaderdata.h b/src/render/frontend/qshaderdata.h
index b38409cfb..681c41439 100644
--- a/src/render/frontend/qshaderdata.h
+++ b/src/render/frontend/qshaderdata.h
@@ -60,6 +60,7 @@ class QT3DRENDERERSHARED_EXPORT QShaderData : public QComponent
Q_OBJECT
public:
explicit QShaderData(QNode *parent = 0);
+ ~QShaderData();
enum TransformType {
ModelToEye = 0,
diff --git a/src/render/frontend/qshaderprogram.cpp b/src/render/frontend/qshaderprogram.cpp
index 7eb170b6b..5787825b8 100644
--- a/src/render/frontend/qshaderprogram.cpp
+++ b/src/render/frontend/qshaderprogram.cpp
@@ -73,6 +73,11 @@ QShaderProgram::QShaderProgram(QNode *parent)
{
}
+QShaderProgram::~QShaderProgram()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent)
: QNode(dd, parent)
diff --git a/src/render/frontend/qshaderprogram.h b/src/render/frontend/qshaderprogram.h
index 94383302b..1fada18b4 100644
--- a/src/render/frontend/qshaderprogram.h
+++ b/src/render/frontend/qshaderprogram.h
@@ -58,6 +58,7 @@ class QT3DRENDERERSHARED_EXPORT QShaderProgram : public QNode
public:
explicit QShaderProgram(QNode *parent = 0);
+ ~QShaderProgram();
enum ShaderType {
Vertex = 0,
diff --git a/src/render/frontend/qspheremesh.cpp b/src/render/frontend/qspheremesh.cpp
index 7e103e8fe..0c6fdbaa3 100644
--- a/src/render/frontend/qspheremesh.cpp
+++ b/src/render/frontend/qspheremesh.cpp
@@ -89,6 +89,11 @@ QSphereMesh::QSphereMesh(QNode *parent)
update();
}
+QSphereMesh::~QSphereMesh()
+{
+ QNode::cleanup();
+}
+
void QSphereMesh::copy(const QNode *ref)
{
QAbstractMesh::copy(ref);
diff --git a/src/render/frontend/qspheremesh.h b/src/render/frontend/qspheremesh.h
index 567b1ed49..317a8fe8c 100644
--- a/src/render/frontend/qspheremesh.h
+++ b/src/render/frontend/qspheremesh.h
@@ -46,7 +46,7 @@ namespace Qt3D {
class QSphereMeshPrivate;
-class QT3DRENDERERSHARED_EXPORT QSphereMesh : public Qt3D::QAbstractMesh
+class QT3DRENDERERSHARED_EXPORT QSphereMesh : public QAbstractMesh
{
Q_OBJECT
Q_PROPERTY(int rings READ rings WRITE setRings NOTIFY ringsChanged)
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QSphereMesh : public Qt3D::QAbstractMesh
public:
explicit QSphereMesh(QNode *parent = 0);
+ ~QSphereMesh();
void setRings(int rings);
void setSlices(int slices);
diff --git a/src/render/frontend/qstenciltest.cpp b/src/render/frontend/qstenciltest.cpp
index 2ff78625d..66b24dfed 100644
--- a/src/render/frontend/qstenciltest.cpp
+++ b/src/render/frontend/qstenciltest.cpp
@@ -67,6 +67,11 @@ QStencilTest::QStencilTest(QNode *parent)
{
}
+QStencilTest::~QStencilTest()
+{
+ QNode::cleanup();
+}
+
void QStencilTest::copy(const QNode *ref)
{
QRenderState::copy(ref);
diff --git a/src/render/frontend/qstenciltest.h b/src/render/frontend/qstenciltest.h
index fdc61037b..d05675a15 100644
--- a/src/render/frontend/qstenciltest.h
+++ b/src/render/frontend/qstenciltest.h
@@ -76,6 +76,7 @@ public:
Q_ENUM(StencilFunc)
explicit QStencilTest(QNode *parent = 0);
+ ~QStencilTest();
uint mask() const;
void setMask(uint mask);
diff --git a/src/render/frontend/qtechnique.cpp b/src/render/frontend/qtechnique.cpp
index dd72ec458..01699715e 100644
--- a/src/render/frontend/qtechnique.cpp
+++ b/src/render/frontend/qtechnique.cpp
@@ -65,6 +65,11 @@ QTechnique::QTechnique(QNode *parent)
QObject::connect(&d->m_openGLFilter, SIGNAL(openGLFilterChanged()), this, SLOT(_q_openGLFilterChanged()));
}
+QTechnique::~QTechnique()
+{
+ QNode::cleanup();
+}
+
/*! \internal */
QTechnique::QTechnique(QTechniquePrivate &dd, QNode *parent)
: QNode(dd, parent)
diff --git a/src/render/frontend/qtechnique.h b/src/render/frontend/qtechnique.h
index d3d2bf559..b1df01dd3 100644
--- a/src/render/frontend/qtechnique.h
+++ b/src/render/frontend/qtechnique.h
@@ -59,6 +59,7 @@ class QT3DRENDERERSHARED_EXPORT QTechnique : public QNode
public:
explicit QTechnique(QNode *parent = 0);
+ ~QTechnique();
void addAnnotation(QAnnotation *criterion);
void removeAnnotation(QAnnotation *criterion);
diff --git a/src/render/frontend/qtextureimage.cpp b/src/render/frontend/qtextureimage.cpp
index cc3725ebc..d052f8b3c 100644
--- a/src/render/frontend/qtextureimage.cpp
+++ b/src/render/frontend/qtextureimage.cpp
@@ -125,6 +125,7 @@ QTextureImage::QTextureImage(QNode *parent)
*/
QTextureImage::~QTextureImage()
{
+ QNode::cleanup();
}
/*!
diff --git a/src/render/frontend/qtextureproviders.cpp b/src/render/frontend/qtextureproviders.cpp
index eabcc2cf7..2852f5c32 100644
--- a/src/render/frontend/qtextureproviders.cpp
+++ b/src/render/frontend/qtextureproviders.cpp
@@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3D {
/*!
- \class QT3D::QTexture1D
+ \class Qt3D::QTexture1D
\since 5.5
\brief A QAbstractTextureProvider with a Target1D target format.
*/
@@ -59,7 +59,7 @@ QTexture1D::~QTexture1D()
}
/*!
- \class QT3D::QTexture1DArray
+ \class Qt3D::QTexture1DArray
\since 5.5
\brief A QAbstractTextureProvider with a Target1DArray target format.
*/
@@ -77,7 +77,7 @@ QTexture1DArray::~QTexture1DArray()
}
/*!
- \class QT3D::QTexture2D
+ \class Qt3D::QTexture2D
\since 5.5
\brief A QAbstractTextureProvider with a Target2D target format.
*/
@@ -95,7 +95,7 @@ QTexture2D::~QTexture2D()
}
/*!
- \class QT3D::QTexture2DArray
+ \class Qt3D::QTexture2DArray
\since 5.5
\brief A QAbstractTextureProvider with a Target2DArray target format.
*/
@@ -114,7 +114,7 @@ QTexture2DArray::~QTexture2DArray()
/*!
- \class QT3D::QTexture3D
+ \class Qt3D::QTexture3D
\since 5.5
\brief A QAbstractTextureProvider with a Target3D target format.
*/
@@ -132,7 +132,7 @@ QTexture3D::~QTexture3D()
}
/*!
- \class QT3D::QTextureCubeMap
+ \class Qt3D::QTextureCubeMap
\since 5.5
\brief A QAbstractTextureProvider with a TargetCubeMap target format.
*/
@@ -150,7 +150,7 @@ QTextureCubeMap::~QTextureCubeMap()
}
/*!
- \class QT3D::QTextureCubeMapArray
+ \class Qt3D::QTextureCubeMapArray
\since 5.5
\brief A QAbstractTextureProvider with a TargetCubeMapArray target format.
*/
@@ -165,10 +165,11 @@ QTextureCubeMapArray::QTextureCubeMapArray(QNode *parent)
QTextureCubeMapArray::~QTextureCubeMapArray()
{
+ QNode::cleanup();
}
/*!
- \class QT3D::QTexture2DMultisample
+ \class Qt3D::QTexture2DMultisample
\since 5.5
\brief A QAbstractTextureProvider with a Target2DMultisample target format.
*/
@@ -186,7 +187,7 @@ QTexture2DMultisample::~QTexture2DMultisample()
}
/*!
- \class QT3D::QTexture2DMultisampleArray
+ \class Qt3D::QTexture2DMultisampleArray
\since 5.5
\brief A QAbstractTextureProvider with a Target2DMultisampleArray target format.
*/
@@ -204,7 +205,7 @@ QTexture2DMultisampleArray::~QTexture2DMultisampleArray()
}
/*!
- \class QT3D::QTextureRectangle
+ \class Qt3D::QTextureRectangle
\since 5.5
\brief A QAbstractTextureProvider with a TargetRectangle target format.
*/
@@ -222,7 +223,7 @@ QTextureRectangle::~QTextureRectangle()
}
/*!
- \class QT3D::QTextureBuffer
+ \class Qt3D::QTextureBuffer
\since 5.5
\brief A QAbstractTextureProvider with a TargetBuffer target format.
*/
diff --git a/src/render/frontend/qtorusmesh.cpp b/src/render/frontend/qtorusmesh.cpp
index 4a975d8d8..d4f3e3ba0 100644
--- a/src/render/frontend/qtorusmesh.cpp
+++ b/src/render/frontend/qtorusmesh.cpp
@@ -98,6 +98,12 @@ QTorusMesh::QTorusMesh(QNode *parent)
{
update();
}
+
+QTorusMesh::~QTorusMesh()
+{
+ QNode::cleanup();
+}
+
void QTorusMesh::setRings(int rings)
{
Q_D(QTorusMesh);
diff --git a/src/render/frontend/qtorusmesh.h b/src/render/frontend/qtorusmesh.h
index 0e0edacd9..a434008b5 100644
--- a/src/render/frontend/qtorusmesh.h
+++ b/src/render/frontend/qtorusmesh.h
@@ -47,7 +47,7 @@ namespace Qt3D {
class QTorusMeshPrivate;
-class QT3DRENDERERSHARED_EXPORT QTorusMesh : public Qt3D::QAbstractMesh
+class QT3DRENDERERSHARED_EXPORT QTorusMesh : public QAbstractMesh
{
Q_OBJECT
Q_PROPERTY(int rings READ rings WRITE setRings NOTIFY ringsChanged)
@@ -56,6 +56,7 @@ class QT3DRENDERERSHARED_EXPORT QTorusMesh : public Qt3D::QAbstractMesh
Q_PROPERTY(float minorRadius READ minorRadius WRITE setMinorRadius NOTIFY minorRadiusChanged)
public:
explicit QTorusMesh(QNode *parent = 0);
+ ~QTorusMesh();
void setRings(int rings);
void setSlices(int slices);
diff --git a/src/render/frontend/qwrapmode.cpp b/src/render/frontend/qwrapmode.cpp
index a040183c4..c5a3a5056 100644
--- a/src/render/frontend/qwrapmode.cpp
+++ b/src/render/frontend/qwrapmode.cpp
@@ -99,7 +99,7 @@ void QTextureWrapMode::setX(WrapMode x)
}
/*!
- \returns the wrap mode of the x dimension.
+ Returns the wrap mode of the x dimension.
*/
QTextureWrapMode::WrapMode QTextureWrapMode::x() const
{
@@ -121,7 +121,7 @@ void QTextureWrapMode::setY(WrapMode y)
}
/*!
- \returns the wrap mode of the y dimension.
+ Returns the wrap mode of the y dimension.
*/
QTextureWrapMode::WrapMode QTextureWrapMode::y() const
{
@@ -143,7 +143,7 @@ void QTextureWrapMode::setZ(WrapMode z)
}
/*!
- \returns the wrap mode of the y dimension.
+ Returns the wrap mode of the y dimension.
*/
QTextureWrapMode::WrapMode QTextureWrapMode::z() const
{
diff --git a/src/render/frontend/qwrapmode.h b/src/render/frontend/qwrapmode.h
index 1fac8d153..e6c1e24f1 100644
--- a/src/render/frontend/qwrapmode.h
+++ b/src/render/frontend/qwrapmode.h
@@ -46,7 +46,7 @@ namespace Qt3D {
class QTextureWrapModePrivate;
-class QT3DRENDERERSHARED_EXPORT QTextureWrapMode: public QObject
+class QT3DRENDERERSHARED_EXPORT QTextureWrapMode : public QObject
{
Q_OBJECT
Q_PROPERTY(WrapMode x READ x WRITE setX NOTIFY xChanged)
diff --git a/src/render/io/gltfparser.cpp b/src/render/io/gltfparser.cpp
index 68aa14826..745180e56 100644
--- a/src/render/io/gltfparser.cpp
+++ b/src/render/io/gltfparser.cpp
@@ -788,8 +788,8 @@ void GLTFParser::processJSONImage( QString id, QJsonObject jsonObj)
void GLTFParser::processJSONTexture( QString id, QJsonObject jsonObj)
{
- Q_UNUSED(id)
- Q_UNUSED(jsonObj)
+ Q_UNUSED(id);
+ Q_UNUSED(jsonObj);
// int target = jsonObj.value(KEY_TARGET).toInt();
// QAbstractTextureProvider* tex = new QAbstractTextureProvider(static_cast<QAbstractTextureProvider::Target>(target));
diff --git a/tests/auto/core/cloning/tst_cloning.cpp b/tests/auto/core/cloning/tst_cloning.cpp
index ad608730d..96e98f334 100644
--- a/tests/auto/core/cloning/tst_cloning.cpp
+++ b/tests/auto/core/cloning/tst_cloning.cpp
@@ -58,6 +58,11 @@ public:
explicit MyQNode(Qt3D::QNode *parent = 0) : QNode(parent)
{}
+ ~MyQNode()
+ {
+ QNode::cleanup();
+ }
+
void setCustomProperty(const QString &s) { m_customProperty = s; }
QString customProperty() const { return m_customProperty; }
@@ -85,17 +90,24 @@ public:
explicit MyQComponent(Qt3D::QNode *parent = 0) : QComponent(parent)
{}
+ ~MyQComponent()
+ {
+ QNode::cleanup();
+ }
+
QT3D_CLONEABLE(MyQComponent)
};
void tst_Cloning::checkEntityCloning()
{
+ // GIVEN
Qt3D::QScene *scene = new Qt3D::QScene();
MyQNode *root = new MyQNode();
Qt3D::QNodePrivate::get(root)->setScene(scene);
Qt3D::QEntity *entity = new Qt3D::QEntity(root);
+ // WHEN
MyQComponent *comp1 = new MyQComponent();
MyQComponent *comp2 = new MyQComponent();
MyQComponent *comp3 = new MyQComponent();
@@ -107,14 +119,16 @@ void tst_Cloning::checkEntityCloning()
root->setCustomProperty(QStringLiteral("Corvette"));
- // VERIFY Initial state
+ // THEN
QVERIFY(root->customProperty() == QStringLiteral("Corvette"));
QCOMPARE(root->children().count(), 1);
QCOMPARE(entity->children().count(), 4);
QCOMPARE(entity->components().count(), 3);
+ //WHEN
MyQNode *cloneRoot = qobject_cast<MyQNode *>(MyQNode::clone(root));
+ // THEN
QCOMPARE(cloneRoot->children().count(), 1);
QCOMPARE(cloneRoot->id(), root->id());
QVERIFY(cloneRoot->customProperty() == root->customProperty());
diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp
index 693488712..05af6b615 100644
--- a/tests/auto/core/nodes/tst_nodes.cpp
+++ b/tests/auto/core/nodes/tst_nodes.cpp
@@ -34,7 +34,7 @@
**
****************************************************************************/
-#include <QtTest/QtTest>
+#include <QtTest/QTest>
#include <Qt3DCore/qnode.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qcomponent.h>
@@ -55,14 +55,31 @@ private slots:
void defaultNodeConstruction();
void defaultComponentConstruction();
void defaultEntityConstrution();
- void appendChildNodesToNode();
- void removingChildNodesFromNode();
+
+ void appendSingleChildNodeToNodeNoSceneExplicitParenting();
+ void appendSingleChildNodeToNodeNoSceneImplicitParenting();
+ void appendMultipleChildNodesToNodeNoScene();
+
+ void appendSingleChildNodeToNodeSceneExplicitParenting();
+ void appendSingleChildNodeToNodeSceneImplicitParenting();
+ void appendMultipleChildNodesToNodeScene();
+
+ void checkParentChangeToNull();
+ void checkParentChangeToOtherParent();
+
+ void removingSingleChildNodeFromNode();
+ void removingMultipleChildNodesFromNode();
+
void appendingChildEntitiesToNode();
void removingChildEntitiesFromNode();
- void appendingComponentsToEntity();
- void removingComponentsFromEntity();
+
+ void appendingComponentToEntity();
+ void appendingParentlessComponentToEntity();
+ void removingComponentFromEntity();
+
void changeCustomProperty();
void checkDestruction();
+ void verifyCopy();
};
class ObserverSpy : public Qt3D::QLockableObserverInterface
@@ -72,17 +89,26 @@ public:
{
public:
ChangeRecord(const Qt3D::QSceneChangePtr &event, bool locked)
- : QPair<Qt3D::QSceneChangePtr, bool>(event, locked) {}
+ : QPair<Qt3D::QSceneChangePtr, bool>(event, locked)
+ {}
+
Qt3D::QSceneChangePtr change() const { return first; }
+
bool wasLocked() const { return second; }
};
ObserverSpy(Qt3D::QNode *node)
: Qt3D::QLockableObserverInterface()
+ , m_node(node)
{
Qt3D::QNodePrivate::get(node)->setArbiter(this);
}
+ ~ObserverSpy()
+ {
+ Qt3D::QNodePrivate::get(m_node)->setArbiter(Q_NULLPTR);
+ }
+
void sceneChangeEventWithLock(const Qt3D::QSceneChangePtr &e) Q_DECL_OVERRIDE
{
events << ChangeRecord(e, true);
@@ -94,6 +120,7 @@ public:
}
QList<ChangeRecord> events;
+ Qt3D::QNode *m_node;
};
class MyQNode : public Qt3D::QNode
@@ -101,9 +128,17 @@ class MyQNode : public Qt3D::QNode
Q_OBJECT
Q_PROPERTY(QString customProperty READ customProperty WRITE setCustomProperty NOTIFY customPropertyChanged)
public:
- explicit MyQNode(Qt3D::QNode *parent = 0) : QNode(parent)
+ explicit MyQNode(Qt3D::QNode *parent = 0)
+ : QNode(parent)
+ , m_scene(Q_NULLPTR)
{}
+ ~MyQNode()
+ {
+ QNode::cleanup();
+ delete m_scene;
+ }
+
void setCustomProperty(const QString &s)
{
if (m_customProperty == s)
@@ -118,6 +153,18 @@ public:
return m_customProperty;
}
+ void assignScene()
+ {
+ if (!m_scene)
+ m_scene = new Qt3D::QScene();
+ Qt3D::QNodePrivate::get(this)->setScene(m_scene);
+ }
+
+ void makeCopyOf(QNode *other)
+ {
+ QNode::copy(other);
+ }
+
signals:
void customPropertyChanged();
@@ -125,7 +172,7 @@ protected:
QT3D_CLONEABLE(MyQNode)
QString m_customProperty;
-
+ Qt3D::QScene *m_scene;
};
class MyQComponent : public Qt3D::QComponent
@@ -135,6 +182,11 @@ public:
explicit MyQComponent(Qt3D::QNode *parent = 0) : QComponent(parent)
{}
+ ~MyQComponent()
+ {
+ QNode::cleanup();
+ }
+
// QNode interface
protected:
QT3D_CLONEABLE(MyQComponent)
@@ -143,334 +195,550 @@ protected:
void tst_Nodes::defaultNodeConstruction()
{
- MyQNode *node = new MyQNode();
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ // THEN
QVERIFY(node != Q_NULLPTR);
QVERIFY(node->children().isEmpty());
- MyQNode *node2 = new MyQNode(node);
- QVERIFY(node2->parent() == node);
+
+ // GIVEN
+ MyQNode *node2 = new MyQNode(node.data());
+
+ // THEN
+ QVERIFY(node2->parent() == node.data());
QVERIFY(!node->children().isEmpty());
QVERIFY(node2->children().isEmpty());
-
- delete node;
}
void tst_Nodes::defaultComponentConstruction()
{
- MyQComponent *comp = new MyQComponent();
- MyQComponent *comp2 = new MyQComponent(comp);
+ // GIVEN
+ QScopedPointer<MyQComponent> comp(new MyQComponent());
+ MyQComponent *comp2 = new MyQComponent(comp.data());
+ // THEN
QVERIFY(comp != Q_NULLPTR);
- QCOMPARE(comp2->parent(), comp);
-
- delete comp;
+ QCOMPARE(comp2->parent(), comp.data());
}
void tst_Nodes::defaultEntityConstrution()
{
- Qt3D::QEntity *entity = new Qt3D::QEntity();
- Qt3D::QEntity *entity2 = new Qt3D::QEntity(entity);
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new Qt3D::QEntity());
+ Qt3D::QEntity *entity2 = new Qt3D::QEntity(entity.data());
+ // THEN
QVERIFY(entity->components().isEmpty());
QVERIFY(entity2->components().isEmpty());
- QCOMPARE(entity2->parent(), entity);
+ QCOMPARE(entity2->parent(), entity.data());
+}
- delete entity;
+void tst_Nodes::appendSingleChildNodeToNodeNoSceneExplicitParenting()
+{
+ // Check nodes added when no scene is set
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() == Q_NULLPTR);
+ // WHEN
+ QScopedPointer<MyQNode> child(new MyQNode());
+
+ // THEN
+ QVERIFY(child->parent() == Q_NULLPTR);
+
+ // WHEN
+ child->setParent(node.data());
+
+ // THEN
+ QVERIFY(child->parent() == node.data());
+ QVERIFY(child->parentNode() == node.data());
+ QCOMPARE(node->children().count(), 1);
+
+ // Events are only sent when a scene is set on the root node
+ QCOMPARE(spy.events.size(), 0);
}
-void tst_Nodes::appendChildNodesToNode()
+void tst_Nodes::appendSingleChildNodeToNodeNoSceneImplicitParenting()
{
- MyQNode *node = new MyQNode();
- ObserverSpy spy(node);
+ // Check nodes added when no scene is set
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() == Q_NULLPTR);
+ // WHEN
+ QScopedPointer<MyQNode> child(new MyQNode(node.data()));
+
+ // THEN
+ QVERIFY(child->parent() == node.data());
+ QVERIFY(child->parentNode() == node.data());
+ QCOMPARE(node->children().count(), 1);
+
+ // Events are only sent when a scene is set on the root node
+ QCOMPARE(spy.events.size(), 0);
+}
+void tst_Nodes::appendMultipleChildNodesToNodeNoScene()
+{
+ // Check multiple nodes added with no scene set
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() == Q_NULLPTR);
+ // WHEN
for (int i = 0; i < 10; i++) {
- MyQNode *child = new MyQNode();
- QVERIFY(child->parent() == Q_NULLPTR);
- child->setParent(node);
- QVERIFY(child->parent() == node);
- QVERIFY(child->parentNode() == node);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
- QCOMPARE(event->type(), Qt3D::NodeCreated);
- QCOMPARE(event->propertyName(), "node");
- Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), child->id());
- QCOMPARE(clone->parentNode()->id(), node->id());
+ // WHEN
+ Qt3D::QNode *child = Q_NULLPTR;
+ if (i % 2 == 0) {
+ child = new MyQNode(node.data());
+ } else {
+ child = new MyQNode();
+ child->setParent(node.data());
+ }
+ // THEN
+ QVERIFY(child->parent() == node.data());
}
- QVERIFY(node->children().count() == 10);
+
+ // THEN
+ QCOMPARE(node->children().count(), 10);
+
+ // Events are only sent when a scene is set on the root node
+ QCOMPARE(spy.events.size(), 0);
+}
+
+void tst_Nodes::appendSingleChildNodeToNodeSceneExplicitParenting()
+{
+ // Check nodes added when scene is set
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+ // WHEN
+ node->assignScene();
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() != Q_NULLPTR);
+
+ // WHEN
+ QScopedPointer<MyQNode> child(new MyQNode());
+
+ // THEN
+ QVERIFY(child->parent() == Q_NULLPTR);
+
+ // WHEN
+ child->setParent(node.data());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(child->parent() == node.data());
+ QVERIFY(child->parentNode() == node.data());
+ QCOMPARE(spy.events.size(), 1);
+ QVERIFY(spy.events.first().wasLocked());
+ QCOMPARE(node->children().count(), 1);
+
+ Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeCreated);
+ QCOMPARE(event->propertyName(), "node");
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QCOMPARE(clone->parentNode()->id(), node->id());
+}
+
+void tst_Nodes::appendSingleChildNodeToNodeSceneImplicitParenting()
+{
+ // Check nodes added when scene is set
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+ // WHEN
+ node->assignScene();
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() != Q_NULLPTR);
+
+ // WHEN
+ QScopedPointer<MyQNode> child(new MyQNode(node.data()));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(child->parent() == node.data());
+ QVERIFY(child->parentNode() == node.data());
+ QVERIFY(Qt3D::QNodePrivate::get(child.data())->scene() != Q_NULLPTR);
+
+ QCOMPARE(spy.events.size(), 1);
+ QVERIFY(spy.events.first().wasLocked());
+ QCOMPARE(node->children().count(), 1);
+
+ Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeCreated);
+ QCOMPARE(event->propertyName(), "node");
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QCOMPARE(clone->parentNode()->id(), node->id());
+}
+
+void tst_Nodes::appendMultipleChildNodesToNodeScene()
+{
+ // Check nodes added when scene is set
+
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ // WHEN
+ node->assignScene();
+ ObserverSpy spy(node.data());
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(node.data())->scene() != Q_NULLPTR);
+
+ // WHEN
for (int i = 0; i < 10; i++) {
- MyQNode *child = new MyQNode();
- child->setParent(node);
- QVERIFY(child->parent() == node);
- QVERIFY(child->parentNode() == node);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ // WHEN
+ Qt3D::QNode *child = Q_NULLPTR;
+ if (i % 2 == 0) {
+ child = new MyQNode(node.data());
+ QCoreApplication::processEvents();
+ QCOMPARE(spy.events.size(), i + 1);
+ } else {
+ child = new MyQNode();
+ child->setParent(node.data());
+ }
+ // THEN
+ QVERIFY(child->parent() == node.data());
+ QVERIFY(Qt3D::QNodePrivate::get(child)->scene() != Q_NULLPTR);
+ }
+ // THEN
+ QCOMPARE(node->children().count(), 10);
+
+ // THEN
+ QCOMPARE(spy.events.size(), 10);
+ Q_FOREACH (const ObserverSpy::ChangeRecord &r, spy.events) {
+
+ QVERIFY(r.wasLocked());
+ Qt3D::QScenePropertyChangePtr event = r.change().dynamicCast<Qt3D::QScenePropertyChange>();
QCOMPARE(event->type(), Qt3D::NodeCreated);
QCOMPARE(event->propertyName(), "node");
Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), child->id());
- QCOMPARE(clone->parentNode()->id(), node->id());
- }
- QVERIFY(node->children().count() == 20);
- Qt3D::QNode *child = qobject_cast<Qt3D::QNode *>(node->children().first());
- QScopedPointer<ObserverSpy> childSpy(new ObserverSpy(child));
- Qt3D::QNode *parent = node;
- for (int i = 0; i < 10; i++) {
- QVERIFY(child->parent() == parent);
- QVERIFY(child->parentNode() == parent);
- (void) new MyQNode(child);
- parent = child;
- child = qobject_cast<Qt3D::QNode *>(child->children().first());
-
- QVERIFY(childSpy->events.isEmpty());
- childSpy.reset(new ObserverSpy(child));
- }
- QVERIFY(node->children().count() == 20);
- child = qobject_cast<Qt3D::QNode *>(node->children().first());
- parent = node;
- for (int i = 0; i < 10; i++) {
- QVERIFY(child->parent() == parent);
- QVERIFY(child->parentNode() == parent);
- QVERIFY(child->children().count() == 1);
- parent = child;
- child = qobject_cast<Qt3D::QNode *>(child->children().first());
+
+ bool found = false;
+ Q_FOREACH (QObject *c, node->children()) {
+ if (clone->id() == qobject_cast<Qt3D::QNode *>(c)->id()) {
+ found = true;
+ QCOMPARE(clone->parentNode()->id(), node->id());
+ break;
+ }
+ }
+ QVERIFY(found);
}
- QVERIFY(child->children().count() == 0);
}
-void tst_Nodes::removingChildNodesFromNode()
+void tst_Nodes::checkParentChangeToNull()
{
- MyQNode *root = new MyQNode();
- Qt3D::QNode *child = new MyQNode();
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
+ ObserverSpy spy(root.data());
- child->setParent(root);
- QVERIFY(root->children().count() == 1);
- child->setParent(Q_NULLPTR);
- QVERIFY(root->children().count() == 0);
+ // WHEN
+ root->assignScene();
+ QScopedPointer<Qt3D::QNode> child(new MyQNode(root.data()));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(child->parent() == root.data());
+ QCOMPARE(spy.events.size(), 1);
+ QCOMPARE(root->children().size(), 1);
+
+ // WHEN
+ spy.events.clear();
+ child->setParent(Q_NODE_NULLPTR);
+
+ // THEN
QVERIFY(child->parent() == Q_NULLPTR);
+ QCOMPARE(root->children().size(), 0);
+ QCOMPARE(spy.events.size(), 1);
- for (int i = 0; i < 10; i++) {
- (void) new MyQNode(root);
- }
- QVERIFY(root->children().count() == 10);
- Q_FOREACH (QObject *c, root->children())
- c->setParent(Q_NULLPTR);
- QVERIFY(root->children().count() == 0);
+ QVERIFY(spy.events.first().wasLocked());
+ Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeAboutToBeDeleted);
+ QCOMPARE(event->propertyName(), "node");
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QVERIFY(!clone->parentNode());
+}
- Qt3D::QNode *firstChild = child;
- for (int i = 0; i < 10; i++) {
- (void) new MyQNode(child);
- child = qobject_cast<Qt3D::QNode *>(child->children().first());
- }
- QVERIFY(root->children().count() == 0);
- firstChild->setParent(root);
+void tst_Nodes::checkParentChangeToOtherParent()
+{
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
+ root->assignScene();
+ ObserverSpy spy(root.data());
+ QScopedPointer<MyQNode> parent1(new MyQNode(root.data()));
+ QScopedPointer<MyQNode> parent2(new MyQNode(root.data()));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(spy.events.size(), 2);
+
+ // WHEN
+ ObserverSpy spyParent1(parent1.data());
+ ObserverSpy spyParent2(parent2.data());
+ QScopedPointer<Qt3D::QNode> child(new MyQNode(parent1.data()));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(child->parent() == parent1.data());
+ QCOMPARE(parent1->children().size(), 1);
+ QCOMPARE(parent2->children().size(), 0);
+ QVERIFY(Qt3D::QNodePrivate::get(child.data())->scene() != Q_NULLPTR);
+ QCOMPARE(spyParent1.events.size(), 1);
+
+ // WHEN
+ spyParent1.events.clear();
+ child->setParent(parent2.data());
+
+ // THEN
+ QVERIFY(child->parent() == parent2.data());
+ QCOMPARE(parent1->children().size(), 0);
+ QCOMPARE(parent2->children().size(), 1);
+ QCOMPARE(spyParent1.events.size(), 1);
+ QCOMPARE(spyParent2.events.size(), 1);
+
+ // CHECK event 1 is a Node Deleted event
+ QVERIFY(spyParent1.events.first().wasLocked());
+ Qt3D::QScenePropertyChangePtr event = spyParent1.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeAboutToBeDeleted);
+ QCOMPARE(event->propertyName(), "node");
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QVERIFY(!clone->parentNode());
+
+ // CHECK event 2 is a Node Added event
+ QVERIFY(spyParent2.events.last().wasLocked());
+ event = spyParent2.events.last().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeCreated);
+ QCOMPARE(event->propertyName(), "node");
+ clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QVERIFY(clone->parentNode());
+}
+
+
+void tst_Nodes::removingSingleChildNodeFromNode()
+{
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
+ QScopedPointer<Qt3D::QNode> child(new MyQNode());
+
+ // WHEN
+ child->setParent(root.data());
+
+ // THEN
QVERIFY(root->children().count() == 1);
+ QVERIFY(child->parentNode() == root.data());
- Qt3D::QNode *parent = child->parentNode();
- for (int i = 0; i < 10; i++) {
- QVERIFY(parent->children().count() == 1);
- QVERIFY(child->parentNode() == parent);
+ // WHEN
+ ObserverSpy spy(root.data());
+ child->setParent(Q_NODE_NULLPTR);
+
+ // THEN
+ QVERIFY(child->parent() == Q_NULLPTR);
+ QVERIFY(root->children().count() == 0);
+
+ QCOMPARE(spy.events.size(), 1);
+ QVERIFY(spy.events.first().wasLocked());
+ Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ QCOMPARE(event->type(), Qt3D::NodeAboutToBeDeleted);
+ QCOMPARE(event->propertyName(), "node");
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), child->id());
+ QVERIFY(!clone->parentNode());
+}
+
+void tst_Nodes::removingMultipleChildNodesFromNode()
+{
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
- ObserverSpy spy(parent);
- child->setParent(Q_NULLPTR);
+ // WHEN
+ root->assignScene();
+ ObserverSpy spy(root.data());
- QVERIFY(child->parent() == Q_NULLPTR);
- QVERIFY(parent->children().count() == 0);
+ // THEN
+ QVERIFY(Qt3D::QNodePrivate::get(root.data())->scene() != Q_NULLPTR);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ // WHEN
+ for (int i = 0; i < 10; i++)
+ (void) new MyQNode(root.data());
+
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(root->children().count(), 10);
+ QCOMPARE(spy.events.size(), 10);
+
+ // WHEN
+ spy.events.clear();
+ Q_FOREACH (QObject *c, root->children())
+ delete c;
+
+ // THEN
+ QVERIFY(root->children().count() == 0);
+ QCOMPARE(spy.events.size(), 10);
+ Q_FOREACH (const ObserverSpy::ChangeRecord &r, spy.events) {
+ QVERIFY(r.wasLocked());
+ Qt3D::QScenePropertyChangePtr event = r.change().dynamicCast<Qt3D::QScenePropertyChange>();
QCOMPARE(event->type(), Qt3D::NodeAboutToBeDeleted);
QCOMPARE(event->propertyName(), "node");
Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), child->id());
QVERIFY(!clone->parentNode());
-
- child = parent;
- parent = parent->parentNode();
}
- QVERIFY(parent == root);
- QVERIFY(parent->children().first() == firstChild);
- QVERIFY(firstChild->children().isEmpty());
}
void tst_Nodes::appendingChildEntitiesToNode()
{
- MyQNode *root = new MyQNode();
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
- Qt3D::QEntity *childEntity = new Qt3D::QEntity(root);
+ // WHEN
+ Qt3D::QEntity *childEntity = new Qt3D::QEntity(root.data());
+ // THEN
QVERIFY(root->children().first() == childEntity);
QVERIFY(childEntity->parentEntity() == Q_NULLPTR);
- QVERIFY(childEntity->parentNode() == root);
+ QVERIFY(childEntity->parentNode() == root.data());
}
void tst_Nodes::removingChildEntitiesFromNode()
{
- MyQNode *root = new MyQNode();
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
- Qt3D::QEntity *childEntity = new Qt3D::QEntity(root);
+ // WHEN
+ Qt3D::QEntity *childEntity = new Qt3D::QEntity(root.data());
+ // THEN
QVERIFY(root->children().first() == childEntity);
QVERIFY(childEntity->parentEntity() == Q_NULLPTR);
- QVERIFY(childEntity->parentNode() == root);
+ QVERIFY(childEntity->parentNode() == root.data());
- childEntity->setParent(Q_NULLPTR);
+ // WHEN
+ childEntity->setParent(Q_NODE_NULLPTR);
+ // THEN
QVERIFY(root->children().isEmpty());
QVERIFY(childEntity->parentNode() == Q_NULLPTR);
QVERIFY(childEntity->parent() == Q_NULLPTR);
}
-void tst_Nodes::appendingComponentsToEntity()
+void tst_Nodes::appendingParentlessComponentToEntity()
{
- MyQNode *root = new MyQNode();
-
- Qt3D::QEntity *entity = new Qt3D::QEntity(root);
-
- MyQComponent *comp1 = new MyQComponent(root);
-
- MyQComponent *comp2 = new MyQComponent(entity);
- MyQComponent *comp3 = new MyQComponent();
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new Qt3D::QEntity());
+ MyQComponent *comp = new MyQComponent();
- QVERIFY(entity->parentNode() == root);
- QVERIFY(root->children().count() == 2);
- QVERIFY(entity->children().count() == 1);
+ // THEN
+ QVERIFY(entity->parentNode() == Q_NULLPTR);
+ QVERIFY(entity->children().count() == 0);
QVERIFY(entity->components().empty());
- QVERIFY(comp3->parentNode() == Q_NULLPTR);
+ QVERIFY(comp->parentNode() == Q_NULLPTR);
- ObserverSpy spy(entity);
+ // WHEN
+ ObserverSpy spy(entity.data());
+ entity->addComponent(comp);
- entity->addComponent(comp1);
+ // THEN
QVERIFY(entity->components().count() == 1);
- QVERIFY(entity->components().first() == comp1);
- QVERIFY(comp1->parentNode() == root);
- QVERIFY(comp2->parentNode() == entity);
- QVERIFY(comp3->parentNode() == Q_NULLPTR);
+ QVERIFY(entity->components().first() == comp);
+ QVERIFY(comp->parentNode() == entity.data());
QCOMPARE(spy.events.size(), 1);
QVERIFY(spy.events.first().wasLocked());
+
+ // Note: since QEntity has no scene in this test case, we only have the
+ // ComponentAdded event In theory we should also get the NodeCreated event
+ // when setting the parent but that doesn't happen since no scene is
+ // actually set on the entity and that QNodePrivate::_q_addChild will
+ // return early in such a case.
+
+ // Check that we received ComponentAdded
Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
QCOMPARE(event->type(), Qt3D::ComponentAdded);
QCOMPARE(event->propertyName(), "component");
Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), comp1->id());
- QVERIFY(!clone->parentNode());
-
- entity->addComponent(comp2);
- QVERIFY(entity->components().count() == 2);
- QVERIFY(entity->components().first() == comp1);
- QVERIFY(entity->components().last() == comp2);
- QVERIFY(comp1->parentNode() == root);
- QVERIFY(comp2->parentNode() == entity);
- QVERIFY(comp3->parentNode() == Q_NULLPTR);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
- QCOMPARE(event->type(), Qt3D::ComponentAdded);
- QCOMPARE(event->propertyName(), "component");
- clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), comp2->id());
+ QCOMPARE(clone->id(), comp->id());
QVERIFY(!clone->parentNode());
+}
- entity->addComponent(comp3);
- QVERIFY(entity->components().count() == 3);
- QVERIFY(entity->components().first() == comp1);
- QVERIFY(entity->components().last() == comp3);
- QVERIFY(comp1->parentNode() == root);
- QVERIFY(comp2->parentNode() == entity);
- QVERIFY(comp3->parentNode() == entity);
- QCOMPARE(entity->children().count(), 2);
+void tst_Nodes::appendingComponentToEntity()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new Qt3D::QEntity());
+ MyQComponent *comp = new MyQComponent(entity.data());
+ QCoreApplication::processEvents();
- QCOMPARE(spy.events.size(), 2);
+ // THEN
+ QVERIFY(entity->parentNode() == Q_NULLPTR);
+ QVERIFY(entity->children().count() == 1);
+ QVERIFY(entity->components().empty());
+ QVERIFY(comp->parentNode() == entity.data());
- QVERIFY(spy.events.first().wasLocked());
- event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
- QCOMPARE(event->type(), Qt3D::NodeCreated);
- QCOMPARE(event->propertyName(), "node");
- clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), comp3->id());
- QCOMPARE(clone->parentNode()->id(), entity->id());
+ // WHEN
+ ObserverSpy spy(entity.data());
+ entity->addComponent(comp);
+ // THEN
+ QVERIFY(entity->components().count() == 1);
+ QVERIFY(entity->components().first() == comp);
+ QVERIFY(comp->parentNode() == entity.data());
+ QCOMPARE(spy.events.size(), 1);
QVERIFY(spy.events.first().wasLocked());
- event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
+ Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
QCOMPARE(event->type(), Qt3D::ComponentAdded);
QCOMPARE(event->propertyName(), "component");
- clone = event->value().value<Qt3D::QNodePtr>();
- QCOMPARE(clone->id(), comp3->id());
+ Qt3D::QNodePtr clone = event->value().value<Qt3D::QNodePtr>();
+ QCOMPARE(clone->id(), comp->id());
QVERIFY(!clone->parentNode());
}
-void tst_Nodes::removingComponentsFromEntity()
+void tst_Nodes::removingComponentFromEntity()
{
- MyQNode *root = new MyQNode();
- Qt3D::QEntity *entity = new Qt3D::QEntity(root);
-
- MyQComponent *comp1 = new MyQComponent(root);
- MyQComponent *comp2 = new MyQComponent(entity);
- MyQComponent *comp3 = new MyQComponent();
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new Qt3D::QEntity());
+ MyQComponent *comp = new MyQComponent();
+ // WHEN
+ entity->addComponent(comp);
- entity->addComponent(comp1);
- entity->addComponent(comp2);
- entity->addComponent(comp3);
- QVERIFY(entity->components().count() == 3);
- QCOMPARE(entity->children().count(), 2);
+ // THEN
+ QVERIFY(entity->components().count() == 1);
+ QCOMPARE(entity->children().count(), 1);
+ QVERIFY(comp->parent() == entity.data());
- ObserverSpy spy(entity);
+ ObserverSpy spy(entity.data());
+ // WHEN
+ entity->removeComponent(comp);
- entity->removeComponent(comp2);
- QVERIFY(entity->components().count() == 2);
- QVERIFY(comp2->parent() == entity);
- QVERIFY(entity->children().count() == 2);
+ // THEN
+ QVERIFY(entity->components().count() == 0);
+ QVERIFY(comp->parent() == entity.data());
+ QVERIFY(entity->children().count() == 1);
QCOMPARE(spy.events.size(), 1);
QVERIFY(spy.events.first().wasLocked());
Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
QCOMPARE(event->type(), Qt3D::ComponentRemoved);
QCOMPARE(event->propertyName(), "componentId");
Qt3D::QNodeId nodeId = event->value().value<Qt3D::QNodeId>();
- QCOMPARE(nodeId, comp2->id());
-
- entity->removeComponent(comp1);
- QVERIFY(entity->components().count() == 1);
- QVERIFY(comp1->parentNode() == root);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
- QCOMPARE(event->type(), Qt3D::ComponentRemoved);
- QCOMPARE(event->propertyName(), "componentId");
- nodeId = event->value().value<Qt3D::QNodeId>();
- QCOMPARE(nodeId, comp1->id());
-
- entity->removeComponent(comp3);
- QVERIFY(entity->components().count() == 0);
- QVERIFY(comp3->parentNode() == entity);
- QCOMPARE(spy.events.size(), 1);
- QVERIFY(spy.events.first().wasLocked());
- event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
- QCOMPARE(event->type(), Qt3D::ComponentRemoved);
- QCOMPARE(event->propertyName(), "componentId");
- nodeId = event->value().value<Qt3D::QNodeId>();
- QCOMPARE(nodeId, comp3->id());
-
- entity->addComponent(comp1);
- entity->addComponent(comp2);
- entity->addComponent(comp3);
- QVERIFY(entity->components().count() == 3);
- QCOMPARE(entity->children().count(), 2);
-
- Q_FOREACH (QObject *c, entity->children())
- c->setParent(Q_NULLPTR);
- QCOMPARE(entity->components().count(), 3);
- QCOMPARE(entity->children().count(), 0);
+ QCOMPARE(nodeId, comp->id());
}
void tst_Nodes::changeCustomProperty()
{
- MyQNode *node = new MyQNode();
- ObserverSpy spy(node);
+ // GIVEN
+ QScopedPointer<MyQNode> node(new MyQNode());
+ ObserverSpy spy(node.data());
+ // WHEN
node->setCustomProperty(QStringLiteral("foo"));
+ // THEN
QCOMPARE(spy.events.size(), 1);
QVERIFY(spy.events.first().wasLocked());
Qt3D::QScenePropertyChangePtr event = spy.events.takeFirst().change().dynamicCast<Qt3D::QScenePropertyChange>();
@@ -481,21 +749,54 @@ void tst_Nodes::changeCustomProperty()
void tst_Nodes::checkDestruction()
{
- MyQNode *root = new MyQNode();
- Qt3D::QEntity *entity = new Qt3D::QEntity(root);
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
+ Qt3D::QEntity *entity = new Qt3D::QEntity(root.data());
MyQComponent *comp1 = new MyQComponent();
MyQComponent *comp2 = new MyQComponent();
MyQComponent *comp3 = new MyQComponent();
-
entity->addComponent(comp1);
entity->addComponent(comp2);
entity->addComponent(comp3);
- delete root;
+ // THEN
+ QVERIFY(!root->children().isEmpty());
+
+ // WHEN
+ delete entity;
+
+ // THEN
+ QVERIFY(root->children().isEmpty());
+}
+
+void tst_Nodes::verifyCopy()
+{
+ // GIVEN
+ QScopedPointer<MyQNode> root(new MyQNode());
+ MyQNode *other1 = new MyQNode();
+ MyQNode *other2 = new MyQNode();
+
+ // THEN
+ QVERIFY(root->id() != other1->id());
+ QVERIFY(root->id() != other2->id());
+ QVERIFY(other1->id() != other2->id());
+
+ // WHEN
+ other1->makeCopyOf(root.data());
+
+ // THEN
+ QVERIFY(root->id() == other1->id());
+ QVERIFY(root->id() != other2->id());
+
+ // WHEN
+ other2->makeCopyOf(other1);
+
+ // THEN
+ QVERIFY(root->id() == other1->id() && root->id() == other2->id());
}
-QTEST_GUILESS_MAIN(tst_Nodes)
+QTEST_MAIN(tst_Nodes)
#include "tst_nodes.moc"
diff --git a/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp b/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
index 5dd229a50..d405358fd 100644
--- a/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
+++ b/tests/auto/core/qchangearbiter/tst_qchangearbiter.cpp
@@ -528,7 +528,7 @@ void tst_QChangeArbiter::unregisterSceneObservers()
QVERIFY(s->lastChange()->type() == Qt3D::NodeCreated);
}
- child->setParent(Q_NULLPTR);
+ child->setParent(Q_NODE_NULLPTR);
arbiter->syncChanges();
Q_FOREACH (tst_SimpleObserver *o, observers) {
diff --git a/tests/auto/core/qentity/tst_qentity.cpp b/tests/auto/core/qentity/tst_qentity.cpp
index 4c207ed3f..2f7ebf314 100644
--- a/tests/auto/core/qentity/tst_qentity.cpp
+++ b/tests/auto/core/qentity/tst_qentity.cpp
@@ -36,6 +36,7 @@
#include <QtTest/QtTest>
#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qcomponent.h>
#include <QtCore/qscopedpointer.h>
using namespace Qt3D;
@@ -50,21 +51,554 @@ public:
private slots:
void constructionDestruction();
- // TODO: Add more entity tests
+ void addComponentSingleParentSingleAggregation();
+ void addComponentSingleParentSeveralAggregations();
+ void addComponentsSeveralParentsSingleAggregations();
+ void addComponentsSeveralParentsSeveralAggregations();
+
+ void removeComponentSingleParentSingleAggregation();
+ void removeComponentSingleParentSeveralAggregations();
+ void removeComponentsSeveralParentsSingleAggreation();
+ void removeComponentsSeveralParentsSeveralAggregations();
+
+ void addSeveralTimesSameComponent();
+ void removeSeveralTimesSameComponent();
+ void verifyCopy();
+};
+
+class MyQComponent : public Qt3D::QComponent
+{
+ Q_OBJECT
+public:
+ explicit MyQComponent(Qt3D::QNode *parent = 0)
+ : QComponent(parent)
+ {}
+
+ ~MyQComponent()
+ {
+ QNode::cleanup();
+ }
+
+protected:
+ QT3D_CLONEABLE(MyQComponent)
+};
+
+
+class MyEntity : public Qt3D::QEntity
+{
+public:
+ explicit MyEntity(Qt3D::QNode *parent = 0)
+ : QEntity(parent)
+ {}
+
+ void makeCopyOf(Qt3D::QEntity *other)
+ {
+ QEntity::copy(other);
+ }
};
void tst_Entity::constructionDestruction()
{
+ // GIVEN
QEntity *entity = Q_NULLPTR;
+ // WHEN
entity = new QEntity;
+ // THEN
QVERIFY(entity != Q_NULLPTR);
delete entity;
+ // GIVEN
QScopedPointer<QEntity> entity2(new QEntity);
+ // WHEN
entity2.reset(Q_NULLPTR);
+ // THEN
+ // this should not crash
}
-QTEST_APPLESS_MAIN(tst_Entity)
+void tst_Entity::addComponentSingleParentSingleAggregation()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new QEntity());
+ MyQComponent *comp = new MyQComponent(entity.data());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 0);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 0);
+
+ // WHEN
+ entity->addComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 1);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 1);
+}
+
+void tst_Entity::addComponentSingleParentSeveralAggregations()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity1.data());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity1.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 3);
+ QCOMPARE(entity2->children().size(), 0);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+
+ // WHEN
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+ entity1->addComponent(comp3);
+
+ entity2->addComponent(comp1);
+ entity2->addComponent(comp2);
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity1.data());
+
+ QCOMPARE(entity1->components().size(), 3);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 3);
+ QCOMPARE(entity2->children().size(), 0);
+
+ QCOMPARE(comp1->entities().size(), 2);
+ QCOMPARE(comp2->entities().size(), 2);
+ QCOMPARE(comp3->entities().size(), 2);
+}
+
+void tst_Entity::addComponentsSeveralParentsSingleAggregations()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity2.data());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+
+ // WHEN
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 2);
+ QCOMPARE(entity2->components().size(), 1);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 1);
+ QCOMPARE(comp2->entities().size(), 1);
+ QCOMPARE(comp3->entities().size(), 1);
+}
+
+void tst_Entity::addComponentsSeveralParentsSeveralAggregations()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity2.data());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+
+ // WHEN
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+ entity1->addComponent(comp3);
+
+ entity2->addComponent(comp1);
+ entity2->addComponent(comp2);
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 3);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 2);
+ QCOMPARE(comp2->entities().size(), 2);
+ QCOMPARE(comp3->entities().size(), 2);
+}
+
+void tst_Entity::removeComponentSingleParentSingleAggregation()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new QEntity());
+ MyQComponent *comp = new MyQComponent(entity.data());
+ QCoreApplication::processEvents();
+ entity->addComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 1);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 1);
+
+ // WHEN
+ entity->removeComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 0);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 0);
+}
+
+void tst_Entity::removeComponentSingleParentSeveralAggregations()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity1.data());
+ QCoreApplication::processEvents();
+
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+ entity1->addComponent(comp3);
+
+ entity2->addComponent(comp1);
+ entity2->addComponent(comp2);
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity1.data());
+
+ QCOMPARE(entity1->components().size(), 3);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 3);
+ QCOMPARE(entity2->children().size(), 0);
+
+ QCOMPARE(comp1->entities().size(), 2);
+ QCOMPARE(comp2->entities().size(), 2);
+ QCOMPARE(comp3->entities().size(), 2);
+
+ // WHEN
+ entity1->removeComponent(comp1);
+ entity1->removeComponent(comp2);
+ entity1->removeComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity1.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 3);
+ QCOMPARE(entity2->children().size(), 0);
+
+ QCOMPARE(comp1->entities().size(), 1);
+ QCOMPARE(comp2->entities().size(), 1);
+ QCOMPARE(comp3->entities().size(), 1);
+
+ // WHEN
+ entity2->removeComponent(comp1);
+ entity2->removeComponent(comp2);
+ entity2->removeComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity1.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 3);
+ QCOMPARE(entity2->children().size(), 0);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+}
+
+void tst_Entity::removeComponentsSeveralParentsSingleAggreation()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity2.data());
+ QCoreApplication::processEvents();
+
+ // WHEN
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 2);
+ QCOMPARE(entity2->components().size(), 1);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 1);
+ QCOMPARE(comp2->entities().size(), 1);
+ QCOMPARE(comp3->entities().size(), 1);
+
+ // WHEN
+ entity1->removeComponent(comp1);
+ entity1->removeComponent(comp2);
+ entity2->removeComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+}
+
+void tst_Entity::removeComponentsSeveralParentsSeveralAggregations()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity1(new QEntity());
+ QScopedPointer<Qt3D::QEntity> entity2(new QEntity());
+
+ MyQComponent *comp1 = new MyQComponent(entity1.data());
+ MyQComponent *comp2 = new MyQComponent(entity1.data());
+ MyQComponent *comp3 = new MyQComponent(entity2.data());
+ QCoreApplication::processEvents();
+
+ // WHEN
+ entity1->addComponent(comp1);
+ entity1->addComponent(comp2);
+ entity1->addComponent(comp3);
+
+ entity2->addComponent(comp1);
+ entity2->addComponent(comp2);
+ entity2->addComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 3);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 2);
+ QCOMPARE(comp2->entities().size(), 2);
+ QCOMPARE(comp3->entities().size(), 2);
+
+ // WHEN
+ entity1->removeComponent(comp1);
+ entity1->removeComponent(comp2);
+ entity1->removeComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 3);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 1);
+ QCOMPARE(comp2->entities().size(), 1);
+ QCOMPARE(comp3->entities().size(), 1);
+
+ // WHEN
+ entity2->removeComponent(comp1);
+ entity2->removeComponent(comp2);
+ entity2->removeComponent(comp3);
+
+ // THEN
+ QVERIFY(comp1->parent() == entity1.data());
+ QVERIFY(comp2->parent() == entity1.data());
+ QVERIFY(comp3->parent() == entity2.data());
+
+ QCOMPARE(entity1->components().size(), 0);
+ QCOMPARE(entity2->components().size(), 0);
+
+ QCOMPARE(entity1->children().size(), 2);
+ QCOMPARE(entity2->children().size(), 1);
+
+ QCOMPARE(comp1->entities().size(), 0);
+ QCOMPARE(comp2->entities().size(), 0);
+ QCOMPARE(comp3->entities().size(), 0);
+}
+
+void tst_Entity::addSeveralTimesSameComponent()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new QEntity());
+ MyQComponent *comp = new MyQComponent(entity.data());
+ QCoreApplication::processEvents();
+ entity->addComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 1);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 1);
+
+ // WHEN
+ entity->addComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 1);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 1);
+}
+
+void tst_Entity::removeSeveralTimesSameComponent()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> entity(new QEntity());
+ MyQComponent *comp = new MyQComponent(entity.data());
+ QCoreApplication::processEvents();
+ entity->addComponent(comp);
+ entity->removeComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 0);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 0);
+
+ // WHEN
+ entity->removeComponent(comp);
+
+ // THEN
+ QVERIFY(comp->parent() == entity.data());
+ QCOMPARE(entity->components().size(), 0);
+ QCOMPARE(entity->children().size(), 1);
+ QCOMPARE(comp->entities().size(), 0);
+}
+
+void tst_Entity::verifyCopy()
+{
+ // GIVEN
+ QScopedPointer<Qt3D::QEntity> root(new Qt3D::QEntity());
+ MyEntity *parentLessEntity = new MyEntity();
+ MyEntity *parentedEntity = new MyEntity(root.data());
+
+ QCoreApplication::processEvents();
+
+ // THEN
+ QVERIFY(root->id() != parentLessEntity->id());
+ QVERIFY(root->id() != parentedEntity->id());
+ QVERIFY(root->parentEntityId().isNull());
+ QVERIFY(!parentedEntity->parentEntityId().isNull());
+ QVERIFY(parentLessEntity->parentEntityId().isNull());
+
+ // WHEN
+ MyEntity *parentedEntityCopy = new MyEntity();
+ parentedEntityCopy->makeCopyOf(parentedEntity);
+
+ // THEN
+ QVERIFY(parentedEntityCopy->id() == parentedEntity->id());
+ QVERIFY(parentedEntityCopy->parentEntityId() == parentedEntity->parentEntityId());
+
+ // WHEN
+ MyEntity *parentLessEntityCopy = new MyEntity();
+ parentLessEntityCopy->makeCopyOf(parentLessEntity);
+
+ // THEN
+ QVERIFY(parentLessEntityCopy->id() == parentLessEntity->id());
+ QVERIFY(parentLessEntityCopy->parentEntityId() == parentLessEntity->parentEntityId());
+}
+
+
+QTEST_MAIN(tst_Entity)
#include "tst_qentity.moc"
diff --git a/tests/auto/core/qscene/tst_qscene.cpp b/tests/auto/core/qscene/tst_qscene.cpp
index fd7be1fcd..51a469836 100644
--- a/tests/auto/core/qscene/tst_qscene.cpp
+++ b/tests/auto/core/qscene/tst_qscene.cpp
@@ -88,6 +88,12 @@ class tst_Node : public Qt3D::QNode
public:
tst_Node() : Qt3D::QNode()
{}
+
+ ~tst_Node()
+ {
+ QNode::cleanup();
+ }
+
protected:
QT3D_CLONEABLE(tst_Node)
};
@@ -97,12 +103,19 @@ class tst_Component : public Qt3D::QComponent
public:
tst_Component() : Qt3D::QComponent()
{}
+
+ ~tst_Component()
+ {
+ QNode::cleanup();
+ }
+
protected:
QT3D_CLONEABLE(tst_Component)
};
void tst_QScene::addObservable()
{
+ // GIVEN
Qt3D::QNode *node1 = new tst_Node();
Qt3D::QNode *node2 = new tst_Node();
@@ -114,6 +127,7 @@ void tst_QScene::addObservable()
Qt3D::QScene *scene = new Qt3D::QScene;
scene->setArbiter(new tst_LockableObserver);
+ // WHEN
for (int i = 0; i < 5; i++)
scene->addObservable(observables.at(i), node1->id());
@@ -123,6 +137,7 @@ void tst_QScene::addObservable()
Qt3D::QObservableList obs1 = scene->lookupObservables(node1->id());
Qt3D::QObservableList obs2 = scene->lookupObservables(node2->id());
+ // THEN
QCOMPARE(obs1.count(), 5);
QCOMPARE(obs2.count(), obs1.count());
@@ -138,6 +153,7 @@ void tst_QScene::addObservable()
void tst_QScene::addNodeObservable()
{
+ // GIBEN
QList<Qt3D::QNode *> nodes;
for (int i = 0; i < 10; i++)
@@ -146,9 +162,11 @@ void tst_QScene::addNodeObservable()
Qt3D::QScene *scene = new Qt3D::QScene;
scene->setArbiter(new tst_LockableObserver);
+ // WHEN
for (int i = 0; i < 10; i++)
scene->addObservable(nodes.at(i));
+ // THEN
Q_FOREACH (Qt3D::QNode *n, nodes) {
QVERIFY(n == scene->lookupNode(n->id()));
QVERIFY(scene->lookupObservables(n->id()).isEmpty());
@@ -157,6 +175,7 @@ void tst_QScene::addNodeObservable()
void tst_QScene::removeObservable()
{
+ // GIVEN
Qt3D::QNode *node1 = new tst_Node();
Qt3D::QNode *node2 = new tst_Node();
@@ -168,6 +187,7 @@ void tst_QScene::removeObservable()
Qt3D::QScene *scene = new Qt3D::QScene;
scene->setArbiter(new tst_LockableObserver);
+ // WHEN
for (int i = 0; i < 5; i++)
scene->addObservable(observables.at(i), node1->id());
@@ -177,27 +197,36 @@ void tst_QScene::removeObservable()
Qt3D::QObservableList obs1 = scene->lookupObservables(node1->id());
Qt3D::QObservableList obs2 = scene->lookupObservables(node2->id());
+ // THEN
QCOMPARE(obs1.count(), 5);
QCOMPARE(obs2.count(), obs1.count());
+ // WHEN
scene->removeObservable(observables.at(0), node1->id());
+ // THEN
QCOMPARE(scene->lookupObservables(node1->id()).count(), 4);
+ // WHEN
scene->removeObservable(observables.at(0), node1->id());
+ // THEN
QCOMPARE(scene->lookupObservables(node1->id()).count(), 4);
+ // WHEN
scene->removeObservable(observables.at(6), node1->id());
+ // THEN
QCOMPARE(scene->lookupObservables(node1->id()).count(), 4);
QCOMPARE(scene->lookupObservables(node2->id()).count(), 5);
+ // WHEN
scene->removeObservable(observables.at(0), node2->id());
+ // THEN
QCOMPARE(scene->lookupObservables(node2->id()).count(), 5);
-
QVERIFY(scene->nodeIdFromObservable(observables.at(0)) == Qt3D::QNodeId());
}
void tst_QScene::removeNodeObservable()
{
+ // GIVEN
Qt3D::QNode *node1 = new tst_Node();
Qt3D::QNode *node2 = new tst_Node();
@@ -209,6 +238,7 @@ void tst_QScene::removeNodeObservable()
Qt3D::QScene *scene = new Qt3D::QScene;
scene->setArbiter(new tst_LockableObserver);
+ // WHEN
scene->addObservable(node1);
scene->addObservable(node2);
@@ -218,14 +248,17 @@ void tst_QScene::removeNodeObservable()
for (int i = 0; i < 5; i++)
scene->addObservable(observables.at(i + 5), node2->id());
+ // THEN
Qt3D::QObservableList obs1 = scene->lookupObservables(node1->id());
Qt3D::QObservableList obs2 = scene->lookupObservables(node2->id());
QCOMPARE(obs1.count(), 5);
QCOMPARE(obs2.count(), obs1.count());
+ // WHEN
scene->removeObservable(node1);
+ // THEN
QVERIFY(scene->lookupNode(node1->id()) == Q_NULLPTR);
QVERIFY(scene->lookupObservables(node1->id()).empty());
QVERIFY(scene->nodeIdFromObservable(observables.at(0)) == Qt3D::QNodeId());
@@ -237,13 +270,20 @@ void tst_QScene::removeNodeObservable()
void tst_QScene::addChildNode()
{
+ // GIVEN
Qt3D::QScene *scene = new Qt3D::QScene;
QList<Qt3D::QNode *> nodes;
Qt3D::QNode *root = new tst_Node();
Qt3D::QNodePrivate::get(root)->setScene(scene);
+
+ // WHEN
scene->addObservable(root);
+ // THEN
+ QVERIFY(scene->lookupNode(root->id()) == root);
+
+ // WHEN
for (int i = 0; i < 10; i++) {
Qt3D::QNode *child = new tst_Node();
if (nodes.isEmpty())
@@ -252,10 +292,9 @@ void tst_QScene::addChildNode()
child->setParent(nodes.last());
nodes.append(child);
}
-
- QVERIFY(scene->lookupNode(root->id()) == root);
QCoreApplication::processEvents();
+ // THEN
Q_FOREACH (Qt3D::QNode *n, nodes) {
QVERIFY(scene->lookupNode(n->id()) == n);
}
@@ -263,6 +302,7 @@ void tst_QScene::addChildNode()
void tst_QScene::removeChildNode()
{
+ // GIVEN
Qt3D::QScene *scene = new Qt3D::QScene;
QList<Qt3D::QNode *> nodes;
@@ -270,6 +310,8 @@ void tst_QScene::removeChildNode()
Qt3D::QNode *root = new tst_Node;
Qt3D::QNodePrivate::get(root)->setScene(scene);
scene->addObservable(root);
+
+ // WHEN
for (int i = 0; i < 10; i++) {
Qt3D::QNode *child = new tst_Node;
if (nodes.isEmpty())
@@ -279,11 +321,12 @@ void tst_QScene::removeChildNode()
nodes.append(child);
}
+ // THEN
while (!nodes.isEmpty()) {
Qt3D::QNode *lst = nodes.takeLast();
QVERIFY(scene->lookupNode(lst->id()) == lst);
if (lst->parentNode() != Q_NULLPTR) {
- lst->setParent(Q_NULLPTR);
+ lst->setParent(Q_NODE_NULLPTR);
QCoreApplication::processEvents();
QVERIFY(scene->lookupNode(lst->id()) == Q_NULLPTR);
}
@@ -292,6 +335,7 @@ void tst_QScene::removeChildNode()
void tst_QScene::addEntityForComponent()
{
+ // GIVEN
Qt3D::QScene *scene = new Qt3D::QScene;
QList<Qt3D::QEntity *> entities;
@@ -307,6 +351,7 @@ void tst_QScene::addEntityForComponent()
components << comp;
}
+ // WHEN
for (int i = 0; i < 10; i++) {
Qt3D::QEntity *e = entities.at(i);
for (int j = 0; j < 10; j++) {
@@ -314,6 +359,7 @@ void tst_QScene::addEntityForComponent()
}
}
+ // THEN
for (int i = 0; i < 10; i++) {
QList<Qt3D::QNodeId> ids = scene->entitiesForComponent(components.at(i)->id());
QCOMPARE(ids.count(), 10);
@@ -322,6 +368,7 @@ void tst_QScene::addEntityForComponent()
void tst_QScene::removeEntityForComponent()
{
+ // GIVEN
Qt3D::QScene *scene = new Qt3D::QScene;
QList<Qt3D::QEntity *> entities;
@@ -337,6 +384,7 @@ void tst_QScene::removeEntityForComponent()
components << comp;
}
+ // WHEN
for (int i = 0; i < 10; i++) {
Qt3D::QEntity *e = entities.at(i);
for (int j = 0; j < 10; j++) {
@@ -344,6 +392,7 @@ void tst_QScene::removeEntityForComponent()
}
}
+ // THEN
for (int i = 0; i < 10; i++) {
Qt3D::QEntity *e = entities.at(i);
for (int j = 0; j < 10; j++) {