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 #include <Qt3DCore/private/sqt_p.h>
57 
58 #include <QtCore/qbitarray.h>
59 #include <QtCore/qdebug.h>
60 #include <qmath.h>
61 
62 QT_BEGIN_NAMESPACE
63 
64 namespace Qt3DAnimation {
65 class QAnimationCallback;
66 namespace Animation {
67 
68 struct Channel;
69 class BlendedClipAnimator;
70 class Handler;
71 class AnimationClip;
72 class ChannelMapper;
73 class ChannelMapping;
74 
75 typedef QVector<int> ComponentIndices;
76 
77 enum JointTransformComponent {
78     NoTransformComponent = 0,
79     Scale,
80     Rotation,
81     Translation
82 };
83 
84 struct MappingData
85 {
86     Qt3DCore::QNodeId targetId;
87     Skeleton *skeleton = nullptr;
88     int jointIndex = -1;
89     JointTransformComponent jointTransformComponent = NoTransformComponent;
90     const char *propertyName;
91     QAnimationCallback *callback = nullptr;
92     QAnimationCallback::Flags callbackFlags;
93     int type;
94     ComponentIndices channelIndices;
95 };
96 
97 #ifndef QT_NO_DEBUG_STREAM
98 inline QDebug operator<<(QDebug dbg, const MappingData &mapping)
99 {
100     QDebugStateSaver saver(dbg);
101     dbg << "targetId =" << mapping.targetId << Qt::endl
102         << "jointIndex =" << mapping.jointIndex << Qt::endl
103         << "jointTransformComponent: " << mapping.jointTransformComponent << Qt::endl
104         << "propertyName:" << mapping.propertyName << Qt::endl
105         << "channelIndices:" << mapping.channelIndices;
106     return dbg;
107 }
108 #endif
109 
110 struct AnimatorEvaluationData
111 {
112     double elapsedTime;
113     double currentTime;
114     int loopCount;
115     int currentLoop;
116     double playbackRate;
117     float normalizedLocalTime;
118 };
119 
120 struct ClipEvaluationData
121 {
122     int currentLoop;
123     float normalizedLocalTime;
124     double localTime;
125     bool isFinalFrame;
126 };
127 
128 typedef QVector<float> ClipResults;
129 
130 struct ChannelNameAndType
131 {
132     QString jointName;
133     QString name;
134     int type;
135     int jointIndex;
136     Qt3DCore::QNodeId mappingId;
137     JointTransformComponent jointTransformComponent;
138     int componentCount;
139 
140     static const int invalidIndex = -1;
141 
ChannelNameAndTypeChannelNameAndType142     ChannelNameAndType()
143         : jointName()
144         , name()
145         , type(-1)
146         , jointIndex(-1)
147         , mappingId()
148         , jointTransformComponent(NoTransformComponent)
149         , componentCount(-1)
150     {}
151 
152     ChannelNameAndType(const QString &_name,
153                        int _type,
154                        int componentCount,
155                        Qt3DCore::QNodeId _mappingId = Qt3DCore::QNodeId(),
156                        int _jointIndex = invalidIndex)
jointNameChannelNameAndType157         : jointName()
158         , name(_name)
159         , type(_type)
160         , jointIndex(_jointIndex)
161         , mappingId(_mappingId)
162         , jointTransformComponent(NoTransformComponent)
163         , componentCount(componentCount)
164     {}
165 
ChannelNameAndTypeChannelNameAndType166     ChannelNameAndType(const QString &_name,
167                        int _type,
168                        JointTransformComponent _jointTransformComponent)
169         : jointName()
170         , name(_name)
171         , type(_type)
172         , jointIndex(invalidIndex)
173         , mappingId()
174         , jointTransformComponent(_jointTransformComponent)
175         , componentCount(-1)
176     {
177         switch (_jointTransformComponent) {
178         case  NoTransformComponent:
179             break;
180         case Scale:
181         case Translation:
182             componentCount = 3;
183             break;
184         case Rotation:
185             componentCount = 4;
186             break;
187         }
188     }
189 
190     bool operator==(const ChannelNameAndType &rhs) const
191     {
192         return name == rhs.name
193             && type == rhs.type
194             && jointIndex == rhs.jointIndex
195             && mappingId == rhs.mappingId
196             && jointTransformComponent == rhs.jointTransformComponent
197             && componentCount == rhs.componentCount;
198     }
199 };
200 
201 #ifndef QT_NO_DEBUG_STREAM
202 inline QDebug operator<<(QDebug dbg, const ChannelNameAndType &nameAndType)
203 {
204     QDebugStateSaver saver(dbg);
205     dbg << "name =" << nameAndType.name
206         << "type =" << nameAndType.type
207         << "mappingId =" << nameAndType.mappingId
208         << "jointIndex =" << nameAndType.jointIndex
209         << "jointName =" << nameAndType.jointName
210         << "jointTransformComponent =" << nameAndType.jointTransformComponent
211         << "componentCount =" << nameAndType.componentCount;
212     return dbg;
213 }
214 #endif
215 
216 struct ComponentValue
217 {
218     int componentIndex;
219     float value;
220 };
221 QT3D_DECLARE_TYPEINFO_2(Qt3DAnimation, Animation, ComponentValue, Q_PRIMITIVE_TYPE)
222 
223 struct ClipFormat
224 {
225     // TODO: Remove the mask and store both the sourceClipIndices and
226     // formattedComponentIndices in flat vectors. This will require a
227     // way to look up the offset and number of elements for each channel.
228     ComponentIndices sourceClipIndices;
229     QVector<QBitArray> sourceClipMask;
230     QVector<ComponentIndices> formattedComponentIndices;
231     QVector<ChannelNameAndType> namesAndTypes;
232     QVector<ComponentValue> defaultComponentValues;
233 };
234 
235 #ifndef QT_NO_DEBUG_STREAM
236 inline QDebug operator<<(QDebug dbg, const ClipFormat &format)
237 {
238     QDebugStateSaver saver(dbg);
239     int sourceIndex = 0;
240     for (int i = 0; i < format.namesAndTypes.size(); ++i) {
241         dbg << i
242             << format.namesAndTypes[i].jointIndex
243             << format.namesAndTypes[i].jointName
244             << format.namesAndTypes[i].name
245             << format.namesAndTypes[i].type
246             << "formatted results dst indices =" << format.formattedComponentIndices[i];
247         const int componentCount = format.formattedComponentIndices[i].size();
248 
249         dbg << "clip src indices =";
250         for (int j = sourceIndex; j < sourceIndex + componentCount; ++j)
251             dbg << format.sourceClipIndices[j] << "";
252 
253         dbg << "src clip mask =" << format.sourceClipMask[i];
254         dbg << Qt::endl;
255         sourceIndex += componentCount;
256     }
257     return dbg;
258 }
259 #endif
260 
261 struct AnimationCallbackAndValue
262 {
263     QAnimationCallback *callback;
264     QAnimationCallback::Flags flags;
265     QVariant value;
266 };
267 
268 struct AnimationRecord {
269     struct TargetChange {
TargetChangeAnimationRecord::TargetChange270         TargetChange(Qt3DCore::QNodeId id, const char *name, QVariant v)
271             : targetId(id), propertyName(name), value(v) {
272 
273         }
274 
275         Qt3DCore::QNodeId targetId;
276         const char *propertyName = nullptr;
277         QVariant value;
278     };
279 
280     Qt3DCore::QNodeId animatorId;
281     QVector<TargetChange> targetChanges;
282     QVector<QPair<Qt3DCore::QNodeId, QVector<Qt3DCore::Sqt>>> skeletonChanges;
283     float normalizedTime = -1.f;
284     bool finalFrame = false;
285 };
286 
287 Q_AUTOTEST_EXPORT
288 AnimationRecord prepareAnimationRecord(Qt3DCore::QNodeId animatorId,
289                                        const QVector<MappingData> &mappingDataVec,
290                                        const QVector<float> &channelResults,
291                                        bool finalFrame,
292                                        float normalizedLocalTime);
293 
toSecs(qint64 nsecs)294 inline constexpr double toSecs(qint64 nsecs) { return nsecs / 1.0e9; }
toNsecs(double seconds)295 inline qint64 toNsecs(double seconds) { return qRound64(seconds * 1.0e9); }
296 
297 template<typename Animator>
evaluationDataForAnimator(Animator animator,Clock * clock,qint64 nsSincePreviousFrame)298 AnimatorEvaluationData evaluationDataForAnimator(Animator animator,
299                                                  Clock* clock,
300                                                  qint64 nsSincePreviousFrame)
301 {
302     const bool seeking = animator->isSeeking();
303     AnimatorEvaluationData data;
304     data.loopCount = animator->loops();
305     data.currentLoop = animator->currentLoop();
306     // The playback-rate is always 1.0 when seeking
307     data.playbackRate = ((clock != nullptr) && !seeking) ? clock->playbackRate() : 1.0;
308     // Convert global time from nsec to sec
309     data.elapsedTime = toSecs(nsSincePreviousFrame);
310     // When seeking we base it on the current time being at the start of the clip
311     data.currentTime = seeking ? 0.0 : animator->lastLocalTime();
312     // If we're not seeking the local normalized time will be calculate in
313     // evaluationDataForClip().
314     data.normalizedLocalTime = seeking ? animator->normalizedLocalTime() : -1.0;
315     return data;
316 }
317 
isFinalFrame(double localTime,double duration,int currentLoop,int loopCount,double playbackRate)318 inline bool isFinalFrame(double localTime,
319                          double duration,
320                          int currentLoop,
321                          int loopCount,
322                          double playbackRate)
323 {
324     // We must be on the final loop and
325     // - if playing forward, localTime must be equal or above the duration
326     // - if playing backward, localTime must be equal or below 0
327     if (playbackRate >= 0.0)
328         return (loopCount != 0 && currentLoop >= loopCount - 1 && localTime >= duration);
329     return (loopCount != 0  && currentLoop <= 0 && localTime <= 0);
330 }
331 
isValidNormalizedTime(float t)332 inline bool isValidNormalizedTime(float t)
333 {
334     return !(t < 0.0f) && !(t > 1.0f);
335 }
336 
337 Q_AUTOTEST_EXPORT
338 ClipEvaluationData evaluationDataForClip(AnimationClip *clip,
339                                          const AnimatorEvaluationData &animatorData);
340 
341 Q_AUTOTEST_EXPORT
342 ComponentIndices channelComponentsToIndices(const Channel &channel,
343                                             int dataType,
344                                             int expectedComponentCount,
345                                             int offset);
346 
347 Q_AUTOTEST_EXPORT
348 ComponentIndices channelComponentsToIndicesHelper(const Channel &channelGroup,
349                                                   int expectedComponentCount,
350                                                   int offset,
351                                                   const QVector<char> &suffixes);
352 
353 Q_AUTOTEST_EXPORT
354 ClipResults evaluateClipAtLocalTime(AnimationClip *clip,
355                                     float localTime);
356 
357 Q_AUTOTEST_EXPORT
358 ClipResults evaluateClipAtPhase(AnimationClip *clip,
359                                 float phase);
360 
361 Q_AUTOTEST_EXPORT
362 QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
363                                                     const QVector<float> &channelResults);
364 
365 Q_AUTOTEST_EXPORT
366 QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping *> &channelMappings,
367                                            const QVector<ChannelNameAndType> &channelNamesAndTypes,
368                                            const QVector<ComponentIndices> &channelComponentIndices,
369                                            const QVector<QBitArray> &sourceClipMask);
370 
371 Q_AUTOTEST_EXPORT
372 QVector<ChannelNameAndType> buildRequiredChannelsAndTypes(Handler *handler,
373                                                           const ChannelMapper *mapper);
374 
375 Q_AUTOTEST_EXPORT
376 QVector<ComponentIndices> assignChannelComponentIndices(const QVector<ChannelNameAndType> &namesAndTypes);
377 
378 Q_AUTOTEST_EXPORT
379 double localTimeFromElapsedTime(double t_current_local, double t_elapsed_global,
380                                 double playbackRate, double duration,
381                                 int loopCount, int &currentLoop);
382 
383 Q_AUTOTEST_EXPORT
384 double phaseFromElapsedTime(double t_current_local, double t_elapsed_global,
385                            double playbackRate, double duration,
386                            int loopCount, int &currentLoop);
387 
388 Q_AUTOTEST_EXPORT
389 QVector<Qt3DCore::QNodeId> gatherValueNodesToEvaluate(Handler *handler,
390                                                       Qt3DCore::QNodeId blendTreeRootId);
391 
392 Q_AUTOTEST_EXPORT
393 ClipFormat generateClipFormatIndices(const QVector<ChannelNameAndType> &targetChannels,
394                                      const QVector<ComponentIndices> &targetIndices,
395                                      const AnimationClip *clip);
396 
397 Q_AUTOTEST_EXPORT
398 ClipResults formatClipResults(const ClipResults &rawClipResults,
399                               const ComponentIndices &format);
400 
401 Q_AUTOTEST_EXPORT
402 ClipResults evaluateBlendTree(Handler *handler,
403                               BlendedClipAnimator *animator,
404                               Qt3DCore::QNodeId blendNodeId);
405 
406 Q_AUTOTEST_EXPORT
407 QVector<float> defaultValueForChannel(Handler *handler, const ChannelNameAndType &channelDescription);
408 
409 Q_AUTOTEST_EXPORT
410 void applyComponentDefaultValues(const QVector<ComponentValue> &componentDefaults,
411                                  ClipResults &formattedClipResults);
412 
413 } // Animation
414 } // Qt3DAnimation
415 
416 QT_END_NAMESPACE
417 
418 Q_DECLARE_METATYPE(Qt3DAnimation::Animation::AnimationRecord) // LCOV_EXCL_LINE
419 
420 
421 #endif // QT3DANIMATION_ANIMATION_ANIMATIONUTILS_P_H
422