#include "Animation.h" #include "../model/DisplayData.h" #include "../model/AnimationConfig.h" #include "../model/AnimationData.h" #include "../armature/Armature.h" #include "../armature/Bone.h" #include "../armature/Slot.h" #include "AnimationState.h" DRAGONBONES_NAMESPACE_BEGIN void Animation::_onClear() { for (const auto animationState : _animationStates) { animationState->returnToPool(); } if (_animationConfig != nullptr) { _animationConfig->returnToPool(); } timeScale = 1.0f; _animationDirty = false; _inheritTimeScale = 1.0f; _animations.clear(); _animationNames.clear(); _animationStates.clear(); _armature = nullptr; _animationConfig = nullptr; _lastAnimationState = nullptr; } void Animation::_fadeOut(AnimationConfig* animationConfig) { switch (animationConfig->fadeOutMode) { case AnimationFadeOutMode::SameLayer: for (const auto animationState : _animationStates) { if (animationState->layer == (unsigned)animationConfig->layer) { animationState->fadeOut(animationConfig->fadeOutTime, animationConfig->pauseFadeOut); } } break; case AnimationFadeOutMode::SameGroup: for (const auto animationState : _animationStates) { if (animationState->group == animationConfig->group) { animationState->fadeOut(animationConfig->fadeOutTime, animationConfig->pauseFadeOut); } } break; case AnimationFadeOutMode::SameLayerAndGroup: for (const auto animationState : _animationStates) { if (animationState->layer == (unsigned)animationConfig->layer && animationState->group == animationConfig->group) { animationState->fadeOut(animationConfig->fadeOutTime, animationConfig->pauseFadeOut); } } break; case AnimationFadeOutMode::All: for (const auto animationState : _animationStates) { animationState->fadeOut(animationConfig->fadeOutTime, animationConfig->pauseFadeOut); } break; case AnimationFadeOutMode::None: case AnimationFadeOutMode::Single: default: break; } } void Animation::init(Armature* armature) { if (_armature != nullptr) { return; } _armature = armature; _animationConfig = BaseObject::borrowObject(); } void Animation::advanceTime(float passedTime) { if (passedTime < 0.0f) { passedTime = -passedTime; } if (_armature->inheritAnimation && _armature->_parent != nullptr) // Inherit parent animation timeScale. { _inheritTimeScale = _armature->_parent->_armature->getAnimation()->_inheritTimeScale * timeScale; } else { _inheritTimeScale = timeScale; } if (_inheritTimeScale != 1.0f) { passedTime *= _inheritTimeScale; } const auto animationStateCount = _animationStates.size(); if (animationStateCount == 1) { const auto animationState = _animationStates[0]; if (animationState->_fadeState > 0 && animationState->_subFadeState > 0) { _armature->_dragonBones->bufferObject(animationState); _animationStates.clear(); _lastAnimationState = nullptr; } else { const auto animationData = animationState->_animationData; const auto cacheFrameRate = animationData->cacheFrameRate; if (_animationDirty && cacheFrameRate > 0.0f) // Update cachedFrameIndices. { _animationDirty = false; for (const auto bone : _armature->getBones()) { bone->_cachedFrameIndices = animationData->getBoneCachedFrameIndices(bone->getName()); } for (const auto slot : _armature->getSlots()) { const auto rawDisplayDatas = slot->getRawDisplayDatas(); if (rawDisplayDatas != nullptr && !(*rawDisplayDatas).empty()) { const auto rawDsplayData = (*rawDisplayDatas)[0]; if (rawDsplayData != nullptr) { if (rawDsplayData->parent == _armature->getArmatureData()->defaultSkin) { slot->_cachedFrameIndices = animationData->getSlotCachedFrameIndices(slot->getName()); continue; } } } slot->_cachedFrameIndices = nullptr; } } animationState->advanceTime(passedTime, cacheFrameRate); } } else if (animationStateCount > 1) { for (std::size_t i = 0, r = 0; i < animationStateCount; ++i) { const auto animationState = _animationStates[i]; if (animationState->_fadeState > 0 && animationState->_subFadeState > 0) { r++; _armature->_dragonBones->bufferObject(animationState); _animationDirty = true; if (_lastAnimationState == animationState) { _lastAnimationState = nullptr; } } else { if (r > 0) { _animationStates[i - r] = animationState; } animationState->advanceTime(passedTime, 0.0f); } if (i == animationStateCount - 1 && r > 0) { _animationStates.resize(animationStateCount - r); if (_lastAnimationState == nullptr && !_animationStates.empty()) { _lastAnimationState = _animationStates[_animationStates.size() - 1]; } } } _armature->_cacheFrameIndex = -1; } else { _armature->_cacheFrameIndex = -1; } } void Animation::reset() { for (const auto animationState : _animationStates) { animationState->returnToPool(); } _animationDirty = false; _animationConfig->clear(); _animationStates.clear(); _lastAnimationState = nullptr; } void Animation::stop(std::string_view animationName) { if (!animationName.empty()) { const auto animationState = getState(animationName); if (animationState != nullptr) { animationState->stop(); } } else { for (const auto animationState : _animationStates) { animationState->stop(); } } } AnimationState* Animation::playConfig(AnimationConfig* animationConfig) { const auto& animationName = animationConfig->animation; if (_animations.find(animationName) == _animations.end()) { DRAGONBONES_ASSERT(false, "Non-existent animation.\n" + " DragonBones name: " + this->_armature->getArmatureData().parent->name + " Armature name: " + this->_armature->name + " Animation name: " + animationName); return nullptr; } const auto animationData = _animations[animationName]; if (animationConfig->fadeOutMode == AnimationFadeOutMode::Single) { for (const auto animationState : _animationStates) { if (animationState->_animationData == animationData) { return animationState; } } } if (animationConfig->fadeInTime < 0.0f) { if (_animationStates.empty()) { animationConfig->fadeInTime = 0.0f; } else { animationConfig->fadeInTime = animationData->fadeInTime; } } if (animationConfig->fadeOutTime < 0.0f) { animationConfig->fadeOutTime = animationConfig->fadeInTime; } if (animationConfig->timeScale <= -100.0f) { animationConfig->timeScale = 1.0f / animationData->scale; } if (animationData->frameCount > 1) { if (animationConfig->position < 0.0f) { animationConfig->position = fmod(animationConfig->position, animationData->duration); animationConfig->position = animationData->duration - animationConfig->position; } else if (animationConfig->position == animationData->duration) { animationConfig->position -= 0.000001f; // Play a little time before end. } else if (animationConfig->position > animationData->duration) { animationConfig->position = fmod(animationConfig->position, animationData->duration); } if (animationConfig->duration > 0.0f && animationConfig->position + animationConfig->duration > animationData->duration) { animationConfig->duration = animationData->duration - animationConfig->position; } if (animationConfig->playTimes < 0) { animationConfig->playTimes = animationData->playTimes; } } else { animationConfig->playTimes = 1; animationConfig->position = 0.0f; if (animationConfig->duration > 0.0f) { animationConfig->duration = 0.0f; } } if (animationConfig->duration == 0.0f) { animationConfig->duration = -1.0f; } _fadeOut(animationConfig); const auto animationState = BaseObject::borrowObject(); animationState->init(_armature, animationData, animationConfig); _animationDirty = true; _armature->_cacheFrameIndex = -1; if (!_animationStates.empty()) { auto added = false; for (std::size_t i = 0, l = _animationStates.size(); i < l; ++i) { if (animationState->layer > _animationStates[i]->layer) { added = true; auto parentInerator = std::find(_animationStates.begin(), _animationStates.end(), _animationStates[i]); _animationStates.insert(parentInerator, animationState); break; } else if (i != l - 1 && animationState->layer > _animationStates[i + 1]->layer) { added = true; auto parentInerator = std::find(_animationStates.begin(), _animationStates.end(), _animationStates[i]); _animationStates.insert(parentInerator + 1, animationState); break; } } if (!added) { _animationStates.push_back(animationState); } } else { _animationStates.push_back(animationState); } // Child armature play same name animation. for (const auto slot : _armature->getSlots()) { const auto childArmature = slot->getChildArmature(); if (childArmature != nullptr && childArmature->inheritAnimation && childArmature->getAnimation()->hasAnimation(animationName) && childArmature->getAnimation()->getState(animationName) == nullptr) { childArmature->getAnimation()->fadeIn(animationName); // } } if (animationConfig->fadeInTime <= 0.0f) // Blend animation state, update armature. { _armature->advanceTime(0.0f); } _lastAnimationState = animationState; return animationState; } AnimationState* Animation::play(std::string_view animationName, int playTimes) { _animationConfig->clear(); _animationConfig->resetToPose = true; _animationConfig->playTimes = playTimes; _animationConfig->fadeInTime = 0.0f; _animationConfig->animation = animationName; if (!animationName.empty()) { playConfig(_animationConfig); } else if (_lastAnimationState == nullptr) { const auto defaultAnimation = _armature->_armatureData->defaultAnimation; if (defaultAnimation != nullptr) { _animationConfig->animation = defaultAnimation->name; playConfig(_animationConfig); } } else if (!_lastAnimationState->isPlaying() && !_lastAnimationState->isCompleted()) { _lastAnimationState->play(); } else { _animationConfig->animation = _lastAnimationState->name; playConfig(_animationConfig); } return _lastAnimationState; } #ifdef EGRET_WASM AnimationState* Animation::fadeIn(std::string_view animationName, float fadeInTime, int playTimes, int layer, std::string_view group, int fadeOutMode /*AnimationFadeOutMode*/ #else AnimationState* Animation::fadeIn(std::string_view animationName, float fadeInTime, int playTimes, int layer, std::string_view group, AnimationFadeOutMode fadeOutMode #endif // EGRET_WASM ) { _animationConfig->clear(); _animationConfig->fadeOutMode = (AnimationFadeOutMode)fadeOutMode; _animationConfig->playTimes = playTimes; _animationConfig->layer = layer; _animationConfig->fadeInTime = fadeInTime; _animationConfig->animation = animationName; _animationConfig->group = group; return playConfig(_animationConfig); } AnimationState* Animation::gotoAndPlayByTime(std::string_view animationName, float time, int playTimes) { _animationConfig->clear(); _animationConfig->resetToPose = true; _animationConfig->playTimes = playTimes; _animationConfig->position = time; _animationConfig->fadeInTime = 0.0f; _animationConfig->animation = animationName; return playConfig(_animationConfig); } AnimationState* Animation::gotoAndPlayByFrame(std::string_view animationName, unsigned frame, int playTimes) { _animationConfig->clear(); _animationConfig->resetToPose = true; _animationConfig->playTimes = playTimes; _animationConfig->fadeInTime = 0.0f; _animationConfig->animation = animationName; const auto animationData = mapFind(_animations, animationName); if (animationData != nullptr) { _animationConfig->position = animationData->duration * frame / animationData->frameCount; } return playConfig(_animationConfig); } AnimationState* Animation::gotoAndPlayByProgress(std::string_view animationName, float progress, int playTimes) { _animationConfig->clear(); _animationConfig->resetToPose = true; _animationConfig->playTimes = playTimes; _animationConfig->fadeInTime = 0.0f; _animationConfig->animation = animationName; const auto animationData = mapFind(_animations, animationName); if (animationData != nullptr) { _animationConfig->position = animationData->duration * (progress > 0.0f ? progress : 0.0f); } return playConfig(_animationConfig); } AnimationState* Animation::gotoAndStopByTime(std::string_view animationName, float time) { const auto animationState = gotoAndPlayByTime(animationName, time, 1); if (animationState != nullptr) { animationState->stop(); } return animationState; } AnimationState* Animation::gotoAndStopByFrame(std::string_view animationName, unsigned frame) { const auto animationState = gotoAndPlayByFrame(animationName, frame, 1); if (animationState != nullptr) { animationState->stop(); } return animationState; } AnimationState* Animation::gotoAndStopByProgress(std::string_view animationName, float progress) { const auto animationState = gotoAndPlayByProgress(animationName, progress, 1); if (animationState != nullptr) { animationState->stop(); } return animationState; } AnimationState* Animation::getState(std::string_view animationName) const { int i = _animationStates.size(); while (i--) { const auto animationState = _animationStates[i]; if (animationState->name == animationName) { return animationState; } } return nullptr; } bool Animation::hasAnimation(std::string_view animationName) const { return _animations.find(animationName) != _animations.end(); } bool Animation::isPlaying() const { for (const auto animationState : _animationStates) { if (animationState->isPlaying()) { return true; } } return false; } bool Animation::isCompleted() const { for (const auto animationState : _animationStates) { if (!animationState->isCompleted()) { return false; } } return !_animationStates.empty(); } std::string_view Animation::getLastAnimationName() const { if (_lastAnimationState != nullptr) { return _lastAnimationState->name; } static const std::string DEFAULT_NAME = ""; return DEFAULT_NAME; } void Animation::setAnimations(const std::map& value) { if (_animations == value) { return; } _animationNames.clear(); _animations.clear(); for (const auto& pair : value) { _animationNames.push_back(pair.first); _animations[pair.first] = pair.second; } } AnimationConfig* Animation::getAnimationConfig() const { _animationConfig->clear(); return _animationConfig; } DRAGONBONES_NAMESPACE_END