summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2017-01-19 19:47:27 +0000
committerSean Harmer <sean.harmer@kdab.com>2017-01-23 21:45:24 +0000
commit45b5514ee1f816b24461f7523b779f65c6c93ea5 (patch)
tree53fd48ded880df657ee830ca61f64c69dde89847
parenta6c5261671379da7e8fb78b10508fc00d3e7b16a (diff)
LevelOfDetail (LOD) node
Component to control complexity of entities based on either distance to camera or size on screen. Given a specific camera, the LevelOfDetail computes the distance to the observer, or the screen size of the entity. The currentIndex property is updated to identify which of the entries in the provided array of distance or size ranges contains the current value. A disabled LevelOfDetail component will act as a simple (user controlled) switch. Updates are not done on disabled sub trees since their bounding boxes may not be valid. Change-Id: Ifa4c088de6b80b6a6ed203070411761574686cdb Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/doc/src/levelofdetailloader.qdoc57
-rw-r--r--src/quick3d/imports/extras/defaults/defaults.pri3
-rw-r--r--src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml80
-rw-r--r--src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp2
-rw-r--r--src/quick3d/imports/render/qt3dquick3drenderplugin.cpp4
-rw-r--r--src/render/backend/entity.cpp32
-rw-r--r--src/render/backend/entity_p.h10
-rw-r--r--src/render/backend/handle_types_p.h2
-rw-r--r--src/render/backend/levelofdetail.cpp128
-rw-r--r--src/render/backend/levelofdetail_p.h103
-rw-r--r--src/render/backend/managers_p.h12
-rw-r--r--src/render/backend/nodemanagers.cpp8
-rw-r--r--src/render/backend/nodemanagers_p.h7
-rw-r--r--src/render/backend/render-backend.pri2
-rw-r--r--src/render/backend/renderer.cpp7
-rw-r--r--src/render/backend/renderer_p.h5
-rw-r--r--src/render/frontend/qboundingsphere.cpp148
-rw-r--r--src/render/frontend/qboundingsphere.h82
-rw-r--r--src/render/frontend/qboundingsphere_p.h76
-rw-r--r--src/render/frontend/qlevelofdetail.cpp482
-rw-r--r--src/render/frontend/qlevelofdetail.h110
-rw-r--r--src/render/frontend/qlevelofdetail_p.h94
-rw-r--r--src/render/frontend/qrenderaspect.cpp2
-rw-r--r--src/render/frontend/render-frontend.pri6
-rw-r--r--src/render/jobs/job_common_p.h1
-rw-r--r--src/render/jobs/jobs.pri2
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp2
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h3
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp230
-rw-r--r--src/render/jobs/updatelevelofdetailjob_p.h103
-rw-r--r--tests/auto/render/levelofdetail/levelofdetail.pro12
-rw-r--r--tests/auto/render/levelofdetail/tst_levelofdetail.cpp145
-rw-r--r--tests/auto/render/qlevelofdetail/qlevelofdetail.pro12
-rw-r--r--tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp123
-rw-r--r--tests/auto/render/render.pro2
-rw-r--r--tests/manual/lod/ConeEntity.qml74
-rw-r--r--tests/manual/lod/CuboidEntity.qml75
-rw-r--r--tests/manual/lod/CylinderEntity.qml74
-rw-r--r--tests/manual/lod/SphereEntity.qml73
-rw-r--r--tests/manual/lod/lod.pro20
-rw-r--r--tests/manual/lod/lod.qrc9
-rw-r--r--tests/manual/lod/main.cpp63
-rw-r--r--tests/manual/lod/main.qml180
-rw-r--r--tests/manual/manual.pro1
44 files changed, 2665 insertions, 1 deletions
diff --git a/src/doc/src/levelofdetailloader.qdoc b/src/doc/src/levelofdetailloader.qdoc
new file mode 100644
index 000000000..65fda072a
--- /dev/null
+++ b/src/doc/src/levelofdetailloader.qdoc
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmltype LevelOfDetailLoader
+ \inqmlmodule Qt3D.Render
+ \since 5.9
+ \brief An entity loader that changes depending on distance to camera or screen size
+
+ A LevelOfDetailLoader will load the entity matching the \l LevelOfDetail::currentIndex.
+ The source is selected from the \l sources property.
+ The range is specified using the \l {minimum} and the \l{maximum} values.
+
+ \sa LevelOfDetail
+*/
+
+/*!
+ \qmlproperty list<string> LevelOfDetailLoader::sources
+
+ The list of sources (array of strings) to load from.
+*/
diff --git a/src/quick3d/imports/extras/defaults/defaults.pri b/src/quick3d/imports/extras/defaults/defaults.pri
index 65271afeb..98f542fd6 100644
--- a/src/quick3d/imports/extras/defaults/defaults.pri
+++ b/src/quick3d/imports/extras/defaults/defaults.pri
@@ -22,4 +22,5 @@ QML_FILES = \
$$PWD/qml/TextureMaterial.qml \
$$PWD/qml/OrbitCameraController.qml \
$$PWD/qml/FirstPersonCameraController.qml \
- $$PWD/qml/NormalDiffuseMapAlphaEffect.qml
+ $$PWD/qml/NormalDiffuseMapAlphaEffect.qml \
+ $$PWD/qml/LevelOfDetailLoader.qml
diff --git a/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml b/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml
new file mode 100644
index 000000000..83655a7bc
--- /dev/null
+++ b/src/quick3d/imports/extras/defaults/qml/LevelOfDetailLoader.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.2
+
+Entity {
+ id:root
+
+ property var sources: []
+ readonly property alias entity: loader.entity
+ readonly property alias source: loader.source
+
+ property alias camera: lod.camera
+ property alias currentIndex: lod.currentIndex
+ property alias thresholdType: lod.thresholdType
+ property alias thresholds: lod.thresholds
+ property alias volumeOverride: lod.volumeOverride
+
+ EntityLoader {
+ id: loader
+ components: [
+ LevelOfDetail {
+ id: lod
+ enabled: root.enabled
+ currentIndex: -1
+ onCurrentIndexChanged: if (currentIndex >= 0 && currentIndex < root.sources.length)
+ loader.source = root.sources[currentIndex]
+ }
+ ]
+ }
+}
+
diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
index b20e416c2..7d695ea5b 100644
--- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
+++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
@@ -75,6 +75,8 @@ static const struct {
{ "DefaultEffect", 2, 0 },
{ "DefaultAlphaEffect", 2, 0 },
{ "NormalDiffuseMapAlphaEffect", 2, 0 },
+ // Scene Graph
+ { "LevelOfDetailLoader", 2, 2 },
// FrameGraphs
{ "ForwardRenderer", 2, 0 },
// Entities
diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
index 2e68893d6..5ca889943 100644
--- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
+++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
@@ -55,6 +55,8 @@
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qfilterkey.h>
#include <Qt3DRender/qlayer.h>
+#include <Qt3DRender/qlevelofdetail.h>
+#include <Qt3DRender/qboundingsphere.h>
#include <Qt3DRender/qabstractlight.h>
#include <Qt3DRender/qspotlight.h>
#include <Qt3DRender/qdirectionallight.h>
@@ -191,6 +193,8 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DRender::Render::Quick::Quick3DBuffer>(uri, 2, 0, "Buffer");
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QGeometry, Qt3DRender::Render::Quick::Quick3DGeometry>("QGeometry", "Qt3D.Render/Geometry", uri, 2, 0, "Geometry");
qmlRegisterType<Qt3DRender::QGeometryRenderer>(uri, 2, 0, "GeometryRenderer");
+ qmlRegisterType<Qt3DRender::QLevelOfDetail>(uri, 2, 2, "LevelOfDetail");
+ qmlRegisterType<Qt3DRender::QBoundingSphere>(uri, 2, 2, "BoundingSphere");
// Mesh
qmlRegisterType<Qt3DRender::QMesh>(uri, 2, 0, "Mesh");
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index f4a57fa43..42233c85a 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -42,6 +42,7 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qabstractlight.h>
#include <Qt3DRender/qlayer.h>
+#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/private/renderlogging_p.h>
@@ -114,6 +115,7 @@ void Entity::cleanup()
m_computeComponent = QNodeId();
m_childrenHandles.clear();
m_layerComponents.clear();
+ m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
m_localBoundingVolume.reset();
@@ -169,6 +171,7 @@ void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
m_boundingVolumeDebugComponent = QNodeId();
m_computeComponent = QNodeId();
m_layerComponents.clear();
+ m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
m_localBoundingVolume.reset(new Sphere(peerId()));
@@ -284,6 +287,8 @@ void Entity::addComponent(Qt3DCore::QComponent *component)
m_cameraComponent = component->id();
} else if (qobject_cast<QLayer *>(component) != nullptr) {
m_layerComponents.append(component->id());
+ } else if (qobject_cast<QLevelOfDetail *>(component) != nullptr) {
+ m_levelOfDetailComponents.append(component->id());
} else if (qobject_cast<QMaterial *>(component) != nullptr) {
m_materialComponent = component->id();
} else if (qobject_cast<QAbstractLight *>(component) != nullptr) {
@@ -315,6 +320,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
m_cameraComponent = id;
} else if (type->inherits(&QLayer::staticMetaObject)) {
m_layerComponents.append(id);
+ } else if (type->inherits(&QLevelOfDetail::staticMetaObject)) {
+ m_levelOfDetailComponents.append(id);
} else if (type->inherits(&QMaterial::staticMetaObject)) {
m_materialComponent = id;
} else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData
@@ -341,6 +348,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
m_cameraComponent = QNodeId();
} else if (m_layerComponents.contains(nodeId)) {
m_layerComponents.removeAll(nodeId);
+ } else if (m_levelOfDetailComponents.contains(nodeId)) {
+ m_levelOfDetailComponents.removeAll(nodeId);
} else if (m_materialComponent == nodeId) {
m_materialComponent = QNodeId();
} else if (m_shaderDataComponents.contains(nodeId)) {
@@ -412,6 +421,16 @@ QVector<HLayer> Entity::componentsHandle<Layer>() const
}
template<>
+QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const
+{
+ QVector<HLevelOfDetail> lodHandles;
+ lodHandles.reserve(m_levelOfDetailComponents.size());
+ for (QNodeId id : m_levelOfDetailComponents)
+ lodHandles.append(m_nodeManagers->levelOfDetailManager()->lookupHandle(id));
+ return lodHandles;
+}
+
+template<>
QVector<HShaderData> Entity::componentsHandle<ShaderData>() const
{
QVector<HShaderData> shaderDataHandles;
@@ -486,6 +505,16 @@ QVector<Layer *> Entity::renderComponents<Layer>() const
}
template<>
+QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const
+{
+ QVector<LevelOfDetail *> lods;
+ lods.reserve(m_levelOfDetailComponents.size());
+ for (QNodeId id : m_levelOfDetailComponents)
+ lods.append(m_nodeManagers->levelOfDetailManager()->lookupResource(id));
+ return lods;
+}
+
+template<>
QVector<ShaderData *> Entity::renderComponents<ShaderData>() const
{
QVector<ShaderData *> shaderDatas;
@@ -532,6 +561,9 @@ template<>
QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const { return m_layerComponents; }
template<>
+QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const { return m_levelOfDetailComponents; }
+
+template<>
QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const { return m_shaderDataComponents; }
template<>
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index 213dc041e..fe970d325 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -190,6 +190,7 @@ private:
Qt3DCore::QNodeId m_materialComponent;
Qt3DCore::QNodeId m_cameraComponent;
QVector<Qt3DCore::QNodeId> m_layerComponents;
+ QVector<Qt3DCore::QNodeId> m_levelOfDetailComponents;
QVector<Qt3DCore::QNodeId> m_shaderDataComponents;
QVector<Qt3DCore::QNodeId> m_lightComponents;
Qt3DCore::QNodeId m_geometryRendererComponent;
@@ -221,6 +222,9 @@ template<>
QVector<HLayer> Entity::componentsHandle<Layer>() const;
template<>
+QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const;
+
+template<>
QVector<HShaderData> Entity::componentsHandle<ShaderData>() const;
//template<>
@@ -252,6 +256,9 @@ template<>
QVector<Layer *> Entity::renderComponents<Layer>() const;
template<>
+QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const;
+
+template<>
QVector<ShaderData *> Entity::renderComponents<ShaderData>() const;
//template<>
@@ -277,6 +284,9 @@ template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const;
template<>
+Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const;
+
+template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const;
template<>
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index e68f0f1c5..c8c73b749 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -72,6 +72,7 @@ class Entity;
class Shader;
class FrameGraphNode;
class Layer;
+class LevelOfDetail;
class Material;
class Technique;
class Texture;
@@ -100,6 +101,7 @@ typedef Qt3DCore::QHandle<Effect, 16> HEffect;
typedef Qt3DCore::QHandle<Entity, 16> HEntity;
typedef Qt3DCore::QHandle<FrameGraphNode *, 8> HFrameGraphNode;
typedef Qt3DCore::QHandle<Layer, 16> HLayer;
+typedef Qt3DCore::QHandle<LevelOfDetail, 16> HLevelOfDetail;
typedef Qt3DCore::QHandle<Material, 16> HMaterial;
typedef Qt3DCore::QHandle<QMatrix4x4, 16> HMatrix;
typedef Qt3DCore::QHandle<OpenGLVertexArrayObject, 16> HVao;
diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp
new file mode 100644
index 000000000..9ff0ef532
--- /dev/null
+++ b/src/render/backend/levelofdetail.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "levelofdetail_p.h"
+#include <Qt3DRender/QLevelOfDetail>
+#include <Qt3DRender/QBoundingSphere>
+#include <Qt3DRender/private/qlevelofdetail_p.h>
+#include <Qt3DRender/private/stringtoint_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+LevelOfDetail::LevelOfDetail()
+ : BackendNode(BackendNode::ReadWrite)
+ , m_currentIndex(0)
+ , m_thresholdType(QLevelOfDetail::DistanceToCamera)
+ , m_radius(1.f)
+{
+}
+
+LevelOfDetail::~LevelOfDetail()
+{
+ cleanup();
+}
+
+void LevelOfDetail::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLevelOfDetailData>>(change);
+ const auto &data = typedChange->data;
+ m_camera = data.camera;
+ m_currentIndex = data.currentIndex;
+ m_thresholdType = data.thresholdType;
+ m_thresholds = data.thresholds;
+ m_radius = data.radius;
+ m_center = data.center;
+}
+
+void LevelOfDetail::cleanup()
+{
+ QBackendNode::setEnabled(false);
+}
+
+void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex")) {
+ m_currentIndex = propertyChange->value().value<int>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("camera")) {
+ m_camera = propertyChange->value().value<Qt3DCore::QNodeId>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) {
+ m_thresholdType = propertyChange->value().value<QLevelOfDetail::ThresholdType>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) {
+ m_thresholds = propertyChange->value().value<QVector<qreal>>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) {
+ m_center = propertyChange->value().value<QVector3D>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) {
+ m_radius = propertyChange->value().value<float>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride")) {
+ auto volumeOverride = propertyChange->value().value<Qt3DRender::QBoundingSphere*>();
+ m_center = volumeOverride ? volumeOverride->center() : QVector3D();
+ m_radius = volumeOverride ? volumeOverride->radius() : -1.f;
+ }
+ }
+
+ markDirty(AbstractRenderer::GeometryDirty);
+
+ BackendNode::sceneChangeEvent(e);
+}
+
+void LevelOfDetail::setCurrentIndex(int currentIndex)
+{
+ if (m_currentIndex != currentIndex) {
+ m_currentIndex = currentIndex;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("currentIndex");
+ e->setValue(m_currentIndex);
+ notifyObservers(e);
+ }
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h
new file mode 100644
index 000000000..83809a631
--- /dev/null
+++ b/src/render/backend/levelofdetail_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_LEVELOFDETAIL_H
+#define QT3DRENDER_RENDER_LEVELOFDETAIL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DRender/qt3drender_global.h>
+#include <Qt3DRender/qlevelofdetail.h>
+#include <QStringList>
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QLevelOfDetail;
+
+namespace Render {
+
+class LevelOfDetailManager;
+
+class Q_AUTOTEST_EXPORT LevelOfDetail : public BackendNode
+{
+public:
+ LevelOfDetail();
+ ~LevelOfDetail();
+ void cleanup();
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL;
+
+ Qt3DCore::QNodeId camera() const { return m_camera; }
+ int currentIndex() const { return m_currentIndex; }
+ QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; }
+ QVector<qreal> thresholds() const { return m_thresholds; }
+ float radius() const { return m_radius; }
+ QVector3D center() const { return m_center; }
+
+ void setCurrentIndex(int currentIndex);
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ Qt3DCore::QNodeId m_camera;
+ int m_currentIndex;
+ QLevelOfDetail::ThresholdType m_thresholdType;
+ QVector<qreal> m_thresholds;
+ float m_radius;
+ QVector3D m_center;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_LEVELOFDETAIL_H
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index ed43fde13..ce6767958 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -58,6 +58,7 @@
#include <Qt3DRender/private/effect_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/layer_p.h>
+#include <Qt3DRender/private/levelofdetail_p.h>
#include <Qt3DRender/private/material_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/private/texture_p.h>
@@ -176,6 +177,17 @@ public:
LayerManager() {}
};
+class LevelOfDetailManager : public Qt3DCore::QResourceManager<
+ LevelOfDetail,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ LevelOfDetailManager() {}
+};
+
class MaterialManager : public Qt3DCore::QResourceManager<
Material,
Qt3DCore::QNodeId,
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index e9b2abc3a..d83623ce2 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -71,6 +71,7 @@ NodeManagers::NodeManagers()
, m_textureImageDataManager(new TextureImageDataManager())
, m_glTextureManager(new GLTextureManager(m_textureImageManager, m_textureDataManager, m_textureImageDataManager))
, m_layerManager(new LayerManager())
+ , m_levelOfDetailManager(new LevelOfDetailManager())
, m_filterKeyManager(new FilterKeyManager())
, m_frameGraphManager(new FrameGraphManager())
, m_transformManager(new TransformManager())
@@ -107,6 +108,7 @@ NodeManagers::~NodeManagers()
delete m_textureDataManager;
delete m_textureImageDataManager;
delete m_layerManager;
+ delete m_levelOfDetailManager;
delete m_filterKeyManager;
delete m_frameGraphManager;
delete m_transformManager;
@@ -202,6 +204,12 @@ LayerManager *NodeManagers::manager<Layer>() const Q_DECL_NOTHROW
}
template<>
+LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const Q_DECL_NOTHROW
+{
+ return m_levelOfDetailManager;
+}
+
+template<>
FilterKeyManager *NodeManagers::manager<FilterKey>() const Q_DECL_NOTHROW
{
return m_filterKeyManager;
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index e46e9355c..b1ea2a0de 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -94,6 +94,7 @@ class TextureManager;
class TextureDataManager;
class TextureImageDataManager;
class LayerManager;
+class LevelOfDetailManager;
class LightManager;
class ComputeCommandManager;
class RenderStateManager;
@@ -108,6 +109,7 @@ class Effect;
class RenderPass;
class Texture;
class Layer;
+class LevelOfDetail;
class FilterKey;
class FrameGraphNode;
class Transform;
@@ -183,6 +185,7 @@ public:
inline TextureDataManager *textureDataManager() const Q_DECL_NOEXCEPT { return m_textureDataManager; }
inline TextureImageDataManager *textureImageDataManager() const Q_DECL_NOEXCEPT { return m_textureImageDataManager; }
inline LayerManager *layerManager() const Q_DECL_NOEXCEPT { return m_layerManager; }
+ inline LevelOfDetailManager *levelOfDetailManager() const Q_DECL_NOEXCEPT { return m_levelOfDetailManager; }
inline FilterKeyManager *filterKeyManager() const Q_DECL_NOEXCEPT { return m_filterKeyManager; }
inline FrameGraphManager *frameGraphManager() const Q_DECL_NOEXCEPT { return m_frameGraphManager; }
inline TransformManager *transformManager() const Q_DECL_NOEXCEPT { return m_transformManager; }
@@ -219,6 +222,7 @@ private:
TextureImageDataManager *m_textureImageDataManager;
GLTextureManager *m_glTextureManager;
LayerManager *m_layerManager;
+ LevelOfDetailManager *m_levelOfDetailManager;
FilterKeyManager *m_filterKeyManager;
FrameGraphManager *m_frameGraphManager;
TransformManager *m_transformManager;
@@ -278,6 +282,9 @@ template<>
QT3DRENDERSHARED_PRIVATE_EXPORT LayerManager *NodeManagers::manager<Layer>() const Q_DECL_NOEXCEPT;
template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT LevelOfDetailManager *NodeManagers::manager<LevelOfDetail>() const Q_DECL_NOEXCEPT;
+
+template<>
QT3DRENDERSHARED_PRIVATE_EXPORT FilterKeyManager *NodeManagers::manager<FilterKey>() const Q_DECL_NOEXCEPT;
template<>
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 8cd904efd..93e323caa 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -21,6 +21,7 @@ HEADERS += \
$$PWD/cameralens_p.h \
$$PWD/entity_p.h \
$$PWD/layer_p.h \
+ $$PWD/levelofdetail_p.h \
$$PWD/nodefunctor_p.h \
$$PWD/transform_p.h \
$$PWD/boundingvolumedebug_p.h \
@@ -56,6 +57,7 @@ SOURCES += \
$$PWD/cameralens.cpp \
$$PWD/entity.cpp \
$$PWD/layer.cpp \
+ $$PWD/levelofdetail.cpp \
$$PWD/transform.cpp \
$$PWD/boundingvolumedebug.cpp \
$$PWD/nodemanagers.cpp \
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index e1b1ee873..08ee7f428 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -83,6 +83,7 @@
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/loadbufferjob_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/updatelevelofdetailjob_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/qcameralens.h>
@@ -167,6 +168,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create())
, m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
+ , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create())
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
@@ -198,6 +200,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
// All world stuff depends on the RenderEntity's localBoundingVolume
+ m_updateLevelOfDetailJob->addDependency(m_updateMeshTriangleListJob);
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
m_filterCompatibleTechniqueJob->setRenderer(this);
@@ -252,6 +255,7 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_pickBoundingVolumeJob->setManagers(m_nodesManager);
m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager());
m_sendRenderCaptureJob->setManagers(m_nodesManager);
+ m_updateLevelOfDetailJob->setManagers(m_nodesManager);
m_updateMeshTriangleListJob->setManagers(m_nodesManager);
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
}
@@ -443,6 +447,7 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_calculateBoundingVolumeJob->setRoot(m_renderSceneRoot);
m_cleanupJob->setRoot(m_renderSceneRoot);
m_pickBoundingVolumeJob->setRoot(m_renderSceneRoot);
+ m_updateLevelOfDetailJob->setRoot(m_renderSceneRoot);
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
}
@@ -1226,6 +1231,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_pickBoundingVolumeJob->setRenderSettings(settings());
m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents());
+ m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
// Set dependencies of resource gatherer
for (const QAspectJobPtr &jobPtr : renderBinJobs) {
jobPtr->addDependency(m_bufferGathererJob);
@@ -1237,6 +1243,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_updateShaderDataTransformJob);
renderBinJobs.push_back(m_updateMeshTriangleListJob);
renderBinJobs.push_back(m_updateTreeEnabledJob);
+ renderBinJobs.push_back(m_updateLevelOfDetailJob);
renderBinJobs.push_back(m_expandBoundingVolumeJob);
renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
renderBinJobs.push_back(m_calculateBoundingVolumeJob);
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index c7c8e247a..9b5c35ed1 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -138,6 +138,9 @@ class VSyncFrameAdvanceService;
class PickEventFilter;
class NodeManagers;
+class UpdateLevelOfDetailJob;
+typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr;
+
using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
class QT3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer
@@ -195,6 +198,7 @@ public:
inline UpdateTreeEnabledJobPtr updateTreeEnabledJob() const { return m_updateTreeEnabledJob; }
inline UpdateWorldTransformJobPtr updateWorldTransformJob() const { return m_worldTransformJob; }
inline UpdateWorldBoundingVolumeJobPtr updateWorldBoundingVolumeJob() const { return m_updateWorldBoundingVolumeJob; }
+ inline UpdateLevelOfDetailJobPtr updateLevelOfDetailJob() const { return m_updateLevelOfDetailJob; }
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
@@ -310,6 +314,7 @@ private:
UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob;
UpdateTreeEnabledJobPtr m_updateTreeEnabledJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
+ UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob;
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
diff --git a/src/render/frontend/qboundingsphere.cpp b/src/render/frontend/qboundingsphere.cpp
new file mode 100644
index 000000000..4d8b1aba8
--- /dev/null
+++ b/src/render/frontend/qboundingsphere.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qboundingsphere.h"
+#include "qboundingsphere_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QBoundingSpherePrivate::QBoundingSpherePrivate()
+ : QObjectPrivate()
+ , m_radius(1.f)
+{
+
+}
+
+/*!
+ \class Qt3DRender::QBoundingSphere
+ \inmodule Qt3DRender
+ \since 5.9
+ \brief The QBoundingSphere class provides a simple spherical volume, defined by it's center and radius.
+*/
+
+/*!
+ \qmltype LevelOfDetail
+ \instantiates Qt3DRender::QLevelOfDetail
+ \inherits Component3D
+ \inqmlmodule Qt3D.Render
+ \brief The BoundingSphere class provides a simple spherical volume, defined by it's center and radius.
+*/
+
+/*!
+ * \qmlproperty QVector3D BoundingSphere::center
+ *
+ * Specifies the center of the bounding sphere
+ */
+
+/*!
+ * \property QBoundingSphere::center
+ *
+ * Specifies the center of the bounding sphere
+ */
+
+/*!
+ * \qmlproperty qreal BoundingSphere::radius
+ *
+ * Specifies the radius of the bounding sphere
+ */
+
+/*!
+ * \property QBoundingSphere::radius
+ *
+ * Specifies the radius of the bounding sphere
+ */
+
+/*! \fn Qt3DRender::QBoundingSphere::QBoundingSphere(QObject *parent)
+ Constructs a new QBoundingSphere with the specified \a parent.
+ */
+QBoundingSphere::QBoundingSphere(QObject *parent)
+ : QObject(*new QBoundingSpherePrivate, parent)
+{
+
+}
+
+QBoundingSphere::QBoundingSphere(const QVector3D &center, float radius, QObject *parent)
+ : QBoundingSphere(parent)
+{
+ Q_D(QBoundingSphere);
+ d->m_center = center;
+ d->m_radius = radius;
+}
+
+QVector3D QBoundingSphere::center() const
+{
+ Q_D(const QBoundingSphere);
+ return d->m_center;
+}
+
+float QBoundingSphere::radius() const
+{
+ Q_D(const QBoundingSphere);
+ return d->m_radius;
+}
+
+/*!
+ * Sets the radius of the bounding sphere.
+ */
+void QBoundingSphere::setRadius(float radius)
+{
+ Q_D(QBoundingSphere);
+ if (d->m_radius != radius) {
+ d->m_radius = radius;
+ emit radiusChanged(radius);
+ }
+}
+
+/*!
+ * Sets the center of the bounding sphere.
+ */
+void QBoundingSphere::setCenter(const QVector3D &center)
+{
+ Q_D(QBoundingSphere);
+ if (d->m_center != center) {
+ d->m_center = center;
+ emit centerChanged(center);
+ }
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/frontend/qboundingsphere.h b/src/render/frontend/qboundingsphere.h
new file mode 100644
index 000000000..e7f9b7784
--- /dev/null
+++ b/src/render/frontend/qboundingsphere.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QBOUNDINGSPHERE_H
+#define QT3DRENDER_QBOUNDINGSPHERE_H
+
+#include <Qt3DCore/qcomponent.h>
+#include <Qt3DRender/qt3drender_global.h>
+
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QBoundingSpherePrivate;
+
+class QT3DRENDERSHARED_EXPORT QBoundingSphere : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY centerChanged)
+ Q_PROPERTY(float radius READ radius WRITE setRadius NOTIFY radiusChanged)
+public:
+ explicit QBoundingSphere(QObject *parent = nullptr);
+ QBoundingSphere(const QVector3D &center, float radius, QObject *parent = nullptr);
+
+ QVector3D center() const;
+ float radius() const;
+
+public Q_SLOTS:
+ void setRadius(float radius);
+ void setCenter(const QVector3D &center);
+
+Q_SIGNALS:
+ void radiusChanged(float radius);
+ void centerChanged(const QVector3D &center);
+
+private:
+ Q_DECLARE_PRIVATE(QBoundingSphere)
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBOUNDINGSPHERE_H
diff --git a/src/render/frontend/qboundingsphere_p.h b/src/render/frontend/qboundingsphere_p.h
new file mode 100644
index 000000000..171e4440f
--- /dev/null
+++ b/src/render/frontend/qboundingsphere_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QBOUNDINGSPHERE_P_H
+#define QT3DRENDER_QBOUNDINGSPHERE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+#include <qboundingsphere.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QT3DRENDERSHARED_EXPORT QBoundingSpherePrivate : public QObjectPrivate
+{
+public:
+ QBoundingSpherePrivate();
+
+ Q_DECLARE_PUBLIC(QBoundingSphere)
+
+ QVector3D m_center;
+ float m_radius;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBOUNDINGSPHERE_P_H
diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp
new file mode 100644
index 000000000..0d70803ca
--- /dev/null
+++ b/src/render/frontend/qlevelofdetail.cpp
@@ -0,0 +1,482 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qboundingsphere.h"
+#include "qlevelofdetail.h"
+#include "qlevelofdetail_p.h"
+#include "qcamera.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QLevelOfDetailPrivate::QLevelOfDetailPrivate()
+ : QComponentPrivate()
+ , m_camera(nullptr)
+ , m_currentIndex(0)
+ , m_thresholdType(QLevelOfDetail::DistanceToCamera)
+ , m_volumeOverride(nullptr)
+{
+ Q_Q(QLevelOfDetail);
+ m_volumeOverride = new QBoundingSphere(q);
+ QObject::connect(m_volumeOverride, SIGNAL(radiusChanged(float)), q, SLOT(_q_radiusChanged(float)));
+ QObject::connect(m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), q, SLOT(_q_centerChanged(const QVector3D&)));
+}
+
+void QLevelOfDetailPrivate::_q_radiusChanged(float radius)
+{
+ notifyPropertyChange("radius", radius);
+}
+
+void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
+{
+ notifyPropertyChange("center", center);
+}
+
+/*!
+ \class Qt3DRender::QLevelOfDetail
+ \inmodule Qt3DRender
+ \since 5.9
+ \brief The QLevelOfDetail class provides a way of controlling the complexity
+ of rendered entities based on their size on the screen.
+
+ QLevelOfDetail can be used to control the representation of an entity
+ based on distance from the observer or size on the screen.
+
+ In order to improve rendering performance, objects that are very small
+ can be rendered using far fewer details, in geometry or texture.
+
+ The component is controlled by specifying thresholds of values which are interpreted
+ as either distances from the camera or screen size.
+
+ As the point of view changes, the currentIndex property will change to
+ reflect matching value in the range array.
+
+ The currentIndex property can then be used, for example, to enable or
+ disable entities, change material, etc.
+
+ The LevelOfDetail component is not shareable between multiple Entity's.
+
+ \code
+ #include <Qt3DCore/QEntity>
+ #include <Qt3DRender/QGeometryRenderer>
+ #include <Qt3DRender/QLevelOfDetail>
+
+ // Scene
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::Qt3DCore::QEntity;
+
+ Qt3DCore::QEntity *renderableEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DCore::QGeometryRenderer(renderableEntity);
+ renderableEntity->addComponent(geometryRenderer);
+ Qt3DRender::QLevelOfDetail* lod = new Qt3Render::QLevelOfDetail(renderableEntity);
+ QVector<qreal> thresholds = {20, 35, 50, 65};
+ lod->setThresholds(thresholds);
+ lod->setCamera(mainCamera);
+ renderableEntity->addComponent(lod);
+
+ // connect to QLevelOfDetail::currentIndexChanged to toggle rendering
+ ...
+ \endcode
+*/
+
+/*!
+ \qmltype LevelOfDetail
+ \instantiates Qt3DRender::QLevelOfDetail
+ \inherits Component3D
+ \inqmlmodule Qt3D.Render
+ \since 5.9
+ \brief LevelOfDetail provides a way of controlling the complexity of
+ rendered entities based on their size on the screen.
+
+ LevelOfDetail can be used to control the representation of an entity
+ based on distance from the observer or size on the screen.
+
+ In order to improve rendering performance, objects that are very small
+ can be rendered using far fewer details, in geometry or texture.
+
+ The component is controlled by specifying thresholds of values which are interpreted
+ as either distances from the camera or screen size.
+
+ As the point of view changes, the currentIndex property will change to
+ reflect matching value in the range array.
+
+ The currentIndex property can then be used, for example, to enable or
+ disable entities, change source in an EntityLoader, or material.
+
+ The LevelOfDetail component is not shareable between multiple Entity's.
+
+ \code
+ import Qt3D.Core 2.0
+ import Qt3D.Render 2.0
+
+ Entity {
+ id: root
+
+ // Scene
+ Camera { id: mainCamera }
+
+ LevelOfDetail {
+ id: lod
+ camera: mainCamera
+ thresholds: [20, 35, 50, 65]
+ thresholdType: LevelOfDetail.DistanceToCamera
+ }
+
+ CylinderMesh {
+ id: mesh
+
+ property var sliceValues: [20, 10, 6, 4]
+ slices: sliceValues[lod.currentIndex]
+ }
+
+ Entity {
+ id: renderableEntity
+ components: [ mesh, lod ]
+ }
+ }
+ \endcode
+*/
+
+
+/*!
+ * \enum Qt3DRender::QLevelOfDetail::ThresholdType
+ *
+ * Specifies how the values in the thresholds are interpreted
+ *
+ * \value DistanceToCamera Distance from the entity to the selected camera
+ * \value ProjectedScreenPixelSize Size of the entity when projected on the
+ * screen as seen from the selected camera, expressed in number of
+ * pixels on the side of the bounding square in screen space.
+ */
+
+/*!
+ * \qmlproperty enumeration LevelOfDetail::ThresholdType
+ *
+ * Specifies how the values in the thresholds are interpreted
+ *
+ * \list
+ * \li DistanceToCamera Distance from the entity to the selected camera
+ * \li ProjectedScreenPixelSize Size of the entity when projected on the
+ * screen as seen from the selected camera, expressed in number of
+ * pixels on the side of the bounding square in screen space.
+ * \endlist
+ * \sa Qt3DRender::QLevelOfDetail::ThresholdType
+ */
+
+
+/*!
+ * \enum Qt3DRender::QLevelOfDetail::SizeProxyMode
+ *
+ * Specifies what is used as a proxy for the entity when computing distance
+ * or size.
+ *
+ * \value BoundingSphere use the bounding sphere specified by the center
+ * and radius properties.
+ * \value ChildrenBoundingSphere use the bounding sphere of the entity the
+ * component is attached to.
+ */
+
+/*!
+ * \qmlproperty enumeration LevelOfDetail::SizeProxyMode
+ *
+ * Specifies what is used as a proxy for the entity when computing distance
+ * or size.
+ *
+ * \list
+ * \li BoundingSphere use the bounding sphere specified by the center
+ * and radius properties.
+ * \li ChildrenBoundingSphere use the bounding sphere of the entity the
+ * component is attached to.
+ * \endlist
+ * \sa Qt3DRender::QLevelOfDetail::SizeProxyMode
+ */
+
+
+/*!
+ * \qmlproperty Camera LevelOfDetail::camera
+ *
+ * Holds the id of the camera that is used to compute the actual distance or the screen size.
+ */
+
+/*!
+ * \property QLevelOfDetail::camera
+ *
+ * Holds the id of the camera that is used to compute the actual distance or the screen size.
+ */
+
+/*!
+ * \qmlproperty int LevelOfDetail::currentIndex
+ *
+ * The index in the range array which matches the current distance to the camera or screen size.
+ */
+
+/*!
+ * \property QLevelOfDetail::currentIndex
+ *
+ * The index in the range array which matches the current distance to the camera or screen size.
+ */
+
+/*!
+ * \qmlproperty int LevelOfDetail::thresholdType
+ *
+ * Specifies how range values are interpreted.
+ */
+
+/*!
+ * \property QLevelOfDetail::thresholdType
+ *
+ * Specifies how range values are interpreted.
+ * \sa Qt3DRender::QLevelOfDetail::ThresholdType
+ */
+
+/*!
+ * \qmlproperty QVector<qreal> LevelOfDetail::thresholds
+ *
+ * Array of range values as float point numbers. The value for the most detailed representation
+ * should be specified first.
+ *
+ * If LevelOfDetail::thresholdType is set to LevelOfDetail.Distance, values should be specified in
+ * ascending order, in camera space coordinates
+ *
+ * If LevelOfDetail::thresholdType is set to LevelOfDetail.ProjectedScreenPixelSize, values should
+ * be specified in descending order, in screen space pixels.
+ */
+
+/*!
+ * \property QLevelOfDetail::thresholds
+ *
+ * Array of range values as float point numbers. The value for the most detailed representation
+ * should be specified first.
+ *
+ * If Qt3DRender::QLevelOfDetail::thresholdType is set to Qt3DRender::QLevelOfDetail::Distance, values should be specified in
+ * ascending order, in camera space coordinates
+ *
+ * If Qt3DRender::QLevelOfDetail::thresholdType is set to Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize, values should
+ * be specified in descending order, in screen space pixels.
+ *
+ * \sa Qt3DRender::QLevelOfDetail::ThresholdType
+ */
+
+/*!
+ * \qmlproperty int LevelOfDetail::volumeOverride
+ *
+ * Specifies what is used to evaluate the distance or screen size.
+ *
+ * The default is a sphere of radius 1 and centered at the local origin of the entity.
+ * This proxy volume is used to compute the distance to the camera or the size
+ * of the screen projection.
+ *
+ * If this value to null, the bounding volume of the entity is used. Care must be
+ * taken that this bounding volume never becomes invalid.
+ *
+ * \sa BoundingSphere
+ */
+
+/*!
+ * \property QLevelOfDetail::volumeOverride
+ *
+ * The default is a sphere of radius 1 and centered at the local origin of the entity.
+ * This proxy volume is used to compute the distance to the camera or the size
+ * of the screen projection.
+ *
+ * If this value to nullptr, the bounding volume of the entity is used. Care must be
+ * taken that this bounding volume never becomes invalid.
+ *
+ * \sa QBoundingSphere
+ */
+
+
+/*! \fn Qt3DRender::QLevelOfDetail::QLevelOfDetail(Qt3DCore::QNode *parent)
+ Constructs a new QLevelOfDetail with the specified \a parent.
+ */
+QLevelOfDetail::QLevelOfDetail(QNode *parent)
+ : QComponent(*new QLevelOfDetailPrivate, parent)
+{
+}
+
+/*! \internal */
+QLevelOfDetail::~QLevelOfDetail()
+{
+}
+
+/*! \internal */
+QLevelOfDetail::QLevelOfDetail(QLevelOfDetailPrivate &dd, QNode *parent)
+ : QComponent(dd, parent)
+{
+}
+
+/*! \internal */
+Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QLevelOfDetailData>::create(this);
+ auto &data = creationChange->data;
+
+ Q_D(const QLevelOfDetail);
+ if (d->m_camera)
+ data.camera = d->m_camera->id();
+ data.currentIndex = d->m_currentIndex;
+ data.thresholdType = d->m_thresholdType;
+ data.thresholds = d->m_thresholds;
+ data.radius = d->m_volumeOverride ? d->m_volumeOverride->radius() : -1.f;
+ data.center = d->m_volumeOverride ? d->m_volumeOverride->center() : QVector3D();
+
+ return creationChange;
+}
+
+/*! \internal */
+void QLevelOfDetail::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Q_D(QLevelOfDetail);
+ Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->type() == Qt3DCore::PropertyUpdated) {
+ if (e->propertyName() == QByteArrayLiteral("currentIndex")) {
+ int ndx = e->value().value<int>();
+ d->m_currentIndex = ndx;
+ emit currentIndexChanged(ndx);
+ }
+ }
+}
+
+QCamera *QLevelOfDetail::camera() const
+{
+ Q_D(const QLevelOfDetail);
+ return d->m_camera;
+}
+
+/*!
+ * Sets the camera relative to which distance and size are computed.
+ */
+void QLevelOfDetail::setCamera(QCamera *camera)
+{
+ Q_D(QLevelOfDetail);
+ if (d->m_camera != camera) {
+ d->m_camera = camera;
+ emit cameraChanged(d->m_camera);
+ }
+}
+
+int QLevelOfDetail::currentIndex() const
+{
+ Q_D(const QLevelOfDetail);
+ return d->m_currentIndex;
+}
+
+/*!
+ * Sets the current index.
+ *
+ * \note This should not normally be set by the user.
+ *
+ * However, if the component is disabled, then changing the
+ * current index is a simple way of switching between multiple
+ * representations.
+ */
+void QLevelOfDetail::setCurrentIndex(int currentIndex)
+{
+ Q_D(QLevelOfDetail);
+ if (d->m_currentIndex != currentIndex) {
+ d->m_currentIndex = currentIndex;
+ emit currentIndexChanged(d->m_currentIndex);
+ }
+}
+
+QLevelOfDetail::ThresholdType QLevelOfDetail::thresholdType() const
+{
+ Q_D(const QLevelOfDetail);
+ return d->m_thresholdType;
+}
+
+/*!
+ * Sets the way thresholds values are interpreted
+ * \sa Qt3DRender::QLevelOfDetail::ThresholdType
+ */
+void QLevelOfDetail::setThresholdType(QLevelOfDetail::ThresholdType thresholdType)
+{
+ Q_D(QLevelOfDetail);
+ if (d->m_thresholdType != thresholdType) {
+ d->m_thresholdType = thresholdType;
+ emit thresholdTypeChanged(d->m_thresholdType);
+ }
+}
+
+QVector<qreal> QLevelOfDetail::thresholds() const
+{
+ Q_D(const QLevelOfDetail);
+ return d->m_thresholds;
+}
+
+/*!
+ * Sets the range values.
+ * \sa Qt3DRender::QLevelOfDetail::thresholdType
+ */
+void QLevelOfDetail::setThresholds(QVector<qreal> thresholds)
+{
+ Q_D(QLevelOfDetail);
+ if (d->m_thresholds != thresholds) {
+ d->m_thresholds = thresholds;
+ thresholdsChanged(d->m_thresholds);
+ }
+}
+
+QBoundingSphere *QLevelOfDetail::volumeOverride() const
+{
+ Q_D(const QLevelOfDetail);
+ return d->m_volumeOverride;
+}
+
+void QLevelOfDetail::setVolumeOverride(QBoundingSphere *volumeOverride)
+{
+ Q_D(QLevelOfDetail);
+ if (d->m_volumeOverride != volumeOverride) {
+ if (d->m_volumeOverride)
+ disconnect(d->m_volumeOverride);
+ d->m_volumeOverride = volumeOverride;
+ if (d->m_volumeOverride) {
+ connect(d->m_volumeOverride, SIGNAL(radiusChanged(float)), this, SLOT(_q_radiusChanged(float)));
+ connect(d->m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), this, SLOT(_q_centerChanged(const QVector3D&)));
+ }
+ emit volumeOverrideChanged(volumeOverride);
+ }
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#include "moc_qlevelofdetail.cpp"
diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h
new file mode 100644
index 000000000..677169f02
--- /dev/null
+++ b/src/render/frontend/qlevelofdetail.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QLEVELOFDETAIL_H
+#define QT3DRENDER_QLEVELOFDETAIL_H
+
+#include <Qt3DCore/qcomponent.h>
+#include <Qt3DRender/qt3drender_global.h>
+
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QCamera;
+class QBoundingSphere;
+class QLevelOfDetailPrivate;
+
+class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged)
+ Q_PROPERTY(QVector<qreal> thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged)
+ Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged)
+
+public:
+ enum ThresholdType {
+ DistanceToCamera,
+ ProjectedScreenPixelSize,
+ };
+ Q_ENUM(ThresholdType) // LCOV_EXCL_LINE
+
+ explicit QLevelOfDetail(Qt3DCore::QNode *parent = nullptr);
+ ~QLevelOfDetail();
+
+ QCamera *camera() const;
+ int currentIndex() const;
+ ThresholdType thresholdType() const;
+ QVector<qreal> thresholds() const;
+ QBoundingSphere *volumeOverride() const;
+
+public Q_SLOTS:
+ void setCamera(QCamera *camera);
+ void setCurrentIndex(int currentIndex);
+ void setThresholdType(ThresholdType thresholdType);
+ void setThresholds(QVector<qreal> thresholds);
+ void setVolumeOverride(QBoundingSphere *volumeOverride);
+
+Q_SIGNALS:
+ void cameraChanged(QCamera *camera);
+ void currentIndexChanged(int currentIndex);
+ void thresholdTypeChanged(ThresholdType thresholdType);
+ void thresholdsChanged(QVector<qreal> thresholds);
+ void volumeOverrideChanged(QBoundingSphere *volumeOverride);
+
+protected:
+ explicit QLevelOfDetail(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QLevelOfDetail)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
+ Q_PRIVATE_SLOT(d_func(), void _q_radiusChanged(float))
+ Q_PRIVATE_SLOT(d_func(), void _q_centerChanged(const QVector3D&))
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QLEVELOFDETAIL_H
diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h
new file mode 100644
index 000000000..ab25e9ad3
--- /dev/null
+++ b/src/render/frontend/qlevelofdetail_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QLEVELOFDETAIL_P_H
+#define QT3DRENDER_QLEVELOFDETAIL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qcomponent_p.h>
+#include <qlevelofdetail.h>
+
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QLevelOfDetailPrivate : public Qt3DCore::QComponentPrivate
+{
+public:
+ QLevelOfDetailPrivate();
+
+ Q_DECLARE_PUBLIC(QLevelOfDetail)
+
+ void _q_radiusChanged(float radius);
+ void _q_centerChanged(const QVector3D &center);
+
+ QCamera *m_camera;
+ int m_currentIndex;
+ QLevelOfDetail::ThresholdType m_thresholdType;
+ QVector<qreal> m_thresholds;
+ QPointer<QBoundingSphere> m_volumeOverride;
+};
+
+struct QLevelOfDetailData
+{
+ Qt3DCore::QNodeId camera;
+ int currentIndex;
+ QLevelOfDetail::ThresholdType thresholdType;
+ QVector<qreal> thresholds;
+ float radius;
+ QVector3D center;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QLEVELOFDETAIL_P_H
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index f518e7ce7..7bddecadf 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -51,6 +51,7 @@
#include <Qt3DRender/qcameraselector.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlayerfilter.h>
+#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qparameter.h>
@@ -190,6 +191,7 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<Qt3DRender::QCameraLens>(QSharedPointer<Render::NodeFunctor<Render::CameraLens, Render::CameraManager> >::create(m_renderer));
q->registerBackendType<QLayer>(QSharedPointer<Render::NodeFunctor<Render::Layer, Render::LayerManager> >::create(m_renderer));
+ q->registerBackendType<QLevelOfDetail>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
q->registerBackendType<QSceneLoader>(QSharedPointer<Render::RenderSceneFunctor>::create(m_renderer, m_nodeManagers->sceneManager()));
q->registerBackendType<QRenderTarget>(QSharedPointer<Render::NodeFunctor<Render::RenderTarget, Render::RenderTargetManager> >::create(m_renderer));
q->registerBackendType<QRenderTargetOutput>(QSharedPointer<Render::NodeFunctor<Render::RenderTargetOutput, Render::AttachmentManager> >::create(m_renderer));
diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri
index 829e3d756..649b3d673 100644
--- a/src/render/frontend/render-frontend.pri
+++ b/src/render/frontend/render-frontend.pri
@@ -2,11 +2,15 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qabstractfunctor.h \
+ $$PWD/qboundingsphere.h \
+ $$PWD/qboundingsphere_p.h \
$$PWD/qrenderaspect.h \
$$PWD/qrenderaspect_p.h \
$$PWD/qitemmodelbuffer_p.h \
$$PWD/qlayer.h \
$$PWD/qlayer_p.h \
+ $$PWD/qlevelofdetail.h \
+ $$PWD/qlevelofdetail_p.h \
$$PWD/qrendertarget.h \
$$PWD/qrendertarget_p.h \
$$PWD/sphere_p.h \
@@ -25,10 +29,12 @@ HEADERS += \
SOURCES += \
$$PWD/qabstractfunctor.cpp \
+ $$PWD/qboundingsphere.cpp \
$$PWD/qrenderaspect.cpp \
$$PWD/qitemmodelbuffer.cpp \
$$PWD/sphere.cpp \
$$PWD/qlayer.cpp \
+ $$PWD/qlevelofdetail.cpp \
$$PWD/qrendertarget.cpp \
$$PWD/qcamera.cpp \
$$PWD/qcameralens.cpp \
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index f3be2e6b0..90e29d0dc 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -96,6 +96,7 @@ namespace JobTypes {
ClearBufferDrawIndex,
UpdateMeshTriangleList,
FilterCompatibleTechniques,
+ UpdateLevelOfDetail,
SyncTextureLoading
};
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index 2827d959d..d7f05ec4c 100644
--- a/src/render/jobs/jobs.pri
+++ b/src/render/jobs/jobs.pri
@@ -24,6 +24,7 @@ HEADERS += \
$$PWD/updateworldboundingvolumejob_p.h \
$$PWD/sendrendercapturejob_p.h \
$$PWD/updateshaderdatatransformjob_p.h \
+ $$PWD/updatelevelofdetailjob_p.h \
$$PWD/updatemeshtrianglelistjob_p.h \
$$PWD/pickboundingvolumeutils_p.h \
$$PWD/filtercompatibletechniquejob_p.h \
@@ -51,6 +52,7 @@ SOURCES += \
$$PWD/sendrendercapturejob.cpp \
$$PWD/updateshaderdatatransformjob.cpp \
$$PWD/updatemeshtrianglelistjob.cpp \
+ $$PWD/updatelevelofdetailjob.cpp \
$$PWD/pickboundingvolumeutils.cpp \
$$PWD/filtercompatibletechniquejob.cpp \
$$PWD/updatetreeenabledjob.cpp
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index 1498021a7..1573aa112 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -102,6 +102,8 @@ QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraph
// Find all viewport/camera pairs by traversing from leaf to root
for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) {
ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf);
+ if (!m_targetCamera.isNull() && vcaTriplet.cameraId != m_targetCamera)
+ continue;
if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet))
vcaTriplets.push_back(vcaTriplet);
}
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index f514c045f..0a65c58cc 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <Qt3DCore/QNodeId>
#include <Qt3DRender/private/qray3d_p.h>
#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/qraycastingservice_p.h>
@@ -82,9 +83,11 @@ QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaTrip
class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer
{
public:
+ ViewportCameraAreaGatherer(const Qt3DCore::QNodeId &nodeId = Qt3DCore::QNodeId()) : m_targetCamera(nodeId) { }
QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root);
private:
+ Qt3DCore::QNodeId m_targetCamera;
QVector<FrameGraphNode *> m_leaves;
void visit(FrameGraphNode *node);
diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp
new file mode 100644
index 000000000..940d26850
--- /dev/null
+++ b/src/render/jobs/updatelevelofdetailjob.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "updatelevelofdetailjob_p.h"
+#include <Qt3DRender/QLevelOfDetail>
+#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+
+template <unsigned N>
+double approxRollingAverage(double avg, double input) {
+ avg -= avg / N;
+ avg += input / N;
+ return avg;
+}
+
+}
+namespace Qt3DRender {
+
+namespace Render {
+
+UpdateLevelOfDetailJob::UpdateLevelOfDetailJob()
+ : m_manager(nullptr)
+ , m_frameGraphRoot(nullptr)
+ , m_root(nullptr)
+ , m_filterValue(0.)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLevelOfDetail, 0);
+}
+
+UpdateLevelOfDetailJob::~UpdateLevelOfDetailJob()
+{
+}
+
+void UpdateLevelOfDetailJob::setRoot(Entity *root)
+{
+ m_root = root;
+}
+
+void UpdateLevelOfDetailJob::setManagers(NodeManagers *manager)
+{
+ m_manager = manager;
+}
+
+void UpdateLevelOfDetailJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot)
+{
+ m_frameGraphRoot = frameGraphRoot;
+}
+
+void UpdateLevelOfDetailJob::run()
+{
+ Q_ASSERT(m_frameGraphRoot && m_root && m_manager);
+ updateEntityLod(m_root);
+}
+
+bool UpdateLevelOfDetailJob::viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId,
+ QMatrix4x4 &viewMatrix,
+ QMatrix4x4 &projectionMatrix) const
+{
+ Render::CameraLens *lens = nullptr;
+ Entity *camNode = m_manager->renderNodesManager()->lookupResource(cameraId);
+ if (camNode != nullptr &&
+ (lens = camNode->renderComponent<CameraLens>()) != nullptr &&
+ lens->isEnabled()) {
+ viewMatrix = *camNode->worldTransform();
+ projectionMatrix = lens->projection();
+ return true;
+ }
+ return false;
+}
+
+QRect UpdateLevelOfDetailJob::windowViewport(const QSize &area, const QRectF &relativeViewport) const
+{
+ if (area.isValid()) {
+ const int areaWidth = area.width();
+ const int areaHeight = area.height();
+ return QRect(relativeViewport.x() * areaWidth,
+ (1.0 - relativeViewport.y() - relativeViewport.height()) * areaHeight,
+ relativeViewport.width() * areaWidth,
+ relativeViewport.height() * areaHeight);
+ }
+ return relativeViewport.toRect();
+}
+
+void UpdateLevelOfDetailJob::updateEntityLod(Entity *entity)
+{
+ if (!entity->isEnabled())
+ return; // skip disabled sub-trees, since their bounding box is probably not valid anyway
+
+ QVector<LevelOfDetail *> lods = entity->renderComponents<LevelOfDetail>();
+ if (!lods.empty()) {
+ LevelOfDetail* lod = lods.front(); // other lods are ignored
+
+ if (lod->isEnabled() && !lod->thresholds().isEmpty()) {
+ switch (lod->thresholdType()) {
+ case QLevelOfDetail::DistanceToCamera:
+ updateEntityLodByDistance(entity, lod);
+ break;
+ case QLevelOfDetail::ProjectedScreenPixelSize:
+ updateEntityLodByScreenArea(entity, lod);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+ }
+
+ const auto children = entity->children();
+ for (Qt3DRender::Render::Entity *child : children)
+ updateEntityLod(child);
+}
+
+void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDetail *lod)
+{
+ QMatrix4x4 viewMatrix;
+ QMatrix4x4 projectionMatrix;
+ if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix))
+ return;
+
+ const QVector<qreal> thresholds = lod->thresholds();
+ QVector3D center = lod->center();
+ if (lod->radius() > 0.f || entity->worldBoundingVolume() == nullptr) {
+ center = *entity->worldTransform() * center;
+ } else {
+ center = entity->worldBoundingVolume()->center();
+ }
+
+ const QVector3D tcenter = viewMatrix * center;
+ const float dist = tcenter.length();
+ const int n = thresholds.size();
+ for (int i=0; i<n; ++i) {
+ if (dist <= thresholds[i] || i == n -1) {
+ m_filterValue = approxRollingAverage<30>(m_filterValue, i);
+ i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1);
+ if (lod->currentIndex() != i)
+ lod->setCurrentIndex(i);
+ break;
+ }
+ }
+}
+
+void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOfDetail *lod)
+{
+ QMatrix4x4 viewMatrix;
+ QMatrix4x4 projectionMatrix;
+ if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix))
+ return;
+
+ PickingUtils::ViewportCameraAreaGatherer vcaGatherer(lod->camera());
+ const QVector<PickingUtils::ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot);
+ if (vcaTriplets.isEmpty())
+ return;
+
+ const PickingUtils::ViewportCameraAreaTriplet &vca = vcaTriplets.front();
+
+ const QVector<qreal> thresholds = lod->thresholds();
+ Sphere bv(lod->center(), lod->radius());
+ if (lod->radius() <= 0.f && entity->worldBoundingVolume() != nullptr) {
+ bv = *(entity->worldBoundingVolume());
+ } else {
+ bv.transform(*entity->worldTransform());
+ }
+
+ bv.transform(projectionMatrix * viewMatrix);
+ const float sideLength = bv.radius() * 2.f;
+ float area = vca.viewport.width() * sideLength * vca.viewport.height() * sideLength;
+
+ const QRect r = windowViewport(vca.area, vca.viewport);
+ area = std::sqrt(area * r.width() * r.height());
+
+ const int n = thresholds.size();
+ for (int i = 0; i < n; ++i) {
+ if (thresholds[i] < area || i == n -1) {
+ m_filterValue = approxRollingAverage<30>(m_filterValue, i);
+ i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1);
+ if (lod->currentIndex() != i)
+ lod->setCurrentIndex(i);
+ break;
+ }
+ }
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/updatelevelofdetailjob_p.h b/src/render/jobs/updatelevelofdetailjob_p.h
new file mode 100644
index 000000000..30fe3004d
--- /dev/null
+++ b/src/render/jobs/updatelevelofdetailjob_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_UPDATELEVELOFDETAILJOB_H
+#define QT3DRENDER_RENDER_UPDATELEVELOFDETAILJOB_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Entity;
+class NodeManagers;
+class LevelOfDetail;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateLevelOfDetailJob : public Qt3DCore::QAspectJob
+{
+public:
+ UpdateLevelOfDetailJob();
+ ~UpdateLevelOfDetailJob();
+
+ void setManagers(NodeManagers *manager);
+ void setFrameGraphRoot(FrameGraphNode *frameGraphRoot);
+ void setRoot(Entity *root);
+ void run() Q_DECL_FINAL;
+
+ NodeManagers *managers() const { return m_manager; }
+ Entity *root() const { return m_root; }
+
+private:
+ void updateEntityLod(Entity *entity);
+ void updateEntityLodByDistance(Entity *entity, LevelOfDetail *lod);
+ void updateEntityLodByScreenArea(Entity *entity, LevelOfDetail *lod);
+ bool viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId, QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix) const;
+ QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const;
+
+ NodeManagers *m_manager;
+ FrameGraphNode *m_frameGraphRoot;
+ Entity *m_root;
+ double m_filterValue;
+};
+
+typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr;
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_UPDATELEVELOFDETAILJOB_H
diff --git a/tests/auto/render/levelofdetail/levelofdetail.pro b/tests/auto/render/levelofdetail/levelofdetail.pro
new file mode 100644
index 000000000..496efc35c
--- /dev/null
+++ b/tests/auto/render/levelofdetail/levelofdetail.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_levelofdetail
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_levelofdetail.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/levelofdetail/tst_levelofdetail.cpp b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp
new file mode 100644
index 000000000..ab0e8c4b8
--- /dev/null
+++ b/tests/auto/render/levelofdetail/tst_levelofdetail.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <qbackendnodetester.h>
+#include <Qt3DRender/QLevelOfDetail>
+#include <Qt3DRender/QBoundingSphere>
+#include <Qt3DRender/private/levelofdetail_p.h>
+#include <Qt3DRender/private/qlevelofdetail_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include "testpostmanarbiter.h"
+#include "testrenderer.h"
+
+class tst_LevelOfDetail : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ Qt3DRender::Render::LevelOfDetail renderLod;
+ Qt3DRender::QLevelOfDetail lod;
+
+ // WHEN
+ simulateInitialization(&lod, &renderLod);
+
+ // THEN
+ QCOMPARE(renderLod.peerId(), lod.id());
+ QVERIFY(renderLod.camera().isNull() && lod.camera() == nullptr);
+ QCOMPARE(renderLod.currentIndex(), lod.currentIndex());
+ QCOMPARE(renderLod.thresholdType(), lod.thresholdType());
+ QCOMPARE(renderLod.thresholds(), lod.thresholds());
+ QCOMPARE(renderLod.center(), lod.volumeOverride()->center());
+ QCOMPARE(renderLod.radius(), lod.volumeOverride()->radius());
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ Qt3DRender::Render::LevelOfDetail renderLod;
+ TestRenderer renderer;
+
+ // THEN
+ QCOMPARE(renderLod.camera(), Qt3DCore::QNodeId{});
+ QCOMPARE(renderLod.currentIndex(), 0);
+ QCOMPARE(renderLod.thresholdType(), Qt3DRender::QLevelOfDetail::DistanceToCamera);
+ QVERIFY(renderLod.thresholds().empty());
+ QCOMPARE(renderLod.radius(), 1.f);
+ QCOMPARE(renderLod.center(), QVector3D{});
+ QVERIFY(renderLod.peerId().isNull());
+
+ // GIVEN
+ Qt3DRender::QLevelOfDetail lod;
+ lod.setThresholdType(Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize);
+
+ // WHEN
+ renderLod.setRenderer(&renderer);
+ simulateInitialization(&lod, &renderLod);
+
+ // THEN
+ QCOMPARE(renderLod.thresholdType(), lod.thresholdType());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ Qt3DRender::Render::LevelOfDetail renderLod;
+ renderLod.setRenderer(&renderer);
+
+ // THEN
+ QVERIFY(renderLod.thresholdType() != Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize);
+ QVERIFY(renderLod.camera().isNull());
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setValue(static_cast<int>(Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize));
+ updateChange->setPropertyName("thresholdType");
+ renderLod.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(renderLod.thresholdType(), Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize);
+ QVERIFY(renderer.dirtyBits() != 0);
+ }
+
+ {
+ QVector<qreal> thresholds = {20.f, 30.f, 40.f};
+ QVariant v;
+ v.setValue<decltype(thresholds)>(thresholds);
+
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setValue(v);
+ updateChange->setPropertyName("thresholds");
+ renderLod.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(renderLod.thresholds(), thresholds);
+ }
+
+ {
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setValue(QVector3D(1., 2., 3.));
+ updateChange->setPropertyName("center");
+ renderLod.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(renderLod.center(), QVector3D(1., 2., 3.));
+ }
+ }
+};
+
+
+QTEST_APPLESS_MAIN(tst_LevelOfDetail)
+
+#include "tst_levelofdetail.moc"
diff --git a/tests/auto/render/qlevelofdetail/qlevelofdetail.pro b/tests/auto/render/qlevelofdetail/qlevelofdetail.pro
new file mode 100644
index 000000000..e8d7010a3
--- /dev/null
+++ b/tests/auto/render/qlevelofdetail/qlevelofdetail.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qlevelofdetail
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qlevelofdetail.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp
new file mode 100644
index 000000000..e2ffdd9da
--- /dev/null
+++ b/tests/auto/render/qlevelofdetail/tst_qlevelofdetail.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+
+#include <Qt3DRender/qlevelofdetail.h>
+#include <Qt3DRender/private/qlevelofdetail_p.h>
+
+#include "testpostmanarbiter.h"
+
+class tst_QLevelOfDetail: public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkCloning_data()
+ {
+ QTest::addColumn<Qt3DRender::QLevelOfDetail *>("lod");
+
+ Qt3DRender::QLevelOfDetail *defaultConstructed = new Qt3DRender::QLevelOfDetail();
+ QTest::newRow("defaultConstructed") << defaultConstructed;
+
+ Qt3DRender::QLevelOfDetail *lodDst = new Qt3DRender::QLevelOfDetail();
+ QTest::newRow("distLod") << lodDst;
+
+ Qt3DRender::QLevelOfDetail *lodPx = new Qt3DRender::QLevelOfDetail();
+ QTest::newRow("pxLod") << lodPx;
+ }
+
+ void checkCloning()
+ {
+ // GIVEN
+ QFETCH(Qt3DRender::QLevelOfDetail *, lod);
+
+ // WHEN
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(lod);
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
+
+ // THEN
+ QCOMPARE(creationChanges.size(), 1);
+
+ const Qt3DCore::QNodeCreatedChangePtr<Qt3DRender::QLevelOfDetailData> creationChangeData =
+ qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QLevelOfDetailData>>(creationChanges.first());
+ const Qt3DRender::QLevelOfDetailData &cloneData = creationChangeData->data;
+
+ QCOMPARE(lod->id(), creationChangeData->subjectId());
+ QCOMPARE(lod->isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(lod->metaObject(), creationChangeData->metaObject());
+ QCOMPARE(lod->currentIndex(), cloneData.currentIndex);
+ QCOMPARE(lod->thresholdType(), cloneData.thresholdType);
+ QCOMPARE(lod->thresholds(), cloneData.thresholds);
+ }
+
+ void checkPropertyUpdates()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QScopedPointer<Qt3DRender::QLevelOfDetail> lod(new Qt3DRender::QLevelOfDetail());
+ arbiter.setArbiterOnNode(lod.data());
+
+ {
+ // WHEN
+ lod->setThresholdType(Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "thresholdType");
+ QCOMPARE(change->value().value<int>(), static_cast<int>(Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize));
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ QVector<qreal> thresholds = {10., 20., 30.};
+ lod->setThresholds(thresholds);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "thresholds");
+ QCOMPARE(change->value().value<decltype(thresholds)>(), thresholds);
+
+ arbiter.events.clear();
+ }
+ }
+};
+
+QTEST_MAIN(tst_QLevelOfDetail)
+
+#include "tst_qlevelofdetail.moc"
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index 666723ae8..c1de2aff8 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -18,6 +18,8 @@ qtConfig(private_tests) {
qbuffer \
qgeometry \
qgeometryrenderer \
+ qlevelofdetail \
+ levelofdetail \
buffer \
attribute \
geometry \
diff --git a/tests/manual/lod/ConeEntity.qml b/tests/manual/lod/ConeEntity.qml
new file mode 100644
index 000000000..bfe6703b6
--- /dev/null
+++ b/tests/manual/lod/ConeEntity.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ components: [ mesh, phongMaterial, transform ]
+
+ ConeMesh {
+ id: mesh
+ bottomRadius: 1.5
+ length: 3
+ }
+
+ PhongMaterial {
+ id: phongMaterial
+ diffuse: "red"
+ }
+
+ Transform {
+ id: transform
+ scale: 4
+ }
+}
diff --git a/tests/manual/lod/CuboidEntity.qml b/tests/manual/lod/CuboidEntity.qml
new file mode 100644
index 000000000..875d98b32
--- /dev/null
+++ b/tests/manual/lod/CuboidEntity.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ components: [ mesh, phongMaterial, transform ]
+
+ CuboidMesh {
+ id: mesh
+ yzMeshResolution: Qt.size(2, 2)
+ xzMeshResolution: Qt.size(2, 2)
+ xyMeshResolution: Qt.size(2, 2)
+ }
+
+ PhongMaterial {
+ id: phongMaterial
+ diffuse: "yellow"
+ }
+
+ Transform {
+ id: transform
+ scale: 4
+ }
+}
diff --git a/tests/manual/lod/CylinderEntity.qml b/tests/manual/lod/CylinderEntity.qml
new file mode 100644
index 000000000..f89bd3eeb
--- /dev/null
+++ b/tests/manual/lod/CylinderEntity.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ components: [ mesh, phongMaterial, transform ]
+
+ CylinderMesh {
+ id: mesh
+ radius: 1
+ length: 3
+ }
+
+ PhongMaterial {
+ id: phongMaterial
+ diffuse: "green"
+ }
+
+ Transform {
+ id: transform
+ scale: 4
+ }
+}
diff --git a/tests/manual/lod/SphereEntity.qml b/tests/manual/lod/SphereEntity.qml
new file mode 100644
index 000000000..3671921b8
--- /dev/null
+++ b/tests/manual/lod/SphereEntity.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ components: [ mesh, material, transform ]
+
+ SphereMesh {
+ id: mesh
+ radius: 1
+ }
+
+ PhongMaterial {
+ id: material
+ diffuse: "blue"
+ }
+
+ Transform {
+ id: transform
+ scale: 4
+ }
+}
diff --git a/tests/manual/lod/lod.pro b/tests/manual/lod/lod.pro
new file mode 100644
index 000000000..32ccc6571
--- /dev/null
+++ b/tests/manual/lod/lod.pro
@@ -0,0 +1,20 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ lod.qrc
+
+DISTFILES += \
+ ConeEntity.qml \
+ CuboidEntity.qml \
+ CylinderEntity.qml \
+ SphereEntity.qml
diff --git a/tests/manual/lod/lod.qrc b/tests/manual/lod/lod.qrc
new file mode 100644
index 000000000..746ac679e
--- /dev/null
+++ b/tests/manual/lod/lod.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>ConeEntity.qml</file>
+ <file>CuboidEntity.qml</file>
+ <file>CylinderEntity.qml</file>
+ <file>SphereEntity.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/lod/main.cpp b/tests/manual/lod/main.cpp
new file mode 100644
index 000000000..dba6e0bff
--- /dev/null
+++ b/tests/manual/lod/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+ Qt3DExtras::Quick::Qt3DQuickWindow view;
+
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/lod/main.qml b/tests/manual/lod/main.qml
new file mode 100644
index 000000000..aea87f653
--- /dev/null
+++ b/tests/manual/lod/main.qml
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.2
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.2
+
+import QtQuick 2.0 as QQ2
+
+Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ 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, 0.0 )
+ }
+
+ OrbitCameraController { camera: camera }
+
+ Entity {
+ id: headlight
+ components: [
+ DirectionalLight {
+ color: Qt.rgba(0.8, 0.8, 0.8, 1.0)
+ worldDirection: camera.viewVector
+ }
+ ]
+ }
+
+ RenderSettings {
+ id : external_forward_renderer
+ activeFrameGraph : ForwardRenderer {
+ camera: camera
+ clearColor: "white"
+ }
+ }
+
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { id: inputSettings }
+
+ components: [external_forward_renderer, inputSettings]
+
+ Entity {
+ components: [
+ Transform {
+ id: transform
+ }
+ ]
+
+ Entity {
+ components: [
+ CylinderMesh {
+ id: mesh
+ radius: 1
+ length: 3
+ rings: 2
+ slices: sliceValues[lod.currentIndex]
+
+ property var sliceValues: [20, 10, 6, 4]
+ },
+ Transform {
+ scale: 1.5
+ translation: Qt.vector3d(-5, 0, 0)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ },
+ PhongMaterial {
+ id: material
+ diffuse: "lightgreen"
+ },
+ LevelOfDetail {
+ id: lod
+ camera: camera
+ thresholds: [1000, 600, 300, 180]
+ thresholdType: LevelOfDetail.ProjectedScreenPixelSize
+ volumeOverride: BoundingSphere {
+ radius: 2.
+ }
+ }
+ ]
+ }
+ }
+
+ Entity {
+ components: [
+ Transform {
+ translation: transform.translation
+ }
+ ]
+
+ LevelOfDetailLoader {
+ components: [ Transform {
+ scale: .5
+ translation: Qt.vector3d(5, 0, 0)
+ } ]
+
+ camera: camera
+ thresholds: [20, 35, 50, 65]
+ thresholdType: LevelOfDetail.DistanceToCamera
+ volumeOverride: null
+ sources: ["qrc:/SphereEntity.qml", "qrc:/CylinderEntity.qml", "qrc:/ConeEntity.qml", "qrc:/CuboidEntity.qml"]
+ }
+ }
+
+ QQ2.SequentialAnimation {
+ QQ2.Vector3dAnimation {
+ target: transform
+ properties: "translation"
+ from: Qt.vector3d(0, 0, 10)
+ to: Qt.vector3d(0, 0, -50)
+ duration: 2500
+ easing.type: QQ2.Easing.InOutQuad
+ }
+ QQ2.PropertyAnimation {
+ target: transform
+ properties: "translation"
+ from: Qt.vector3d(0, 0, -50)
+ to: Qt.vector3d(0, 0, 10)
+ duration: 2500
+ easing.type: QQ2.Easing.InOutQuad
+ }
+
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+}
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index bfb95bfc2..3b036e2ba 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -21,6 +21,7 @@ SUBDIRS += \
gooch-qml \
keyboardinput-qml \
loader-qml \
+ lod \
mouseinput-qml \
multiplewindows-qml \
picking-qml \