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/qlerpclipblend.h>
32#include <Qt3DAnimation/qanimationcliploader.h>
33#include <Qt3DAnimation/private/qlerpclipblend_p.h>
34#include <Qt3DAnimation/private/lerpclipblend_p.h>
35#include "qbackendnodetester.h"
36
37using namespace Qt3DAnimation::Animation;
38
39Q_DECLARE_METATYPE(Handler *)
40Q_DECLARE_METATYPE(LerpClipBlend *)
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_LerpClipBlend : 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 LerpClipBlend *createLerpClipBlendNode(Handler *handler, const float &blendFactor)
92 {
93 auto id = Qt3DCore::QNodeId::createId();
94 LerpClipBlend *node = new LerpClipBlend();
95 node->setBlendFactor(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 LerpClipBlend backendLerpBlend;
121
122 // THEN
123 QCOMPARE(backendLerpBlend.isEnabled(), false);
124 QVERIFY(backendLerpBlend.peerId().isNull());
125 QCOMPARE(backendLerpBlend.blendFactor(), 0.0f);
126 QCOMPARE(backendLerpBlend.blendType(), ClipBlendNode::LerpBlendType);
127 }
128
129 void checkInitializeFromPeer()
130 {
131 // GIVEN
132 Qt3DAnimation::QLerpClipBlend lerpBlend;
133 Qt3DAnimation::QAnimationClipLoader clip;
134 lerpBlend.setBlendFactor(0.8f);
135
136 {
137 // WHEN
138 LerpClipBlend backendLerpBlend;
139 simulateInitializationSync(frontend: &lerpBlend, backend: &backendLerpBlend);
140
141 // THEN
142 QCOMPARE(backendLerpBlend.isEnabled(), true);
143 QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id());
144 QCOMPARE(backendLerpBlend.blendFactor(), 0.8f);
145 }
146 {
147 // WHEN
148 LerpClipBlend backendLerpBlend;
149 lerpBlend.setEnabled(false);
150 simulateInitializationSync(frontend: &lerpBlend, backend: &backendLerpBlend);
151
152 // THEN
153 QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id());
154 QCOMPARE(backendLerpBlend.isEnabled(), false);
155 }
156 }
157
158 void checkSceneChangeEvents()
159 {
160 // GIVEN
161 Qt3DAnimation::QLerpClipBlend lerpBlend;
162 LerpClipBlend backendLerpBlend;
163 simulateInitializationSync(frontend: &lerpBlend, backend: &backendLerpBlend);
164
165 {
166 // WHEN
167 const bool newValue = false;
168 lerpBlend.setEnabled(newValue);
169 backendLerpBlend.syncFromFrontEnd(frontEnd: &lerpBlend, firstTime: false);
170
171 // THEN
172 QCOMPARE(backendLerpBlend.isEnabled(), newValue);
173 }
174 {
175 // WHEN
176 const float newValue = 0.883f;
177 lerpBlend.setBlendFactor(newValue);
178 backendLerpBlend.syncFromFrontEnd(frontEnd: &lerpBlend, firstTime: false);
179
180 // THEN
181 QCOMPARE(backendLerpBlend.blendFactor(), newValue);
182 }
183 }
184
185 void checkDependencyIds()
186 {
187 // GIVEN
188 LerpClipBlend lerpBlend;
189 auto startClipId = Qt3DCore::QNodeId::createId();
190 auto endClipId = Qt3DCore::QNodeId::createId();
191
192 // WHEN
193 lerpBlend.setStartClipId(startClipId);
194 lerpBlend.setEndClipId(endClipId);
195 QVector<Qt3DCore::QNodeId> actualIds = lerpBlend.currentDependencyIds();
196
197 // THEN
198 QCOMPARE(actualIds.size(), 2);
199 QCOMPARE(actualIds[0], startClipId);
200 QCOMPARE(actualIds[1], endClipId);
201
202 // WHEN
203 auto anotherEndClipId = Qt3DCore::QNodeId::createId();
204 lerpBlend.setEndClipId(anotherEndClipId);
205 actualIds = lerpBlend.currentDependencyIds();
206
207 // THEN
208 QCOMPARE(actualIds.size(), 2);
209 QCOMPARE(actualIds[0], startClipId);
210 QCOMPARE(actualIds[1], anotherEndClipId);
211 }
212
213 void checkDuration()
214 {
215 // GIVEN
216 auto handler = new Handler();
217 const double startNodeDuration = 10.0;
218 const double endNodeDuration = 20.0;
219 const float blendFactor = 0.25f;
220 const double expectedDuration = 12.5;
221
222 auto startNode = createTestBlendNode(handler, duration: startNodeDuration);
223 auto endNode = createTestBlendNode(handler, duration: endNodeDuration);
224
225 LerpClipBlend blendNode;
226 blendNode.setHandler(handler);
227 blendNode.setClipBlendNodeManager(handler->clipBlendNodeManager());
228 blendNode.setStartClipId(startNode->peerId());
229 blendNode.setEndClipId(endNode->peerId());
230 blendNode.setBlendFactor(blendFactor);
231
232 // WHEN
233 double actualDuration = blendNode.duration();
234
235 // THEN
236 QCOMPARE(actualDuration, expectedDuration);
237 }
238
239 void checkDoBlend_data()
240 {
241 QTest::addColumn<Handler *>(name: "handler");
242 QTest::addColumn<LerpClipBlend *>(name: "blendNode");
243 QTest::addColumn<Qt3DCore::QNodeId>(name: "animatorId");
244 QTest::addColumn<ClipResults>(name: "expectedResults");
245
246 {
247 auto handler = new Handler();
248
249 const qint64 globalStartTimeNS = 0;
250 const int loopCount = 1;
251 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
252
253 const double duration = 1.0;
254 auto startNode = createTestBlendNode(handler, duration);
255 startNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
256 auto endNode = createTestBlendNode(handler, duration);
257 endNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
258
259 const float blendFactor = 0.0f;
260 auto blendNode = createLerpClipBlendNode(handler, blendFactor);
261 blendNode->setStartClipId(startNode->peerId());
262 blendNode->setEndClipId(endNode->peerId());
263 blendNode->setBlendFactor(blendFactor);
264
265 ClipResults expectedResults = { 0.0f, 0.0f, 0.0f };
266
267 QTest::addRow(format: "unit lerp, beta = 0.0")
268 << handler << blendNode << animator->peerId() << expectedResults;
269 }
270
271 {
272 auto handler = new Handler();
273
274 const qint64 globalStartTimeNS = 0;
275 const int loopCount = 1;
276 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
277
278 const double duration = 1.0;
279 auto startNode = createTestBlendNode(handler, duration);
280 startNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
281 auto endNode = createTestBlendNode(handler, duration);
282 endNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
283
284 const float blendFactor = 0.5f;
285 auto blendNode = createLerpClipBlendNode(handler, blendFactor);
286 blendNode->setStartClipId(startNode->peerId());
287 blendNode->setEndClipId(endNode->peerId());
288 blendNode->setBlendFactor(blendFactor);
289
290 ClipResults expectedResults = { 0.5f, 0.5f, 0.5f };
291
292 QTest::addRow(format: "unit lerp, beta = 0.5")
293 << handler << blendNode << animator->peerId() << expectedResults;
294 }
295
296 {
297 auto handler = new Handler();
298
299 const qint64 globalStartTimeNS = 0;
300 const int loopCount = 1;
301 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
302
303 const double duration = 1.0;
304 auto startNode = createTestBlendNode(handler, duration);
305 startNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 0.0f, 0.0f });
306 auto endNode = createTestBlendNode(handler, duration);
307 endNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 1.0f, 1.0f });
308
309 const float blendFactor = 1.0f;
310 auto blendNode = createLerpClipBlendNode(handler, blendFactor);
311 blendNode->setStartClipId(startNode->peerId());
312 blendNode->setEndClipId(endNode->peerId());
313 blendNode->setBlendFactor(blendFactor);
314
315 ClipResults expectedResults = { 1.0f, 1.0f, 1.0f };
316
317 QTest::addRow(format: "unit lerp, beta = 1.0")
318 << handler << blendNode << animator->peerId() << expectedResults;
319 }
320
321 {
322 auto handler = new Handler();
323
324 const qint64 globalStartTimeNS = 0;
325 const int loopCount = 1;
326 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
327
328 const double duration = 1.0;
329 auto startNode = createTestBlendNode(handler, duration);
330 startNode->setClipResults(animatorId: animator->peerId(), clipResults: { 0.0f, 1.0f, 2.0f });
331 auto endNode = createTestBlendNode(handler, duration);
332 endNode->setClipResults(animatorId: animator->peerId(), clipResults: { 1.0f, 2.0f, 3.0f });
333
334 const float blendFactor = 0.5f;
335 auto blendNode = createLerpClipBlendNode(handler, blendFactor);
336 blendNode->setStartClipId(startNode->peerId());
337 blendNode->setEndClipId(endNode->peerId());
338 blendNode->setBlendFactor(blendFactor);
339
340 ClipResults expectedResults = { 0.5f, 1.5f, 2.5f };
341
342 QTest::addRow(format: "lerp varying data, beta = 0.5")
343 << handler << blendNode << animator->peerId() << expectedResults;
344 }
345
346 {
347 auto handler = new Handler();
348
349 const qint64 globalStartTimeNS = 0;
350 const int loopCount = 1;
351 auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loops: loopCount);
352
353 const double duration = 1.0;
354 const int dataCount = 1000;
355 ClipResults startData(dataCount);
356 ClipResults endData(dataCount);
357 ClipResults expectedResults(dataCount);
358 for (int i = 0; i < dataCount; ++i) {
359 startData[i] = float(i);
360 endData[i] = 2.0f * float(i);
361 expectedResults[i] = 1.5f * float(i);
362 }
363 auto startNode = createTestBlendNode(handler, duration);
364 startNode->setClipResults(animatorId: animator->peerId(), clipResults: startData);
365 auto endNode = createTestBlendNode(handler, duration);
366 endNode->setClipResults(animatorId: animator->peerId(), clipResults: endData);
367
368 const float blendFactor = 0.5f;
369 auto blendNode = createLerpClipBlendNode(handler, blendFactor);
370 blendNode->setStartClipId(startNode->peerId());
371 blendNode->setEndClipId(endNode->peerId());
372 blendNode->setBlendFactor(blendFactor);
373
374 QTest::addRow(format: "lerp lots of data, beta = 0.5")
375 << handler << blendNode << animator->peerId() << expectedResults;
376 }
377 }
378
379 void checkDoBlend()
380 {
381 // GIVEN
382 QFETCH(Handler *, handler);
383 QFETCH(LerpClipBlend *, blendNode);
384 QFETCH(Qt3DCore::QNodeId, animatorId);
385 QFETCH(ClipResults, expectedResults);
386
387 // WHEN
388 blendNode->blend(animatorId);
389
390 // THEN
391 const ClipResults actualResults = blendNode->clipResults(animatorId);
392 QCOMPARE(actualResults.size(), expectedResults.size());
393 for (int i = 0; i < actualResults.size(); ++i)
394 QCOMPARE(actualResults[i], expectedResults[i]);
395
396 // Cleanup
397 delete handler;
398 }
399};
400
401QTEST_MAIN(tst_LerpClipBlend)
402
403#include "tst_lerpclipblend.moc"
404

source code of qt3d/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp