diff options
Diffstat (limited to 'tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp')
-rw-r--r-- | tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp | 801 |
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" |