1/****************************************************************************
2**
3** Copyright (C) 2017 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#include <QtTest/QTest>
30#include <Qt3DAnimation/qanimationcliploader.h>
31#include <Qt3DAnimation/qclipanimator.h>
32#include <Qt3DAnimation/qchannelmapper.h>
33#include <Qt3DAnimation/qchannelmapping.h>
34#include <Qt3DAnimation/private/clipanimator_p.h>
35#include <Qt3DAnimation/private/channelmapper_p.h>
36#include <Qt3DAnimation/private/channelmapping_p.h>
37#include <Qt3DAnimation/private/findrunningclipanimatorsjob_p.h>
38#include <Qt3DAnimation/private/handler_p.h>
39#include <Qt3DAnimation/private/managers_p.h>
40#include <Qt3DCore/private/qnode_p.h>
41#include <Qt3DCore/private/qscene_p.h>
42#include <Qt3DCore/private/qbackendnode_p.h>
43#include <qbackendnodetester.h>
44#include <testpostmanarbiter.h>
45
46using namespace Qt3DAnimation::Animation;
47
48Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*)
49Q_DECLARE_METATYPE(QVector<Qt3DAnimation::Animation::HClipAnimator>)
50
51typedef QHash<ClipAnimator*, QVector<Qt3DAnimation::Animation::MappingData>> MappingDataResults;
52Q_DECLARE_METATYPE(MappingDataResults)
53
54class tst_FindRunningClipAnimatorsJob: public Qt3DCore::QBackendNodeTester
55{
56 Q_OBJECT
57public:
58 ChannelMapping *createChannelMapping(Handler *handler,
59 const QString &channelName,
60 const Qt3DCore::QNodeId targetId,
61 const char *propertyName,
62 int type,
63 int componentCount)
64 {
65 auto channelMappingId = Qt3DCore::QNodeId::createId();
66 ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(id: channelMappingId);
67 setPeerId(backend: channelMapping, id: channelMappingId);
68 channelMapping->setHandler(handler);
69 channelMapping->setTargetId(targetId);
70 channelMapping->setPropertyName(propertyName);
71 channelMapping->setChannelName(channelName);
72 channelMapping->setType(type);
73 channelMapping->setComponentCount(componentCount);
74 channelMapping->setMappingType(ChannelMapping::ChannelMappingType);
75 return channelMapping;
76 }
77
78 ChannelMapper *createChannelMapper(Handler *handler,
79 const QVector<Qt3DCore::QNodeId> &mappingIds)
80 {
81 auto channelMapperId = Qt3DCore::QNodeId::createId();
82 ChannelMapper *channelMapper = handler->channelMapperManager()->getOrCreateResource(id: channelMapperId);
83 setPeerId(backend: channelMapper, id: channelMapperId);
84 channelMapper->setHandler(handler);
85 channelMapper->setMappingIds(mappingIds);
86 return channelMapper;
87 }
88
89 AnimationClip *createAnimationClipLoader(Handler *handler,
90 const QUrl &source)
91 {
92 auto clipId = Qt3DCore::QNodeId::createId();
93 AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(id: clipId);
94 setPeerId(backend: clip, id: clipId);
95 clip->setHandler(handler);
96 clip->setDataType(AnimationClip::File);
97 clip->setSource(source);
98 clip->loadAnimation();
99 return clip;
100 }
101
102 ClipAnimator *createClipAnimator(Handler *handler,
103 qint64 globalStartTimeNS,
104 int loops)
105 {
106 auto animatorId = Qt3DCore::QNodeId::createId();
107 ClipAnimator *animator = handler->clipAnimatorManager()->getOrCreateResource(id: animatorId);
108 setPeerId(backend: animator, id: animatorId);
109 animator->setHandler(handler);
110 animator->setStartTime(globalStartTimeNS);
111 animator->setLoops(loops);
112 return animator;
113 }
114
115private Q_SLOTS:
116 void checkJob_data()
117 {
118 QTest::addColumn<Handler *>(name: "handler");
119 QTest::addColumn<QVector<HClipAnimator>>(name: "dirtyClipAnimators");
120 QTest::addColumn<MappingDataResults>(name: "expectedResults");
121
122
123 {
124 Handler *handler;
125 AnimationClip *clip;
126 ClipAnimator *animator;
127 QVector<HClipAnimator> dirtyClipAnimators;
128 ChannelMapper *channelMapper;
129 MappingDataResults expectedResults;
130 handler = new Handler();
131 clip = createAnimationClipLoader(handler, source: QUrl("qrc:/clip1.json"));
132
133 const qint64 globalStartTimeNS = 0;
134 const int loops = 1;
135 animator = createClipAnimator(handler, globalStartTimeNS, loops);
136 animator->setClipId(clip->peerId());
137 dirtyClipAnimators = (QVector<HClipAnimator>()
138 << handler->clipAnimatorManager()->getOrAcquireHandle(id: animator->peerId()));
139
140 auto channelMapping = createChannelMapping(handler,
141 channelName: QLatin1String("Location"),
142 targetId: Qt3DCore::QNodeId::createId(),
143 propertyName: "translation",
144 type: static_cast<int>(QVariant::Vector3D),
145 componentCount: 3);
146 QVector<ChannelMapping *> channelMappings;
147 channelMappings.push_back(t: channelMapping);
148
149 channelMapper = createChannelMapper(handler, mappingIds: QVector<Qt3DCore::QNodeId>() << channelMapping->peerId());
150 animator->setMapperId(channelMapper->peerId());
151 animator->setRunning(true); // Has to be marked as running for the job to process it
152 animator->setEnabled(true); // Has to be marked as enabled for the job to process it
153
154 const ComponentIndices locationIndices = { 0, 1, 2 };
155 MappingData expectedMapping;
156 expectedMapping.targetId = channelMapping->targetId();
157 expectedMapping.propertyName = channelMapping->propertyName();
158 expectedMapping.type = channelMapping->type();
159 expectedMapping.channelIndices = locationIndices;
160 expectedResults.insert(akey: animator, avalue: QVector<MappingData>() << expectedMapping);
161
162 QTest::newRow(dataTag: "single mapping")
163 << handler
164 << dirtyClipAnimators
165 << expectedResults;
166 }
167
168 {
169 Handler *handler;
170 AnimationClip *clip;
171 ClipAnimator *animator;
172 QVector<HClipAnimator> dirtyClipAnimators;
173 ChannelMapper *channelMapper;
174 MappingDataResults expectedResults;
175 handler = new Handler();
176 clip = createAnimationClipLoader(handler, source: QUrl("qrc:/clip1.json"));
177
178 const qint64 globalStartTimeNS = 0;
179 const int loops = 1;
180 animator = createClipAnimator(handler, globalStartTimeNS, loops);
181 animator->setClipId(clip->peerId());
182 dirtyClipAnimators = (QVector<HClipAnimator>()
183 << handler->clipAnimatorManager()->getOrAcquireHandle(id: animator->peerId()));
184
185 auto channelMapping = createChannelMapping(handler,
186 channelName: QLatin1String("Location"),
187 targetId: Qt3DCore::QNodeId::createId(),
188 propertyName: "translation",
189 type: static_cast<int>(QVariant::Vector3D),
190 componentCount: 3);
191 QVector<ChannelMapping *> channelMappings;
192 channelMappings.push_back(t: channelMapping);
193
194 channelMapper = createChannelMapper(handler, mappingIds: QVector<Qt3DCore::QNodeId>() << channelMapping->peerId());
195 animator->setMapperId(channelMapper->peerId());
196 animator->setRunning(true); // Has to be marked as running for the job to process it
197 animator->setEnabled(false); // Has to be marked as enabled for the job to process it
198
199 QTest::newRow(dataTag: "disabled animator")
200 << handler
201 << dirtyClipAnimators
202 << expectedResults;
203 }
204 }
205
206 void checkJob()
207 {
208 // GIVEN
209 QFETCH(Handler *, handler);
210 QFETCH(QVector<HClipAnimator>, dirtyClipAnimators);
211 QFETCH(MappingDataResults, expectedResults);
212 FindRunningClipAnimatorsJob job;
213
214 // WHEN
215 job.setHandler(handler);
216 job.setDirtyClipAnimators(dirtyClipAnimators);
217 job.run();
218
219 // THEN - check the resulting MappingData on the animator matches the expected results
220 for (const auto &dirtyClipAnimator : dirtyClipAnimators) {
221 const auto animator = handler->clipAnimatorManager()->data(handle: dirtyClipAnimator);
222 const QVector<MappingData> actualMappingData = animator->mappingData();
223 const QVector<MappingData> expectedMappingData = expectedResults[animator];
224
225 QCOMPARE(expectedMappingData.size(), actualMappingData.size());
226 for (int i = 0; i < actualMappingData.size(); ++i) {
227 QCOMPARE(expectedMappingData[i].targetId, actualMappingData[i].targetId);
228 QCOMPARE(expectedMappingData[i].type, actualMappingData[i].type);
229 QVERIFY(qstrcmp(expectedMappingData[i].propertyName, actualMappingData[i].propertyName) == 0);
230 QCOMPARE(expectedMappingData[i].channelIndices.size(), actualMappingData[i].channelIndices.size());
231
232 for (int j = 0; j < actualMappingData[i].channelIndices.size(); ++j) {
233 QCOMPARE(expectedMappingData[i].channelIndices[j], actualMappingData[i].channelIndices[j]);
234 }
235 }
236 }
237 }
238};
239
240QTEST_APPLESS_MAIN(tst_FindRunningClipAnimatorsJob)
241
242#include "tst_findrunningclipanimatorsjob.moc"
243

source code of qt3d/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp