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 #include "evaluateblendclipanimatorjob_p.h"
38 #include <Qt3DCore/private/qaspectmanager_p.h>
39 #include <Qt3DCore/private/qskeleton_p.h>
40 #include <Qt3DAnimation/qblendedclipanimator.h>
41 #include <Qt3DAnimation/private/handler_p.h>
42 #include <Qt3DAnimation/private/managers_p.h>
43 #include <Qt3DAnimation/private/animationlogging_p.h>
44 #include <Qt3DAnimation/private/animationutils_p.h>
45 #include <Qt3DAnimation/private/clipblendvalue_p.h>
46 #include <Qt3DAnimation/private/lerpclipblend_p.h>
47 #include <Qt3DAnimation/private/clipblendnodevisitor_p.h>
48 #include <Qt3DAnimation/private/job_common_p.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 namespace Qt3DAnimation {
53 namespace Animation {
54 
EvaluateBlendClipAnimatorJob()55 EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob()
56     : AbstractEvaluateClipAnimatorJob()
57     , m_handler(nullptr)
58 {
59     SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0)
60 }
61 
run()62 void EvaluateBlendClipAnimatorJob::run()
63 {
64     // Find the set of clips that need to be evaluated by querying each node
65     // in the blend tree.
66     // TODO: We should be able to cache this for each blend animator and only
67     // update when a node indicates its dependencies have changed as a result
68     // of blend factors changing
69 
70     BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle);
71     Q_ASSERT(blendedClipAnimator);
72     const bool running = blendedClipAnimator->isRunning();
73     const bool seeking = blendedClipAnimator->isSeeking();
74     if (!running && !seeking) {
75         m_handler->setBlendedClipAnimatorRunning(m_blendClipAnimatorHandle, false);
76         return;
77     }
78 
79     Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId();
80     const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId);
81 
82     // Calculate the resulting duration of the blend tree based upon its current state
83     ClipBlendNodeManager *blendNodeManager = m_handler->clipBlendNodeManager();
84     ClipBlendNode *blendTreeRootNode = blendNodeManager->lookupNode(blendTreeRootId);
85     Q_ASSERT(blendTreeRootNode);
86     const double duration = blendTreeRootNode->duration();
87 
88     Clock *clock = m_handler->clockManager()->lookupResource(blendedClipAnimator->clockId());
89 
90     qint64 globalTimeNS = m_handler->simulationTime();
91     qint64 nsSincePreviousFrame = seeking ? toNsecs(duration * blendedClipAnimator->normalizedLocalTime())
92                                           : blendedClipAnimator->nsSincePreviousFrame(globalTimeNS);
93 
94     // Calculate the phase given the blend tree duration and global time
95     AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, nsSincePreviousFrame);
96     const double phase = phaseFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime,
97                                               animatorData.playbackRate,
98                                               duration,
99                                               animatorData.loopCount,
100                                               animatorData.currentLoop);
101 
102     // Iterate over the value nodes of the blend tree, evaluate the
103     // contained animation clips at the current phase and store the results
104     // in the animator indexed by node.
105     AnimationClipLoaderManager *clipLoaderManager = m_handler->animationClipLoaderManager();
106     for (const auto valueNodeId : valueNodeIdsToEvaluate) {
107         ClipBlendValue *valueNode = static_cast<ClipBlendValue *>(blendNodeManager->lookupNode(valueNodeId));
108         Q_ASSERT(valueNode);
109         AnimationClip *clip = clipLoaderManager->lookupResource(valueNode->clipId());
110         Q_ASSERT(clip);
111 
112         ClipResults rawClipResults = evaluateClipAtPhase(clip, float(phase));
113 
114         // Reformat the clip results into the layout used by this animator/blend tree
115         const ClipFormat format = valueNode->clipFormat(blendedClipAnimator->peerId());
116         ClipResults formattedClipResults = formatClipResults(rawClipResults, format.sourceClipIndices);
117         applyComponentDefaultValues(format.defaultComponentValues, formattedClipResults);
118         valueNode->setClipResults(blendedClipAnimator->peerId(), formattedClipResults);
119     }
120 
121     // Evaluate the blend tree
122     ClipResults blendedResults = evaluateBlendTree(m_handler, blendedClipAnimator, blendTreeRootId);
123 
124     const double localTime = phase * duration;
125     blendedClipAnimator->setLastGlobalTimeNS(globalTimeNS);
126     blendedClipAnimator->setLastLocalTime(localTime);
127     blendedClipAnimator->setLastNormalizedLocalTime(float(phase));
128     blendedClipAnimator->setCurrentLoop(animatorData.currentLoop);
129 
130     // Prepare the change record
131     const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount, animatorData.playbackRate);
132     const QVector<MappingData> mappingData = blendedClipAnimator->mappingData();
133     auto record = prepareAnimationRecord(blendedClipAnimator->peerId(),
134                                          mappingData,
135                                          blendedResults,
136                                          finalFrame,
137                                          float(phase));
138 
139     // Trigger callbacks either on this thread or by notifying the gui thread.
140     auto callbacks = prepareCallbacks(mappingData, blendedResults);
141 
142     // Update the normalized time on the backend node so that
143     // frontend <-> backend sync will not mark things dirty
144     // unless the frontend normalized time really is different
145     blendedClipAnimator->setNormalizedLocalTime(record.normalizedTime, false);
146 
147     setPostFrameData(record, callbacks);
148 }
149 
150 } // Animation
151 } // Qt3DAnimation
152 
153 QT_END_NAMESPACE
154