blob: 6d349f994c86c76ff26f29f8eee7ce96a499d557 [file] [log] [blame]
/****************************************************************************
**
** 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"