summaryrefslogtreecommitdiffstats
path: root/src/animation/backend/evaluateblendclipanimatorjob.cpp
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2017-01-31 11:57:02 +0100
committerPaul Lemire <paul.lemire@kdab.com>2017-01-31 14:09:55 +0000
commitc35f8e7c5f573fcc89b3042157d5843d9322ac90 (patch)
tree441f70a284d957056d917842b76881fe6420b13e /src/animation/backend/evaluateblendclipanimatorjob.cpp
parent26b1dd88d374b17314218584487a383e3d558018 (diff)
BlendedAnimations: allow nested blending nodes evaluation
Change-Id: Ic6a70ee57f56dff7406b5917d620ea15b74ecb44 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/animation/backend/evaluateblendclipanimatorjob.cpp')
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob.cpp175
1 files changed, 125 insertions, 50 deletions
diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp
index 349156f39..0f79edbe6 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp
@@ -40,6 +40,7 @@
#include <Qt3DAnimation/private/animationlogging_p.h>
#include <Qt3DAnimation/private/animationutils_p.h>
#include <Qt3DAnimation/private/lerpblend_p.h>
+#include <Qt3DAnimation/private/clipblendnodevisitor_p.h>
QT_BEGIN_NAMESPACE
@@ -48,63 +49,32 @@ namespace Animation {
EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob()
: Qt3DCore::QAspectJob()
+ , m_currentLoop(std::numeric_limits<int>::max())
+ , m_isFinalFrame(true)
{
// TO DO: Add Profiler ID
}
-void EvaluateBlendClipAnimatorJob::run()
-{
- const qint64 globalTime = m_handler->simulationTime();
-
- BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle);
- Q_ASSERT(blendedClipAnimator);
-
- // TO DO: Right now we are doing LERP but refactor to handle other types
- ClipBlendNode *blendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId());
-
- const Qt3DCore::QNodeIdVector clipIds = blendNode->clipIds();
-
- // Evaluate the fcurves for both clip
- AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(clipIds.first());
- AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(clipIds.last());
- Q_ASSERT(clip1 && clip2);
-
- // Prepare for evaluation (convert global time to local time ....)
- const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime);
- const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData);
- const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData);
-
- // Evaluate the clips
- const QVector<float> channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime);
- const QVector<float> channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime);
+namespace {
- // Update loops and running of the animator
- blendedClipAnimator->setCurrentLoop(std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop));
- const bool isFinalFrame = preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame;
- if (isFinalFrame)
- blendedClipAnimator->setRunning(false);
-
- // Perform blending between the two clips
- QVector<AnimationUtils::MappingData> blendedMappingData;
+QVector<float> blendValuesBasedOnMappings(ClipBlendNode *node,
+ const QVector<float> &channelResults1,
+ const QVector<float> &channelResults2,
+ const QVector<AnimationUtils::BlendingMappingData> &blendingMappingData)
+{
QVector<float> blendedValues;
+ blendedValues.reserve(blendingMappingData.size());
// Build a combined vector of blended value
- const QVector<AnimationUtils::BlendingMappingData> blendingMappingData = blendedClipAnimator->mappingData();
for (const AnimationUtils::BlendingMappingData &mapping : blendingMappingData) {
- AnimationUtils::MappingData finalMapping;
- finalMapping.type = mapping.type;
- finalMapping.targetId = mapping.targetId;
- finalMapping.propertyName = mapping.propertyName;
-
switch (mapping.blendAction) {
case AnimationUtils::BlendingMappingData::ClipBlending: {
Q_ASSERT(mapping.channelIndicesClip1.size() == mapping.channelIndicesClip2.size());
for (int i = 0, m = mapping.channelIndicesClip1.size(); i < m; ++i) {
- const float value1 = channelResultsClip1.at(mapping.channelIndicesClip1[i]);
- const float value2 = channelResultsClip2.at(mapping.channelIndicesClip2[i]);
- const float blendedValue = blendNode->blend(value1, value2);
- finalMapping.channelIndices.push_back(blendedValues.size());
+ const float value1 = channelResults1.at(mapping.channelIndicesClip1[i]);
+ const float value2 = channelResults2.at(mapping.channelIndicesClip2[i]);
+ const float blendedValue = node->blend(value1, value2);
blendedValues.push_back(blendedValue);
}
break;
@@ -112,10 +82,9 @@ void EvaluateBlendClipAnimatorJob::run()
case AnimationUtils::BlendingMappingData::NoBlending: {
const bool useClip1 = !mapping.channelIndicesClip1.empty();
const QVector<int> channelIndices = useClip1 ? mapping.channelIndicesClip1 : mapping.channelIndicesClip2;
- const QVector<float> values = useClip1 ? channelResultsClip1 : channelResultsClip2;
+ const QVector<float> values = useClip1 ? channelResults1 : channelResults2;
for (int i = 0, m = channelIndices.size(); i < m; ++i) {
const float value = values.at(channelIndices[i]);
- finalMapping.channelIndices.push_back(blendedValues.size());
blendedValues.push_back(value);
}
break;
@@ -124,21 +93,127 @@ void EvaluateBlendClipAnimatorJob::run()
Q_UNREACHABLE();
break;
}
+ }
+ return blendedValues;
+}
- blendedMappingData.push_back(finalMapping);
+QVector<AnimationUtils::MappingData> fromBlendingMappingData(const QVector<AnimationUtils::BlendingMappingData> &blendingMappingData)
+{
+ const int blendingMappingDataSize = blendingMappingData.size();
+ QVector<AnimationUtils::MappingData> mappingData(blendingMappingDataSize);
+ for (int i = 0; i < blendingMappingDataSize; ++i) {
+ mappingData[i] = blendingMappingData[i];
}
+ return mappingData;
+}
+
+} // anonymous
+
+void EvaluateBlendClipAnimatorJob::blendClips(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData,
+ const AnimationUtils::AnimatorEvaluationData &animatorEvaluationData)
+{
+ AnimationClip *clip1 = m_handler->animationClipManager()->lookupResource(nodeData.left);
+ AnimationClip *clip2 = m_handler->animationClipManager()->lookupResource(nodeData.right);
+ Q_ASSERT(clip1 && clip2);
+
+ // Prepare for evaluation (convert global time to local time ....)
+ const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip1 = AnimationUtils::evaluationDataForClip(clip1, animatorEvaluationData);
+ const AnimationUtils::ClipPreEvaluationData preEvaluationDataForClip2 = AnimationUtils::evaluationDataForClip(clip2, animatorEvaluationData);
+
+ // Evaluate the fcurves for both clip
+ const QVector<float> channelResultsClip1 = AnimationUtils::evaluateClipAtLocalTime(clip1, preEvaluationDataForClip1.localTime);
+ const QVector<float> channelResultsClip2 = AnimationUtils::evaluateClipAtLocalTime(clip2, preEvaluationDataForClip2.localTime);
+
+ // Update loops and running of the animator
+ m_currentLoop = std::min(m_currentLoop, std::min(preEvaluationDataForClip1.currentLoop, preEvaluationDataForClip2.currentLoop));
+ // isFinalFrame remains true only if all the clips have reached their final frame
+ m_isFinalFrame &= (preEvaluationDataForClip1.isFinalFrame && preEvaluationDataForClip2.isFinalFrame);
+
+ const QVector<AnimationUtils::BlendingMappingData> blendingMappingData = nodeData.mappingData;
+ // Perform blending between the two clips
+ const QVector<float> blendedValues = blendValuesBasedOnMappings(node, channelResultsClip1,
+ channelResultsClip2, blendingMappingData);
+
+ m_clipBlendResultsTable.insert(node, blendedValues);
+}
+
+void EvaluateBlendClipAnimatorJob::blendNodes(ClipBlendNode *node, const BlendedClipAnimator::BlendNodeData &nodeData)
+{
+ ClipBlendNode *node1 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.left);
+ ClipBlendNode *node2 = m_handler->clipBlendNodeManager()->lookupNode(nodeData.right);
+ Q_ASSERT(node1 && node2);
+
+ // Retrieve results for the childNodes
+ const QVector<float> channelResultsNode1 = m_clipBlendResultsTable.take(node1);
+ const QVector<float> channelResultsNode2 = m_clipBlendResultsTable.take(node2);
+
+ // Build a combined vector of blended value
+ const QVector<AnimationUtils::BlendingMappingData> blendingMappingData = nodeData.mappingData;
+ // Perform blending between the two nodes
+ const QVector<float> blendedValues = blendValuesBasedOnMappings(node, channelResultsNode1,
+ channelResultsNode2, blendingMappingData);
+
+ m_clipBlendResultsTable.insert(node, blendedValues);
+}
+
+void EvaluateBlendClipAnimatorJob::run()
+{
+ const qint64 globalTime = m_handler->simulationTime();
+
+ BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle);
+ Q_ASSERT(blendedClipAnimator);
+
+ const AnimationUtils::AnimatorEvaluationData animatorEvaluationData = AnimationUtils::animatorEvaluationDataForAnimator(blendedClipAnimator, globalTime);
+ const QHash<Qt3DCore::QNodeId, BlendedClipAnimator::BlendNodeData> blendindNodeTable = blendedClipAnimator->blendTreeTable();
+
+ // Reset globals
+ m_currentLoop = std::numeric_limits<int>::max();
+ m_isFinalFrame = true;
+
+ // Perform blending of the tree (Post-order traversal)
+ ClipBlendNodeVisitor visitor(m_handler->clipBlendNodeManager());
+ visitor.traverse(blendedClipAnimator->blendTreeRootId(), [&, this] (ClipBlendNode *blendNode) {
+ // Retrieve BlendingData for the not
+ const BlendedClipAnimator::BlendNodeData &nodeData = blendindNodeTable.value(blendNode->peerId());
+
+ switch (nodeData.type) {
+ case BlendedClipAnimator::BlendNodeData::BlendNodeType:
+ // Blend two ClipBlendNode
+ blendNodes(blendNode, nodeData);
+ break;
+ case BlendedClipAnimator::BlendNodeData::ClipType: // Leaf
+ // Blend two clips
+ blendClips(blendNode, nodeData, animatorEvaluationData);
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ });
+
+
+ // Set current loop and running if need
+ if (m_isFinalFrame)
+ blendedClipAnimator->setRunning(false);
+ blendedClipAnimator->setCurrentLoop(m_currentLoop);
+
+ // Prepare property changes using the root node which should now be filled with correct values
+ ClipBlendNode *rootBlendNode = m_handler->clipBlendNodeManager()->lookupNode(blendedClipAnimator->blendTreeRootId());
+ Q_ASSERT(m_clipBlendResultsTable.size() == 1 && m_clipBlendResultsTable.contains(rootBlendNode));
+
+ const QVector<float> blendedValues = m_clipBlendResultsTable.take(rootBlendNode);
+ const BlendedClipAnimator::BlendNodeData &rootNodeData = blendindNodeTable.value(rootBlendNode->peerId());
+ const QVector<AnimationUtils::MappingData> mappingData = fromBlendingMappingData(rootNodeData.mappingData);
// Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend)
const QVector<Qt3DCore::QSceneChangePtr> changes = AnimationUtils::preparePropertyChanges(blendedClipAnimator->peerId(),
- blendedMappingData,
+ mappingData,
blendedValues,
- isFinalFrame);
-
+ m_isFinalFrame);
// Send the property changes
blendedClipAnimator->sendPropertyChanges(changes);
}
-
} // Animation
} // Qt3DAnimation