summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2016-12-16 18:31:48 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2016-12-16 18:31:48 +0000
commitc6258f2a294347283272b40164cf76230899e536 (patch)
tree871f4e7dda53cfcd570e680095321c4b41712252
parent7daf5199bc521d0982324321bcb485f37646c0b0 (diff)
parented8da73ff148d959a1ef7d54f073b322032ec64b (diff)
Merge "Merge branch '5.8.0' into 5.8" into refs/staging/5.8
-rw-r--r--dist/changes-5.8.051
-rw-r--r--src/core/changes/qcomponentaddedchange.cpp3
-rw-r--r--src/core/changes/qcomponentremovedchange.cpp3
-rw-r--r--src/core/changes/qpropertynodeaddedchange.cpp2
-rw-r--r--src/input/backend/axisaccumulator.cpp155
-rw-r--r--src/input/backend/axisaccumulator_p.h101
-rw-r--r--src/input/backend/axisaccumulatorjob.cpp73
-rw-r--r--src/input/backend/axisaccumulatorjob_p.h89
-rw-r--r--src/input/backend/backend.pri8
-rw-r--r--src/input/backend/handle_types_p.h2
-rw-r--r--src/input/backend/inputhandler.cpp2
-rw-r--r--src/input/backend/inputhandler_p.h3
-rw-r--r--src/input/backend/inputmanagers_p.h11
-rw-r--r--src/input/backend/job_common_p.h3
-rw-r--r--src/input/frontend/qaxisaccumulator.cpp38
-rw-r--r--src/input/frontend/qaxisaccumulator.h7
-rw-r--r--src/input/frontend/qaxisaccumulator_p.h6
-rw-r--r--src/input/frontend/qinputaspect.cpp24
-rw-r--r--src/input/frontend/qinputaspect_p.h1
-rw-r--r--src/quick3d/imports/input/qt3dquick3dinputplugin.cpp2
-rw-r--r--src/quick3d/imports/render/qt3dquick3drenderplugin.cpp4
-rw-r--r--src/quick3d/quick3d/items/quick3dentityloader.cpp8
-rw-r--r--src/quick3d/quick3d/items/quick3dentityloader_p.h1
-rw-r--r--src/render/backend/abstractrenderer_p.h7
-rw-r--r--src/render/backend/managers_p.h15
-rw-r--r--src/render/backend/offscreensurfacehelper.cpp81
-rw-r--r--src/render/backend/offscreensurfacehelper_p.h86
-rw-r--r--src/render/backend/render-backend.pri6
-rw-r--r--src/render/backend/renderer.cpp119
-rw-r--r--src/render/backend/renderer_p.h16
-rw-r--r--src/render/backend/trianglesvisitor.cpp49
-rw-r--r--src/render/backend/uniform.cpp1
-rw-r--r--src/render/backend/uniform_p.h4
-rw-r--r--src/render/frontend/qrenderaspect.cpp20
-rw-r--r--src/render/frontend/qrenderaspect_p.h5
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp9
-rw-r--r--src/render/jobs/job_common_p.h3
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp29
-rw-r--r--src/render/materialsystem/shader.cpp7
-rw-r--r--src/render/materialsystem/shader_p.h1
-rw-r--r--src/render/texture/apitexturemanager_p.h1
-rw-r--r--src/render/texture/gltexture.cpp26
-rw-r--r--src/render/texture/gltexture_p.h12
-rw-r--r--src/render/texture/qtexture.cpp6
-rw-r--r--src/render/texture/texture.cpp9
-rw-r--r--src/render/texture/texturedatamanager_p.h26
-rw-r--r--tests/auto/input/axisaccumulator/axisaccumulator.pro11
-rw-r--r--tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp311
-rw-r--r--tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro11
-rw-r--r--tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp101
-rw-r--r--tests/auto/input/input.pro4
-rw-r--r--tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp11
-rw-r--r--tests/auto/render/commons/testrenderer.cpp10
-rw-r--r--tests/auto/render/commons/testrenderer.h4
-rw-r--r--tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp6
-rw-r--r--tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp1
-rw-r--r--tests/manual/dynamic-model-loader-qml/CuboidEntity.qml97
-rw-r--r--tests/manual/dynamic-model-loader-qml/SphereEntity.qml89
-rw-r--r--tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.pro16
-rw-r--r--tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.qrc7
-rw-r--r--tests/manual/dynamic-model-loader-qml/main.cpp63
-rw-r--r--tests/manual/dynamic-model-loader-qml/main.qml140
-rw-r--r--tests/manual/manual.pro3
-rw-r--r--tests/manual/rendercapture-qml/CaptureScene.qml2
-rw-r--r--tests/manual/rendercapture-qml/main.qml2
65 files changed, 1915 insertions, 109 deletions
diff --git a/dist/changes-5.8.0 b/dist/changes-5.8.0
new file mode 100644
index 000000000..4d41f0ee5
--- /dev/null
+++ b/dist/changes-5.8.0
@@ -0,0 +1,51 @@
+Qt 5.8 introduces many new features and improvements as well as bugfixes
+over the 5.7.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+ http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.8 series is binary compatible with the 5.7.x series.
+Applications compiled for 5.7 will continue to run with 5.8.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+General
+-------
+
+ - Greatly improved test coverage
+ - Added more documentation
+ - Fixed large number of bugs across all of Qt 3D
+
+Render
+------
+
+ - Texture system reworked to improve sharing of textures on the backend
+ and to minimize uploads to the GPU.
+ - Do not mirror texture coordinates or textures by default.
+ - Uniform handling system overhauled to remove usage of QVariant on the
+ backend.
+ - QRenderCapture framegraph node added to allow read back of the write
+ framebuffer to a QImage.
+ - Improved parallelisation of several job types.
+ - Improved parallelisation of OpenGL submission thread with building the
+ next frame.
+ - QObjectPicker is now also able to pick back facing triangles.
+
+Input
+-----
+
+ - Added QAxisAccumulator to allow tracking and integration of QAxis values
+ by treating the axis values as velocity or acceleration values.
+ - Added concept of proxy devices to allow new device plugins to easily
+ enumerate axes and buttons.
+
+Extras
+------
+
+ - Various fixes to the geometry attributes
diff --git a/src/core/changes/qcomponentaddedchange.cpp b/src/core/changes/qcomponentaddedchange.cpp
index 8d7ce425a..985567849 100644
--- a/src/core/changes/qcomponentaddedchange.cpp
+++ b/src/core/changes/qcomponentaddedchange.cpp
@@ -41,6 +41,7 @@
#include "qcomponentaddedchange_p.h"
#include <Qt3DCore/qcomponent.h>
#include <Qt3DCore/qentity.h>
+#include <private/qnode_p.h>
QT_BEGIN_NAMESPACE
@@ -51,7 +52,7 @@ QComponentAddedChangePrivate::QComponentAddedChangePrivate(const QEntity *entity
: QSceneChangePrivate()
, m_entityId(entity->id())
, m_componentId(component->id())
- , m_componentMetaObject(component->metaObject())
+ , m_componentMetaObject(QNodePrivate::findStaticMetaObject(component->metaObject()))
{
}
diff --git a/src/core/changes/qcomponentremovedchange.cpp b/src/core/changes/qcomponentremovedchange.cpp
index 5b5ef247a..30863cd89 100644
--- a/src/core/changes/qcomponentremovedchange.cpp
+++ b/src/core/changes/qcomponentremovedchange.cpp
@@ -41,6 +41,7 @@
#include "qcomponentremovedchange_p.h"
#include <Qt3DCore/qcomponent.h>
#include <Qt3DCore/qentity.h>
+#include <private/qnode_p.h>
QT_BEGIN_NAMESPACE
@@ -51,7 +52,7 @@ QComponentRemovedChangePrivate::QComponentRemovedChangePrivate(const QEntity *en
: QSceneChangePrivate()
, m_entityId(entity->id())
, m_componentId(component->id())
- , m_componentMetaObject(component->metaObject())
+ , m_componentMetaObject(QNodePrivate::findStaticMetaObject(component->metaObject()))
{
}
diff --git a/src/core/changes/qpropertynodeaddedchange.cpp b/src/core/changes/qpropertynodeaddedchange.cpp
index e159276dd..66b5c70d3 100644
--- a/src/core/changes/qpropertynodeaddedchange.cpp
+++ b/src/core/changes/qpropertynodeaddedchange.cpp
@@ -74,7 +74,7 @@ QPropertyNodeAddedChange::QPropertyNodeAddedChange(QNodeId subjectId, QNode *nod
: QStaticPropertyValueAddedChangeBase(*new QPropertyNodeAddedChangePrivate, subjectId)
{
Q_D(QPropertyNodeAddedChange);
- d->m_addedNodeIdTypePair = QNodeIdTypePair(node->id(), node->metaObject());
+ d->m_addedNodeIdTypePair = QNodeIdTypePair(node->id(), QNodePrivate::findStaticMetaObject(node->metaObject()));
}
/*! \internal */
diff --git a/src/input/backend/axisaccumulator.cpp b/src/input/backend/axisaccumulator.cpp
new file mode 100644
index 000000000..3b0423f47
--- /dev/null
+++ b/src/input/backend/axisaccumulator.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "axisaccumulator_p.h"
+#include <Qt3DInput/private/qaxisaccumulator_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+AxisAccumulator::AxisAccumulator()
+ : Qt3DCore::QBackendNode(ReadWrite)
+ , m_sourceAxisId()
+ , m_sourceAxisType(QAxisAccumulator::Velocity)
+ , m_scale(1.0f)
+ , m_value(0.0f)
+ , m_velocity(0.0f)
+{
+}
+
+void AxisAccumulator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAxisAccumulatorData>>(change);
+ const auto &data = typedChange->data;
+ m_sourceAxisId = data.sourceAxisId;
+ m_sourceAxisType = data.sourceAxisType;
+ m_scale = data.scale;
+ m_value = 0.0f;
+ m_velocity = 0.0f;
+}
+
+void AxisAccumulator::cleanup()
+{
+ QBackendNode::setEnabled(false);
+ m_sourceAxisId = Qt3DCore::QNodeId();
+ m_sourceAxisType = QAxisAccumulator::Velocity;
+ m_scale = 1.0f;
+ m_value = 0.0f;
+}
+
+void AxisAccumulator::setValue(float value)
+{
+ if (isEnabled() && value != m_value) {
+ m_value = value;
+
+ // Send a change to the frontend
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("value");
+ e->setValue(m_value);
+ notifyObservers(e);
+ }
+}
+
+void AxisAccumulator::setVelocity(float velocity)
+{
+ if (isEnabled() && velocity != m_velocity) {
+ m_velocity = velocity;
+
+ // Send a change to the frontend
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("velocity");
+ e->setValue(m_velocity);
+ notifyObservers(e);
+ }
+}
+
+void AxisAccumulator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ switch (e->type()) {
+ case Qt3DCore::PropertyUpdated: {
+ const auto change = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("sourceAxis"))
+ m_sourceAxisId = change->value().value<Qt3DCore::QNodeId>();
+ else if (change->propertyName() == QByteArrayLiteral("sourceAxisType"))
+ m_sourceAxisType = change->value().value<QAxisAccumulator::SourceAxisType>();
+ else if (change->propertyName() == QByteArrayLiteral("scale"))
+ m_scale = change->value().toFloat();
+ break;
+ }
+
+ default:
+ break;
+ }
+ QBackendNode::sceneChangeEvent(e);
+}
+
+void AxisAccumulator::stepIntegration(AxisManager *axisManager, float dt)
+{
+ Axis *sourceAxis = axisManager->lookupResource(m_sourceAxisId);
+ if (!sourceAxis)
+ return;
+
+ const float axisValue = sourceAxis->axisValue();
+ float newVelocity = 0.0f;
+ float newValue = 0.0f;
+ switch (m_sourceAxisType) {
+ case QAxisAccumulator::Velocity:
+ newVelocity = axisValue * m_scale;
+ newValue = m_value + newVelocity * dt;
+ break;
+
+ case QAxisAccumulator::Acceleration:
+ newVelocity = m_velocity + axisValue * m_scale * dt;
+ newValue = m_value + newVelocity * dt;
+ break;
+ }
+ setVelocity(newVelocity);
+ setValue(newValue);
+}
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
diff --git a/src/input/backend/axisaccumulator_p.h b/src/input/backend/axisaccumulator_p.h
new file mode 100644
index 000000000..67eb3906a
--- /dev/null
+++ b/src/input/backend/axisaccumulator_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QT3DINPUT_INPUT_AXISACCUMULATOR_H
+#define QT3DINPUT_INPUT_AXISACCUMULATOR_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/qbackendnode.h>
+#include <Qt3DCore/qnodeid.h>
+
+#include <Qt3DInput/qaxisaccumulator.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+class AxisManager;
+
+class Q_AUTOTEST_EXPORT AxisAccumulator : public Qt3DCore::QBackendNode
+{
+public:
+ AxisAccumulator();
+ void cleanup();
+
+ Qt3DCore::QNodeId sourceAxisId() const { return m_sourceAxisId; }
+ QAxisAccumulator::SourceAxisType sourceAxisType() const { return m_sourceAxisType; }
+ float scale() const { return m_scale; }
+
+ float value() const Q_DECL_NOTHROW { return m_value; }
+ void setValue(float value);
+
+ float velocity() const Q_DECL_NOTHROW { return m_velocity; }
+ void setVelocity(float velocity);
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+ void stepIntegration(AxisManager *axisManager, float dt);
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ Qt3DCore::QNodeId m_sourceAxisId;
+ QAxisAccumulator::SourceAxisType m_sourceAxisType;
+ float m_scale;
+ float m_value;
+ float m_velocity;
+};
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_INPUT_AXISACCUMULATOR_H
diff --git a/src/input/backend/axisaccumulatorjob.cpp b/src/input/backend/axisaccumulatorjob.cpp
new file mode 100644
index 000000000..133f9713a
--- /dev/null
+++ b/src/input/backend/axisaccumulatorjob.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "axisaccumulatorjob_p.h"
+#include <Qt3DInput/private/axisaccumulator_p.h>
+#include <Qt3DInput/private/job_common_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+AxisAccumulatorJob::AxisAccumulatorJob(AxisAccumulatorManager *axisAccumulatormanager,
+ AxisManager *axisManager)
+ : Qt3DCore::QAspectJob()
+ , m_axisAccumulatorManager(axisAccumulatormanager)
+ , m_axisManager(axisManager)
+ , m_dt(0.0f)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::AxisAccumulatorIntegration, 0);
+}
+
+void AxisAccumulatorJob::run()
+{
+ // Iterate over the accumulators and ask each to step the integrations
+ for (auto accumulatorHandle : m_axisAccumulatorManager->activeHandles()) {
+ AxisAccumulator *accumulator = m_axisAccumulatorManager->data(accumulatorHandle);
+ if (accumulator->isEnabled())
+ accumulator->stepIntegration(m_axisManager, m_dt);
+ }
+}
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
diff --git a/src/input/backend/axisaccumulatorjob_p.h b/src/input/backend/axisaccumulatorjob_p.h
new file mode 100644
index 000000000..d8ced8a3a
--- /dev/null
+++ b/src/input/backend/axisaccumulatorjob_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QT3DINPUT_INPUT_AXISACCUMULATORJOB_H
+#define QT3DINPUT_INPUT_AXISACCUMULATORJOB_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 <Qt3DCore/qnodeid.h>
+#include <Qt3DInput/private/handle_types_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+class AxisAccumulatorManager;
+class AxisManager;
+
+class Q_AUTOTEST_EXPORT AxisAccumulatorJob : public Qt3DCore::QAspectJob
+{
+public:
+ AxisAccumulatorJob(AxisAccumulatorManager *axisAccumulatormanager,
+ AxisManager *axisManager);
+
+ void setDeltaTime(float dt) { m_dt = dt; }
+
+ void run() override;
+
+private:
+ AxisAccumulatorManager *m_axisAccumulatorManager;
+ AxisManager *m_axisManager;
+ float m_dt;
+};
+
+typedef QSharedPointer<AxisAccumulatorJob> AxisAccumulatorJobPtr;
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_INPUT_AXISACCUMULATORJOB_H
diff --git a/src/input/backend/backend.pri b/src/input/backend/backend.pri
index 846fb1705..71c1a9a1c 100644
--- a/src/input/backend/backend.pri
+++ b/src/input/backend/backend.pri
@@ -34,7 +34,9 @@ HEADERS += \
$$PWD/job_common_p.h \
$$PWD/physicaldeviceproxy_p.h \
$$PWD/loadproxydevicejob_p.h \
- $$PWD/utils_p.h
+ $$PWD/utils_p.h \
+ $$PWD/axisaccumulator_p.h \
+ $$PWD/axisaccumulatorjob_p.h
SOURCES += \
$$PWD/keyboarddevice.cpp \
@@ -66,6 +68,8 @@ SOURCES += \
$$PWD/inputsettings.cpp \
$$PWD/eventsourcesetterhelper.cpp \
$$PWD/physicaldeviceproxy.cpp \
- $$PWD/loadproxydevicejob.cpp
+ $$PWD/loadproxydevicejob.cpp \
+ $$PWD/axisaccumulator.cpp \
+ $$PWD/axisaccumulatorjob.cpp
INCLUDEPATH += $$PWD
diff --git a/src/input/backend/handle_types_p.h b/src/input/backend/handle_types_p.h
index cc78a68ba..c132fdc99 100644
--- a/src/input/backend/handle_types_p.h
+++ b/src/input/backend/handle_types_p.h
@@ -73,6 +73,7 @@ class InputChord;
class LogicalDevice;
class GenericDeviceBackendNode;
class PhysicalDeviceProxy;
+class AxisAccumulator;
typedef Qt3DCore::QHandle<KeyboardDevice, 8> HKeyboardDevice;
typedef Qt3DCore::QHandle<KeyboardHandler, 16> HKeyboardHandler;
@@ -89,6 +90,7 @@ typedef Qt3DCore::QHandle<InputChord, 16> HInputChord;
typedef Qt3DCore::QHandle<LogicalDevice, 16> HLogicalDevice;
typedef Qt3DCore::QHandle<GenericDeviceBackendNode, 8> HGenericDeviceBackendNode;
typedef Qt3DCore::QHandle<PhysicalDeviceProxy, 16> HPhysicalDeviceProxy;
+typedef Qt3DCore::QHandle<AxisAccumulator, 16> HAxisAccumulator;
} // namespace Input
} // namespace Qt3DInput
diff --git a/src/input/backend/inputhandler.cpp b/src/input/backend/inputhandler.cpp
index 82b5c7c7c..aebf2c8f1 100644
--- a/src/input/backend/inputhandler.cpp
+++ b/src/input/backend/inputhandler.cpp
@@ -64,6 +64,7 @@ InputHandler::InputHandler()
, m_keyboardEventFilter(new KeyboardEventFilter())
, m_mouseEventFilter(new MouseEventFilter())
, m_axisManager(new AxisManager())
+ , m_axisAccumulatorManager(new AxisAccumulatorManager())
, m_actionManager(new ActionManager())
, m_axisSettingManager(new AxisSettingManager())
, m_actionInputManager(new ActionInputManager())
@@ -93,6 +94,7 @@ InputHandler::~InputHandler()
delete m_keyboardEventFilter;
delete m_mouseEventFilter;
delete m_axisManager;
+ delete m_axisAccumulatorManager;
delete m_actionManager;
delete m_axisSettingManager;
delete m_analogAxisInputManager;
diff --git a/src/input/backend/inputhandler_p.h b/src/input/backend/inputhandler_p.h
index 1628f3975..eff0c0c24 100644
--- a/src/input/backend/inputhandler_p.h
+++ b/src/input/backend/inputhandler_p.h
@@ -79,6 +79,7 @@ class MouseDeviceManager;
class MouseInputManager;
class MouseEventFilter;
class AxisManager;
+class AxisAccumulatorManager;
class ActionManager;
class AxisSettingManager;
class ActionInputManager;
@@ -104,6 +105,7 @@ public:
inline MouseDeviceManager *mouseDeviceManager() const { return m_mouseDeviceManager; }
inline MouseInputManager *mouseInputManager() const { return m_mouseInputManager; }
inline AxisManager *axisManager() const { return m_axisManager; }
+ inline AxisAccumulatorManager *axisAccumulatorManager() const { return m_axisAccumulatorManager; }
inline ActionManager *actionManager() const { return m_actionManager; }
inline AxisSettingManager *axisSettingManager() const { return m_axisSettingManager; }
inline ActionInputManager *actionInputManager() const { return m_actionInputManager; }
@@ -171,6 +173,7 @@ private:
mutable QMutex m_mutex;
AxisManager *m_axisManager;
+ AxisAccumulatorManager *m_axisAccumulatorManager;
ActionManager *m_actionManager;
AxisSettingManager *m_axisSettingManager;
ActionInputManager *m_actionInputManager;
diff --git a/src/input/backend/inputmanagers_p.h b/src/input/backend/inputmanagers_p.h
index d162ea519..473042867 100644
--- a/src/input/backend/inputmanagers_p.h
+++ b/src/input/backend/inputmanagers_p.h
@@ -63,6 +63,7 @@
#include <Qt3DInput/private/inputchord_p.h>
#include <Qt3DInput/private/action_p.h>
#include <Qt3DInput/private/axis_p.h>
+#include <Qt3DInput/private/axisaccumulator_p.h>
#include <Qt3DInput/private/axissetting_p.h>
#include <Qt3DInput/private/analogaxisinput_p.h>
#include <Qt3DInput/private/buttonaxisinput_p.h>
@@ -238,6 +239,16 @@ private:
QVector<Qt3DCore::QNodeId> m_pendingProxies;
};
+class AxisAccumulatorManager : public Qt3DCore::QResourceManager<
+ AxisAccumulator,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy>
+{
+public:
+ AxisAccumulatorManager() {}
+};
+
} // namespace Input
} // namespace Qt3DInput
diff --git a/src/input/backend/job_common_p.h b/src/input/backend/job_common_p.h
index 589c75fb9..7377e4729 100644
--- a/src/input/backend/job_common_p.h
+++ b/src/input/backend/job_common_p.h
@@ -66,7 +66,8 @@ namespace JobTypes {
KeyEventDispatcher,
MouseEventDispatcher,
UpdateAxisAction,
- DeviceProxyLoading
+ DeviceProxyLoading,
+ AxisAccumulatorIntegration
};
} // JobTypes
diff --git a/src/input/frontend/qaxisaccumulator.cpp b/src/input/frontend/qaxisaccumulator.cpp
index d205bce16..0785ad689 100644
--- a/src/input/frontend/qaxisaccumulator.cpp
+++ b/src/input/frontend/qaxisaccumulator.cpp
@@ -51,7 +51,7 @@ namespace Qt3DInput {
Constructs a new QAxisAccumulator instance with \a parent.
\class Qt3DInput::QAxisAccumulator
\inmodule Qt3DInput
- \inherits Qt3DCore::QNode
+ \inherits Qt3DCore::QComponent
\brief QAxisAccumulator processes velocity or acceleration data from a QAxis.
\since 5.8
@@ -103,11 +103,12 @@ namespace Qt3DInput {
/*! \internal */
QAxisAccumulatorPrivate::QAxisAccumulatorPrivate()
- : Qt3DCore::QNodePrivate()
+ : Qt3DCore::QComponentPrivate()
, m_sourceAxis(nullptr)
, m_sourceAxisType(QAxisAccumulator::Velocity)
, m_scale(1.0f)
, m_value(0.0f)
+ , m_velocity(0.0f)
{
}
@@ -115,8 +116,23 @@ QAxisAccumulatorPrivate::QAxisAccumulatorPrivate()
void QAxisAccumulatorPrivate::setValue(float value)
{
if (value != m_value) {
+ Q_Q(QAxisAccumulator);
m_value = value;
- q_func()->valueChanged(m_value);
+ const bool wasBlocked = q->blockNotifications(true);
+ q->valueChanged(m_value);
+ q->blockNotifications(wasBlocked);
+ }
+}
+
+/*! \internal */
+void QAxisAccumulatorPrivate::setVelocity(float velocity)
+{
+ if (velocity != m_velocity) {
+ Q_Q(QAxisAccumulator);
+ m_velocity = velocity;
+ const bool wasBlocked = q->blockNotifications(true);
+ q->velocityChanged(m_velocity);
+ q->blockNotifications(wasBlocked);
}
}
@@ -124,7 +140,7 @@ void QAxisAccumulatorPrivate::setValue(float value)
Constructs a new QAxisAccumulator instance with parent \a parent.
*/
QAxisAccumulator::QAxisAccumulator(Qt3DCore::QNode *parent)
- : Qt3DCore::QNode(*new QAxisAccumulatorPrivate, parent)
+ : Qt3DCore::QComponent(*new QAxisAccumulatorPrivate, parent)
{
}
@@ -180,6 +196,18 @@ float QAxisAccumulator::value() const
}
/*!
+ Returns the velocity. If the sourceAxisType is set to Velocity this is
+ simply the value of the source axis multiplied by the scale. If the
+ sourceAxisType is set to Acceleration, the velocity is integrated using
+ the source axis' value as an acceleration.
+ */
+float QAxisAccumulator::velocity() const
+{
+ Q_D(const QAxisAccumulator);
+ return d->m_velocity;
+}
+
+/*!
\qmlproperty real Qt3D.Input::AxisAccumulator::value
The amount to scale the axis value by when accumulating. This can be
@@ -255,6 +283,8 @@ void QAxisAccumulator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
auto e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
if (e->type() == Qt3DCore::PropertyUpdated && e->propertyName() == QByteArrayLiteral("value"))
d->setValue(e->value().toFloat());
+ else if (e->type() == Qt3DCore::PropertyUpdated && e->propertyName() == QByteArrayLiteral("velocity"))
+ d->setVelocity(e->value().toFloat());
}
/*! \internal */
diff --git a/src/input/frontend/qaxisaccumulator.h b/src/input/frontend/qaxisaccumulator.h
index 461f21c4a..b31f57a48 100644
--- a/src/input/frontend/qaxisaccumulator.h
+++ b/src/input/frontend/qaxisaccumulator.h
@@ -41,7 +41,7 @@
#define QT3DINPUT_QAXISACCUMULATOR_H
#include <Qt3DInput/qt3dinput_global.h>
-#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/qcomponent.h>
QT_BEGIN_NAMESPACE
@@ -50,13 +50,14 @@ namespace Qt3DInput {
class QAxis;
class QAxisAccumulatorPrivate;
-class QT3DINPUTSHARED_EXPORT QAxisAccumulator : public Qt3DCore::QNode
+class QT3DINPUTSHARED_EXPORT QAxisAccumulator : public Qt3DCore::QComponent
{
Q_OBJECT
Q_PROPERTY(Qt3DInput::QAxis *sourceAxis READ sourceAxis WRITE setSourceAxis NOTIFY sourceAxisChanged)
Q_PROPERTY(SourceAxisType sourceAxisType READ sourceAxisType WRITE setSourceAxisType NOTIFY sourceAxisTypeChanged)
Q_PROPERTY(float scale READ scale WRITE setScale NOTIFY scaleChanged)
Q_PROPERTY(float value READ value NOTIFY valueChanged)
+ Q_PROPERTY(float velocity READ velocity NOTIFY velocityChanged)
public:
enum SourceAxisType {
@@ -71,6 +72,7 @@ public:
Qt3DInput::QAxis *sourceAxis() const;
SourceAxisType sourceAxisType() const;
float value() const;
+ float velocity() const;
float scale() const;
public Q_SLOTS:
@@ -82,6 +84,7 @@ Q_SIGNALS:
void sourceAxisChanged(Qt3DInput::QAxis *sourceAxis);
void sourceAxisTypeChanged(QAxisAccumulator::SourceAxisType sourceAxisType);
void valueChanged(float value);
+ void velocityChanged(float value);
void scaleChanged(float scale);
protected:
diff --git a/src/input/frontend/qaxisaccumulator_p.h b/src/input/frontend/qaxisaccumulator_p.h
index a07284009..532f01b6b 100644
--- a/src/input/frontend/qaxisaccumulator_p.h
+++ b/src/input/frontend/qaxisaccumulator_p.h
@@ -51,14 +51,14 @@
// We mean it.
//
-#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DInput/qaxisaccumulator.h>
QT_BEGIN_NAMESPACE
namespace Qt3DInput {
-class QAxisAccumulatorPrivate : public Qt3DCore::QNodePrivate
+class QAxisAccumulatorPrivate : public Qt3DCore::QComponentPrivate
{
public:
QAxisAccumulatorPrivate();
@@ -66,11 +66,13 @@ public:
Q_DECLARE_PUBLIC(QAxisAccumulator)
void setValue(float value);
+ void setVelocity(float velocity);
QAxis *m_sourceAxis;
QAxisAccumulator::SourceAxisType m_sourceAxisType;
float m_scale;
float m_value;
+ float m_velocity;
};
struct QAxisAccumulatorData
diff --git a/src/input/frontend/qinputaspect.cpp b/src/input/frontend/qinputaspect.cpp
index 5ad5c644c..5c5fd3b06 100644
--- a/src/input/frontend/qinputaspect.cpp
+++ b/src/input/frontend/qinputaspect.cpp
@@ -61,6 +61,7 @@
#include <QPluginLoader>
#include <Qt3DInput/qaxis.h>
+#include <Qt3DInput/qaxisaccumulator.h>
#include <Qt3DInput/qaction.h>
#include <Qt3DInput/qaxissetting.h>
#include <Qt3DInput/qactioninput.h>
@@ -72,6 +73,7 @@
#include <Qt3DInput/qabstractphysicaldevice.h>
#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
#include <Qt3DInput/private/axis_p.h>
+#include <Qt3DInput/private/axisaccumulator_p.h>
#include <Qt3DInput/private/action_p.h>
#include <Qt3DInput/private/axissetting_p.h>
#include <Qt3DInput/private/actioninput_p.h>
@@ -86,6 +88,7 @@
#include <Qt3DInput/private/inputsettings_p.h>
#include <Qt3DInput/private/eventsourcesetterhelper_p.h>
#include <Qt3DInput/private/loadproxydevicejob_p.h>
+#include <Qt3DInput/private/axisaccumulatorjob_p.h>
#ifdef HAVE_QGAMEPAD
# include <Qt3DInput/private/qgamepadinput_p.h>
@@ -101,6 +104,7 @@ QInputAspectPrivate::QInputAspectPrivate()
: QAbstractAspectPrivate()
, m_inputHandler(new Input::InputHandler())
, m_keyboardMouseIntegration(new Input::KeyboardMouseGenericDeviceIntegration(m_inputHandler.data()))
+ , m_time(0)
{
}
@@ -129,11 +133,15 @@ QInputAspect::QInputAspect(QInputAspectPrivate &dd, QObject *parent)
: QAbstractAspect(dd, parent)
{
setObjectName(QStringLiteral("Input Aspect"));
+
+ qRegisterMetaType<Qt3DInput::QAbstractPhysicalDevice*>();
+
registerBackendType<QKeyboardDevice>(QBackendNodeMapperPtr(new Input::KeyboardDeviceFunctor(this, d_func()->m_inputHandler.data())));
registerBackendType<QKeyboardHandler>(QBackendNodeMapperPtr(new Input::KeyboardHandlerFunctor(d_func()->m_inputHandler.data())));
registerBackendType<QMouseDevice>(QBackendNodeMapperPtr(new Input::MouseDeviceFunctor(this, d_func()->m_inputHandler.data())));
registerBackendType<QMouseHandler>(QBackendNodeMapperPtr(new Input::MouseHandlerFunctor(d_func()->m_inputHandler.data())));
registerBackendType<QAxis>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::Axis, Input::AxisManager>(d_func()->m_inputHandler->axisManager())));
+ registerBackendType<QAxisAccumulator>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisAccumulator, Input::AxisAccumulatorManager>(d_func()->m_inputHandler->axisAccumulatorManager())));
registerBackendType<QAnalogAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AnalogAxisInput, Input::AnalogAxisInputManager>(d_func()->m_inputHandler->analogAxisInputManager())));
registerBackendType<QButtonAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::ButtonAxisInput, Input::ButtonAxisInputManager>(d_func()->m_inputHandler->buttonAxisInputManager())));
registerBackendType<QAxisSetting>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisSetting, Input::AxisSettingManager>(d_func()->m_inputHandler->axisSettingManager())));
@@ -213,6 +221,10 @@ QStringList QInputAspect::availablePhysicalDevices() const
QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
{
Q_D(QInputAspect);
+ const qint64 deltaTime = time - d->m_time;
+ const float dt = static_cast<const float>(deltaTime) / 1.0e9;
+ d->m_time = time;
+
QVector<QAspectJobPtr> jobs;
d->m_inputHandler->updateEventSource();
@@ -240,6 +252,8 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
// Jobs that update Axis/Action (store combined axis/action value)
const auto devHandles = d->m_inputHandler->logicalDeviceManager()->activeDevices();
+ QVector<QAspectJobPtr> axisActionJobs;
+ axisActionJobs.reserve(devHandles.size());
for (Input::HLogicalDevice devHandle : devHandles) {
const auto device = d->m_inputHandler->logicalDeviceManager()->data(devHandle);
if (!device->isEnabled())
@@ -247,10 +261,20 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(time, d->m_inputHandler.data(), devHandle));
jobs += updateAxisActionJob;
+ axisActionJobs.push_back(updateAxisActionJob);
for (const QAspectJobPtr &job : dependsOnJobs)
updateAxisActionJob->addDependency(job);
}
+ // Once all the axes have been updated we can step the integrations on
+ // the AxisAccumulators
+ auto accumulateJob = Input::AxisAccumulatorJobPtr::create(d->m_inputHandler->axisAccumulatorManager(),
+ d->m_inputHandler->axisManager());
+ accumulateJob->setDeltaTime(dt);
+ for (const QAspectJobPtr &job : qAsConst(axisActionJobs))
+ accumulateJob->addDependency(job);
+ jobs.push_back(accumulateJob);
+
return jobs;
}
diff --git a/src/input/frontend/qinputaspect_p.h b/src/input/frontend/qinputaspect_p.h
index d123e6216..35a4ffa02 100644
--- a/src/input/frontend/qinputaspect_p.h
+++ b/src/input/frontend/qinputaspect_p.h
@@ -73,6 +73,7 @@ public:
Q_DECLARE_PUBLIC(QInputAspect)
QScopedPointer<Input::InputHandler> m_inputHandler;
QScopedPointer<Input::KeyboardMouseGenericDeviceIntegration> m_keyboardMouseIntegration;
+ qint64 m_time;
};
} // namespace Qt3DInput
diff --git a/src/quick3d/imports/input/qt3dquick3dinputplugin.cpp b/src/quick3d/imports/input/qt3dquick3dinputplugin.cpp
index a403c38f5..d31680b4d 100644
--- a/src/quick3d/imports/input/qt3dquick3dinputplugin.cpp
+++ b/src/quick3d/imports/input/qt3dquick3dinputplugin.cpp
@@ -46,6 +46,7 @@
#include <Qt3DInput/qmouseevent.h>
#include <Qt3DInput/qaxis.h>
+#include <Qt3DInput/qaxisaccumulator.h>
#include <Qt3DInput/qaxissetting.h>
#include <Qt3DInput/qaction.h>
#include <Qt3DInput/qactioninput.h>
@@ -96,6 +97,7 @@ void Qt3DQuick3DInputPlugin::registerTypes(const char *uri)
qmlRegisterExtendedType<Qt3DInput::QInputSequence, Qt3DInput::Input::Quick::Quick3DInputSequence>(uri, 2, 0, "InputSequence");
qmlRegisterExtendedType<Qt3DInput::QInputChord, Qt3DInput::Input::Quick::Quick3DInputChord>(uri, 2, 0, "InputChord");
qmlRegisterExtendedUncreatableType<Qt3DInput::QAbstractPhysicalDevice, Qt3DInput::Input::Quick::Quick3DPhysicalDevice>(uri, 2, 0, "QAbstractPhysicalDevice", QStringLiteral("QAbstractPhysicalDevice is abstract"));
+ qmlRegisterType<Qt3DInput::QAxisAccumulator>(uri, 2, 1, "AxisAccumulator");
#ifdef HAVE_QGAMEPAD
qmlRegisterType<Qt3DInput::QGamepadInput>(uri, 2, 0, "GamepadInput");
diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
index 28416d894..2e68893d6 100644
--- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
+++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
@@ -224,8 +224,8 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DRender::QNoDraw>(uri, 2, 0, "NoDraw");
qmlRegisterType<Qt3DRender::QFrustumCulling>(uri, 2, 0, "FrustumCulling");
qmlRegisterType<Qt3DRender::QDispatchCompute>(uri, 2, 0, "DispatchCompute");
- qmlRegisterType<Qt3DRender::QRenderCapture>(uri, 2, 0, "RenderCapture");
- qmlRegisterUncreatableType<Qt3DRender::QRenderCaptureReply>(uri, 2, 0, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture"));
+ qmlRegisterType<Qt3DRender::QRenderCapture>(uri, 2, 1, "RenderCapture");
+ qmlRegisterUncreatableType<Qt3DRender::QRenderCaptureReply>(uri, 2, 1, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture"));
// RenderTarget
qmlRegisterType<Qt3DRender::QRenderTargetOutput>(uri, 2, 0, "RenderTargetOutput");
diff --git a/src/quick3d/quick3d/items/quick3dentityloader.cpp b/src/quick3d/quick3d/items/quick3dentityloader.cpp
index 63f4cceac..9f305d977 100644
--- a/src/quick3d/quick3d/items/quick3dentityloader.cpp
+++ b/src/quick3d/quick3d/items/quick3dentityloader.cpp
@@ -54,7 +54,7 @@ class Quick3DEntityLoaderIncubator : public QQmlIncubator
{
public:
Quick3DEntityLoaderIncubator(Quick3DEntityLoader *loader)
- : QQmlIncubator(Asynchronous),
+ : QQmlIncubator(AsynchronousIfNested),
m_loader(loader)
{
}
@@ -100,6 +100,12 @@ Quick3DEntityLoader::Quick3DEntityLoader(QNode *parent)
{
}
+Quick3DEntityLoader::~Quick3DEntityLoader()
+{
+ Q_D(Quick3DEntityLoader);
+ d->clear();
+}
+
/*!
\qmlproperty QtQml::QtObject Qt3DCore::EntityLoader::entity
\readonly
diff --git a/src/quick3d/quick3d/items/quick3dentityloader_p.h b/src/quick3d/quick3d/items/quick3dentityloader_p.h
index 928f31ada..5721af115 100644
--- a/src/quick3d/quick3d/items/quick3dentityloader_p.h
+++ b/src/quick3d/quick3d/items/quick3dentityloader_p.h
@@ -76,6 +76,7 @@ class QT3DQUICKSHARED_PRIVATE_EXPORT Quick3DEntityLoader : public QEntity
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
public:
explicit Quick3DEntityLoader(QNode *parent = 0);
+ ~Quick3DEntityLoader();
QObject *entity() const;
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index cb8b7c621..8b17cbf45 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/private/qt3drender_global_p.h>
#include <Qt3DCore/qaspectjob.h>
#include <Qt3DCore/qnodeid.h>
+#include <QtGui/qsurfaceformat.h>
QT_BEGIN_NAMESPACE
@@ -79,7 +80,7 @@ class Entity;
class FrameGraphNode;
class RenderSettings;
class BackendNode;
-
+class OffscreenSurfaceHelper;
class QT3DRENDERSHARED_PRIVATE_EXPORT AbstractRenderer
{
@@ -135,6 +136,7 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
@@ -148,6 +150,9 @@ public:
virtual RenderSettings *settings() const = 0;
virtual QVariant executeCommand(const QStringList &args) = 0;
+
+ virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
+ virtual QSurfaceFormat format() = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet)
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index 4ae2dc058..ed43fde13 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -218,6 +218,21 @@ class TextureManager : public Qt3DCore::QResourceManager<
{
public:
TextureManager() {}
+
+ // Called in AspectThread by Texture node functor destroy
+ void addTextureIdToCleanup(Qt3DCore::QNodeId id)
+ {
+ m_textureIdsToCleanup.push_back(id);
+ }
+
+ // Called by RenderThread in updateGLResources (locked)
+ QVector<Qt3DCore::QNodeId> takeTexturesIdsToCleanup()
+ {
+ return std::move(m_textureIdsToCleanup);
+ }
+
+private:
+ QVector<Qt3DCore::QNodeId> m_textureIdsToCleanup;
};
class TransformManager : public Qt3DCore::QResourceManager<
diff --git a/src/render/backend/offscreensurfacehelper.cpp b/src/render/backend/offscreensurfacehelper.cpp
new file mode 100644
index 000000000..89dc6211f
--- /dev/null
+++ b/src/render/backend/offscreensurfacehelper.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "offscreensurfacehelper_p.h"
+
+#include <Qt3DRender/private/abstractrenderer_p.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+/*! \internal */
+OffscreenSurfaceHelper::OffscreenSurfaceHelper(AbstractRenderer *renderer,
+ QObject *parent)
+ : QObject(parent)
+ , m_renderer(renderer)
+ , m_offscreenSurface(nullptr)
+{
+ Q_ASSERT(renderer);
+}
+
+/*!
+ * \internal
+ * Called in context of main thread to create an offscreen surface
+ * which can later be made current with the Qt 3D OpenGL context to
+ * then allow graphics resources to be released cleanly.
+ */
+void OffscreenSurfaceHelper::createOffscreenSurface()
+{
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+ m_offscreenSurface = new QOffscreenSurface;
+ m_offscreenSurface->setParent(this);
+ m_offscreenSurface->setFormat(m_renderer->format());
+ m_offscreenSurface->create();
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/offscreensurfacehelper_p.h b/src/render/backend/offscreensurfacehelper_p.h
new file mode 100644
index 000000000..a2c383162
--- /dev/null
+++ b/src/render/backend/offscreensurfacehelper_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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_OFFSCREENSURFACEHELPER_H
+#define QT3DRENDER_RENDER_OFFSCREENSURFACEHELPER_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 <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenSurface;
+
+namespace Qt3DRender {
+namespace Render {
+
+class AbstractRenderer;
+
+class OffscreenSurfaceHelper : public QObject
+{
+ Q_OBJECT
+public:
+ OffscreenSurfaceHelper(AbstractRenderer *renderer,
+ QObject *parent = nullptr);
+ inline QOffscreenSurface *offscreenSurface() const { return m_offscreenSurface; }
+
+public slots:
+ void createOffscreenSurface();
+
+private:
+ Render::AbstractRenderer *m_renderer;
+ QOffscreenSurface *m_offscreenSurface;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_OFFSCREENSURFACEHELPER_H
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 9f517d714..8cd904efd 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -39,7 +39,8 @@ HEADERS += \
$$PWD/uniform_p.h \
$$PWD/shaderparameterpack_p.h \
$$PWD/renderviewbuilder_p.h \
- $$PWD/frameprofiler_p.h
+ $$PWD/frameprofiler_p.h \
+ $$PWD/offscreensurfacehelper_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -71,5 +72,6 @@ SOURCES += \
$$PWD/openglvertexarrayobject.cpp \
$$PWD/uniform.cpp \
$$PWD/shaderparameterpack.cpp \
- $$PWD/renderviewbuilder.cpp
+ $$PWD/renderviewbuilder.cpp \
+ $$PWD/offscreensurfacehelper.cpp
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index a463d9d53..439327102 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/offscreensurfacehelper_p.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
@@ -91,6 +92,7 @@
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
#include <QStack>
+#include <QOffscreenSurface>
#include <QSurface>
#include <QElapsedTimer>
#include <QLibraryInfo>
@@ -169,7 +171,9 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
, m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
, m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
+ , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
, m_ownedContext(false)
+ , m_offscreenHelper(nullptr)
#ifdef QT3D_JOBS_RUN_STATS
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
@@ -187,6 +191,10 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob);
m_updateShaderDataTransformJob->addDependency(m_worldTransformJob);
+ // Dirty texture gathering depends on m_syncTextureLoadingJob
+ // m_syncTextureLoadingJob will depend on the texture loading jobs
+ m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
+
// All world stuff depends on the RenderEntity's localBoundingVolume
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
@@ -208,6 +216,9 @@ Renderer::~Renderer()
delete m_renderQueue;
delete m_defaultRenderStateSet;
+
+ if (!m_ownedContext)
+ QObject::disconnect(m_contextConnection);
}
void Renderer::dumpInfo() const
@@ -285,12 +296,24 @@ void Renderer::initialize()
else
qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
m_ownedContext = true;
+ } else {
+ // Context is not owned by us, so we need to know if it gets destroyed
+ m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
+ [this] { releaseGraphicsResources(); });
}
// Note: we don't have a surface at this point
// The context will be made current later on (at render time)
m_graphicsContext->setOpenGLContext(ctx);
+ // Store the format used by the context and queue up creating an
+ // offscreen surface in the main thread so that it is available
+ // for use when we want to shutdown the renderer. We need to create
+ // the offscreen surface on the main thread because on some platforms
+ // (MS Windows), an offscreen surface is just a hidden QWindow.
+ m_format = ctx->format();
+ QMetaObject::invokeMethod(m_offscreenHelper, "createOffscreenSurface");
+
// Awake setScenegraphRoot in case it was waiting
m_waitForInitializationToBeCompleted.release(1);
// Allow the aspect manager to proceed
@@ -330,15 +353,46 @@ void Renderer::shutdown()
When using a threaded renderer this function is called in the context of the
RenderThread to do any shutdown and cleanup that needs to be performed in the
thread where the OpenGL context lives.
+
+ When using Scene3D or anything that provides a custom QOpenGLContext (not
+ owned by Qt3D) this function is called whenever the signal
+ QOpenGLContext::aboutToBeDestroyed is emitted. In that case this function
+ is called in the context of the emitter's thread.
*/
void Renderer::releaseGraphicsResources()
{
- // Clean up the graphics context and any resources
- const QVector<GLTexture*> activeTextures = m_nodesManager->glTextureManager()->activeResources();
- for (GLTexture *tex : activeTextures)
- tex->destroyGLTexture();
+ // We may get called twice when running inside of a Scene3D. Once when Qt Quick
+ // wants to shutdown, and again when the render aspect gets unregistered. So
+ // check that we haven't already cleaned up before going any further.
+ if (!m_graphicsContext)
+ return;
+
+ // Try to temporarily make the context current so we can free up any resources
+ QMutexLocker locker(&m_offscreenSurfaceMutex);
+ QOffscreenSurface *offscreenSurface = m_offscreenHelper->offscreenSurface();
+ if (!offscreenSurface) {
+ qWarning() << "Failed to make context current: OpenGL resources will not be destroyed";
+ return;
+ }
+
+ QOpenGLContext *context = m_graphicsContext->openGLContext();
+ Q_ASSERT(context);
+ if (context->makeCurrent(offscreenSurface)) {
+
+ // Clean up the graphics context and any resources
+ const QVector<GLTexture*> activeTextures = m_nodesManager->glTextureManager()->activeResources();
+ for (GLTexture *tex : activeTextures)
+ tex->destroyGLTexture();
+
+ // TO DO: Do the same thing with buffers
+
+ context->doneCurrent();
+ } else {
+ qWarning() << "Failed to make context current: OpenGL resources will not be destroyed";
+ }
- // TO DO: Do the same thing with buffers
+ if (m_ownedContext)
+ delete context;
m_graphicsContext.reset(nullptr);
qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown";
@@ -474,11 +528,11 @@ void Renderer::doRender()
if (!m_ownedContext)
m_graphicsContext->setCurrentStateSet(nullptr);
if (m_graphicsContext->beginDrawing(surface)) {
- // 1) Execute commands for buffer uploads, texture updates, shader loading first
- updateGLResources();
- // 2) Update VAO and copy data into commands to allow concurrent submission
- prepareCommandsSubmission(renderViews);
- preprocessingComplete = true;
+ // 1) Execute commands for buffer uploads, texture updates, shader loading first
+ updateGLResources();
+ // 2) Update VAO and copy data into commands to allow concurrent submission
+ prepareCommandsSubmission(renderViews);
+ preprocessingComplete = true;
}
}
}
@@ -645,6 +699,21 @@ QVariant Renderer::executeCommand(const QStringList &args)
return QVariant();
}
+/*!
+ \internal
+ Called in the context of the aspect thread from QRenderAspect::onRegistered
+*/
+void Renderer::setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper)
+{
+ QMutexLocker locker(&m_offscreenSurfaceMutex);
+ m_offscreenHelper = helper;
+}
+
+QSurfaceFormat Renderer::format()
+{
+ return m_format;
+}
+
// When this function is called, we must not be processing the commands for frame n+1
void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderViews)
{
@@ -784,6 +853,7 @@ void Renderer::lookForDirtyShaders()
}
}
+// Render Thread
void Renderer::updateGLResources()
{
{
@@ -820,8 +890,21 @@ void Renderer::updateGLResources()
updateTexture(texture);
}
}
+ // When Textures are cleaned up, their id is saved
+ // so that they can be cleaned up in the render thread
+ // Note: we perform this step in second so that the previous updateTexture call
+ // has a chance to find a shared texture
+ const QVector<Qt3DCore::QNodeId> cleanedUpTextureIds = m_nodesManager->textureManager()->takeTexturesIdsToCleanup();
+ for (const Qt3DCore::QNodeId textureCleanedUpId: cleanedUpTextureIds) {
+ cleanupTexture(m_nodesManager->textureManager()->lookupResource(textureCleanedUpId));
+ // We can really release the texture at this point
+ m_nodesManager->textureManager()->releaseResource(textureCleanedUpId);
+ }
+
+
}
+// Render Thread
void Renderer::updateTexture(Texture *texture)
{
// For implementing unique, non-shared, non-cached textures.
@@ -900,6 +983,16 @@ void Renderer::updateTexture(Texture *texture)
texture->unsetDirty();
}
+// Render Thread
+void Renderer::cleanupTexture(const Texture *texture)
+{
+ GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
+ GLTexture *glTexture = glTextureManager->lookupResource(texture->peerId());
+
+ if (glTexture != nullptr)
+ glTextureManager->abandon(glTexture, texture);
+}
+
// Happens in RenderThread context when all RenderViewJobs are done
// Returns the id of the last bound FBO
@@ -1145,6 +1238,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
+ renderBinJobs.push_back(m_syncTextureLoadingJob);
renderBinJobs.push_back(m_bufferGathererJob);
renderBinJobs.push_back(m_textureGathererJob);
renderBinJobs.push_back(m_shaderGathererJob);
@@ -1168,6 +1262,11 @@ QAspectJobPtr Renderer::pickBoundingVolumeJob()
return m_pickBoundingVolumeJob;
}
+QAspectJobPtr Renderer::syncTextureLoadingJob()
+{
+ return m_syncTextureLoadingJob;
+}
+
QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const
{
return static_cast<Qt3DCore::QAbstractFrameAdvanceService *>(m_vsyncFrameAdvanceService.data());
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 1a987f72e..501c158ef 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -137,6 +137,8 @@ class VSyncFrameAdvanceService;
class PickEventFilter;
class NodeManagers;
+using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
+
class QT3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer
{
public:
@@ -181,6 +183,8 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE;
+ Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE;
+
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
@@ -191,6 +195,7 @@ public:
inline UpdateWorldBoundingVolumeJobPtr updateWorldBoundingVolumeJob() const { return m_updateWorldBoundingVolumeJob; }
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
+ inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const Q_DECL_OVERRIDE;
@@ -201,6 +206,7 @@ public:
void updateGLResources();
void updateTexture(Texture *texture);
+ void cleanupTexture(const Texture *texture);
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
@@ -228,6 +234,8 @@ public:
bool isReadyToSubmit();
QVariant executeCommand(const QStringList &args) Q_DECL_OVERRIDE;
+ void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) Q_DECL_OVERRIDE;
+ QSurfaceFormat format() Q_DECL_OVERRIDE;
struct ViewSubmissionResultData
{
@@ -266,6 +274,7 @@ private:
ShaderParameterPack m_defaultUniformPack;
QScopedPointer<GraphicsContext> m_graphicsContext;
+ QSurfaceFormat m_format;
RenderQueue *m_renderQueue;
QScopedPointer<RenderThread> m_renderThread;
@@ -313,6 +322,8 @@ private:
GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
+ SynchronizerJobPtr m_syncTextureLoadingJob;
+
void lookForDirtyBuffers();
void lookForDirtyTextures();
void lookForDirtyShaders();
@@ -323,10 +334,15 @@ private:
bool m_ownedContext;
+ OffscreenSurfaceHelper *m_offscreenHelper;
+ QMutex m_offscreenSurfaceMutex;
+
#ifdef QT3D_JOBS_RUN_STATS
QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter;
friend class Qt3DRender::Debug::CommandExecuter;
#endif
+
+ QMetaObject::Connection m_contextConnection;
};
} // namespace Render
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 9f5abaac3..35cdecc29 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -108,8 +108,8 @@ void traverseTrianglesIndexed(index *indices,
QVector3D abc[3];
while (i < indexInfo.count) {
for (uint u = 0; u < 3; ++u) {
- uint idx = indices[i + u] * verticesStride;
- ndx[u] = idx;
+ ndx[u] = indices[i + u];
+ uint idx = ndx[u] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u][j] = vertices[idx + j];
}
@@ -134,8 +134,8 @@ void traverseTriangles(vertex *vertices,
QVector3D abc[3];
while (i < vertexInfo.count) {
for (uint u = 0; u < 3; ++u) {
- uint idx = (i + u) * verticesStride;
- ndx[u] = idx;
+ ndx[u] = (i + u);
+ uint idx = ndx[u] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u][j] = vertices[idx + j];
}
@@ -171,12 +171,12 @@ void traverseTriangleStripIndexed(index *indices,
while (i < indexInfo.count - 2) {
bool degenerate = false;
for (uint u = 0; u < 3; ++u) {
- uint idx = indices[i + u] * verticesStride;
- if (checkDegenerate(ndx, idx, u)) {
+ ndx[u] = indices[i + u];
+ if (checkDegenerate(ndx, ndx[u], u)) {
degenerate = true;
break;
}
- ndx[u] = idx;
+ uint idx = ndx[u] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j)
abc[u][j] = vertices[idx + j];
}
@@ -199,15 +199,15 @@ void traverseTriangleStrip(vertex *vertices,
uint ndx[3];
QVector3D abc[3];
- while (i < vertexInfo.count) {
+ while (i < vertexInfo.count - 2) {
for (uint u = 0; u < 3; ++u) {
- uint idx = (i + u) * verticesStride;
- ndx[u] = idx;
+ ndx[u] = (i + u);
+ uint idx = ndx[u] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u][j] = vertices[idx + j];
}
}
- visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[2], abc[0]);
+ visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
++i;
}
}
@@ -229,18 +229,18 @@ void traverseTriangleFanIndexed(index *indices,
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j];
}
-
+ ndx[0] = indices[0];
uint i = 1;
- while (i < indexInfo.count) {
+ while (i < indexInfo.count - 1) {
for (uint u = 0; u < 2; ++u) {
- uint idx = indices[i + u] * verticesStride;
- ndx[i] = idx;
+ ndx[u + 1] = indices[i + u];
+ uint idx = ndx[u + 1] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u + 1][j] = vertices[idx + j];
}
}
visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
- i += 2;
+ i += 1;
}
}
@@ -259,18 +259,19 @@ void traverseTriangleFan(vertex *vertices,
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[0][j] = vertices[j];
}
+ ndx[0] = 0;
uint i = 1;
- while (i < vertexInfo.count) {
+ while (i < vertexInfo.count - 1) {
for (uint u = 0; u < 2; ++u) {
- uint idx = (i + u) * verticesStride;
- ndx[u] = idx;
+ ndx[u + 1] = (i + u);
+ uint idx = ndx[u + 1] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u + 1][j] = vertices[idx + j];
}
}
visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]);
- i += 2;
+ i += 1;
}
}
@@ -290,8 +291,8 @@ void traverseTriangleAdjacencyIndexed(index *indices,
QVector3D abc[3];
while (i < indexInfo.count) {
for (uint u = 0; u < 6; u += 2) {
- uint idx = indices[i + u] * verticesStride;
- ndx[u / 2] = idx;
+ ndx[u / 2] = indices[i + u];
+ uint idx = ndx[u / 2] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u / 2][j] = vertices[idx + j];
}
@@ -316,8 +317,8 @@ void traverseTriangleAdjacency(Vertex *vertices,
QVector3D abc[3];
while (i < vertexInfo.count) {
for (uint u = 0; u < 6; u += 2) {
- uint idx = (i + u) * verticesStride;
- ndx[u / 2] = idx;
+ ndx[u / 2] = (i + u);
+ uint idx = ndx[u / 2] * verticesStride;
for (uint j = 0; j < maxVerticesDataSize; ++j) {
abc[u / 2][j] = vertices[idx + j];
}
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index 0369f3f5e..821dd6992 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -121,6 +121,7 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
case QMetaType::Char:
case QMetaType::UChar:
v.data<int>()[0] = variant.toInt();
+ v.m_storedType = Int;
break;
case QMetaType::Float:
case QMetaType::Double: // Convert double to floats
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index 56a50aea2..6b5ae4172 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -169,6 +169,7 @@ public:
}
ValueType valueType() const { return m_valueType; }
+ UniformType storedType() const { return m_storedType; }
static UniformValue fromVariant(const QVariant &variant);
@@ -199,6 +200,9 @@ private:
QVarLengthArray<float, 4> m_data;
ValueType m_valueType = ScalarValue;
+
+ // TODO: Replace this hack see QTBUG-57510
+ UniformType m_storedType = Unknown;
};
} // namespace Render
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index 0b01e7848..63b1cf3f9 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -47,6 +47,7 @@
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/qsceneloader.h>
+#include <Qt3DRender/qcamera.h>
#include <Qt3DRender/qcameraselector.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlayerfilter.h>
@@ -121,6 +122,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
#include <Qt3DRender/private/technique_p.h>
+#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
@@ -178,6 +180,7 @@ void QRenderAspectPrivate::registerBackendTypes()
qRegisterMetaType<Qt3DRender::QBuffer*>();
qRegisterMetaType<Qt3DRender::QEffect*>();
qRegisterMetaType<Qt3DRender::QFrameGraphNode *>();
+ qRegisterMetaType<Qt3DRender::QCamera*>();
q->registerBackendType<Qt3DCore::QEntity>(QSharedPointer<Render::RenderEntityFunctor>::create(m_renderer, m_nodeManagers));
q->registerBackendType<Qt3DCore::QTransform>(QSharedPointer<Render::NodeFunctor<Render::Transform, Render::TransformManager> >::create(m_renderer));
@@ -351,7 +354,7 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
// Create jobs that will get exectued by the threadpool
QVector<QAspectJobPtr> jobs;
- // 1 LoadBufferJobs, GeometryJobs, SceneLoaderJobs
+ // 1 LoadBufferJobs, GeometryJobs, SceneLoaderJobs, LoadTextureJobs
// 2 CalculateBoundingVolumeJob (depends on LoadBuffer)
// 3 WorldTransformJob
// 4 UpdateBoundingVolume, FramePreparationJob (depend on WorlTransformJob)
@@ -371,17 +374,21 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
}
Render::NodeManagers *manager = d->m_renderer->nodeManagers();
+ QAspectJobPtr textureLoadingSync = d->m_renderer->syncTextureLoadingJob();
+ textureLoadingSync->removeDependency(QWeakPointer<QAspectJob>());
// Launch texture generator jobs
const QVector<QTextureImageDataGeneratorPtr> pendingImgGen = manager->textureImageDataManager()->pendingGenerators();
for (const QTextureImageDataGeneratorPtr &imgGen : pendingImgGen) {
auto loadTextureJob = Render::LoadTextureDataJobPtr::create(imgGen);
+ textureLoadingSync->addDependency(loadTextureJob);
loadTextureJob->setNodeManagers(manager);
jobs.append(loadTextureJob);
}
const QVector<QTextureGeneratorPtr> pendingTexGen = manager->textureDataManager()->pendingGenerators();
for (const QTextureGeneratorPtr &texGen : pendingTexGen) {
auto loadTextureJob = Render::LoadTextureDataJobPtr::create(texGen);
+ textureLoadingSync->addDependency(loadTextureJob);
loadTextureJob->setNodeManagers(manager);
jobs.append(loadTextureJob);
}
@@ -438,6 +445,12 @@ void QRenderAspect::onRegistered()
d->m_renderer = new Render::Renderer(d->m_renderType);
d->m_renderer->setNodeManagers(d->m_nodeManagers);
+ // Create a helper for deferring creation of an offscreen surface used during cleanup
+ // to the main thread, after we knwo what the surface format in use is.
+ d->m_offscreenHelper = new Render::OffscreenSurfaceHelper(d->m_renderer);
+ d->m_offscreenHelper->moveToThread(QCoreApplication::instance()->thread());
+ d->m_renderer->setOffscreenSurfaceHelper(d->m_offscreenHelper);
+
// Register backend types now that we have a renderer
d->registerBackendTypes();
@@ -475,6 +488,11 @@ void QRenderAspect::onUnregistered()
// Waits for the render thread to join (if using threaded renderer)
delete d->m_renderer;
d->m_renderer = nullptr;
+
+ // Queue the offscreen surface helper for deletion on the main thread.
+ // That will take care of deleting the offscreen surface itself.
+ d->m_offscreenHelper->deleteLater();
+ d->m_offscreenHelper = nullptr;
}
QVector<Qt3DCore::QAspectJobPtr> QRenderAspectPrivate::createGeometryRendererJobs()
diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h
index f196c2ec2..d2c789ada 100644
--- a/src/render/frontend/qrenderaspect_p.h
+++ b/src/render/frontend/qrenderaspect_p.h
@@ -67,6 +67,10 @@ class AbstractRenderer;
class NodeManagers;
}
+namespace Render {
+class OffscreenSurfaceHelper;
+}
+
class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderAspectPrivate : public Qt3DCore::QAbstractAspectPrivate
{
public:
@@ -89,6 +93,7 @@ public:
bool m_initialized;
QList<QSceneIOHandler *> m_sceneIOHandler;
QRenderAspect::RenderType m_renderType;
+ Render::OffscreenSurfaceHelper *m_offscreenHelper;
};
}
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index f9276c4d6..bbcca8a6d 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -1207,7 +1207,14 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
switch (type) {
case UniformType::Float:
- applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, v);
+ // See QTBUG-57510 and uniform_p.h
+ if (v.storedType() == Int) {
+ float value = float(*v.constData<int>());
+ UniformValue floatV(value);
+ applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, floatV);
+ } else {
+ applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, v);
+ }
break;
case UniformType::Vec2:
applyUniformHelper<UniformType::Vec2>(description.m_location, description.m_size, v);
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index f45f5639e..e6eea36a8 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -94,7 +94,8 @@ namespace JobTypes {
SyncFrustumCulling,
ClearBufferDrawIndex,
UpdateMeshTriangleList,
- FilterCompatibleTechniques
+ FilterCompatibleTechniques,
+ SyncTextureLoading
};
} // JobTypes
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 7aa2be759..4a228681a 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -158,35 +158,6 @@ bool PickBoundingVolumeJob::runHelper()
if (vcaTriplets.empty())
return false;
- bool hasMoveEvent = false;
- bool hasOtherEvent = false;
-
- // Quickly look which types of events we've got
- for (const QMouseEvent &event : mouseEvents) {
- const bool isMove = (event.type() == QEvent::MouseMove);
- hasMoveEvent |= isMove;
- hasOtherEvent |= !isMove;
- }
-
- // In the case we have a move event, find if we actually have
- // an object picker that cares about these
- if (!hasOtherEvent) {
- // Retrieve the last used object picker
- ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
-
- // The only way to set lastCurrentPicker is to click
- // so we can return since if we're there it means we
- // have only move events
- if (lastCurrentPicker == nullptr)
- return false;
-
- const bool caresAboutMove = (hasMoveEvent && lastCurrentPicker->isDragEnabled());
- // Early return if the current object picker doesn't care about move events
- if (!caresAboutMove)
- return false;
- }
-
-
// TO DO:
// If we have move or hover move events that someone cares about, we try to avoid expensive computations
// by compressing them into a single one
diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp
index d390d74d4..bd0af0bed 100644
--- a/src/render/materialsystem/shader.cpp
+++ b/src/render/materialsystem/shader.cpp
@@ -71,6 +71,8 @@ Shader::~Shader()
{
// TO DO: ShaderProgram is leaked as of now
// Fix that taking care that they may be shared given a same dna
+
+ QObject::disconnect(m_contextConnection);
}
void Shader::cleanup()
@@ -118,6 +120,11 @@ void Shader::setGraphicsContext(GraphicsContext *context)
{
QMutexLocker lock(&m_mutex);
m_graphicsContext = context;
+ if (m_graphicsContext) {
+ m_contextConnection = QObject::connect(m_graphicsContext->openGLContext(),
+ &QOpenGLContext::aboutToBeDestroyed,
+ [this] { setGraphicsContext(nullptr); });
+ }
}
GraphicsContext *Shader::graphicsContext()
diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h
index 283e5a94c..ad68a3bd6 100644
--- a/src/render/materialsystem/shader_p.h
+++ b/src/render/materialsystem/shader_p.h
@@ -147,6 +147,7 @@ private:
ProgramDNA m_oldDna;
mutable QMutex m_mutex;
GraphicsContext *m_graphicsContext;
+ QMetaObject::Connection m_contextConnection;
void updateDNA();
diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h
index 1be5a1af8..2fd340e7e 100644
--- a/src/render/texture/apitexturemanager_p.h
+++ b/src/render/texture/apitexturemanager_p.h
@@ -182,6 +182,7 @@ public:
if (referencedTextureNodes.empty()) {
m_abandonedTextures.push_back(apiTexture);
m_sharedTextures.remove(apiTexture);
+ tex->destroyResources();
}
}
}
diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp
index 7916e390d..1a76617a7 100644
--- a/src/render/texture/gltexture.cpp
+++ b/src/render/texture/gltexture.cpp
@@ -72,17 +72,19 @@ GLTexture::GLTexture(TextureDataManager *texDataMgr,
, m_dataFunctor(texGen)
{
// make sure texture generator is executed
+ // this is needed when Texture have the TargetAutomatic
+ // to ensure they are loaded before trying to instantiate the QOpenGLTexture
if (!texGen.isNull())
m_textureDataManager->requestData(texGen, this);
}
GLTexture::~GLTexture()
{
- if (m_gl) {
- qWarning() << "[Qt3DRender::GLTexture] Destructor called without properly deleting texture";
- delete m_gl;
- }
+ destroyGLTexture();
+}
+void GLTexture::destroyResources()
+{
// release texture data
for (const Image &img : qAsConst(m_images))
m_textureImageDataManager->releaseData(img.generator, this);
@@ -96,6 +98,8 @@ void GLTexture::destroyGLTexture()
delete m_gl;
m_gl = nullptr;
m_dirty = 0;
+
+ destroyResources();
}
QOpenGLTexture* GLTexture::getOrCreateGLTexture()
@@ -249,11 +253,21 @@ void GLTexture::setImages(const QVector<Image> &images)
}
m_images = images;
- m_dirty |= TextureData;
+
+ // Don't mark the texture data as dirty yet. We defer this until the
+ // generators have been executed and the data is made available to the
+ // TextureDataManager.
// make sure the generators are executed
+ bool newEntriesCreated = false;
for (const Image& img : qAsConst(images)) {
- m_textureImageDataManager->requestData(img.generator, this);
+ newEntriesCreated |= m_textureImageDataManager->requestData(img.generator, this);
+ }
+
+ if (!newEntriesCreated) {
+ // request a data upload (very important in case the image data already
+ // exists and wouldn't trigger an update)
+ requestUpload();
}
}
}
diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h
index f911262be..7c6bf9c90 100644
--- a/src/render/texture/gltexture_p.h
+++ b/src/render/texture/gltexture_p.h
@@ -140,6 +140,10 @@ public:
*/
void destroyGLTexture();
+ // Called by TextureDataManager when it has new texture data from
+ // a generator that needs to be uploaded.
+ void requestUpload() { m_dirty |= TextureData; }
+
protected:
template<class APITexture, class APITextureImage>
@@ -160,15 +164,17 @@ protected:
private:
enum DirtyFlag {
- TextureData = 0x1, // one or more generators need to be executed
- Properties = 0x2, // texture needs to be (re-)created
- Parameters = 0x4 // texture parameters need to be (re-)set
+ TextureData = 0x01, // one or more generators have been executed, data needs uploading to GPU
+ Properties = 0x02, // texture needs to be (re-)created
+ Parameters = 0x04 // texture parameters need to be (re-)set
+
};
Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
QOpenGLTexture *buildGLTexture();
void uploadGLTextureData();
void updateGLTextureParameters();
+ void destroyResources();
bool m_unique;
DirtyFlags m_dirty;
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index a566ecc36..4aa28aa1c 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -626,7 +626,11 @@ QTextureImageDataPtr setDdsFile(const QString &source)
QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D, bool mirrored)
{
QTextureImageDataPtr textureData;
- if (url.isLocalFile() || url.scheme() == QLatin1String("qrc")) {
+ if (url.isLocalFile() || url.scheme() == QLatin1String("qrc")
+#ifdef Q_OS_ANDROID
+ || url.scheme() == QLatin1String("assets")
+#endif
+ ) {
const QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(url);
const CompressedFormatExtension formatExtension = texturedCompressedFormat(source);
switch (formatExtension) {
diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp
index 233dc364a..f9e0aa4ba 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -121,6 +121,8 @@ void Texture::removeTextureImage(Qt3DCore::QNodeId id)
}
}
+// This is called by Renderer::updateGLResources
+// when the texture has been marked for cleanup
void Texture::cleanup()
{
// Whoever calls this must make sure to also check if this
@@ -147,6 +149,8 @@ void Texture::cleanup()
m_parameters.maximumAnisotropy = 1.0f;
m_parameters.comparisonFunction = QAbstractTexture::CompareLessEqual;
m_parameters.comparisonMode = QAbstractTexture::CompareNone;
+
+ m_dirty = NotDirty;
}
// ChangeArbiter/Aspect Thread
@@ -292,7 +296,10 @@ Qt3DCore::QBackendNode *TextureFunctor::get(Qt3DCore::QNodeId id) const
void TextureFunctor::destroy(Qt3DCore::QNodeId id) const
{
- m_textureNodeManager->releaseResource(id);
+ m_textureNodeManager->addTextureIdToCleanup(id);
+ // We only add ourselves to the dirty list
+ // The actual removal needs to be performed after we have
+ // destroyed the associated APITexture in the RenderThread
}
diff --git a/src/render/texture/texturedatamanager_p.h b/src/render/texture/texturedatamanager_p.h
index a93bace52..13ceca0ee 100644
--- a/src/render/texture/texturedatamanager_p.h
+++ b/src/render/texture/texturedatamanager_p.h
@@ -57,6 +57,7 @@
#include <Qt3DRender/qtextureimagedata.h>
#include <Qt3DRender/qtexturegenerator.h>
#include <Qt3DRender/qtextureimagedatagenerator.h>
+#include <Qt3DRender/private/gltexture_p.h>
QT_BEGIN_NAMESPACE
@@ -90,24 +91,28 @@ public:
* If no data for the given generator exists, make sure that the
* generators are executed the next frame. Reference generator by
* given texture
+ *
+ * Returns true if the Entry for a given generator had to be created
*/
- void requestData(const GeneratorPtr &generator, const APITexture *tex)
+ bool requestData(const GeneratorPtr &generator, APITexture *tex)
{
QMutexLocker lock(&m_mutex);
Entry *entry = findEntry(generator);
- if (entry == nullptr)
+ const bool needsToBeCreated = (entry == nullptr);
+ if (needsToBeCreated)
entry = createEntry(generator);
Q_ASSERT(entry);
if (!entry->referencingTextures.contains(tex))
entry->referencingTextures.push_back(tex);
+ return needsToBeCreated;
}
/*!
* Dereference given generator from texture. If no other textures still reference
* the generator, the associated data will be deleted
*/
- void releaseData(const GeneratorPtr &generator, const APITexture *tex)
+ void releaseData(const GeneratorPtr &generator, APITexture *tex)
{
QMutexLocker lock(&m_mutex);
@@ -159,17 +164,24 @@ public:
QMutexLocker lock(&m_mutex);
Entry *entry = findEntry(generator);
- if (!entry)
+ if (!entry) {
qWarning() << "[TextureDataManager] assignData() called with non-existent generator";
- else
+ } else {
entry->data = data;
+
+ // Mark each texture that references this data as being dirty
+ // so that the submission thread knows to upload
+ for (auto texture : qAsConst(entry->referencingTextures)) {
+ texture->requestUpload();
+ }
+ }
}
private:
struct Entry {
GeneratorPtr generator;
- QVector<const APITexture*> referencingTextures;
+ QVector<APITexture*> referencingTextures;
DataPtr data;
};
@@ -198,8 +210,6 @@ private:
QVector<Entry> m_data;
};
-class GLTexture;
-
class Q_AUTOTEST_EXPORT TextureDataManager
: public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture>
{
diff --git a/tests/auto/input/axisaccumulator/axisaccumulator.pro b/tests/auto/input/axisaccumulator/axisaccumulator.pro
new file mode 100644
index 000000000..31a15718a
--- /dev/null
+++ b/tests/auto/input/axisaccumulator/axisaccumulator.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_axisaccumulator
+
+QT += core-private 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_axisaccumulator.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp
new file mode 100644
index 000000000..94cb71030
--- /dev/null
+++ b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DInput/private/axis_p.h>
+#include <Qt3DInput/private/axisaccumulator_p.h>
+#include <Qt3DInput/private/qabstractaxisinput_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DInput/QAnalogAxisInput>
+#include <Qt3DInput/QAxis>
+#include <Qt3DInput/QAxisAccumulator>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include "testpostmanarbiter.h"
+
+class tst_AxisAccumulator: public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ Qt3DInput::Input::AxisAccumulator backendAccumulator;
+ Qt3DInput::QAxisAccumulator axisAccumulator;
+ Qt3DInput::QAxis axis;
+
+ axisAccumulator.setSourceAxis(&axis);
+ axisAccumulator.setSourceAxisType(Qt3DInput::QAxisAccumulator::Velocity);
+ axisAccumulator.setScale(2.0f);
+
+ // WHEN
+ simulateInitialization(&axisAccumulator, &backendAccumulator);
+
+ // THEN
+ QCOMPARE(backendAccumulator.peerId(), axisAccumulator.id());
+ QCOMPARE(backendAccumulator.isEnabled(), axisAccumulator.isEnabled());
+ QCOMPARE(backendAccumulator.sourceAxisType(), axisAccumulator.sourceAxisType());
+ QCOMPARE(backendAccumulator.sourceAxisId(), axisAccumulator.sourceAxis()->id());
+ QCOMPARE(backendAccumulator.scale(), axisAccumulator.scale());
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ Qt3DInput::Input::AxisAccumulator backendAxisAccumulator;
+
+ // THEN
+ QVERIFY(backendAxisAccumulator.peerId().isNull());
+ QCOMPARE(backendAxisAccumulator.isEnabled(), false);
+ QCOMPARE(backendAxisAccumulator.value(), 0.0f);
+ QCOMPARE(backendAxisAccumulator.velocity(), 0.0f);
+ QCOMPARE(backendAxisAccumulator.scale(), 1.0f);
+ QCOMPARE(backendAxisAccumulator.sourceAxisId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendAxisAccumulator.sourceAxisType(), Qt3DInput::QAxisAccumulator::Velocity);
+
+ // GIVEN
+ Qt3DInput::QAxisAccumulator axisAccumulator;
+ Qt3DInput::QAxis axis;
+
+ axisAccumulator.setSourceAxis(&axis);
+ axisAccumulator.setScale(2.0f);
+ axisAccumulator.setSourceAxisType(Qt3DInput::QAxisAccumulator::Acceleration);
+ axisAccumulator.setEnabled(true);
+
+ // WHEN
+ simulateInitialization(&axisAccumulator, &backendAxisAccumulator);
+ backendAxisAccumulator.cleanup();
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.isEnabled(), false);
+ QCOMPARE(backendAxisAccumulator.value(), 0.0f);
+ QCOMPARE(backendAxisAccumulator.velocity(), 0.0f);
+ QCOMPARE(backendAxisAccumulator.scale(), 1.0f);
+ QCOMPARE(backendAxisAccumulator.sourceAxisId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendAxisAccumulator.sourceAxisType(), Qt3DInput::QAxisAccumulator::Velocity);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DInput::Input::AxisAccumulator backendAxisAccumulator;
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange;
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("enabled");
+ updateChange->setValue(true);
+ backendAxisAccumulator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.isEnabled(), true);
+
+ // WHEN
+ Qt3DInput::QAxis axis;
+ const Qt3DCore::QNodeId axisId = axis.id();
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setPropertyName("sourceAxis");
+ updateChange->setValue(QVariant::fromValue(axisId));
+ backendAxisAccumulator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.sourceAxisId(), axisId);
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setPropertyName("sourceAxisType");
+ updateChange->setValue(Qt3DInput::QAxisAccumulator::Acceleration);
+ backendAxisAccumulator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.sourceAxisType(), Qt3DInput::QAxisAccumulator::Acceleration);
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setPropertyName("scale");
+ updateChange->setValue(3.0f);
+ backendAxisAccumulator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.scale(), 3.0f);
+ }
+
+ void checkValuePropertyBackendNotification()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DInput::Input::AxisAccumulator backendAxisAccumulator;
+ backendAxisAccumulator.setEnabled(true);
+ Qt3DCore::QBackendNodePrivate::get(&backendAxisAccumulator)->setArbiter(&arbiter);
+
+ // WHEN
+ backendAxisAccumulator.setValue(454.0f);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.value(), 454.0f);
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "value");
+ QCOMPARE(change->value().toFloat(), backendAxisAccumulator.value());
+
+ arbiter.events.clear();
+
+ // WHEN
+ backendAxisAccumulator.setValue(454.0f);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.value(), 454.0f);
+ QCOMPARE(arbiter.events.count(), 0);
+
+ arbiter.events.clear();
+
+
+ // WHEN
+ backendAxisAccumulator.setVelocity(383.0f);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.velocity(), 383.0f);
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr velocityChange = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(velocityChange->propertyName(), "velocity");
+ QCOMPARE(velocityChange->value().toFloat(), backendAxisAccumulator.velocity());
+
+ arbiter.events.clear();
+
+ // WHEN
+ backendAxisAccumulator.setVelocity(383.0f);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.velocity(), 383.0f);
+ QCOMPARE(arbiter.events.count(), 0);
+
+ arbiter.events.clear();
+ }
+
+ void shouldNotChangeValueWhenDisabled()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DInput::Input::AxisAccumulator backendAxisAccumulator;
+ Qt3DCore::QBackendNodePrivate::get(&backendAxisAccumulator)->setArbiter(&arbiter);
+ backendAxisAccumulator.setEnabled(false);
+
+ // WHEN
+ backendAxisAccumulator.setValue(454.0f);
+
+ // THEN
+ QCOMPARE(backendAxisAccumulator.value(), 0.0f);
+ QCOMPARE(arbiter.events.count(), 0);
+ }
+
+ void checkIntegration_data()
+ {
+ QTest::addColumn<Qt3DInput::QAxisAccumulator::SourceAxisType>("sourceAxisType");
+ QTest::addColumn<float>("axisValue");
+ QTest::addColumn<float>("scale");
+ QTest::addColumn<float>("dt");
+ QTest::addColumn<float>("valueResult");
+ QTest::addColumn<float>("velocityResult");
+
+ QTest::newRow("velocity=10, axis=1, dt=1") << Qt3DInput::QAxisAccumulator::Velocity
+ << 1.0f
+ << 10.0f
+ << 1.0f
+ << 10.0f
+ << 0.0f;
+
+ QTest::newRow("velocity=10, axis=1, dt=0.2") << Qt3DInput::QAxisAccumulator::Velocity
+ << 1.0f
+ << 10.0f
+ << 0.2f
+ << 2.0f
+ << 0.0f;
+
+ QTest::newRow("velocity=20, axis=1, dt=0.1") << Qt3DInput::QAxisAccumulator::Velocity
+ << 1.0f
+ << 20.0f
+ << 0.1f
+ << 2.0f
+ << 0.0f;
+
+ QTest::newRow("velocity=10, axis=0.5, dt=1") << Qt3DInput::QAxisAccumulator::Velocity
+ << 0.5f
+ << 10.0f
+ << 1.0f
+ << 5.0f
+ << 0.0f;
+
+ QTest::newRow("acceleration=10, axis=1, dt=1") << Qt3DInput::QAxisAccumulator::Acceleration
+ << 1.0f
+ << 10.0f
+ << 1.0f
+ << 10.0f
+ << 10.0f;
+ }
+
+ void checkIntegration()
+ {
+ // GIVEN
+ QFETCH(Qt3DInput::QAxisAccumulator::SourceAxisType, sourceAxisType);
+ QFETCH(float, axisValue);
+ QFETCH(float, scale);
+ QFETCH(float, dt);
+ QFETCH(float, valueResult);
+ QFETCH(float, velocityResult);
+
+ Qt3DInput::QAxis *axis = new Qt3DInput::QAxis;
+ Qt3DInput::Input::AxisManager axisManager;
+ Qt3DInput::Input::Axis *backendAxis = axisManager.getOrCreateResource(axis->id());
+ Qt3DInput::QAxisAccumulator axisAccumulator;
+ Qt3DInput::Input::AxisAccumulator backendAxisAccumulator;
+
+ // WHEN
+ backendAxis->setEnabled(true);
+ backendAxis->setAxisValue(axisValue);
+ axisAccumulator.setSourceAxis(axis);
+ axisAccumulator.setScale(scale);
+ axisAccumulator.setSourceAxisType(sourceAxisType);
+ axisAccumulator.setEnabled(true);
+ simulateInitialization(&axisAccumulator, &backendAxisAccumulator);
+
+ backendAxisAccumulator.stepIntegration(&axisManager, dt);
+
+ // THEN
+ switch (sourceAxisType) {
+ case Qt3DInput::QAxisAccumulator::Velocity:
+ QCOMPARE(backendAxisAccumulator.value(), valueResult);
+ break;
+
+ case Qt3DInput::QAxisAccumulator::Acceleration:
+ QCOMPARE(backendAxisAccumulator.velocity(), velocityResult);
+ QCOMPARE(backendAxisAccumulator.value(), valueResult);
+ break;
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_AxisAccumulator)
+
+#include "tst_axisaccumulator.moc"
diff --git a/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro b/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro
new file mode 100644
index 000000000..ad1a1a469
--- /dev/null
+++ b/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_axisaccumulatorjob
+
+QT += core-private 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_axisaccumulatorjob.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp b/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp
new file mode 100644
index 000000000..fa3bca3d2
--- /dev/null
+++ b/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DInput/private/axis_p.h>
+#include <Qt3DInput/private/axisaccumulator_p.h>
+#include <Qt3DInput/private/axisaccumulatorjob_p.h>
+#include <Qt3DInput/private/qabstractaxisinput_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DInput/QAnalogAxisInput>
+#include <Qt3DInput/QAxis>
+#include <Qt3DInput/QAxisAccumulator>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include "testpostmanarbiter.h"
+
+class tst_AxisAccumulatorJob : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkIntegration()
+ {
+ // GIVEN
+ const auto sourceAxisType = Qt3DInput::QAxisAccumulator::Velocity;
+ const float axisValue = 1.0f;
+ const float scale = 10.0f;
+ const float dt = 0.1f;
+ const float valueResultEnabled = 1.0f;
+ const float valueResultDisabled = 0.0f;
+
+ // Set up an axis
+ Qt3DInput::QAxis *axis = new Qt3DInput::QAxis;
+ Qt3DInput::Input::AxisManager axisManager;
+ Qt3DInput::Input::Axis *backendAxis = axisManager.getOrCreateResource(axis->id());
+ backendAxis->setEnabled(true);
+ backendAxis->setAxisValue(axisValue);
+
+ // Hook up a bunch of accumulators to this axis
+ Qt3DInput::Input::AxisAccumulatorManager axisAccumulatorManager;
+ QVector<Qt3DInput::Input::AxisAccumulator *> accumulators;
+ for (int i = 0; i < 10; ++i) {
+ auto axisAccumulator = new Qt3DInput::QAxisAccumulator;
+ Qt3DInput::Input::AxisAccumulator *backendAxisAccumulator
+ = axisAccumulatorManager.getOrCreateResource(axisAccumulator->id());
+ accumulators.push_back(backendAxisAccumulator);
+
+ axisAccumulator->setEnabled(i % 2 == 0); // Enable only even accumulators
+ axisAccumulator->setSourceAxis(axis);
+ axisAccumulator->setScale(scale);
+ axisAccumulator->setSourceAxisType(sourceAxisType);
+ simulateInitialization(axisAccumulator, backendAxisAccumulator);
+ }
+
+ // WHEN
+ Qt3DInput::Input::AxisAccumulatorJob job(&axisAccumulatorManager, &axisManager);
+ job.setDeltaTime(dt);
+ job.run();
+
+
+ // THEN
+ for (const auto accumulator : accumulators) {
+ QCOMPARE(accumulator->value(), accumulator->isEnabled() ? valueResultEnabled
+ : valueResultDisabled);
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_AxisAccumulatorJob)
+
+#include "tst_axisaccumulatorjob.moc"
diff --git a/tests/auto/input/input.pro b/tests/auto/input/input.pro
index f469d07ac..6169d3f7c 100644
--- a/tests/auto/input/input.pro
+++ b/tests/auto/input/input.pro
@@ -27,5 +27,7 @@ qtConfig(private_tests) {
loadproxydevicejob \
qmousedevice \
mousedevice \
- utils
+ utils \
+ axisaccumulator \
+ axisaccumulatorjob
}
diff --git a/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp b/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp
index a98cf09a9..3df09a67a 100644
--- a/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp
+++ b/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp
@@ -183,6 +183,17 @@ private Q_SLOTS:
// THEN
QCOMPARE(value(), 383.0f);
+ QCOMPARE(velocity(), 0.0f);
+
+ // WHEN
+ valueChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ valueChange->setPropertyName("velocity");
+ valueChange->setValue(123.0f);
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(value(), 383.0f);
+ QCOMPARE(velocity(), 123.0f);
}
void checkAxisInputBookkeeping()
diff --git a/tests/auto/render/commons/testrenderer.cpp b/tests/auto/render/commons/testrenderer.cpp
index cda741936..87e60a263 100644
--- a/tests/auto/render/commons/testrenderer.cpp
+++ b/tests/auto/render/commons/testrenderer.cpp
@@ -66,4 +66,14 @@ QVariant TestRenderer::executeCommand(const QStringList &args)
return QVariant();
}
+void TestRenderer::setOffscreenSurfaceHelper(Qt3DRender::Render::OffscreenSurfaceHelper *helper)
+{
+ Q_UNUSED(helper);
+}
+
+QSurfaceFormat TestRenderer::format()
+{
+ return QSurfaceFormat();
+}
+
QT_END_NAMESPACE
diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h
index 48588ab99..2e572582e 100644
--- a/tests/auto/render/commons/testrenderer.h
+++ b/tests/auto/render/commons/testrenderer.h
@@ -59,6 +59,7 @@ public:
void skipNextFrame() Q_DECL_OVERRIDE {}
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE { return QVector<Qt3DCore::QAspectJobPtr>(); }
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); }
+ Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); }
void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Qt3DRender::Render::Entity *root) Q_DECL_OVERRIDE { Q_UNUSED(factory); Q_UNUSED(root); }
Qt3DRender::Render::Entity *sceneRoot() const Q_DECL_OVERRIDE { return nullptr; }
Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const Q_DECL_OVERRIDE { return nullptr; }
@@ -74,6 +75,9 @@ public:
void resetDirty();
QVariant executeCommand(const QStringList &args) Q_DECL_OVERRIDE;
+ void setOffscreenSurfaceHelper(Qt3DRender::Render::OffscreenSurfaceHelper *helper) Q_DECL_OVERRIDE;
+ QSurfaceFormat format() Q_DECL_OVERRIDE;
+
protected:
Qt3DRender::Render::AbstractRenderer::BackendNodeDirtySet m_changes;
};
diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
index f9e177971..11b60f3c2 100644
--- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
+++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
@@ -436,6 +436,8 @@ private Q_SLOTS:
void checkEarlyReturnWhenMoveEventsAndNoCurrentPickers()
{
+ QSKIP("Disabled following removal of early return checks");
+
// GIVEN
QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
@@ -485,11 +487,15 @@ private Q_SLOTS:
void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers_data()
{
+ QSKIP("Disabled following removal of early return checks");
+
generateAllPickingSettingsCombinations();
}
void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers()
{
+ QSKIP("Disabled following removal of early return checks");
+
// GIVEN
QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragdisabled.qml"));
QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
diff --git a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp
index 2b4c9cd91..b76495d93 100644
--- a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp
+++ b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp
@@ -68,6 +68,7 @@ typedef QSharedPointer<FakeData> FakeDataPtr;
struct FakeAPITexture
{
+ void requestUpload() {}
};
using Manager = Qt3DRender::Render::GeneratorDataManager<FakeGeneratorPtr, FakeDataPtr, FakeAPITexture>;
diff --git a/tests/manual/dynamic-model-loader-qml/CuboidEntity.qml b/tests/manual/dynamic-model-loader-qml/CuboidEntity.qml
new file mode 100644
index 000000000..8555b6903
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/CuboidEntity.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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)
+ }
+
+ GoochMaterial {
+ id: phongMaterial
+ }
+
+ Transform {
+ id: transform
+ property real userAngle: 0.0
+ scale: 4
+ rotation: fromAxisAndAngle(Qt.vector3d(0, 1, 0), userAngle)
+ }
+
+ QQ2.ColorAnimation {
+ target: phongMaterial
+ property: "warmColor"
+ from: "red"
+ to: "blue"
+ duration: 2500
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+
+ QQ2.NumberAnimation {
+ target: transform
+ property: "userAngle"
+ duration: 750
+ loops: QQ2.Animation.Infinite
+ running: true
+ easing.type: QQ2.Easing.InOutQuad
+ from: 0
+ to: 360
+ }
+}
diff --git a/tests/manual/dynamic-model-loader-qml/SphereEntity.qml b/tests/manual/dynamic-model-loader-qml/SphereEntity.qml
new file mode 100644
index 000000000..8e11de99e
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/SphereEntity.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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: 3
+ }
+
+ Transform {
+ id: transform
+ scale: 3
+ }
+
+ QQ2.ColorAnimation {
+ target: material
+ property: "diffuse"
+ from: "yellow"
+ to: "orange"
+ duration: 1500
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+
+ QQ2.NumberAnimation {
+ target: transform
+ property: "scale"
+ duration: 1500
+ loops: QQ2.Animation.Infinite
+ running: true
+ easing.type: QQ2.Easing.InOutQuad
+ from: 1
+ to: 1.5
+ }
+}
diff --git a/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.pro b/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.pro
new file mode 100644
index 000000000..b19091873
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.pro
@@ -0,0 +1,16 @@
+!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 \
+ SphereEntity.qml \
+ CuboidEntity.qml
+
+RESOURCES += \
+ dynamic-model-loader-qml.qrc
diff --git a/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.qrc b/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.qrc
new file mode 100644
index 000000000..8cf177b62
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/dynamic-model-loader-qml.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>SphereEntity.qml</file>
+ <file>CuboidEntity.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/dynamic-model-loader-qml/main.cpp b/tests/manual/dynamic-model-loader-qml/main.cpp
new file mode 100644
index 000000000..a75e1d141
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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/dynamic-model-loader-qml/main.qml b/tests/manual/dynamic-model-loader-qml/main.qml
new file mode 100644
index 000000000..72d0529b8
--- /dev/null
+++ b/tests/manual/dynamic-model-loader-qml/main.qml
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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.2 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+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, 40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController { camera: camera }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ camera: camera
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+
+ PhongMaterial {
+ id: material
+ diffuse: "yellow"
+ }
+
+ TorusMesh {
+ id: torusMesh
+ radius: 5
+ minorRadius: 1
+ rings: 100
+ slices: 20
+ }
+
+ Transform {
+ id: torusTransform
+ scale3D: Qt.vector3d(1.5, 1, 0.5)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, material, torusTransform ]
+ }
+
+ QQ2.Timer {
+ interval: 1000
+ running: true
+ repeat: true
+ property bool addMore: true
+
+ onTriggered: {
+ if (instantiator.model > 10 || instantiator.model < 2)
+ addMore = !addMore
+ instantiator.model += (addMore ? 1 : -1)
+ }
+ }
+
+ NodeInstantiator {
+ id: instantiator
+ model: 2
+ readonly property real angleStep: 360.0 / Math.max(count, 1)
+ EntityLoader {
+ components: Transform {
+ id: revolutionTransform
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.rotate(model.index * instantiator.angleStep, Qt.vector3d(0, 1, 0));
+ m.translate(Qt.vector3d(20, 0, 0));
+ return m;
+ }
+ }
+ source: model.index % 2 === 0 ? "qrc:/CuboidEntity.qml" : "qrc:/SphereEntity.qml"
+ }
+
+ }
+}
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 5a10e4e0f..bfb95bfc2 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -33,7 +33,8 @@ SUBDIRS += \
transparency-qml \
transparency-qml-scene3d \
rendercapture-qml \
- additional-attributes-qml
+ additional-attributes-qml \
+ dynamic-model-loader-qml
qtHaveModule(widgets): {
SUBDIRS += \
diff --git a/tests/manual/rendercapture-qml/CaptureScene.qml b/tests/manual/rendercapture-qml/CaptureScene.qml
index 17fa83a5c..2329e4730 100644
--- a/tests/manual/rendercapture-qml/CaptureScene.qml
+++ b/tests/manual/rendercapture-qml/CaptureScene.qml
@@ -50,7 +50,7 @@
import QtQuick 2.2 as QQ2
import Qt3D.Core 2.0
-import Qt3D.Render 2.0
+import Qt3D.Render 2.1
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
diff --git a/tests/manual/rendercapture-qml/main.qml b/tests/manual/rendercapture-qml/main.qml
index 83746c3a9..77e96d739 100644
--- a/tests/manual/rendercapture-qml/main.qml
+++ b/tests/manual/rendercapture-qml/main.qml
@@ -51,7 +51,7 @@
import QtQuick 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4
-import Qt3D.Render 2.0
+import Qt3D.Render 2.1
import QtQuick.Scene3D 2.0
Item {