1/****************************************************************************
2**
3** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QTest>
30#include <qbackendnodetester.h>
31#include <Qt3DCore/qdynamicpropertyupdatedchange.h>
32#include <renderviewjobutils_p.h>
33#include <shadervariables_p.h>
34#include <Qt3DRender/private/shaderdata_p.h>
35#include <Qt3DRender/private/managers_p.h>
36#include <Qt3DRender/private/stringtoint_p.h>
37#include <Qt3DRender/qshaderdata.h>
38#include "testrenderer.h"
39#include "testpostmanarbiter.h"
40
41class tst_RenderViewUtils : public Qt3DCore::QBackendNodeTester
42{
43 Q_OBJECT
44private Q_SLOTS:
45 void topLevelScalarValueNoUniforms();
46 void topLevelScalarValue();
47 void topLevelTextureValueNoUniforms();
48 void topLevelTextureValue();
49 void topLevelArrayValue();
50 void nestedShaderDataValue();
51 void topLevelStructValue_data();
52 void topLevelStructValue();
53 void topLevelDynamicProperties();
54 void transformedProperties();
55 void shouldNotifyDynamicPropertyChanges();
56
57private:
58 void initBackendShaderData(Qt3DRender::Render::AbstractRenderer *renderer,
59 Qt3DRender::QShaderData *frontend,
60 Qt3DRender::Render::ShaderDataManager *manager)
61 {
62 // Create children first
63 for (QObject *c : frontend->children()) {
64 Qt3DRender::QShaderData *cShaderData = qobject_cast<Qt3DRender::QShaderData *>(object: c);
65 if (cShaderData)
66 initBackendShaderData(renderer, frontend: cShaderData, manager);
67 }
68
69 // Create backend element for frontend one
70 Qt3DRender::Render::ShaderData *backend = manager->getOrCreateResource(id: frontend->id());
71 // Init the backend element
72 backend->setRenderer(renderer);
73 simulateInitializationSync(frontend, backend);
74 }
75
76 void initBackendTexture(Qt3DRender::QAbstractTexture *frontend,
77 Qt3DRender::Render::TextureManager *manager)
78 {
79 // Create backend element for frontend one
80 Qt3DRender::Render::Texture *backend = manager->getOrCreateResource(id: frontend->id());
81 // Init the backend element
82 simulateInitialization(frontend, backend);
83 }
84};
85
86class ScalarShaderData : public Qt3DRender::QShaderData
87{
88 Q_OBJECT
89 Q_PROPERTY(float scalar READ scalar WRITE setScalar NOTIFY scalarChanged)
90
91public:
92 ScalarShaderData(Qt3DCore::QNode *parent = nullptr)
93 : Qt3DRender::QShaderData(parent)
94 , m_scalar(0.0f)
95 {
96 }
97
98 void setScalar(float scalar)
99 {
100 if (scalar != m_scalar) {
101 m_scalar = scalar;
102 emit scalarChanged();
103 }
104 }
105
106 float scalar() const
107 {
108 return m_scalar;
109 }
110
111 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
112 {
113 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
114
115 uniforms.insert(akey: blockName + QStringLiteral(".scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
116
117 return uniforms;
118 }
119
120Q_SIGNALS:
121 void scalarChanged();
122
123private:
124 float m_scalar;
125};
126
127class TextureShaderData : public Qt3DRender::QShaderData
128{
129 Q_OBJECT
130 Q_PROPERTY(Qt3DRender::QAbstractTexture* texture READ texture WRITE setTexture NOTIFY textureChanged)
131
132public:
133 TextureShaderData()
134 : Qt3DRender::QShaderData()
135 , m_texture(nullptr)
136 {
137 }
138
139 void setTexture(Qt3DRender::QAbstractTexture *texture)
140 {
141 if (texture != m_texture) {
142 m_texture = texture;
143 emit textureChanged();
144 }
145 }
146
147 Qt3DRender::QAbstractTexture *texture() const
148 {
149 return m_texture;
150 }
151
152 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
153 {
154 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
155
156 uniforms.insert(akey: blockName + QStringLiteral(".texture"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
157
158 return uniforms;
159 }
160
161Q_SIGNALS:
162 void textureChanged();
163
164private:
165 Qt3DRender::QAbstractTexture *m_texture;
166};
167
168
169class ArrayShaderData : public Qt3DRender::QShaderData
170{
171 Q_OBJECT
172 Q_PROPERTY(QVariantList array READ array WRITE setArray NOTIFY arrayChanged)
173
174public:
175 ArrayShaderData()
176 : Qt3DRender::QShaderData()
177 {
178 }
179
180 void setArray(const QVariantList &array)
181 {
182 if (array != m_array) {
183 m_array = array;
184 emit arrayChanged();
185 }
186 }
187
188 QVariantList array() const
189 {
190 return m_array;
191 }
192
193 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
194 {
195 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
196
197 uniforms.insert(akey: blockName + QStringLiteral(".array[0]"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
198
199 return uniforms;
200 }
201
202Q_SIGNALS:
203 void arrayChanged();
204
205private:
206 QVariantList m_array;
207};
208
209class StructShaderData : public Qt3DRender::QShaderData
210{
211 Q_OBJECT
212 Q_PROPERTY(float scalar READ scalar WRITE setScalar NOTIFY scalarChanged)
213 Q_PROPERTY(QVariantList array READ array WRITE setArray NOTIFY arrayChanged)
214
215public:
216 StructShaderData()
217 : Qt3DRender::QShaderData()
218 , m_scalar(0.0f)
219 {
220 }
221
222 void setScalar(float scalar)
223 {
224 if (scalar != m_scalar) {
225 m_scalar = scalar;
226 emit scalarChanged();
227 }
228 }
229
230 float scalar() const
231 {
232 return m_scalar;
233 }
234
235 void setArray(const QVariantList &array)
236 {
237 if (array != m_array) {
238 m_array = array;
239 emit arrayChanged();
240 }
241 }
242
243 QVariantList array() const
244 {
245 return m_array;
246 }
247
248 virtual QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName)
249 {
250 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms;
251
252 uniforms.insert(akey: blockName + QStringLiteral(".scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
253 uniforms.insert(akey: blockName + QStringLiteral(".array[0]"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
254
255 return uniforms;
256 }
257
258 virtual QHash<QString, QVariant> buildUniformMapValues(const QString &blockName)
259 {
260 QHash<QString, QVariant> uniforms;
261
262 uniforms.insert(akey: blockName + QStringLiteral(".scalar"), avalue: QVariant(scalar()));
263 uniforms.insert(akey: blockName + QStringLiteral(".array[0]"), avalue: QVariant(array()));
264
265 return uniforms;
266 }
267
268Q_SIGNALS:
269 void scalarChanged();
270 void arrayChanged();
271
272private:
273 float m_scalar;
274 QVariantList m_array;
275};
276
277class MultiLevelStructShaderData : public StructShaderData
278{
279 Q_OBJECT
280 Q_PROPERTY(Qt3DRender::QShaderData *inner READ inner WRITE setInner NOTIFY innerChanged)
281
282public:
283 MultiLevelStructShaderData()
284 : StructShaderData()
285 , m_inner(nullptr)
286 {
287 }
288
289 void setInner(Qt3DRender::QShaderData *inner)
290 {
291 if (inner != m_inner) {
292 m_inner = inner;
293 emit innerChanged();
294 }
295 }
296
297 Qt3DRender::QShaderData *inner() const
298 {
299 return m_inner;
300 }
301
302 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> buildUniformMap(const QString &blockName) override
303 {
304 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> innerUniforms;
305
306 StructShaderData *innerData = nullptr;
307 if ((innerData = qobject_cast<StructShaderData *>(object: m_inner)) != nullptr)
308 innerUniforms = innerData->buildUniformMap(QStringLiteral(".inner"));
309
310 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform> uniforms = StructShaderData::buildUniformMap(blockName);
311 QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform>::const_iterator it = innerUniforms.begin();
312 const QHash<QString, Qt3DRender::Render::OpenGL::ShaderUniform>::const_iterator end = innerUniforms.end();
313
314 while (it != end) {
315 uniforms.insert(akey: blockName + it.key(), avalue: it.value());
316 ++it;
317 }
318 return uniforms;
319 }
320
321 QHash<QString, QVariant> buildUniformMapValues(const QString &blockName) override
322 {
323 QHash<QString, QVariant> innerUniformsValues;
324
325 StructShaderData *innerData = nullptr;
326 if ((innerData = qobject_cast<StructShaderData *>(object: m_inner)) != nullptr)
327 innerUniformsValues = innerData->buildUniformMapValues(QStringLiteral(".inner"));
328
329 QHash<QString, QVariant> uniformsValues = StructShaderData::buildUniformMapValues(blockName);
330 QHash<QString, QVariant>::const_iterator it = innerUniformsValues.begin();
331 const QHash<QString, QVariant>::const_iterator end = innerUniformsValues.end();
332
333 while (it != end) {
334 uniformsValues.insert(akey: blockName + it.key(), avalue: it.value());
335 ++it;
336 }
337
338 return uniformsValues;
339 }
340
341Q_SIGNALS:
342 void innerChanged();
343
344private:
345 Qt3DRender::QShaderData *m_inner;
346};
347
348void tst_RenderViewUtils::topLevelScalarValueNoUniforms()
349{
350 // GIVEN
351 TestRenderer renderer;
352 QScopedPointer<ScalarShaderData> shaderData(new ScalarShaderData());
353 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
354 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
355
356 // WHEN
357 shaderData->setScalar(883.0f);
358 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
359
360 // THEN
361 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
362 QVERIFY(backendShaderData != nullptr);
363
364 // WHEB
365 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
366 blockBuilder.shaderDataManager = manager.data();
367 blockBuilder.textureManager = textureManager.data();
368 blockBuilder.updatedPropertiesOnly = false;
369 // build name-value map
370 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral(""));
371
372 // THEN
373 // activeUniformNamesToValue should be empty as blockBuilder.uniforms is
374 QVERIFY(blockBuilder.activeUniformNamesToValue.isEmpty());
375}
376
377void tst_RenderViewUtils::topLevelScalarValue()
378{
379 // GIVEN
380 TestRenderer renderer;
381 QScopedPointer<ScalarShaderData> shaderData(new ScalarShaderData());
382 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
383 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
384
385 // WHEN
386 shaderData->setScalar(883.0f);
387 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
388
389 // THEN
390 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
391 QVERIFY(backendShaderData != nullptr);
392
393 // WHEN
394 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
395 blockBuilder.shaderDataManager = manager.data();
396 blockBuilder.textureManager = textureManager.data();
397 blockBuilder.updatedPropertiesOnly = false;
398 blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
399 // build name-value map
400 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral("MyBlock"));
401
402 // THEN
403 QVERIFY(blockBuilder.uniforms.count() == 1);
404 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
405
406 // WHEN
407 Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
408 const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
409
410 while (it != end) {
411 // THEN
412 QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
413 QCOMPARE(it.value(), QVariant(shaderData->scalar()));
414 ++it;
415 }
416}
417
418void tst_RenderViewUtils::topLevelTextureValueNoUniforms()
419{
420 // GIVEN
421 TestRenderer renderer;
422 QScopedPointer<TextureShaderData> shaderData(new TextureShaderData);
423 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager);
424 QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
425 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
426
427 // WHEN
428 shaderData->setTexture(texture.data());
429 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
430
431 // THEN
432 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
433 QVERIFY(backendShaderData != nullptr);
434
435 // WHEB
436 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
437 blockBuilder.shaderDataManager = manager.data();
438 blockBuilder.textureManager = textureManager.data();
439 blockBuilder.updatedPropertiesOnly = false;
440 // build name-value map
441 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral(""));
442
443 // THEN
444 // activeUniformNamesToValue should be empty as blockBuilder.uniforms is
445 QVERIFY(blockBuilder.activeUniformNamesToValue.isEmpty());
446}
447
448void tst_RenderViewUtils::topLevelTextureValue()
449{
450 // GIVEN
451 TestRenderer renderer;
452 QScopedPointer<TextureShaderData> shaderData(new TextureShaderData);
453 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager);
454 QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
455 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
456
457 // WHEN
458 initBackendTexture(frontend: texture.data(), manager: textureManager.data());
459 shaderData->setTexture(texture.data());
460 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
461
462 // THEN
463 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
464 QVERIFY(backendShaderData != nullptr);
465
466 // WHEN
467 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
468 blockBuilder.shaderDataManager = manager.data();
469 blockBuilder.textureManager = textureManager.data();
470 blockBuilder.updatedPropertiesOnly = false;
471 blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
472 // build name-value map
473 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral("MyBlock"));
474
475 // THEN
476 QVERIFY(blockBuilder.uniforms.count() == 1);
477 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
478
479 // WHEN
480 Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
481 const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
482
483 while (it != end) {
484 // THEN
485 QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
486 QCOMPARE(it.value(), QVariant::fromValue(shaderData->texture()->id()));
487 ++it;
488 }
489}
490
491void tst_RenderViewUtils::topLevelArrayValue()
492{
493 // GIVEN
494 TestRenderer renderer;
495 QScopedPointer<ArrayShaderData> shaderData(new ArrayShaderData());
496 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
497 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
498
499 // WHEN
500 QVariantList arrayValues = QVariantList() << 454 << 350 << 383 << 427 << 552;
501 shaderData->setArray(arrayValues);
502 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
503
504 // THEN
505 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
506 QVERIFY(backendShaderData != nullptr);
507
508 // WHEN
509 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
510 blockBuilder.shaderDataManager = manager.data();
511 blockBuilder.textureManager = textureManager.data();
512 blockBuilder.updatedPropertiesOnly = false;
513 blockBuilder.uniforms = shaderData->buildUniformMap(QStringLiteral("MyBlock"));
514 // build name-value map
515 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral("MyBlock"));
516
517 // THEN
518 QVERIFY(blockBuilder.uniforms.count() == 1);
519 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 1);
520
521 // WHEN
522 Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
523 const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
524
525 while (it != end) {
526 // THEN
527 QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
528 QCOMPARE(it.value(), QVariant(arrayValues));
529 ++it;
530 }
531}
532
533void tst_RenderViewUtils::nestedShaderDataValue()
534{
535 // GIVEN
536 TestRenderer renderer;
537 QScopedPointer<ArrayShaderData> arrayShaderData(new ArrayShaderData());
538 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
539 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
540
541 QScopedPointer<ScalarShaderData> shaderData1(new ScalarShaderData(arrayShaderData.data()));
542 QScopedPointer<ScalarShaderData> shaderData2(new ScalarShaderData(arrayShaderData.data()));
543 QScopedPointer<ScalarShaderData> shaderData3(new ScalarShaderData(arrayShaderData.data()));
544
545 shaderData1->setScalar(883.0f);
546 shaderData2->setScalar(1200.0f);
547 shaderData3->setScalar(1340.0f);
548 QHash<QString, QVariant> scalarValues;
549 scalarValues[QStringLiteral("MyBlock.array[0].scalar")] = shaderData1->scalar();
550 scalarValues[QStringLiteral("MyBlock.array[1].scalar")] = shaderData2->scalar();
551 scalarValues[QStringLiteral("MyBlock.array[2].scalar")] = shaderData3->scalar();
552
553
554 const Qt3DCore::QNodeId id1 = shaderData1->id();
555 const Qt3DCore::QNodeId id2 = shaderData2->id();
556 const Qt3DCore::QNodeId id3 = shaderData3->id();
557
558 // WHEN
559 const QVariantList arrayValues = QVariantList() << QVariant::fromValue(value: id1) << QVariant::fromValue(value: id2) << QVariant::fromValue(value: id3);
560 arrayShaderData->setArray(arrayValues);
561 initBackendShaderData(renderer: &renderer, frontend: arrayShaderData.data(), manager: manager.data());
562
563 // THEN
564 Qt3DRender::Render::ShaderData *backendArrayShaderData = manager->lookupResource(id: arrayShaderData->id());
565 Qt3DRender::Render::ShaderData *backendShaderData1 = manager->lookupResource(id: id1);
566 Qt3DRender::Render::ShaderData *backendShaderData2 = manager->lookupResource(id: id2);
567 Qt3DRender::Render::ShaderData *backendShaderData3 = manager->lookupResource(id: id3);
568 QVERIFY(backendArrayShaderData != nullptr);
569 QVERIFY(backendShaderData1 != nullptr);
570 QVERIFY(backendShaderData2 != nullptr);
571 QVERIFY(backendShaderData3 != nullptr);
572
573 // WHEN
574 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
575 blockBuilder.shaderDataManager = manager.data();
576 blockBuilder.textureManager = textureManager.data();
577 blockBuilder.updatedPropertiesOnly = false;
578 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0].scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
579 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[1].scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
580 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[2].scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
581 // build name-value map
582 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendArrayShaderData, QStringLiteral("MyBlock"));
583
584 // THEN
585 QVERIFY(blockBuilder.uniforms.count() == 3);
586 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 3);
587
588 // WHEN
589 auto it = blockBuilder.uniforms.cbegin();
590 const auto end = blockBuilder.uniforms.cend();
591
592 while (it != end) {
593 // THEN
594 const int nameId = Qt3DRender::Render::StringToInt::lookupId(str: it.key());
595 QVERIFY(blockBuilder.activeUniformNamesToValue.contains(nameId));
596 QCOMPARE(blockBuilder.activeUniformNamesToValue[nameId], scalarValues.value(it.key()));
597 ++it;
598 }
599}
600
601void tst_RenderViewUtils::topLevelStructValue_data()
602{
603 QTest::addColumn<StructShaderData*>(name: "shaderData");
604 QTest::addColumn<QString>(name: "blockName");
605
606 QVariantList arrayValues2 = QVariantList() << 180 << 220 << 250 << 270 << 300 << 350 << 550;
607 QVariantList arrayValues = QVariantList() << 454 << 350 << 383 << 427 << 552;
608
609 MultiLevelStructShaderData *twoLevelsNestedShaderData = new MultiLevelStructShaderData();
610 MultiLevelStructShaderData *singleLevelShaderData = new MultiLevelStructShaderData();
611 StructShaderData *shaderData = new StructShaderData();
612
613 // Don't forget to set the parent so that initBackendShaderData
614 // properly initializes nested members
615 shaderData->setParent(singleLevelShaderData);
616 shaderData->setArray(arrayValues);
617 shaderData->setScalar(1584.0f);
618
619 singleLevelShaderData->setParent(twoLevelsNestedShaderData);
620 singleLevelShaderData->setInner(shaderData);
621 singleLevelShaderData->setScalar(1200.0f);
622 singleLevelShaderData->setArray(arrayValues2);
623
624 twoLevelsNestedShaderData->setInner(singleLevelShaderData);
625 twoLevelsNestedShaderData->setArray(arrayValues + arrayValues2);
626 twoLevelsNestedShaderData->setScalar(1340.0f);
627
628 QTest::newRow(dataTag: "simple struct") << shaderData << QStringLiteral("Block");
629 QTest::newRow(dataTag: "single level inner struct") << (StructShaderData *)singleLevelShaderData << QStringLiteral("Block");
630 QTest::newRow(dataTag: "tow level inner struct") << (StructShaderData *)twoLevelsNestedShaderData << QStringLiteral("Block");
631}
632
633void tst_RenderViewUtils::topLevelStructValue()
634{
635 // GIVEN
636 TestRenderer renderer;
637 QFETCH(StructShaderData *, shaderData);
638 QFETCH(QString, blockName);
639 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
640 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
641
642 // WHEN
643 initBackendShaderData(renderer: &renderer, frontend: shaderData, manager: manager.data());
644
645 // THEN
646 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
647 QVERIFY(backendShaderData != nullptr);
648
649 // WHEN
650 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
651 blockBuilder.shaderDataManager = manager.data();
652 blockBuilder.textureManager = textureManager.data();
653 blockBuilder.updatedPropertiesOnly = false;
654 blockBuilder.uniforms = shaderData->buildUniformMap(blockName);
655 const QHash<QString, QVariant> expectedValues = shaderData->buildUniformMapValues(blockName);
656 // build name-value map
657 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, blockName);
658
659 // THEN
660 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), blockBuilder.uniforms.count());
661
662 // WHEN
663 Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator it = blockBuilder.activeUniformNamesToValue.begin();
664 const Qt3DRender::Render::OpenGL::UniformBlockValueBuilderHash::const_iterator end = blockBuilder.activeUniformNamesToValue.end();
665
666 while (it != end) {
667 // THEN
668 QVERIFY(blockBuilder.uniforms.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
669 QVERIFY(expectedValues.contains(Qt3DRender::Render::StringToInt::lookupString(it.key())));
670 QCOMPARE(it.value(), expectedValues.value(Qt3DRender::Render::StringToInt::lookupString(it.key())));
671 ++it;
672 }
673}
674
675void tst_RenderViewUtils::topLevelDynamicProperties()
676{
677 // GIVEN
678 TestRenderer renderer;
679 QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
680 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
681 QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
682 QScopedPointer<Qt3DRender::Render::TextureManager> textureManager(new Qt3DRender::Render::TextureManager());
683
684 // WHEN
685 initBackendTexture(frontend: texture.data(), manager: textureManager.data());
686 shaderData->setProperty(name: "scalar", value: 883.0f);
687 shaderData->setProperty(name: "array", value: QVariantList() << 454 << 350 << 383 << 427 << 552);
688 shaderData->setProperty(name: "texture", value: QVariant::fromValue(value: texture.data()));
689 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
690
691 // THEN
692 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
693 QVERIFY(backendShaderData != nullptr);
694
695 // WHEN
696 Qt3DRender::Render::OpenGL::UniformBlockValueBuilder blockBuilder;
697 blockBuilder.shaderDataManager = manager.data();
698 blockBuilder.textureManager = textureManager.data();
699 blockBuilder.updatedPropertiesOnly = false;
700 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.scalar"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
701 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.array[0]"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
702 blockBuilder.uniforms.insert(QStringLiteral("MyBlock.texture"), avalue: Qt3DRender::Render::OpenGL::ShaderUniform());
703 // build name-value map
704 blockBuilder.buildActiveUniformNameValueMapStructHelper(rShaderData: backendShaderData, QStringLiteral("MyBlock"));
705
706 // THEN
707 QVERIFY(blockBuilder.uniforms.count() == 3);
708 QCOMPARE(blockBuilder.activeUniformNamesToValue.count(), 3);
709
710 QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.scalar")),
711 shaderData->property("scalar"));
712 QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.array[0]")),
713 shaderData->property("array"));
714 QCOMPARE(blockBuilder.activeUniformNamesToValue.value(Qt3DRender::Render::StringToInt::lookupId("MyBlock.texture")),
715 QVariant::fromValue(texture->id()));
716}
717
718void tst_RenderViewUtils::transformedProperties()
719{
720 // GIVEN
721 QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
722 QScopedPointer<Qt3DRender::Render::ShaderDataManager> manager(new Qt3DRender::Render::ShaderDataManager());
723 TestRenderer renderer;
724
725 // WHEN
726 const Vector3D position = Vector3D(15.0f, -5.0f, 10.0f);
727 const QVector3D positionQt = convertToQVector3D(v: position);
728 Matrix4x4 worldMatrix;
729 {
730 QMatrix4x4 m;
731 m.translate(x: -3.0f, y: 2.0f, z: 7.5f);
732 worldMatrix = Matrix4x4(m);
733 }
734 Matrix4x4 viewMatrix;
735 {
736 QMatrix4x4 m;
737 m.translate(x: 9.0f, y: 6.0f, z: 12.0f);
738 viewMatrix = Matrix4x4(m);
739 }
740
741 shaderData->setProperty(name: "position0", value: positionQt);
742 shaderData->setProperty(name: "position1", value: positionQt);
743 shaderData->setProperty(name: "position2", value: positionQt);
744 shaderData->setProperty(name: "position3", value: positionQt);
745 shaderData->setProperty(name: "position1Transformed", value: Qt3DRender::Render::ShaderData::ModelToEye);
746 shaderData->setProperty(name: "position2Transformed", value: Qt3DRender::Render::ShaderData::ModelToWorld);
747 shaderData->setProperty(name: "position3Transformed", value: Qt3DRender::Render::ShaderData::ModelToWorldDirection);
748 initBackendShaderData(renderer: &renderer, frontend: shaderData.data(), manager: manager.data());
749
750 // THEN
751 Qt3DRender::Render::ShaderData *backendShaderData = manager->lookupResource(id: shaderData->id());
752 QVERIFY(backendShaderData != nullptr);
753 QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position0")), Qt3DRender::Render::ShaderData::NoTransform);
754 QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position1")), Qt3DRender::Render::ShaderData::ModelToEye);
755 QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position2")), Qt3DRender::Render::ShaderData::ModelToWorld);
756 QCOMPARE(backendShaderData->propertyTransformType(QStringLiteral("position3")), Qt3DRender::Render::ShaderData::ModelToWorldDirection);
757
758 // WHEN
759 backendShaderData->updateWorldTransform(worldMatrix);
760 const Vector3D position1Value = backendShaderData->getTransformedProperty(QStringLiteral("position1"), viewMatrix).value<Vector3D>();
761 const Vector3D position2Value = backendShaderData->getTransformedProperty(QStringLiteral("position2"), viewMatrix).value<Vector3D>();
762 const Vector3D position3Value = backendShaderData->getTransformedProperty(QStringLiteral("position3"), viewMatrix).value<Vector3D>();
763 const QVariant position0Value = backendShaderData->getTransformedProperty(QStringLiteral("position0"), viewMatrix);
764
765 // THEN
766 QCOMPARE(position0Value, positionQt);
767 QCOMPARE(position1Value, viewMatrix * worldMatrix * position);
768 QCOMPARE(position2Value, worldMatrix * position);
769 QCOMPARE(position3Value, Vector3D((worldMatrix * Vector4D(position, 0.0f))));
770}
771
772void tst_RenderViewUtils::shouldNotifyDynamicPropertyChanges()
773{
774 // GIVEN
775 TestArbiter arbiter;
776 QScopedPointer<Qt3DRender::QShaderData> shaderData(new Qt3DRender::QShaderData());
777 arbiter.setArbiterOnNode(shaderData.data());
778
779 // WHEN
780 shaderData->setProperty(name: "scalar", value: 883.0f);
781
782 // THEN
783 QCOMPARE(arbiter.events.size(), 0);
784 QCOMPARE(arbiter.dirtyNodes.size(), 1);
785 QCOMPARE(arbiter.dirtyNodes.front(), shaderData.data());
786
787 arbiter.dirtyNodes.clear();
788
789 // WHEN
790 QScopedPointer<Qt3DRender::QAbstractTexture> texture(new Qt3DRender::QTexture2D);
791 shaderData->setProperty(name: "texture", value: QVariant::fromValue(value: texture.data()));
792
793 // THEN
794 QCOMPARE(arbiter.events.size(), 0);
795 QCOMPARE(arbiter.dirtyNodes.size(), 1);
796 QCOMPARE(arbiter.dirtyNodes.front(), shaderData.data());
797}
798
799QTEST_MAIN(tst_RenderViewUtils)
800
801#include "tst_renderviewutils.moc"
802

source code of qt3d/tests/auto/render/opengl/renderviewutils/tst_renderviewutils.cpp