| /**************************************************************************** |
| ** |
| ** 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 <Qt3DRender/private/renderviewjobutils_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::ShaderUniform> buildUniformMap(const QString &blockName) |
| { |
| QHash<QString, Qt3DRender::Render::ShaderUniform> uniforms; |
| |
| uniforms.insert(blockName + QStringLiteral(".scalar"), Qt3DRender::Render::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::ShaderUniform> buildUniformMap(const QString &blockName) |
| { |
| QHash<QString, Qt3DRender::Render::ShaderUniform> uniforms; |
| |
| uniforms.insert(blockName + QStringLiteral(".texture"), Qt3DRender::Render::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::ShaderUniform> buildUniformMap(const QString &blockName) |
| { |
| QHash<QString, Qt3DRender::Render::ShaderUniform> uniforms; |
| |
| uniforms.insert(blockName + QStringLiteral(".array[0]"), Qt3DRender::Render::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::ShaderUniform> buildUniformMap(const QString &blockName) |
| { |
| QHash<QString, Qt3DRender::Render::ShaderUniform> uniforms; |
| |
| uniforms.insert(blockName + QStringLiteral(".scalar"), Qt3DRender::Render::ShaderUniform()); |
| uniforms.insert(blockName + QStringLiteral(".array[0]"), Qt3DRender::Render::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::ShaderUniform> buildUniformMap(const QString &blockName) override |
| { |
| QHash<QString, Qt3DRender::Render::ShaderUniform> innerUniforms; |
| |
| StructShaderData *innerData = nullptr; |
| if ((innerData = qobject_cast<StructShaderData *>(m_inner)) != nullptr) |
| innerUniforms = innerData->buildUniformMap(QStringLiteral(".inner")); |
| |
| QHash<QString, Qt3DRender::Render::ShaderUniform> uniforms = StructShaderData::buildUniformMap(blockName); |
| QHash<QString, Qt3DRender::Render::ShaderUniform>::const_iterator it = innerUniforms.begin(); |
| const QHash<QString, Qt3DRender::Render::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::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::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::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin(); |
| const Qt3DRender::Render::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::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::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::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin(); |
| const Qt3DRender::Render::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::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::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin(); |
| const Qt3DRender::Render::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::UniformBlockValueBuilder blockBuilder; |
| blockBuilder.shaderDataManager = manager.data(); |
| blockBuilder.textureManager = textureManager.data(); |
| blockBuilder.updatedPropertiesOnly = false; |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0].scalar"), Qt3DRender::Render::ShaderUniform()); |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[1].scalar"), Qt3DRender::Render::ShaderUniform()); |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[2].scalar"), Qt3DRender::Render::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::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::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin(); |
| const Qt3DRender::Render::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::UniformBlockValueBuilder blockBuilder; |
| blockBuilder.shaderDataManager = manager.data(); |
| blockBuilder.textureManager = textureManager.data(); |
| blockBuilder.updatedPropertiesOnly = false; |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.scalar"), Qt3DRender::Render::ShaderUniform()); |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0]"), Qt3DRender::Render::ShaderUniform()); |
| blockBuilder.uniforms.insert(QStringLiteral("MyBlock.texture"), Qt3DRender::Render::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" |