| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: http://www.qt-project.org/legal |
| ** |
| ** This file is part of the Qt3D module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL3$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see http://www.qt.io/terms-conditions. For further |
| ** information use the contact form at http://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or later as published by the Free |
| ** Software Foundation and appearing in the file LICENSE.GPL included in |
| ** the packaging of this file. Please review the following information to |
| ** ensure the GNU General Public License version 2.0 requirements will be |
| ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "evaluateblendclipanimatorjob_p.h" |
| #include <Qt3DCore/private/qaspectmanager_p.h> |
| #include <Qt3DCore/private/qskeleton_p.h> |
| #include <Qt3DAnimation/qblendedclipanimator.h> |
| #include <Qt3DAnimation/private/handler_p.h> |
| #include <Qt3DAnimation/private/managers_p.h> |
| #include <Qt3DAnimation/private/animationlogging_p.h> |
| #include <Qt3DAnimation/private/animationutils_p.h> |
| #include <Qt3DAnimation/private/clipblendvalue_p.h> |
| #include <Qt3DAnimation/private/lerpclipblend_p.h> |
| #include <Qt3DAnimation/private/clipblendnodevisitor_p.h> |
| #include <Qt3DAnimation/private/job_common_p.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| namespace Qt3DAnimation { |
| namespace Animation { |
| |
| EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob() |
| : AbstractEvaluateClipAnimatorJob() |
| , m_handler(nullptr) |
| { |
| SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0) |
| } |
| |
| void EvaluateBlendClipAnimatorJob::run() |
| { |
| // Find the set of clips that need to be evaluated by querying each node |
| // in the blend tree. |
| // TODO: We should be able to cache this for each blend animator and only |
| // update when a node indicates its dependencies have changed as a result |
| // of blend factors changing |
| |
| BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); |
| Q_ASSERT(blendedClipAnimator); |
| const bool running = blendedClipAnimator->isRunning(); |
| const bool seeking = blendedClipAnimator->isSeeking(); |
| if (!running && !seeking) { |
| m_handler->setBlendedClipAnimatorRunning(m_blendClipAnimatorHandle, false); |
| return; |
| } |
| |
| Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId(); |
| const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId); |
| |
| // Calculate the resulting duration of the blend tree based upon its current state |
| ClipBlendNodeManager *blendNodeManager = m_handler->clipBlendNodeManager(); |
| ClipBlendNode *blendTreeRootNode = blendNodeManager->lookupNode(blendTreeRootId); |
| Q_ASSERT(blendTreeRootNode); |
| const double duration = blendTreeRootNode->duration(); |
| |
| Clock *clock = m_handler->clockManager()->lookupResource(blendedClipAnimator->clockId()); |
| |
| qint64 globalTimeNS = m_handler->simulationTime(); |
| qint64 nsSincePreviousFrame = seeking ? toNsecs(duration * blendedClipAnimator->normalizedLocalTime()) |
| : blendedClipAnimator->nsSincePreviousFrame(globalTimeNS); |
| |
| // Calculate the phase given the blend tree duration and global time |
| AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, nsSincePreviousFrame); |
| const double phase = phaseFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime, |
| animatorData.playbackRate, |
| duration, |
| animatorData.loopCount, |
| animatorData.currentLoop); |
| |
| // Iterate over the value nodes of the blend tree, evaluate the |
| // contained animation clips at the current phase and store the results |
| // in the animator indexed by node. |
| AnimationClipLoaderManager *clipLoaderManager = m_handler->animationClipLoaderManager(); |
| for (const auto valueNodeId : valueNodeIdsToEvaluate) { |
| ClipBlendValue *valueNode = static_cast<ClipBlendValue *>(blendNodeManager->lookupNode(valueNodeId)); |
| Q_ASSERT(valueNode); |
| AnimationClip *clip = clipLoaderManager->lookupResource(valueNode->clipId()); |
| Q_ASSERT(clip); |
| |
| ClipResults rawClipResults = evaluateClipAtPhase(clip, float(phase)); |
| |
| // Reformat the clip results into the layout used by this animator/blend tree |
| const ClipFormat format = valueNode->clipFormat(blendedClipAnimator->peerId()); |
| ClipResults formattedClipResults = formatClipResults(rawClipResults, format.sourceClipIndices); |
| applyComponentDefaultValues(format.defaultComponentValues, formattedClipResults); |
| valueNode->setClipResults(blendedClipAnimator->peerId(), formattedClipResults); |
| } |
| |
| // Evaluate the blend tree |
| ClipResults blendedResults = evaluateBlendTree(m_handler, blendedClipAnimator, blendTreeRootId); |
| |
| const double localTime = phase * duration; |
| blendedClipAnimator->setLastGlobalTimeNS(globalTimeNS); |
| blendedClipAnimator->setLastLocalTime(localTime); |
| blendedClipAnimator->setLastNormalizedLocalTime(float(phase)); |
| blendedClipAnimator->setCurrentLoop(animatorData.currentLoop); |
| |
| // Prepare the change record |
| const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount, animatorData.playbackRate); |
| const QVector<MappingData> mappingData = blendedClipAnimator->mappingData(); |
| auto record = prepareAnimationRecord(blendedClipAnimator->peerId(), |
| mappingData, |
| blendedResults, |
| finalFrame, |
| float(phase)); |
| |
| // Trigger callbacks either on this thread or by notifying the gui thread. |
| auto callbacks = prepareCallbacks(mappingData, blendedResults); |
| |
| // Update the normalized time on the backend node so that |
| // frontend <-> backend sync will not mark things dirty |
| // unless the frontend normalized time really is different |
| blendedClipAnimator->setNormalizedLocalTime(record.normalizedTime, false); |
| |
| setPostFrameData(record, callbacks); |
| } |
| |
| } // Animation |
| } // Qt3DAnimation |
| |
| QT_END_NAMESPACE |