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> |
31 | QT_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 | |
47 | class TestFactory : public Qt3DRender::QGeometryFactory |
48 | { |
49 | public: |
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 | |
69 | private: |
70 | int m_size; |
71 | }; |
72 | |
73 | class tst_QGeometryRenderer: public QObject |
74 | { |
75 | Q_OBJECT |
76 | |
77 | private 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 | |
331 | QTEST_MAIN(tst_QGeometryRenderer) |
332 | |
333 | #include "tst_qgeometryrenderer.moc" |
334 | |