1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> |
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 | |
30 | #include <QtTest/QTest> |
31 | #include <Qt3DAnimation/qclipblendvalue.h> |
32 | #include <Qt3DAnimation/qanimationcliploader.h> |
33 | #include <Qt3DAnimation/private/qclipblendvalue_p.h> |
34 | #include <Qt3DAnimation/private/clipblendvalue_p.h> |
35 | #include "qbackendnodetester.h" |
36 | |
37 | #include <random> |
38 | #include <algorithm> |
39 | |
40 | using namespace Qt3DAnimation::Animation; |
41 | |
42 | Q_DECLARE_METATYPE(ClipBlendValue *) |
43 | Q_DECLARE_METATYPE(QVector<ClipFormat>) |
44 | |
45 | class tst_ClipBlendValue : public Qt3DCore::QBackendNodeTester |
46 | { |
47 | Q_OBJECT |
48 | public: |
49 | AnimationClip *createAnimationClipLoader(Handler *handler, |
50 | double duration) |
51 | { |
52 | auto clipId = Qt3DCore::QNodeId::createId(); |
53 | AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(id: clipId); |
54 | setPeerId(backend: clip, id: clipId); |
55 | clip->setDuration(duration); |
56 | return clip; |
57 | } |
58 | |
59 | private Q_SLOTS: |
60 | void checkInitialState() |
61 | { |
62 | // GIVEN |
63 | ClipBlendValue backendClipBlendValue; |
64 | |
65 | // THEN |
66 | QCOMPARE(backendClipBlendValue.isEnabled(), false); |
67 | QVERIFY(backendClipBlendValue.peerId().isNull()); |
68 | QCOMPARE(backendClipBlendValue.clipId(), Qt3DCore::QNodeId()); |
69 | QCOMPARE(backendClipBlendValue.blendType(), ClipBlendNode::ValueType); |
70 | } |
71 | |
72 | void checkInitializeFromPeer() |
73 | { |
74 | // GIVEN |
75 | Qt3DAnimation::QClipBlendValue clipBlendValue; |
76 | Qt3DAnimation::QAnimationClipLoader clip; |
77 | clipBlendValue.setClip(&clip); |
78 | |
79 | { |
80 | // WHEN |
81 | ClipBlendValue backendClipBlendValue; |
82 | simulateInitializationSync(frontend: &clipBlendValue, backend: &backendClipBlendValue); |
83 | |
84 | // THEN |
85 | QCOMPARE(backendClipBlendValue.isEnabled(), true); |
86 | QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); |
87 | QCOMPARE(backendClipBlendValue.clipId(), clip.id()); |
88 | } |
89 | { |
90 | // WHEN |
91 | ClipBlendValue backendClipBlendValue; |
92 | clipBlendValue.setEnabled(false); |
93 | simulateInitializationSync(frontend: &clipBlendValue, backend: &backendClipBlendValue); |
94 | |
95 | // THEN |
96 | QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); |
97 | QCOMPARE(backendClipBlendValue.isEnabled(), false); |
98 | } |
99 | } |
100 | |
101 | void checkSceneChangeEvents() |
102 | { |
103 | // GIVEN |
104 | Qt3DAnimation::QClipBlendValue clipBlendValue; |
105 | ClipBlendValue backendClipBlendValue; |
106 | simulateInitializationSync(frontend: &clipBlendValue, backend: &backendClipBlendValue); |
107 | { |
108 | // WHEN |
109 | const bool newValue = false; |
110 | clipBlendValue.setEnabled(newValue); |
111 | backendClipBlendValue.syncFromFrontEnd(frontEnd: &clipBlendValue, firstTime: false); |
112 | |
113 | // THEN |
114 | QCOMPARE(backendClipBlendValue.isEnabled(), newValue); |
115 | } |
116 | { |
117 | // WHEN |
118 | Qt3DAnimation::QAnimationClipLoader newValue; |
119 | clipBlendValue.setClip(&newValue); |
120 | backendClipBlendValue.syncFromFrontEnd(frontEnd: &clipBlendValue, firstTime: false); |
121 | |
122 | // THEN |
123 | QCOMPARE(backendClipBlendValue.clipId(), newValue.id()); |
124 | } |
125 | } |
126 | |
127 | void checkDependencyIds() |
128 | { |
129 | // GIVEN |
130 | ClipBlendValue clipNode; |
131 | auto clipId = Qt3DCore::QNodeId::createId(); |
132 | |
133 | // WHEN |
134 | clipNode.setClipId(clipId); |
135 | QVector<Qt3DCore::QNodeId> actualIds = clipNode.currentDependencyIds(); |
136 | |
137 | // THEN |
138 | QCOMPARE(actualIds.size(), 0); |
139 | |
140 | // WHEN |
141 | auto anotherClipId = Qt3DCore::QNodeId::createId(); |
142 | clipNode.setClipId(anotherClipId); |
143 | actualIds = clipNode.currentDependencyIds(); |
144 | |
145 | // THEN |
146 | QCOMPARE(actualIds.size(), 0); |
147 | } |
148 | |
149 | void checkDuration() |
150 | { |
151 | // GIVEN |
152 | auto handler = new Handler(); |
153 | const double expectedDuration = 123.5; |
154 | auto clip = createAnimationClipLoader(handler, duration: expectedDuration); |
155 | ClipBlendValue clipNode; |
156 | clipNode.setHandler(handler); |
157 | clipNode.setClipBlendNodeManager(handler->clipBlendNodeManager()); |
158 | clipNode.setClipId(clip->peerId()); |
159 | |
160 | // WHEN |
161 | double actualDuration = clipNode.duration(); |
162 | |
163 | // THEN |
164 | QCOMPARE(actualDuration, expectedDuration); |
165 | } |
166 | |
167 | void checkFormatIndices_data() |
168 | { |
169 | QTest::addColumn<ClipBlendValue *>(name: "blendNode" ); |
170 | QTest::addColumn<QVector<int>>(name: "indexes" ); |
171 | QTest::addColumn<QVector<Qt3DCore::QNodeId>>(name: "animatorIds" ); |
172 | QTest::addColumn<QVector<ClipFormat>>(name: "expectedClipFormat" ); |
173 | |
174 | // Single entry |
175 | { |
176 | auto blendNode = new ClipBlendValue; |
177 | QVector<Qt3DCore::QNodeId> animatorIds; |
178 | QVector<ClipFormat> expectedClipFormat; |
179 | |
180 | const auto animatorId = Qt3DCore::QNodeId::createId(); |
181 | animatorIds.push_back(t: animatorId); |
182 | |
183 | ClipFormat clipFormat; |
184 | clipFormat.sourceClipIndices = { 0, 1, 2 }; |
185 | expectedClipFormat.push_back(t: clipFormat); |
186 | |
187 | // Set data and indexes |
188 | blendNode->setClipFormat(animatorId, formatIndices: clipFormat); |
189 | QVector<int> indexes = QVector<int>() << 0; |
190 | |
191 | QTest::newRow(dataTag: "single entry" ) |
192 | << blendNode << indexes << animatorIds << expectedClipFormat; |
193 | } |
194 | |
195 | // Multiple entries, ordered |
196 | { |
197 | auto blendNode = new ClipBlendValue; |
198 | QVector<Qt3DCore::QNodeId> animatorIds; |
199 | QVector<ClipFormat> expectedClipFormat; |
200 | |
201 | const int animatorCount = 10; |
202 | for (int j = 0; j < animatorCount; ++j) { |
203 | auto animatorId = Qt3DCore::QNodeId::createId(); |
204 | animatorIds.push_back(t: animatorId); |
205 | |
206 | ClipFormat clipFormat; |
207 | for (int i = 0; i < j + 5; ++i) |
208 | clipFormat.sourceClipIndices.push_back(t: i + j); |
209 | expectedClipFormat.push_back(t: clipFormat); |
210 | |
211 | blendNode->setClipFormat(animatorId, formatIndices: clipFormat); |
212 | } |
213 | |
214 | QVector<int> indexes(animatorCount); |
215 | std::iota(first: indexes.begin(), last: indexes.end(), value: 0); |
216 | |
217 | QTest::newRow(dataTag: "multiple entries, ordered" ) |
218 | << blendNode << indexes << animatorIds << expectedClipFormat; |
219 | } |
220 | |
221 | // Multiple entries, unordered |
222 | { |
223 | auto blendNode = new ClipBlendValue; |
224 | QVector<Qt3DCore::QNodeId> animatorIds; |
225 | QVector<ClipFormat> expectedClipFormat; |
226 | |
227 | const int animatorCount = 10; |
228 | for (int j = 0; j < animatorCount; ++j) { |
229 | auto animatorId = Qt3DCore::QNodeId::createId(); |
230 | animatorIds.push_back(t: animatorId); |
231 | |
232 | ClipFormat clipFormat; |
233 | for (int i = 0; i < j + 5; ++i) |
234 | clipFormat.sourceClipIndices.push_back(t: i + j); |
235 | expectedClipFormat.push_back(t: clipFormat); |
236 | |
237 | blendNode->setClipFormat(animatorId, formatIndices: clipFormat); |
238 | } |
239 | |
240 | // Shuffle the animatorIds to randomise the lookups |
241 | QVector<int> indexes(animatorCount); |
242 | std::iota(first: indexes.begin(), last: indexes.end(), value: 0); |
243 | std::random_device rd; |
244 | std::mt19937 generator(rd()); |
245 | std::shuffle(first: indexes.begin(), last: indexes.end(), g&: generator); |
246 | |
247 | QTest::newRow(dataTag: "multiple entries, unordered" ) |
248 | << blendNode << indexes << animatorIds << expectedClipFormat; |
249 | } |
250 | } |
251 | |
252 | void checkFormatIndices() |
253 | { |
254 | // GIVEN |
255 | QFETCH(ClipBlendValue *, blendNode); |
256 | QFETCH(QVector<int>, indexes); |
257 | QFETCH(QVector<Qt3DCore::QNodeId>, animatorIds); |
258 | QFETCH(QVector<ClipFormat>, expectedClipFormat); |
259 | |
260 | for (int i = 0; i < indexes.size(); ++i) { |
261 | // WHEN |
262 | const int index = indexes[i]; |
263 | const ClipFormat actualClipFormat = blendNode->clipFormat(animatorId: animatorIds[index]); |
264 | |
265 | // THEN |
266 | QCOMPARE(actualClipFormat.sourceClipIndices.size(), expectedClipFormat[index].sourceClipIndices.size()); |
267 | for (int j = 0; j < actualClipFormat.sourceClipIndices.size(); ++j) |
268 | QCOMPARE(actualClipFormat.sourceClipIndices[j], expectedClipFormat[index].sourceClipIndices[j]); |
269 | } |
270 | |
271 | delete blendNode; |
272 | } |
273 | }; |
274 | |
275 | QTEST_MAIN(tst_ClipBlendValue) |
276 | |
277 | #include "tst_clipblendvalue.moc" |
278 | |