1/****************************************************************************
2**
3** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
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 http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#ifndef QT3DANIMATION_ANIMATION_ANIMATIONUTILS_P_H
38#define QT3DANIMATION_ANIMATION_ANIMATIONUTILS_P_H
39
40//
41// W A R N I N G
42// -------------
43//
44// This file is not part of the Qt API. It exists for the convenience
45// of other Qt classes. This header file may change from version to
46// version without notice, or even be removed.
47//
48// We mean it.
49//
50
51#include <Qt3DAnimation/private/qt3danimation_global_p.h>
52#include <Qt3DAnimation/private/clock_p.h>
53#include <Qt3DAnimation/qanimationcallback.h>
54#include <Qt3DCore/qnodeid.h>
55#include <Qt3DCore/qscenechange.h>
56
57#include <QtCore/qbitarray.h>
58#include <QtCore/qdebug.h>
59#include <qmath.h>
60
61QT_BEGIN_NAMESPACE
62
63namespace Qt3DAnimation {
64class QAnimationCallback;
65namespace Animation {
66
67struct Channel;
68class BlendedClipAnimator;
69class Handler;
70class AnimationClip;
71class ChannelMapper;
72class ChannelMapping;
73
74typedef QVector<int> ComponentIndices;
75
76enum JointTransformComponent {
77 NoTransformComponent = 0,
78 Scale,
79 Rotation,
80 Translation
81};
82
83struct MappingData
84{
85 Qt3DCore::QNodeId targetId;
86 Skeleton *skeleton = nullptr;
87 int jointIndex = -1;
88 JointTransformComponent jointTransformComponent = NoTransformComponent;
89 const char *propertyName;
90 QAnimationCallback *callback = nullptr;
91 QAnimationCallback::Flags callbackFlags;
92 int type;
93 ComponentIndices channelIndices;
94};
95
96#ifndef QT_NO_DEBUG_STREAM
97inline QDebug operator<<(QDebug dbg, const MappingData &mapping)
98{
99 QDebugStateSaver saver(dbg);
100 dbg << "targetId =" << mapping.targetId << endl
101 << "jointIndex =" << mapping.jointIndex << endl
102 << "jointTransformComponent: " << mapping.jointTransformComponent << endl
103 << "propertyName:" << mapping.propertyName << endl
104 << "channelIndices:" << mapping.channelIndices;
105 return dbg;
106}
107#endif
108
109struct AnimatorEvaluationData
110{
111 double elapsedTime;
112 double currentTime;
113 int loopCount;
114 int currentLoop;
115 double playbackRate;
116 float normalizedLocalTime;
117};
118
119struct ClipEvaluationData
120{
121 int currentLoop;
122 float normalizedLocalTime;
123 double localTime;
124 bool isFinalFrame;
125};
126
127typedef QVector<float> ClipResults;
128
129struct ChannelNameAndType
130{
131 QString jointName;
132 QString name;
133 int type;
134 int jointIndex;
135 Qt3DCore::QNodeId mappingId;
136 JointTransformComponent jointTransformComponent;
137 int componentCount;
138
139 static const int invalidIndex = -1;
140
141 ChannelNameAndType()
142 : jointName()
143 , name()
144 , type(-1)
145 , jointIndex(-1)
146 , mappingId()
147 , jointTransformComponent(NoTransformComponent)
148 , componentCount(-1)
149 {}
150
151 ChannelNameAndType(const QString &_name,
152 int _type,
153 int componentCount,
154 Qt3DCore::QNodeId _mappingId = Qt3DCore::QNodeId(),
155 int _jointIndex = invalidIndex)
156 : jointName()
157 , name(_name)
158 , type(_type)
159 , jointIndex(_jointIndex)
160 , mappingId(_mappingId)
161 , jointTransformComponent(NoTransformComponent)
162 , componentCount(componentCount)
163 {}
164
165 ChannelNameAndType(const QString &_name,
166 int _type,
167 JointTransformComponent _jointTransformComponent)
168 : jointName()
169 , name(_name)
170 , type(_type)
171 , jointIndex(invalidIndex)
172 , mappingId()
173 , jointTransformComponent(_jointTransformComponent)
174 , componentCount(-1)
175 {
176 switch (_jointTransformComponent) {
177 case NoTransformComponent:
178 break;
179 case Scale:
180 case Translation:
181 componentCount = 3;
182 break;
183 case Rotation:
184 componentCount = 4;
185 break;
186 };
187 }
188
189 bool operator==(const ChannelNameAndType &rhs) const
190 {
191 return name == rhs.name
192 && type == rhs.type
193 && jointIndex == rhs.jointIndex
194 && mappingId == rhs.mappingId
195 && jointTransformComponent == rhs.jointTransformComponent
196 && componentCount == rhs.componentCount;
197 }
198};
199
200#ifndef QT_NO_DEBUG_STREAM
201inline QDebug operator<<(QDebug dbg, const ChannelNameAndType &nameAndType)
202{
203 QDebugStateSaver saver(dbg);
204 dbg << "name =" << nameAndType.name
205 << "type =" << nameAndType.type
206 << "mappingId =" << nameAndType.mappingId
207 << "jointIndex =" << nameAndType.jointIndex
208 << "jointName =" << nameAndType.jointName
209 << "jointTransformComponent =" << nameAndType.jointTransformComponent
210 << "componentCount =" << nameAndType.componentCount;
211 return dbg;
212}
213#endif
214
215struct ComponentValue
216{
217 int componentIndex;
218 float value;
219};
220QT3D_DECLARE_TYPEINFO_2(Qt3DAnimation, Animation, ComponentValue, Q_PRIMITIVE_TYPE)
221
222struct ClipFormat
223{
224 // TODO: Remove the mask and store both the sourceClipIndices and
225 // formattedComponentIndices in flat vectors. This will require a
226 // way to look up the offset and number of elements for each channel.
227 ComponentIndices sourceClipIndices;
228 QVector<QBitArray> sourceClipMask;
229 QVector<ComponentIndices> formattedComponentIndices;
230 QVector<ChannelNameAndType> namesAndTypes;
231 QVector<ComponentValue> defaultComponentValues;
232};
233
234#ifndef QT_NO_DEBUG_STREAM
235inline QDebug operator<<(QDebug dbg, const ClipFormat &format)
236{
237 QDebugStateSaver saver(dbg);
238 int sourceIndex = 0;
239 for (int i = 0; i < format.namesAndTypes.size(); ++i) {
240 dbg << i
241 << format.namesAndTypes[i].jointIndex
242 << format.namesAndTypes[i].jointName
243 << format.namesAndTypes[i].name
244 << format.namesAndTypes[i].type
245 << "formatted results dst indices =" << format.formattedComponentIndices[i];
246 const int componentCount = format.formattedComponentIndices[i].size();
247
248 dbg << "clip src indices =";
249 for (int j = sourceIndex; j < sourceIndex + componentCount; ++j)
250 dbg << format.sourceClipIndices[j] << "";
251
252 dbg << "src clip mask =" << format.sourceClipMask[i];
253 dbg << endl;
254 sourceIndex += componentCount;
255 }
256 return dbg;
257}
258#endif
259
260struct AnimationCallbackAndValue
261{
262 QAnimationCallback *callback;
263 QAnimationCallback::Flags flags;
264 QVariant value;
265};
266
267inline constexpr double toSecs(qint64 nsecs) { return nsecs / 1.0e9; }
268inline qint64 toNsecs(double seconds) { return qRound64(seconds * 1.0e9); }
269
270template<typename Animator>
271AnimatorEvaluationData evaluationDataForAnimator(Animator animator,
272 Clock* clock,
273 qint64 nsSincePreviousFrame)
274{
275 const bool seeking = animator->isSeeking();
276 AnimatorEvaluationData data;
277 data.loopCount = animator->loops();
278 data.currentLoop = animator->currentLoop();
279 // The playback-rate is always 1.0 when seeking
280 data.playbackRate = ((clock != nullptr) && !seeking) ? clock->playbackRate() : 1.0;
281 // Convert global time from nsec to sec
282 data.elapsedTime = toSecs(nsSincePreviousFrame);
283 // When seeking we base it on the current time being at the start of the clip
284 data.currentTime = seeking ? 0.0 : animator->lastLocalTime();
285 // If we're not seeking the local normalized time will be calculate in
286 // evaluationDataForClip().
287 data.normalizedLocalTime = seeking ? animator->normalizedLocalTime() : -1.0;
288 return data;
289}
290
291inline bool isFinalFrame(double localTime,
292 double duration,
293 int currentLoop,
294 int loopCount)
295{
296 return (localTime >= duration &&
297 loopCount != 0 &&
298 currentLoop >= loopCount - 1);
299}
300
301inline bool isValidNormalizedTime(float t)
302{
303 return !(t < 0.0f) && !(t > 1.0f);
304}
305
306Q_AUTOTEST_EXPORT
307ClipEvaluationData evaluationDataForClip(AnimationClip *clip,
308 const AnimatorEvaluationData &animatorData);
309
310Q_AUTOTEST_EXPORT
311ComponentIndices channelComponentsToIndices(const Channel &channel,
312 int dataType,
313 int expectedComponentCount,
314 int offset);
315
316Q_AUTOTEST_EXPORT
317ComponentIndices channelComponentsToIndicesHelper(const Channel &channelGroup,
318 int expectedComponentCount,
319 int offset,
320 const QVector<char> &suffixes);
321
322Q_AUTOTEST_EXPORT
323ClipResults evaluateClipAtLocalTime(AnimationClip *clip,
324 float localTime);
325
326Q_AUTOTEST_EXPORT
327ClipResults evaluateClipAtPhase(AnimationClip *clip,
328 float phase);
329
330Q_AUTOTEST_EXPORT
331QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
332 const QVector<MappingData> &mappingDataVec,
333 const QVector<float> &channelResults,
334 bool finalFrame, float normalizedLocalTime);
335
336Q_AUTOTEST_EXPORT
337QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
338 const QVector<float> &channelResults);
339
340Q_AUTOTEST_EXPORT
341QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping *> &channelMappings,
342 const QVector<ChannelNameAndType> &channelNamesAndTypes,
343 const QVector<ComponentIndices> &channelComponentIndices,
344 const QVector<QBitArray> &sourceClipMask);
345
346Q_AUTOTEST_EXPORT
347QVector<ChannelNameAndType> buildRequiredChannelsAndTypes(Handler *handler,
348 const ChannelMapper *mapper);
349
350Q_AUTOTEST_EXPORT
351QVector<ComponentIndices> assignChannelComponentIndices(const QVector<ChannelNameAndType> &namesAndTypes);
352
353Q_AUTOTEST_EXPORT
354double localTimeFromElapsedTime(double t_current_local, double t_elapsed_global,
355 double playbackRate, double duration,
356 int loopCount, int &currentLoop);
357
358Q_AUTOTEST_EXPORT
359double phaseFromElapsedTime(double t_current_local, double t_elapsed_global,
360 double playbackRate, double duration,
361 int loopCount, int &currentLoop);
362
363Q_AUTOTEST_EXPORT
364QVector<Qt3DCore::QNodeId> gatherValueNodesToEvaluate(Handler *handler,
365 Qt3DCore::QNodeId blendTreeRootId);
366
367Q_AUTOTEST_EXPORT
368ClipFormat generateClipFormatIndices(const QVector<ChannelNameAndType> &targetChannels,
369 const QVector<ComponentIndices> &targetIndices,
370 const AnimationClip *clip);
371
372Q_AUTOTEST_EXPORT
373ClipResults formatClipResults(const ClipResults &rawClipResults,
374 const ComponentIndices &format);
375
376Q_AUTOTEST_EXPORT
377ClipResults evaluateBlendTree(Handler *handler,
378 BlendedClipAnimator *animator,
379 Qt3DCore::QNodeId blendNodeId);
380
381Q_AUTOTEST_EXPORT
382QVector<float> defaultValueForChannel(Handler *handler, const ChannelNameAndType &channelDescription);
383
384Q_AUTOTEST_EXPORT
385void applyComponentDefaultValues(const QVector<ComponentValue> &componentDefaults,
386 ClipResults &formattedClipResults);
387
388} // Animation
389} // Qt3DAnimation
390
391QT_END_NAMESPACE
392
393
394#endif // QT3DANIMATION_ANIMATION_ANIMATIONUTILS_P_H
395