diff --git a/src/game/meshinstance.cpp b/src/game/meshinstance.cpp index 6109e44..957b439 100644 --- a/src/game/meshinstance.cpp +++ b/src/game/meshinstance.cpp @@ -65,7 +65,7 @@ void game::MeshInstance::UpdateBoneMatrices() } } -void game::MeshInstance::PlayAnim(const std::string& name) +void game::MeshInstance::PlayAnim(const std::string& name, int flags) { if (!IsSkeletal()) { @@ -75,7 +75,9 @@ void game::MeshInstance::PlayAnim(const std::string& name) const auto& skeleton = mesh_->GetSkeleton(); current_anim_ = skeleton->GetAnimation(name); // Can be nullptr - anim_time_ = 0.0f; + anim_start_ = *time_ptr_; + anim_flags_ = flags; + anim_done_ = false; } void game::MeshInstance::Update() @@ -119,28 +121,42 @@ const gfx::UniformBuffer& game::MeshInstance::GetBoneUBO() void game::MeshInstance::ApplyAnimFrame() { - ApplySkelAnim(current_anim_, anim_time_, 1.0f); + if (!current_anim_) + { + return; // No animation to apply + } + + float anim_time = *time_ptr_ - anim_start_; + float anim_duration = current_anim_->GetDuration(); + + if (!(anim_flags_ & ANIM_LOOP) && anim_time >= anim_duration) + { + anim_done_ = true; + anim_time = anim_duration; + } + + ApplySkelAnim(*current_anim_, anim_time, 1.0f); } -void game::MeshInstance::ApplySkelAnim(const assets::Animation* anim, float time, float weight) +void game::MeshInstance::ApplySkelAnim(const assets::Animation& anim, float time, float weight) { - float anim_frame = (*time_ptr_ - time) * anim->GetTPS(); + float anim_frame = time * anim.GetTPS(); if (anim_frame < 0.0f) { anim_frame = 0.0f; } - size_t num_anim_frames = anim->GetNumFrames(); + size_t num_anim_frames = anim.GetNumFrames(); size_t frame_i = static_cast(anim_frame); size_t frame0 = frame_i % num_anim_frames; size_t frame1 = (frame_i + 1) % num_anim_frames; float t = anim_frame - static_cast(frame_i); - for (size_t i = 0; i < anim->GetNumChannels(); ++i) + for (size_t i = 0; i < anim.GetNumChannels(); ++i) { - const assets::AnimationChannel& channel = anim->GetChannel(i); + const assets::AnimationChannel& channel = anim.GetChannel(i); TransformNode& node = bone_nodes_[channel.bone_index]; const Transform* t0 = channel.frames[frame0]; diff --git a/src/game/meshinstance.hpp b/src/game/meshinstance.hpp index 33c4fdb..04b1cf7 100644 --- a/src/game/meshinstance.hpp +++ b/src/game/meshinstance.hpp @@ -6,6 +6,11 @@ namespace game { + enum PlayAnimFlags + { + ANIM_LOOP = 1 << 0, + }; + class MeshInstance { std::shared_ptr mesh_; @@ -20,14 +25,16 @@ namespace game bool bone_ubo_dirty_ = true; const assets::Animation* current_anim_ = nullptr; - float anim_time_ = 0.0f; + float anim_start_ = 0.0f; + int anim_flags_ = 0; + bool anim_done_ = false; public: MeshInstance(std::shared_ptr mesh, const TransformNode* root_node, const float* time_ptr); bool IsSkeletal() const { return skeletal_; } - void PlayAnim(const std::string& name); + void PlayAnim(const std::string& name, int flags = 0); void Update(); @@ -38,6 +45,8 @@ namespace game const TransformNode& GetBoneNode(size_t index) const { return bone_nodes_[index]; } const TransformNode* GetBoneNodeByName(const std::string& name) const; + bool AnimDone() const { return anim_done_; } + private: void SetupBoneNodes(); void UpdateBoneMatrices(); @@ -47,7 +56,7 @@ namespace game virtual void ApplyAnimFrame(); private: - void ApplySkelAnim(const assets::Animation* anim, float time, float weight); + void ApplySkelAnim(const assets::Animation& anim, float time, float weight); }; } \ No newline at end of file