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/qpropertyupdatedchange.h>
35#include <Qt3DCore/private/qnode_p.h>
36#include <Qt3DCore/private/qscene_p.h>
37#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
38
39#include <Qt3DRender/qgeometry.h>
40#include <Qt3DRender/private/qgeometry_p.h>
41#include <Qt3DRender/qattribute.h>
42#include <Qt3DRender/qbuffer.h>
43
44#include <QSignalSpy>
45
46#include "testpostmanarbiter.h"
47
48class FakeGeometry : public Qt3DRender::QGeometry
49{
50 Q_OBJECT
51
52public:
53 void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override
54 {
55 Qt3DRender::QGeometry::sceneChangeEvent(change);
56 }
57};
58
59class tst_QGeometry: public QObject
60{
61 Q_OBJECT
62
63private Q_SLOTS:
64
65 void checkCloning_data()
66 {
67 QTest::addColumn<Qt3DRender::QGeometry *>(name: "geometry");
68 QTest::addColumn<int>(name: "attributeCount");
69
70 Qt3DRender::QGeometry *defaultConstructed = new Qt3DRender::QGeometry();
71 QTest::newRow(dataTag: "defaultConstructed") << defaultConstructed << 0;
72
73 Qt3DRender::QGeometry *geometry1 = new Qt3DRender::QGeometry();
74 Qt3DRender::QAttribute *attribute = new Qt3DRender::QAttribute(nullptr, QStringLiteral("Attr1"), Qt3DRender::QAttribute::Float, 4, 454);
75 geometry1->addAttribute(attribute);
76 geometry1->addAttribute(attribute: new Qt3DRender::QAttribute(nullptr, QStringLiteral("Attr2"), Qt3DRender::QAttribute::Float, 4, 555));
77 geometry1->setBoundingVolumePositionAttribute(attribute);
78 QTest::newRow(dataTag: "2 attributes") << geometry1 << 2;
79
80
81 Qt3DRender::QGeometry *geometry2 = new Qt3DRender::QGeometry();
82 attribute = new Qt3DRender::QAttribute(nullptr, QStringLiteral("Attr2"), Qt3DRender::QAttribute::Float, 4, 383);
83 geometry2->addAttribute(attribute: new Qt3DRender::QAttribute(nullptr, QStringLiteral("Attr1"), Qt3DRender::QAttribute::Float, 3, 427));
84 geometry2->addAttribute(attribute);
85 geometry2->addAttribute(attribute: new Qt3DRender::QAttribute(nullptr, QStringLiteral("Attr3"), Qt3DRender::QAttribute::Float, 2, 327));
86 geometry2->removeAttribute(attribute);
87 QTest::newRow(dataTag: "3 - 1 attributes") << geometry2 << 2;
88 }
89
90 void checkCloning()
91 {
92 // GIVEN
93 QFETCH(Qt3DRender::QGeometry *, geometry);
94 QFETCH(int, attributeCount);
95
96 // WHEN
97 Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(geometry);
98 QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
99
100 // THEN
101 QCOMPARE(creationChanges.size(), 1 + geometry->childNodes().size());
102
103 const Qt3DCore::QNodeCreatedChangePtr<Qt3DRender::QGeometryData> creationChangeData =
104 qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QGeometryData>>(src: creationChanges.first());
105 const Qt3DRender::QGeometryData &cloneData = creationChangeData->data;
106
107 QCOMPARE(geometry->id(), creationChangeData->subjectId());
108 QCOMPARE(geometry->isEnabled(), creationChangeData->isNodeEnabled());
109 QCOMPARE(geometry->metaObject(), creationChangeData->metaObject());
110
111 QCOMPARE(attributeCount, geometry->attributes().count());
112 QCOMPARE(attributeCount, cloneData.attributeIds.count());
113 if (geometry->boundingVolumePositionAttribute())
114 QCOMPARE(geometry->boundingVolumePositionAttribute()->id(), cloneData.boundingVolumePositionAttributeId);
115
116 for (int i = 0; i < attributeCount; ++i) {
117 Qt3DRender::QAttribute *originalAttribute = static_cast<Qt3DRender::QAttribute *>(geometry->attributes()[i]);
118 QCOMPARE(originalAttribute->id(), cloneData.attributeIds.at(i));
119 }
120 }
121
122 void checkPropertyUpdates()
123 {
124 // GIVEN
125 TestArbiter arbiter;
126 QScopedPointer<Qt3DRender::QGeometry> geometry(new Qt3DRender::QGeometry());
127 arbiter.setArbiterOnNode(geometry.data());
128
129 // WHEN
130 Qt3DRender::QAttribute attr;
131 geometry->addAttribute(attribute: &attr);
132 QCoreApplication::processEvents();
133
134 // THEN
135 QCOMPARE(arbiter.events.size(), 0);
136 QCOMPARE(arbiter.dirtyNodes.size(), 1);
137 QCOMPARE(arbiter.dirtyNodes.front(), geometry.data());
138
139 arbiter.dirtyNodes.clear();
140
141 // WHEN
142 geometry->addAttribute(attribute: &attr);
143 QCoreApplication::processEvents();
144
145 // THEN
146 QCOMPARE(arbiter.events.size(), 0);
147 QCOMPARE(arbiter.dirtyNodes.size(), 0);
148
149 // WHEN
150 geometry->removeAttribute(attribute: &attr);
151 QCoreApplication::processEvents();
152
153 // THEN
154 QCOMPARE(arbiter.events.size(), 0);
155 QCOMPARE(arbiter.dirtyNodes.size(), 1);
156 QCOMPARE(arbiter.dirtyNodes.front(), geometry.data());
157
158 arbiter.events.clear();
159 }
160
161 void checkAttributeBookkeeping()
162 {
163 // GIVEN
164 QScopedPointer<Qt3DRender::QGeometry> geometry(new Qt3DRender::QGeometry);
165 {
166 // WHEN
167 Qt3DRender::QAttribute attribute;
168 geometry->addAttribute(attribute: &attribute);
169
170 // THEN
171 QCOMPARE(attribute.parent(), geometry.data());
172 QCOMPARE(geometry->attributes().size(), 1);
173 }
174 // THEN (Should not crash and parameter be unset)
175 QVERIFY(geometry->attributes().isEmpty());
176
177 {
178 // WHEN
179 Qt3DRender::QGeometry someOtherGeometry;
180 QScopedPointer<Qt3DRender::QAttribute> attribute(new Qt3DRender::QAttribute(&someOtherGeometry));
181 geometry->addAttribute(attribute: attribute.data());
182
183 // THEN
184 QCOMPARE(attribute->parent(), &someOtherGeometry);
185 QCOMPARE(geometry->attributes().size(), 1);
186
187 // WHEN
188 geometry.reset();
189 attribute.reset();
190
191 // THEN Should not crash when the attribute is destroyed (tests for failed removal of destruction helper)
192 }
193 }
194
195 void checkExtentUpdates()
196 {
197 // GIVEN
198 TestArbiter arbiter;
199 QScopedPointer<FakeGeometry> geometry(new FakeGeometry());
200 arbiter.setArbiterOnNode(geometry.data());
201 QSignalSpy spyMinExtent(geometry.data(), SIGNAL(minExtentChanged(QVector3D)));
202 QSignalSpy spyMaxExtent(geometry.data(), SIGNAL(maxExtentChanged(QVector3D)));
203
204 // THEN
205 QVERIFY(spyMinExtent.isValid());
206 QVERIFY(spyMaxExtent.isValid());
207 QCOMPARE(geometry->minExtent(), QVector3D());
208 QCOMPARE(geometry->maxExtent(), QVector3D());
209
210 // WHEN
211 Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
212 valueChange->setPropertyName("extent");
213 valueChange->setValue(QVariant::fromValue(value: QPair<QVector3D, QVector3D>(QVector3D(10.0f, 10.f, 10.0f),
214 QVector3D())));
215 geometry->sceneChangeEvent(change: valueChange);
216
217 // THEN
218 QCOMPARE(spyMinExtent.count(), 1);
219 QCOMPARE(spyMaxExtent.count(), 0);
220 QCOMPARE(geometry->minExtent(), QVector3D(10.0f, 10.0f, 10.0f));
221
222 spyMinExtent.clear();
223
224 // WHEN
225 valueChange->setPropertyName("extent");
226 valueChange->setValue(QVariant::fromValue(value: QPair<QVector3D, QVector3D>(QVector3D(10.0f, 10.f, 10.0f),
227 QVector3D(11.0f, 11.f, 11.0f))));
228 geometry->sceneChangeEvent(change: valueChange);
229
230 // THEN
231 QCOMPARE(spyMinExtent.count(), 0);
232 QCOMPARE(spyMaxExtent.count(), 1);
233 QCOMPARE(geometry->maxExtent(), QVector3D(11.0f, 11.0f, 11.0f));
234
235 spyMaxExtent.clear();
236 }
237};
238
239QTEST_MAIN(tst_QGeometry)
240
241#include "tst_qgeometry.moc"
242

source code of qt3d/tests/auto/render/qgeometry/tst_qgeometry.cpp