diff --git a/ios/include/components/AnimationComponentManager.hpp b/ios/include/components/AnimationComponentManager.hpp index 72083940..d7cb719c 100644 --- a/ios/include/components/AnimationComponentManager.hpp +++ b/ios/include/components/AnimationComponentManager.hpp @@ -3,6 +3,7 @@ #include "Log.hpp" #include +#include #include #include @@ -22,33 +23,40 @@ #include template class std::vector; -namespace flutter_filament { +namespace flutter_filament +{ using namespace filament; using namespace filament::gltfio; using namespace utils; using namespace std::chrono; - typedef std::chrono::time_point time_point_t; + typedef std::chrono::time_point time_point_t; - enum AnimationType { - MORPH, BONE, GLTF + enum AnimationType + { + MORPH, + BONE, + GLTF }; - struct AnimationStatus { + struct AnimationStatus + { time_point_t start = time_point_t::max(); bool loop = false; bool reverse = false; - float durationInSecs = 0; + float durationInSecs = 0; }; - struct GltfAnimation : AnimationStatus { - int index = -1; + struct GltfAnimation : AnimationStatus + { + int index = -1; }; - // + // // Use this to construct a dynamic (i.e. non-glTF embedded) morph target animation. // - struct MorphAnimation : AnimationStatus { + struct MorphAnimation : AnimationStatus + { utils::Entity meshTarget; int numFrames = -1; float frameLengthInMs = 0; @@ -57,10 +65,11 @@ namespace flutter_filament { int lengthInFrames; }; - // + // // Use this to construct a dynamic (i.e. non-glTF embedded) bone/joint animation. // - struct BoneAnimation : AnimationStatus { + struct BoneAnimation : AnimationStatus + { size_t boneIndex; std::vector meshTargets; size_t skinIndex = 0; @@ -69,67 +78,85 @@ namespace flutter_filament { std::vector frameData; }; - struct AnimationComponent { - FilamentInstance* instance; + struct AnimationComponent + { + std::variant target; std::vector initialJointTransforms; std::vector gltfAnimations; std::vector morphAnimations; std::vector boneAnimations; - - // the index of the last active glTF animation, + + // the index of the last active glTF animation, // used to cross-fade int fadeGltfAnimationIndex = -1; float fadeDuration = 0.0f; float fadeOutAnimationStart = 0.0f; - }; + class AnimationComponentManager : public utils::SingleInstanceComponentManager + { - class AnimationComponentManager : public utils::SingleInstanceComponentManager { + filament::TransformManager &_transformManager; + filament::RenderableManager &_renderableManager; - filament::TransformManager& _transformManager; - filament::RenderableManager& _renderableManager; + public: + AnimationComponentManager( + filament::TransformManager &transformManager, + filament::RenderableManager &renderableManager) : _transformManager(transformManager), + _renderableManager(renderableManager){}; - public: - AnimationComponentManager( - filament::TransformManager& transformManager, - filament::RenderableManager& renderableManager) : - _transformManager(transformManager), - _renderableManager(renderableManager) {}; - - void addAnimationComponent(FilamentInstance* instance) { + void addAnimationComponent(std::variant target) + { + AnimationComponent animationComponent; + animationComponent.target = target; + EntityInstanceBase::Type componentInstance; + if (std::holds_alternative(target)) + { + auto instance = std::get(target); const auto joints = instance->getJointsAt(0); - AnimationComponent animationComponent; - animationComponent.instance = instance; - for(int i = 0; i < instance->getJointCountAt(0); i++) { + + for (int i = 0; i < instance->getJointCountAt(0); i++) + { const auto joint = joints[i]; - const auto& jointTransformInstance = _transformManager.getInstance(joint); - const auto& jointTransform = _transformManager.getTransform(jointTransformInstance); + const auto &jointTransformInstance = _transformManager.getInstance(joint); + const auto &jointTransform = _transformManager.getTransform(jointTransformInstance); animationComponent.initialJointTransforms.push_back(jointTransform); } - auto componentInstance = addComponent(instance->getRoot()); - this->elementAt<0>(componentInstance) = animationComponent; + componentInstance = addComponent(instance->getRoot()); + } + else + { + componentInstance = addComponent(std::get(target)); } - void update() + this->elementAt<0>(componentInstance) = animationComponent; + } + + void update() + { + auto now = high_resolution_clock::now(); + + for (auto it = begin(); it < end(); it++) { - auto now = high_resolution_clock::now(); + const auto &entity = getEntity(it); - // Log("animation component count : %d", ) + Log("Updating anim for entity %d", entity); - for(auto it = begin(); it < end(); it++) { - const auto& entity = getEntity(it); - - auto componentInstance = getInstance(entity); - auto& animationComponent = elementAt<0>(componentInstance); + auto componentInstance = getInstance(entity); + auto &animationComponent = elementAt<0>(componentInstance); + + auto &morphAnimations = animationComponent.morphAnimations; + + if (std::holds_alternative(animationComponent.target)) + { + auto target = std::get(animationComponent.target); + auto animator = target->getAnimator(); + auto &gltfAnimations = animationComponent.gltfAnimations; + auto &boneAnimations = animationComponent.boneAnimations; + + for (int i = ((int)gltfAnimations.size()) - 1; i >= 0; i--) + { - auto animator = animationComponent.instance->getAnimator(); - auto& gltfAnimations = animationComponent.gltfAnimations; - auto& morphAnimations = animationComponent.morphAnimations; - auto& boneAnimations = animationComponent.boneAnimations; - - for (int i = ((int)gltfAnimations.size()) - 1; i >= 0; i--) { - auto animationStatus = animationComponent.gltfAnimations[i]; auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; @@ -155,38 +182,8 @@ namespace flutter_filament { animator->updateBoneMatrices(); - for (int i = (int)morphAnimations.size() - 1; i >= 0; i--) { - - auto animationStatus = morphAnimations[i]; - - auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; - - if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) - { - morphAnimations.erase(morphAnimations.begin() + i); - continue; - } - - - int frameNumber = static_cast(elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs) % animationStatus.lengthInFrames; - // offset from the end if reverse - if (animationStatus.reverse) - { - frameNumber = animationStatus.lengthInFrames - frameNumber; - } - auto baseOffset = frameNumber * animationStatus.morphIndices.size(); - for (int i = 0; i < animationStatus.morphIndices.size(); i++) - { - auto morphIndex = animationStatus.morphIndices[i]; - // set the weights appropriately - _renderableManager.setMorphWeights( - _renderableManager.getInstance(animationStatus.meshTarget), - animationStatus.frameData.data() + baseOffset + i, - 1, - morphIndex); - } - } - for (int i = (int)boneAnimations.size() - 1; i >= 0; i--) { + for (int i = (int)boneAnimations.size() - 1; i >= 0; i--) + { auto animationStatus = boneAnimations[i]; auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; @@ -196,9 +193,9 @@ namespace flutter_filament { boneAnimations.erase(boneAnimations.begin() + i); continue; } - + float elapsedFrames = elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs; - + int currFrame = static_cast(elapsedFrames) % animationStatus.lengthInFrames; float delta = elapsedFrames - currFrame; int nextFrame = currFrame; @@ -208,30 +205,38 @@ namespace flutter_filament { if (animationStatus.reverse) { currFrame = animationStatus.lengthInFrames - currFrame; - if(currFrame > 0) { + if (currFrame > 0) + { nextFrame = currFrame - 1; - } else { + } + else + { nextFrame = 0; } - } else { - if(currFrame < animationStatus.lengthInFrames - 1) { + } + else + { + if (currFrame < animationStatus.lengthInFrames - 1) + { nextFrame = currFrame + 1; - } else { + } + else + { nextFrame = currFrame; } } - + // simple linear interpolation math::mat4f curr = (1 - delta) * (restLocalTransform * animationStatus.frameData[currFrame]); math::mat4f next = delta * (restLocalTransform * animationStatus.frameData[nextFrame]); math::mat4f localTransform = curr + next; - const Entity joint = animationComponent.instance->getJointsAt(animationStatus.skinIndex)[animationStatus.boneIndex]; + const Entity joint = target->getJointsAt(animationStatus.skinIndex)[animationStatus.boneIndex]; auto jointTransform = _transformManager.getInstance(joint); - + _transformManager.setTransform(jointTransform, localTransform); - + animator->updateBoneMatrices(); if (animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) @@ -240,7 +245,38 @@ namespace flutter_filament { } } } - } - }; + for (int i = (int)morphAnimations.size() - 1; i >= 0; i--) + { + auto animationStatus = morphAnimations[i]; + + auto elapsedInSecs = float(std::chrono::duration_cast(now - animationStatus.start).count()) / 1000.0f; + + if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs) + { + morphAnimations.erase(morphAnimations.begin() + i); + continue; + } + + int frameNumber = static_cast(elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs) % animationStatus.lengthInFrames; + // offset from the end if reverse + if (animationStatus.reverse) + { + frameNumber = animationStatus.lengthInFrames - frameNumber; + } + auto baseOffset = frameNumber * animationStatus.morphIndices.size(); + for (int i = 0; i < animationStatus.morphIndices.size(); i++) + { + auto morphIndex = animationStatus.morphIndices[i]; + // set the weights appropriately + _renderableManager.setMorphWeights( + _renderableManager.getInstance(animationStatus.meshTarget), + animationStatus.frameData.data() + baseOffset + i, + 1, + morphIndex); + } + } + } + } + }; }