summaryrefslogtreecommitdiffstats
path: root/tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp')
-rw-r--r--tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp801
1 files changed, 801 insertions, 0 deletions
diff --git a/tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp b/tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp
new file mode 100644
index 000000000..6b714b9e1
--- /dev/null
+++ b/tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp
@@ -0,0 +1,801 @@
+/****************************************************************************
+**
+** 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/qdynamicpropertyupdatedchange.h>
+#include <renderviewjobutils_p.h>
+#include <shadervariables_p.h>
+#include <Qt3DRender/private/shaderdata_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/stringtoint_p.h>
+#include <Qt3DRender/qshaderdata.h>
+#include "testrenderer.h"
+#include "testpostmanarbiter.h"
+
+class tst_RenderViewUtils : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void topLevelScalarValueNoUniforms();
+ void topLevelScalarValue();
+ void topLevelTextureValueNoUniforms();
+ void topLevelTextureValue();
+ void topLevelArrayValue();
+ void nestedShaderDataValue();
+ void topLevelStructValue_data();
+ void topLevelStructValue();
+ void topLevelDynamicProperties();
+ void transformedProperties();
+ void shouldNotifyDynamicPropertyChanges();
+
+private:
+ void initBackendShaderData(Qt3DRender::Render::AbstractRenderer *renderer,
+ Qt3DRender::QShaderData *frontend,
+ Qt3DRender::Render::ShaderDataManager *manager)
+ {
+ // Create children first
+ for (QObject *c : frontend->children()) {
+ Qt3DRender::QShaderData *cShaderData = qobject_cast<Qt3DRender::QShaderData *>(c);
+ if (cShaderData)
+ initBackendShaderData(renderer, cShaderData, manager);
+ }
+
+ // Create backend element for frontend one
+ Qt3DRender::Render::ShaderData *backend = manager->getOrCreateResource(frontend->id());
+ // Init the backend element
+ backend->setRenderer(renderer);
+ simulateInitializationSync(frontend, backend);
+ }
+
+ void initBackendTexture(Qt3DRender::QAbstractTexture *frontend,
+ Qt3DRender::Render::TextureManager *manager)
+ {
+ // Create backend element for frontend one
+ Qt3DRender::Render::Texture *backend = manager->getOrCreateResource(frontend->id());
+ // Init the backend element
+ simulateInitialization(frontend, backend);
+ }
+};
+
+class ScalarShaderData : public Qt3DRender::QShaderData
+{
+ Q_OBJECT
+ Q_PROPERTY(float scalar READ scalar WRITE setScalar NOTIFY scalarChanged)
+
+public:
+ ScalarShaderData(Qt3DCore::QNode *parent = nullptr)
+ : Qt3DRender::QShaderData(parent)
+ , m_scalar(0.0f)
+ {
+ }
+
+ void setScalar(float scalar)
+ {
+ if (scalar != m_scalar) {
+ m_scalar = scalar;
+ emit scalarChanged();
+ }
+ }
+
+ float scalar() const
+ {
+ return m_scalar;
+ }
+
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
+ {
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
+
+ uniforms.insert(blockName + QStringLiteral(".scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+
+ return uniforms;
+ }
+
+Q_SIGNALS:
+ void scalarChanged();
+
+private:
+ float m_scalar;
+};
+
+class TextureShaderData : public Qt3DRender::QShaderData
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QAbstractTexture* texture READ texture WRITE setTexture NOTIFY textureChanged)
+
+public:
+ TextureShaderData()
+ : Qt3DRender::QShaderData()
+ , m_texture(nullptr)
+ {
+ }
+
+ void setTexture(Qt3DRender::QAbstractTexture *texture)
+ {
+ if (texture != m_texture) {
+ m_texture = texture;
+ emit textureChanged();
+ }
+ }
+
+ Qt3DRender::QAbstractTexture *texture() const
+ {
+ return m_texture;
+ }
+
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
+ {
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
+
+ uniforms.insert(blockName + QStringLiteral(".texture"), Qt3DRender::Render::OpenGL::ShaderUniform());
+
+ return uniforms;
+ }
+
+Q_SIGNALS:
+ void textureChanged();
+
+private:
+ Qt3DRender::QAbstractTexture *m_texture;
+};
+
+
+class ArrayShaderData : public Qt3DRender::QShaderData
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariantList array READ array WRITE setArray NOTIFY arrayChanged)
+
+public:
+ ArrayShaderData()
+ : Qt3DRender::QShaderData()
+ {
+ }
+
+ void setArray(const QVariantList &array)
+ {
+ if (array != m_array) {
+ m_array = array;
+ emit arrayChanged();
+ }
+ }
+
+ QVariantList array() const
+ {
+ return m_array;
+ }
+
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
+ {
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
+
+ uniforms.insert(blockName + QStringLiteral(".array[0]"), Qt3DRender::Render::OpenGL::ShaderUniform());
+
+ return uniforms;
+ }
+
+Q_SIGNALS:
+ void arrayChanged();
+
+private:
+ QVariantList m_array;
+};
+
+class StructShaderData : public Qt3DRender::QShaderData
+{
+ Q_OBJECT
+ Q_PROPERTY(float scalar READ scalar WRITE setScalar NOTIFY scalarChanged)
+ Q_PROPERTY(QVariantList array READ array WRITE setArray NOTIFY arrayChanged)
+
+public:
+ StructShaderData()
+ : Qt3DRender::QShaderData()
+ , m_scalar(0.0f)
+ {
+ }
+
+ void setScalar(float scalar)
+ {
+ if (scalar != m_scalar) {
+ m_scalar = scalar;
+ emit scalarChanged();
+ }
+ }
+
+ float scalar() const
+ {
+ return m_scalar;
+ }
+
+ void setArray(const QVariantList &array)
+ {
+ if (array != m_array) {
+ m_array = array;
+ emit arrayChanged();
+ }
+ }
+
+ QVariantList array() const
+ {
+ return m_array;
+ }
+
+ virtual QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
+ {
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
+
+ uniforms.insert(blockName + QStringLiteral(".scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ uniforms.insert(blockName + QStringLiteral(".array[0]"), Qt3DRender::Render::OpenGL::ShaderUniform());
+
+ return uniforms;
+ }
+
+ virtual QHash<QString, QVariant> buildUniformMapValues(const QString &blockName)
+ {
+ QHash<QString, QVariant> uniforms;
+
+ uniforms.insert(blockName + QStringLiteral(".scalar"), QVariant(scalar()));
+ uniforms.insert(blockName + QStringLiteral(".array[0]"), QVariant(array()));
+
+ return uniforms;
+ }
+
+Q_SIGNALS:
+ void scalarChanged();
+ void arrayChanged();
+
+private:
+ float m_scalar;
+ QVariantList m_array;
+};
+
+class MultiLevelStructShaderData : public StructShaderData
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QShaderData *inner READ inner WRITE setInner NOTIFY innerChanged)
+
+public:
+ MultiLevelStructShaderData()
+ : StructShaderData()
+ , m_inner(nullptr)
+ {
+ }
+
+ void setInner(Qt3DRender::QShaderData *inner)
+ {
+ if (inner != m_inner) {
+ m_inner = inner;
+ emit innerChanged();
+ }
+ }
+
+ Qt3DRender::QShaderData *inner() const
+ {
+ return m_inner;
+ }
+
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName) override
+ {
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> innerUniforms;
+
+ StructShaderData *innerData = nullptr;
+ if ((innerData = qobject_cast<StructShaderData *>(m_inner)) != nullptr)
+ innerUniforms = innerData->buildUniformMap(QStringLiteral(".inner"));
+
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms = StructShaderData::buildUniformMap(blockName);
+ QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform>::const_iterator it = innerUniforms.begin();
+ const QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform>::const_iterator end = innerUniforms.end();
+
+ while (it != end) {
+ uniforms.insert(blockName + it.key(), it.value());
+ ++it;
+ }
+ return uniforms;
+ }
+
+ QHash<QString, QVariant> buildUniformMapValues(const QString &blockName) override
+ {
+ QHash<QString, QVariant> innerUniformsValues;
+
+ StructShaderData *innerData = nullptr;
+ if ((innerData = qobject_cast<StructShaderData *>(m_inner)) != nullptr)
+ innerUniformsValues = innerData->buildUniformMapValues(QStringLiteral(".inner"));
+
+ QHash<QString, QVariant> uniformsValues = StructShaderData::buildUniformMapValues(blockName);
+ QHash<QString, QVariant>::const_iterator it = innerUniformsValues.begin();
+ const QHash<QString, QVariant>::const_iterator end = innerUniformsValues.end();
+
+ while (it != end) {
+ uniformsValues.insert(blockName + it.key(), it.value());
+ ++it;
+ }
+
+ return uniformsValues;
+ }
+
+Q_SIGNALS:
+ void innerChanged();
+
+private:
+ Qt3DRender::QShaderData *m_inner;
+};
+
+void tst_RenderViewUtils::topLevelScalarValueNoUniforms()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<ScalarShaderData> shaderData(new ScalarShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ shaderData->setScalar(883.0f);
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEB
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral(""));
+
+ // THEN
+ // activeUniformNamesToValue should be empty as blockBuilder.uniforms is
+ QVERIFY(blockBuilder.activeUniformNamesToValue.isEmpty());
+}
+
+void tst_RenderViewUtils::topLevelScalarValue()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<ScalarShaderData> shaderData(new ScalarShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ shaderData->setScalar(883.0f);
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock"));
+
+ // THEN
+ QVERIFY(blockBuilder.uniforms.count() == 1);
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
+ const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
+
+ while (it != end) {
+ // THEN
+ QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ QCOMPARE(it.value(), QVariant(shaderData->scalar()));
+ ++it;
+ }
+}
+
+void tst_RenderViewUtils::topLevelTextureValueNoUniforms()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<TextureShaderData> shaderData(new TextureShaderData);
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager);
+ QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ shaderData->setTexture(texture.data());
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEB
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral(""));
+
+ // THEN
+ // activeUniformNamesToValue should be empty as blockBuilder.uniforms is
+ QVERIFY(blockBuilder.activeUniformNamesToValue.isEmpty());
+}
+
+void tst_RenderViewUtils::topLevelTextureValue()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<TextureShaderData> shaderData(new TextureShaderData);
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager);
+ QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ initBackendTexture(texture.data(), textureManager.data());
+ shaderData->setTexture(texture.data());
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock"));
+
+ // THEN
+ QVERIFY(blockBuilder.uniforms.count() == 1);
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
+ const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
+
+ while (it != end) {
+ // THEN
+ QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ QCOMPARE(it.value(), QVariant::fromValue(shaderData->texture()->id()));
+ ++it;
+ }
+}
+
+void tst_RenderViewUtils::topLevelArrayValue()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<ArrayShaderData> shaderData(new ArrayShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ QVariantList arrayValues = QVariantList() << 454 << 350 << 383 << 427 << 552;
+ shaderData->setArray(arrayValues);
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock"));
+
+ // THEN
+ QVERIFY(blockBuilder.uniforms.count() == 1);
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
+ const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
+
+ while (it != end) {
+ // THEN
+ QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ QCOMPARE(it.value(), QVariant(arrayValues));
+ ++it;
+ }
+}
+
+void tst_RenderViewUtils::nestedShaderDataValue()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<ArrayShaderData> arrayShaderData(new ArrayShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ QScopedPointer<ScalarShaderData> shaderData1(new ScalarShaderData(arrayShaderData.data()));
+ QScopedPointer<ScalarShaderData> shaderData2(new ScalarShaderData(arrayShaderData.data()));
+ QScopedPointer<ScalarShaderData> shaderData3(new ScalarShaderData(arrayShaderData.data()));
+
+ shaderData1->setScalar(883.0f);
+ shaderData2->setScalar(1200.0f);
+ shaderData3->setScalar(1340.0f);
+ QHash<QString, QVariant> scalarValues;
+ scalarValues[QStringLiteral("MyBlock.array[0].scalar")] = shaderData1->scalar();
+ scalarValues[QStringLiteral("MyBlock.array[1].scalar")] = shaderData2->scalar();
+ scalarValues[QStringLiteral("MyBlock.array[2].scalar")] = shaderData3->scalar();
+
+
+ const Qt3DCore::QNodeId id1 = shaderData1->id();
+ const Qt3DCore::QNodeId id2 = shaderData2->id();
+ const Qt3DCore::QNodeId id3 = shaderData3->id();
+
+ // WHEN
+ const QVariantList arrayValues = QVariantList() << QVariant::fromValue(id1) << QVariant::fromValue(id2) << QVariant::fromValue(id3);
+ arrayShaderData->setArray(arrayValues);
+ initBackendShaderData(&renderer, arrayShaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendArrayShaderData = manager->lookupResource(arrayShaderData->id());
+ Qt3DRender::Render::ShaderData *backendShaderData1 = manager->lookupResource(id1);
+ Qt3DRender::Render::ShaderData *backendShaderData2 = manager->lookupResource(id2);
+ Qt3DRender::Render::ShaderData *backendShaderData3 = manager->lookupResource(id3);
+ QVERIFY(backendArrayShaderData != nullptr);
+ QVERIFY(backendShaderData1 != nullptr);
+ QVERIFY(backendShaderData2 != nullptr);
+ QVERIFY(backendShaderData3 != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0].scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[1].scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[2].scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendArrayShaderData, QStringLiteral("MyBlock"));
+
+ // THEN
+ QVERIFY(blockBuilder.uniforms.count() == 3);
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 3);
+
+ // WHEN
+ auto it = blockBuilder.uniforms.cbegin();
+ const auto end = blockBuilder.uniforms.cend();
+
+ while (it != end) {
+ // THEN
+ const int nameId = Qt3DRender::Render::StringToInt::lookupId(it.key());
+ QVERIFY(blockBuilder.activeUniformNamesToValue.contains(nameId));
+ QCOMPARE(blockBuilder.activeUniformNamesToValue[nameId], scalarValues.value(it.key()));
+ ++it;
+ }
+}
+
+void tst_RenderViewUtils::topLevelStructValue_data()
+{
+ QTest::addColumn<StructShaderData*>("shaderData");
+ QTest::addColumn<QString>("blockName");
+
+ QVariantList arrayValues2 = QVariantList() << 180 << 220 << 250 << 270 << 300 << 350 << 550;
+ QVariantList arrayValues = QVariantList() << 454 << 350 << 383 << 427 << 552;
+
+ MultiLevelStructShaderData *twoLevelsNestedShaderData = new MultiLevelStructShaderData();
+ MultiLevelStructShaderData *singleLevelShaderData = new MultiLevelStructShaderData();
+ StructShaderData *shaderData = new StructShaderData();
+
+ // Don't forget to set the parent so that initBackendShaderData
+ // properly initializes nested members
+ shaderData->setParent(singleLevelShaderData);
+ shaderData->setArray(arrayValues);
+ shaderData->setScalar(1584.0f);
+
+ singleLevelShaderData->setParent(twoLevelsNestedShaderData);
+ singleLevelShaderData->setInner(shaderData);
+ singleLevelShaderData->setScalar(1200.0f);
+ singleLevelShaderData->setArray(arrayValues2);
+
+ twoLevelsNestedShaderData->setInner(singleLevelShaderData);
+ twoLevelsNestedShaderData->setArray(arrayValues + arrayValues2);
+ twoLevelsNestedShaderData->setScalar(1340.0f);
+
+ QTest::newRow("simple struct") << shaderData << QStringLiteral("Block");
+ QTest::newRow("single level inner struct") << (StructShaderData *)singleLevelShaderData << QStringLiteral("Block");
+ QTest::newRow("tow level inner struct") << (StructShaderData *)twoLevelsNestedShaderData << QStringLiteral("Block");
+}
+
+void tst_RenderViewUtils::topLevelStructValue()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QFETCH(StructShaderData *, shaderData);
+ QFETCH(QString, blockName);
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ initBackendShaderData(&renderer, shaderData, manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms = shaderData->buildUniformMap(blockName);
+ const QHash<QString, QVariant> expectedValues = shaderData->buildUniformMapValues(blockName);
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, blockName);
+
+ // THEN
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), blockBuilder.uniforms.count());
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
+ const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
+
+ while (it != end) {
+ // THEN
+ QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ QVERIFY(expectedValues.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ QCOMPARE(it.value(), expectedValues.value(Qt3DRender::Render::StringToInt::lookupString(it.key())));
+ ++it;
+ }
+}
+
+void tst_RenderViewUtils::topLevelDynamicProperties()
+{
+ // GIVEN
+ TestRenderer renderer;
+ QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
+ QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
+
+ // WHEN
+ initBackendTexture(texture.data(), textureManager.data());
+ shaderData->setProperty("scalar", 883.0f);
+ shaderData->setProperty("array", QVariantList() << 454 << 350 << 383 << 427 << 552);
+ shaderData->setProperty("texture", QVariant::fromValue(texture.data()));
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
+ blockBuilder.shaderDataManager = manager.data();
+ blockBuilder.textureManager = textureManager.data();
+ blockBuilder.updatedPropertiesOnly = false;
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.scalar"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0]"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ blockBuilder.uniforms.insert(QStringLiteral("MyBlock.texture"), Qt3DRender::Render::OpenGL::ShaderUniform());
+ // build name-value map
+ blockBuilder.buildActiveUniformNameValueMapStructHelper(backendShaderData, QStringLiteral("MyBlock"));
+
+ // THEN
+ QVERIFY(blockBuilder.uniforms.count() == 3);
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 3);
+
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.scalar")),
+ shaderData->property("scalar"));
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.array[0]")),
+ shaderData->property("array"));
+ QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.texture")),
+ QVariant::fromValue(texture->id()));
+}
+
+void tst_RenderViewUtils::transformedProperties()
+{
+ // GIVEN
+ QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
+ QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
+ TestRenderer renderer;
+
+ // WHEN
+ const Vector3D position = Vector3D(15.0f, -5.0f, 10.0f);
+ const QVector3D positionQt = convertToQVector3D(position);
+ Matrix4x4 worldMatrix;
+ {
+ QMatrix4x4 m;
+ m.translate(-3.0f, 2.0f, 7.5f);
+ worldMatrix = Matrix4x4(m);
+ }
+ Matrix4x4 viewMatrix;
+ {
+ QMatrix4x4 m;
+ m.translate(9.0f, 6.0f, 12.0f);
+ viewMatrix = Matrix4x4(m);
+ }
+
+ shaderData->setProperty("position0", positionQt);
+ shaderData->setProperty("position1", positionQt);
+ shaderData->setProperty("position2", positionQt);
+ shaderData->setProperty("position3", positionQt);
+ shaderData->setProperty("position1Transformed", Qt3DRender::Render::ShaderData::ModelToEye);
+ shaderData->setProperty("position2Transformed", Qt3DRender::Render::ShaderData::ModelToWorld);
+ shaderData->setProperty("position3Transformed", Qt3DRender::Render::ShaderData::ModelToWorldDirection);
+ initBackendShaderData(&renderer, shaderData.data(), manager.data());
+
+ // THEN
+ Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(shaderData->id());
+ QVERIFY(backendShaderData != nullptr);
+ QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position0")), Qt3DRender::Render::ShaderData::NoTransform);
+ QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position1")), Qt3DRender::Render::ShaderData::ModelToEye);
+ QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position2")), Qt3DRender::Render::ShaderData::ModelToWorld);
+ QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position3")), Qt3DRender::Render::ShaderData::ModelToWorldDirection);
+
+ // WHEN
+ backendShaderData->updateWorldTransform(worldMatrix);
+ const Vector3D position1Value = backendShaderData->getTransformedProperty(QStringLiteral("position1"), viewMatrix).value<Vector3D>();
+ const Vector3D position2Value = backendShaderData->getTransformedProperty(QStringLiteral("position2"), viewMatrix).value<Vector3D>();
+ const Vector3D position3Value = backendShaderData->getTransformedProperty(QStringLiteral("position3"), viewMatrix).value<Vector3D>();
+ const QVariant position0Value = backendShaderData->getTransformedProperty(QStringLiteral("position0"), viewMatrix);
+
+ // THEN
+ QCOMPARE(position0Value, positionQt);
+ QCOMPARE(position1Value, viewMatrix * worldMatrix * position);
+ QCOMPARE(position2Value, worldMatrix * position);
+ QCOMPARE(position3Value, Vector3D((worldMatrix * Vector4D(position, 0.0f))));
+}
+
+void tst_RenderViewUtils::shouldNotifyDynamicPropertyChanges()
+{
+ // GIVEN
+ TestArbiter arbiter;
+ QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
+ arbiter.setArbiterOnNode(shaderData.data());
+
+ // WHEN
+ shaderData->setProperty("scalar", 883.0f);
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(arbiter.dirtyNodes.size(), 1);
+ QCOMPARE(arbiter.dirtyNodes.front(), shaderData.data());
+
+ arbiter.dirtyNodes.clear();
+
+ // WHEN
+ QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
+ shaderData->setProperty("texture", QVariant::fromValue(texture.data()));
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(arbiter.dirtyNodes.size(), 1);
+ QCOMPARE(arbiter.dirtyNodes.front(), shaderData.data());
+}
+
+QTEST_MAIN(tst_RenderViewUtils)
+
+#include "tst_renderviewutils.moc"