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// TODO Remove in Qt6
30#include <QtCore/qcompilerdetection.h>
31QT_WARNING_DISABLE_DEPRECATED
32
33#include <QtTest/QTest>
34#include <Qt3DCore/private/qnode_p.h>
35#include <Qt3DCore/private/qscene_p.h>
36#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
37
38#include <Qt3DRender/qgeometryrenderer.h>
39#include <Qt3DRender/qgeometryfactory.h>
40#include <Qt3DRender/qgeometry.h>
41#include <Qt3DRender/qattribute.h>
42#include <Qt3DRender/qbuffer.h>
43#include <Qt3DRender/private/qgeometryrenderer_p.h>
44
45#include "testpostmanarbiter.h"
46
47class TestFactory : public Qt3DRender::QGeometryFactory
48{
49public:
50 explicit TestFactory(int size)
51 : m_size(size)
52 {}
53
54 Qt3DRender::QGeometry *operator ()() final
55 {
56 return nullptr;
57 }
58
59 bool equals(const Qt3DRender::QGeometryFactory &other) const final
60 {
61 const TestFactory *otherFactory = Qt3DRender::functor_cast<TestFactory>(other: &other);
62 if (otherFactory != nullptr)
63 return otherFactory->m_size == m_size;
64 return false;
65 }
66
67 QT3D_FUNCTOR(TestFactory)
68
69private:
70 int m_size;
71};
72
73class tst_QGeometryRenderer: public QObject
74{
75 Q_OBJECT
76
77private Q_SLOTS:
78
79 void checkCloning_data()
80 {
81 QTest::addColumn<Qt3DRender::QGeometryRenderer *>(name: "geometryRenderer");
82
83 Qt3DRender::QGeometryRenderer *defaultConstructed = new Qt3DRender::QGeometryRenderer();
84 QTest::newRow(dataTag: "defaultConstructed") << defaultConstructed ;
85
86 Qt3DRender::QGeometryRenderer *geometry1 = new Qt3DRender::QGeometryRenderer();
87 geometry1->setGeometry(new Qt3DRender::QGeometry());
88 geometry1->setInstanceCount(1);
89 geometry1->setIndexOffset(0);
90 geometry1->setFirstInstance(55);
91 geometry1->setIndexBufferByteOffset(48);
92 geometry1->setRestartIndexValue(-1);
93 geometry1->setPrimitiveRestartEnabled(false);
94 geometry1->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
95 geometry1->setVertexCount(15);
96 geometry1->setVerticesPerPatch(2);
97 geometry1->setGeometryFactory(Qt3DRender::QGeometryFactoryPtr(new TestFactory(383)));
98 QTest::newRow(dataTag: "triangle") << geometry1;
99
100 Qt3DRender::QGeometryRenderer *geometry2 = new Qt3DRender::QGeometryRenderer();
101 geometry2->setGeometry(new Qt3DRender::QGeometry());
102 geometry2->setInstanceCount(200);
103 geometry2->setIndexOffset(58);
104 geometry2->setFirstInstance(10);
105 geometry2->setIndexBufferByteOffset(96);
106 geometry2->setRestartIndexValue(65535);
107 geometry2->setVertexCount(2056);
108 geometry2->setPrimitiveRestartEnabled(true);
109 geometry2->setVerticesPerPatch(3);
110 geometry2->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
111 geometry2->setGeometryFactory(Qt3DRender::QGeometryFactoryPtr(new TestFactory(305)));
112 QTest::newRow(dataTag: "lines with restart") << geometry2;
113 }
114
115 void checkCloning()
116 {
117 // GIVEN
118 QFETCH(Qt3DRender::QGeometryRenderer *, geometryRenderer);
119
120 // WHEN
121 Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(geometryRenderer);
122 QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
123
124 // THEN
125 QCOMPARE(creationChanges.size(), 1 + (geometryRenderer->geometry() ? 1 : 0));
126
127 const Qt3DCore::QNodeCreatedChangePtr<Qt3DRender::QGeometryRendererData> creationChangeData =
128 qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QGeometryRendererData>>(src: creationChanges.first());
129 const Qt3DRender::QGeometryRendererData &cloneData = creationChangeData->data;
130
131 QCOMPARE(geometryRenderer->id(), creationChangeData->subjectId());
132 QCOMPARE(geometryRenderer->isEnabled(), creationChangeData->isNodeEnabled());
133 QCOMPARE(geometryRenderer->metaObject(), creationChangeData->metaObject());
134
135 QCOMPARE(cloneData.instanceCount, geometryRenderer->instanceCount());
136 QCOMPARE(cloneData.vertexCount, geometryRenderer->vertexCount());
137 QCOMPARE(cloneData.indexOffset, geometryRenderer->indexOffset());
138 QCOMPARE(cloneData.firstInstance, geometryRenderer->firstInstance());
139 QCOMPARE(cloneData.indexBufferByteOffset, geometryRenderer->indexBufferByteOffset());
140 QCOMPARE(cloneData.restartIndexValue, geometryRenderer->restartIndexValue());
141 QCOMPARE(cloneData.primitiveRestart, geometryRenderer->primitiveRestartEnabled());
142 QCOMPARE(cloneData.primitiveType, geometryRenderer->primitiveType());
143 QCOMPARE(cloneData.verticesPerPatch, geometryRenderer->verticesPerPatch());
144
145 if (geometryRenderer->geometry() != nullptr)
146 QCOMPARE(cloneData.geometryId, geometryRenderer->geometry()->id());
147
148 QCOMPARE(cloneData.geometryFactory, geometryRenderer->geometryFactory());
149 if (geometryRenderer->geometryFactory())
150 QVERIFY(*cloneData.geometryFactory == *geometryRenderer->geometryFactory());
151 }
152
153 void checkPropertyUpdates()
154 {
155 // GIVEN
156 TestArbiter arbiter;
157 QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
158 arbiter.setArbiterOnNode(geometryRenderer.data());
159
160 // WHEN
161 geometryRenderer->setInstanceCount(256);
162 QCoreApplication::processEvents();
163
164 // THEN
165 QCOMPARE(arbiter.events.size(), 0);
166 QCOMPARE(arbiter.dirtyNodes.size(), 1);
167 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
168
169 arbiter.dirtyNodes.clear();
170
171 // WHEN
172 geometryRenderer->setVertexCount(1340);
173 QCoreApplication::processEvents();
174
175 // THEN
176 QCOMPARE(arbiter.events.size(), 0);
177 QCOMPARE(arbiter.dirtyNodes.size(), 1);
178 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
179
180 arbiter.dirtyNodes.clear();
181
182 // WHEN
183 geometryRenderer->setIndexOffset(883);
184 QCoreApplication::processEvents();
185
186 // THEN
187 QCOMPARE(arbiter.events.size(), 0);
188 QCOMPARE(arbiter.dirtyNodes.size(), 1);
189 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
190
191 arbiter.dirtyNodes.clear();
192
193 // WHEN
194 geometryRenderer->setFirstInstance(1200);
195 QCoreApplication::processEvents();
196
197 // THEN
198 QCOMPARE(arbiter.events.size(), 0);
199 QCOMPARE(arbiter.dirtyNodes.size(), 1);
200 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
201
202 arbiter.dirtyNodes.clear();
203
204 // WHEN
205 geometryRenderer->setIndexBufferByteOffset(91);
206 QCoreApplication::processEvents();
207
208 // THEN
209 QCOMPARE(arbiter.events.size(), 0);
210 QCOMPARE(arbiter.dirtyNodes.size(), 1);
211 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
212
213 arbiter.dirtyNodes.clear();
214
215 // WHEN
216 geometryRenderer->setRestartIndexValue(65535);
217 QCoreApplication::processEvents();
218
219 // THEN
220 QCOMPARE(arbiter.events.size(), 0);
221 QCOMPARE(arbiter.dirtyNodes.size(), 1);
222 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
223
224 arbiter.dirtyNodes.clear();
225
226 // WHEN
227 geometryRenderer->setVerticesPerPatch(2);
228 QCoreApplication::processEvents();
229
230 // THEN
231 QCOMPARE(arbiter.events.size(), 0);
232 QCOMPARE(arbiter.dirtyNodes.size(), 1);
233 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
234
235 arbiter.dirtyNodes.clear();
236
237 // WHEN
238 geometryRenderer->setPrimitiveRestartEnabled(true);
239 QCoreApplication::processEvents();
240
241 // THEN
242 QCOMPARE(arbiter.events.size(), 0);
243 QCOMPARE(arbiter.dirtyNodes.size(), 1);
244 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
245
246 arbiter.dirtyNodes.clear();
247
248 // WHEN
249 geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches);
250 QCoreApplication::processEvents();
251
252 // THEN
253 QCOMPARE(arbiter.events.size(), 0);
254 QCOMPARE(arbiter.dirtyNodes.size(), 1);
255 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
256
257 arbiter.dirtyNodes.clear();
258
259 // WHEN
260 Qt3DRender::QGeometryFactoryPtr factory(new TestFactory(555));
261 geometryRenderer->setGeometryFactory(factory);
262 QCoreApplication::processEvents();
263
264 // THEN
265 QCOMPARE(arbiter.events.size(), 0);
266 QCOMPARE(arbiter.dirtyNodes.size(), 1);
267 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
268
269 arbiter.dirtyNodes.clear();
270
271 // WHEN
272 Qt3DRender::QGeometry geom;
273 geometryRenderer->setGeometry(&geom);
274 QCoreApplication::processEvents();
275
276 // THEN
277 QCOMPARE(arbiter.events.size(), 0);
278 QCOMPARE(arbiter.dirtyNodes.size(), 1);
279 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
280
281 arbiter.dirtyNodes.clear();
282
283 // WHEN
284 Qt3DRender::QGeometry geom2;
285 geometryRenderer->setGeometry(&geom2);
286 QCoreApplication::processEvents();
287
288 // THEN
289 QCOMPARE(arbiter.events.size(), 0);
290 QCOMPARE(arbiter.dirtyNodes.size(), 1);
291 QCOMPARE(arbiter.dirtyNodes.front(), geometryRenderer.data());
292
293 arbiter.dirtyNodes.clear();
294 }
295
296 void checkGeometryBookkeeping()
297 {
298 // GIVEN
299 QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer);
300 {
301 // WHEN
302 Qt3DRender::QGeometry geometry;
303 geometryRenderer->setGeometry(&geometry);
304
305 // THEN
306 QCOMPARE(geometry.parent(), geometryRenderer.data());
307 QCOMPARE(geometryRenderer->geometry(), &geometry);
308 }
309 // THEN (Should not crash and parameter be unset)
310 QVERIFY(geometryRenderer->geometry() == nullptr);
311
312 {
313 // WHEN
314 Qt3DRender::QGeometryRenderer someOtherGeometryRenderer;
315 QScopedPointer<Qt3DRender::QGeometry> geometry(new Qt3DRender::QGeometry(&someOtherGeometryRenderer));
316 geometryRenderer->setGeometry(geometry.data());
317
318 // THEN
319 QCOMPARE(geometry->parent(), &someOtherGeometryRenderer);
320 QCOMPARE(geometryRenderer->geometry(), geometry.data());
321
322 // WHEN
323 geometryRenderer.reset();
324 geometry.reset();
325
326 // THEN Should not crash when the geometry is destroyed (tests for failed removal of destruction helper)
327 }
328 }
329};
330
331QTEST_MAIN(tst_QGeometryRenderer)
332
333#include "tst_qgeometryrenderer.moc"
334

source code of qt3d/tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp