summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 \