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/qadditiveclipblend.h>
32#include <Qt3DAnimation/qanimationcliploader.h>
33#include <Qt3DAnimation/private/qadditiveclipblend_p.h>
34#include <Qt3DAnimation/private/additiveclipblend_p.h>
35#include "qbackendnodetester.h"
36
37using namespace Qt3DAnimation::Animation;
38
39Q_DECLARE_METATYPE(Handler *)
40Q_DECLARE_METATYPE(AdditiveClipBlend *)
41
42namespace {
43
44class TestClipBlendNode : public ClipBlendNode
45{
46public:
47 TestClipBlendNode(double duration)
48 : ClipBlendNode(ClipBlendNode::LerpBlendType)
49 , m_duration(duration)
50 {}
51
52 inline QVector<Qt3DCore::QNodeId> allDependencyIds() const override
53 {
54 return currentDependencyIds();
55 }
56
57 QVector<Qt3DCore::QNodeId> currentDependencyIds() const final
58 {
59 return QVector<Qt3DCore::QNodeId>();
60 }
61
62 using ClipBlendNode::setClipResults;
63
64 double duration() const final { return m_duration; }
65
66protected:
67 ClipResults doBlend(const QVector<ClipResults> &) const final { return ClipResults(); }
68
69private:
70 double m_duration;
71};
72
73} // anonymous
74
75class tst_AdditiveClipBlend : public Qt3DCore::QBackendNodeTester
76{
77 Q_OBJECT
78public:
79 TestClipBlendNode *createTestBlendNode(Handler *handler,
80 double duration)
81 {
82 auto id = Qt3DCore::QNodeId::createId();
83 TestClipBlendNode *node = new TestClipBlendNode(duration);
84 setPeerId(backend: node, id);
85 node->setHandler(handler);
86 node->setClipBlendNodeManager(handler->clipBlendNodeManager());
87 handler->clipBlendNodeManager()->appendNode(id, node);
88 return node;
89 }
90
91 AdditiveClipBlend *createAdditiveClipBlendNode(Handler *handler, const float &blendFactor)
92 {
93 auto id = Qt3DCore::QNodeId::createId();
94 AdditiveClipBlend *node = new AdditiveClipBlend();
95 node->setAdditiveFactor(blendFactor);
96 setPeerId(backend: node, id);
97 node->setHandler(handler);
98 node->setClipBlendNodeManager(handler->clipBlendNodeManager());
99 handler->clipBlendNodeManager()->appendNode(id, node);
100 return node;
101 }
102
103 BlendedClipAnimator *createBlendedClipAnimator(Handler *handler,
104 qint64 globalStartTimeNS,
105 int loops)
106 {
107 auto animatorId = Qt3DCore::QNodeId::createId();
108 BlendedClipAnimator *animator = handler->blendedClipAnimatorManager()->getOrCreateResource(id: animatorId);
109 setPeerId(backend: animator, id: animatorId);
110 animator->setStartTime(globalStartTimeNS);
111 animator->setLoops(loops);
112 return animator;
113 }
114
115private Q_SLOTS:
116
117 void checkInitialState()
118 {
119 // GIVEN
120 AdditiveClipBlend backendAdditiveBlend;
121
122 // THEN
123 QCOMPARE(backendAdditiveBlend.isEnabled(), false);
124 QVERIFY(backendAdditiveBlend.peerId().isNull());
125 QCOMPARE(backendAdditiveBlend.baseClipId(), Qt3DCore::QNodeId());
126 QCOMPARE(backendAdditiveBlend.additiveClipId(), Qt3DCore::QNodeId());
127 QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.0f);
128 QCOMPARE(backendAdditiveBlend.blendType(), ClipBlendNode::AdditiveBlendType);
129 }
130
131 void checkInitializeFromPeer()
132 {
133 // GIVEN
134 Qt3DAnimation::QAdditiveClipBlend additiveBlend;
135 Qt3DAnimation::QAdditiveClipBlend baseClip;
136 Qt3DAnimation::QAdditiveClipBlend additiveClip;
137 Qt3DAnimation::QAnimationClipLoader clip;
138 additiveBlend.setBaseClip(&baseClip);
139 additiveBlend.setAdditiveClip(&additiveClip);
140 additiveBlend.setAdditiveFactor(0.8f);
141
142 {
143 // WHEN
144 AdditiveClipBlend backendAdditiveBlend;
145 simulateInitializationSync(frontend: &additiveBlend, backend: &backendAdditiveBlend);
146
147 // THEN
148 QCOMPARE(backendAdditiveBlend.isEnabled(), true);
149 QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id());
150 QCOMPARE(backendAdditiveBlend.baseClipId(), baseClip.id());
151 QCOMPARE(backendAdditiveBlend.additiveClipId(), additiveClip.id());
152 QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.8f);
153 }
154 {
155 // WHEN
156 AdditiveClipBlend backendAdditiveBlend;
157 additiveBlend.setEnabled(false);
158 simulateInitializationSync(frontend: &additiveBlend, backend: &backendAdditiveBlend);
159
160 // THEN
161 QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id());
162 QCOMPARE(backendAdditiveBlend.isEnabled(), false);
163 }
164 }
165
166 void checkSceneChangeEvents()
167 {
168 // GIVEN
169 Qt3DAnimation::QAdditiveClipBlend additiveBlend;
170 AdditiveClipBlend backendAdditiveBlend;
171 simulateInitializationSync(frontend: &additiveBlend, backend: &backendAdditiveBlend);
172 {
173 // WHEN
174 const bool newValue = false;
175 additiveBlend.setEnabled(newValue);
176 backendAdditiveBlend.syncFromFrontEnd(frontEnd: &additiveBlend, firstTime: false);
177
178 // THEN
179 QCOMPARE(backendAdditiveBlend.isEnabled(), newValue);
180 }
181 {
182 // WHEN
183 const float newValue = 0.883f;
184 additiveBlend.setAdditiveFactor(newValue);
185 backendAdditiveBlend.syncFromFrontEnd(frontEnd: &additiveBlend, firstTime: false);
186
187 // THEN
188 QCOMPARE(backendAdditiveBlend.additiveFactor(), newValue);
189 }
190 {
191 // WHEN
192 Qt3DAnimation::QAdditiveClipBlend newValue;
193 additiveBlend.setBaseClip(&newValue);
194 backendAdditiveBlend.syncFromFrontEnd(frontEnd: &additiveBlend, firstTime: false);
195
196 // THEN
197 QCOMPARE(backendAdditiveBlend.baseClipId(), newValue.id());
198 }
199 {
200 // WHEN
201 Qt3DAnimation::QAdditiveClipBlend newValue;
202 additiveBlend.setAdditiveClip(&newValue);
203 backendAdditiveBlend.syncFromFrontEnd(frontEnd: &additiveBlend, firstTime: false);
204
205 // THEN
206 QCOMPARE(backendAdditiveBlend.additiveClipId(), newValue.id());
207 }
208 }
209
210 void checkDependencyIds()
211 {
212 // GIVEN
213 AdditiveClipBlend addBlend;
214 auto baseClipId = Qt3DCore::QNodeId::createId();
215 auto additiveClipId = Qt3DCore::QNodeId::createId();
216
217 // WHEN
218 addBlend.setBaseClipId(baseClipId);
219 addBlend.setAdditiveClipId(additiveClipId);
220 QVector<Qt3DCore::QNodeId> actualIds = addBlend.currentDependencyIds();
221
222 // THEN
223 QCOMPARE(actualIds.size(), 2);
224 QCOMPARE(actualIds[0], baseClipId);
225 QCOMPARE(actualIds[1], additiveClipId);
226
227 // WHEN
228 auto anotherAdditiveClipId = Qt3DCore::QNodeId::createId();
229 addBlend.setAdditiveClipId(anotherAdditiveClipId);
230 actualIds = addBlend.currentDependencyIds();
231
232 // THEN
233 QCOMPARE(actualIds.size(), 2);
234 QCOMPARE(actualIds[0], baseClipId);
235 QCOMPARE(actualIds[1], anotherAdditiveClipId);
236 }
237
238 void checkDuration()
239 {
240 // GIVEN
241 auto handler = new Handler();
242 const double expectedDuration = 123.5;
243 const double baseNodeDuration = expectedDuration;
244 const double additiveNodeDuration = 5.0;
245
246 auto baseNode = createTestBlendNode(handler, duration: baseNodeDuration);
247 auto additiveNode = createTestBlendNode(handler, duration: additiveNodeDuration);
248
249 AdditiveClipBlend blendNode;
250 blendNode.setHandler(handler);
251 blendNode.setClipBlendNodeManager(handler->clipBlendNodeManager());
252 blendNode.setBaseClipId(baseNode->peerId());
253 blendNode.setAdditiveClipId(additiveNode->peerId());
254
255 // WHEN
256 double actualDuration = blendNode.duration();
257
258 // THEN
259 QCOMPARE(actualDuration, expectedDuration);
260 }
261
262 void checkDoBlend_data()
263 {
264 QTest::addColumn<Handler *>(name: "handler");
265 QTest::addColumn<AdditiveClipBlend *>(name: "blendNode");
266 QTest::addColumn<Qt3DCore::QNodeId>(name: "animatorId");
267 QTest::addColumn<ClipResults>(name: "expectedResults");
268
269 {
270 auto handler = new Handler();
271
272 const qint64 globalStartTimeNS = 0;
273 const int loopCount = 1;
274 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
275
276 const double duration = 1.0;
277 auto baseNode = createTestBlendNode(handler, duration);
278 baseNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
279 auto additiveNode = createTestBlendNode(handler, duration);
280 additiveNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
281
282 const float additiveFactor = 0.0f;
283 auto blendNode = createAdditiveClipBlendNode(handler, blendFactor: additiveFactor);
284 blendNode->setBaseClipId(baseNode->peerId());
285 blendNode->setAdditiveClipId(additiveNode->peerId());
286 blendNode->setAdditiveFactor(additiveFactor);
287
288 ClipResults expectedResults = { 0.0f, 0.0f, 0.0f };
289
290 QTest::addRow(format: "unit additive, beta = 0.0")
291 << handler << blendNode << animator->peerId() << expectedResults;
292 }
293
294 {
295 auto handler = new Handler();
296
297 const qint64 globalStartTimeNS = 0;
298 const int loopCount = 1;
299 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
300
301 const double duration = 1.0;
302 auto baseNode = createTestBlendNode(handler, duration);
303 baseNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
304 auto additiveNode = createTestBlendNode(handler, duration);
305 additiveNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
306
307 const float additiveFactor = 0.5f;
308 auto blendNode = createAdditiveClipBlendNode(handler, blendFactor: additiveFactor);
309 blendNode->setBaseClipId(baseNode->peerId());
310 blendNode->setAdditiveClipId(additiveNode->peerId());
311 blendNode->setAdditiveFactor(additiveFactor);
312
313 ClipResults expectedResults = { 0.5f, 0.5f, 0.5f };
314
315 QTest::addRow(format: "unit additive, beta = 0.5")
316 << handler << blendNode << animator->peerId() << expectedResults;
317 }
318
319 {
320 auto handler = new Handler();
321
322 const qint64 globalStartTimeNS = 0;
323 const int loopCount = 1;
324 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
325
326 const double duration = 1.0;
327 auto baseNode = createTestBlendNode(handler, duration);
328 baseNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
329 auto additiveNode = createTestBlendNode(handler, duration);
330 additiveNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
331
332 const float additiveFactor = 1.0f;
333 auto blendNode = createAdditiveClipBlendNode(handler, blendFactor: additiveFactor);
334 blendNode->setBaseClipId(baseNode->peerId());
335 blendNode->setAdditiveClipId(additiveNode->peerId());
336 blendNode->setAdditiveFactor(additiveFactor);
337
338 ClipResults expectedResults = { 1.0f, 1.0f, 1.0f };
339
340 QTest::addRow(format: "unit additive, beta = 1.0")
341 << handler << blendNode << animator->peerId() << expectedResults;
342 }
343
344 {
345 auto handler = new Handler();
346
347 const qint64 globalStartTimeNS = 0;
348 const int loopCount = 1;
349 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
350
351 const double duration = 1.0;
352 auto baseNode = createTestBlendNode(handler, duration);
353 baseNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 1.0f, 2.0f });
354 auto additiveNode = createTestBlendNode(handler, duration);
355 additiveNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 2.0f, 3.0f });
356
357 const float blendFactor = 0.5f;
358 auto blendNode = createAdditiveClipBlendNode(handler, blendFactor);
359 blendNode->setBaseClipId(baseNode->peerId());
360 blendNode->setAdditiveClipId(additiveNode->peerId());
361 blendNode->setAdditiveFactor(blendFactor);
362
363 ClipResults expectedResults = { 0.5f, 2.0f, 3.5f };
364
365 QTest::addRow(format: "lerp varying data, beta = 0.5")
366 << handler << blendNode << animator->peerId() << expectedResults;
367 }
368
369 {
370 auto handler = new Handler();
371
372 const qint64 globalStartTimeNS = 0;
373 const int loopCount = 1;
374 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
375
376 const double duration = 1.0;
377 const int dataCount = 1000;
378 ClipResults baseData(dataCount);
379 ClipResults additiveData(dataCount);
380 ClipResults expectedResults(dataCount);
381 for (int i = 0; i < dataCount; ++i) {
382 baseData[i] = float(i);
383 additiveData[i] = 2.0f * float(i);
384 expectedResults[i] = 2.0f * float(i);
385 }
386 auto baseNode = createTestBlendNode(handler, duration);
387 baseNode->setClipResults(animatorId: animator->peerId(), clipResults: baseData);
388 auto additiveNode = createTestBlendNode(handler, duration);
389 additiveNode->setClipResults(animatorId: animator->peerId(), clipResults: additiveData);
390
391 const float blendFactor = 0.5f;
392 auto blendNode = createAdditiveClipBlendNode(handler, blendFactor);
393 blendNode->setBaseClipId(baseNode->peerId());
394 blendNode->setAdditiveClipId(additiveNode->peerId());
395 blendNode->setAdditiveFactor(blendFactor);
396
397 QTest::addRow(format: "lerp lots of data, beta = 0.5")
398 << handler << blendNode << animator->peerId() << expectedResults;
399 }
400 }
401
402 void checkDoBlend()
403 {
404 // GIVEN
405 QFETCH(Handler *, handler);
406 QFETCH(AdditiveClipBlend *, blendNode);
407 QFETCH(Qt3DCore::QNodeId, animatorId);
408 QFETCH(ClipResults, expectedResults);
409
410 // WHEN
411 blendNode->blend(animatorId);
412
413 // THEN
414 const ClipResults actualResults = blendNode->clipResults(animatorId);
415 QCOMPARE(actualResults.size(), expectedResults.size());
416 for (int i = 0; i < actualResults.size(); ++i)
417 QCOMPARE(actualResults[i], expectedResults[i]);
418
419 // Cleanup
420 delete handler;
421 }
422};
423
424QTEST_MAIN(tst_AdditiveClipBlend)
425
426#include "tst_additiveclipblend.moc"
427

source code of qt3d/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp