Move animation related classes

This commit is contained in:
Georg Hagen
2025-01-26 18:51:34 +01:00
parent 44f12cf01e
commit dd866cd122
5 changed files with 29 additions and 31 deletions

View File

@@ -0,0 +1,127 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "SequenceAnimationController.hpp"
namespace OpenVulkano::Scene
{
SequenceAnimationController::SequenceAnimationController()
{
m_animationController.OnCompletion += EventHandler(this, &SequenceAnimationController::SequenceCompletedCallback);
}
const SequenceAnimationController::PoseDurationPair& SequenceAnimationController::GetStep(const int index) const
{
return m_steps[std::max(0, std::min(index, static_cast<int>(m_steps.size() - 1)))];
}
void SequenceAnimationController::SequenceCompletedCallback(SimpleAnimationController* ignored)
{
if(m_steps.empty()) return;
if(m_currentStep < m_steps.size() - 1)
{
m_currentStep++;
m_animationController.SetPoses(m_animationController.GetTargetPose(), m_steps[m_currentStep].first);
m_animationController.SetDuration(m_steps[m_currentStep].second);
m_animationController.Reset();
}
else
{
if(m_loop)
{
// NOTE(vb): Maybe compare steps with some epsilon value
if(m_steps.size() > 1 && ((m_steps.front().first == m_steps.back().first) || m_resetTime == 0))
{
m_currentStep = 1;
m_animationController.SetPoses(m_steps[m_currentStep-1].first, m_steps[m_currentStep].first);
m_animationController.SetDuration(m_steps[m_currentStep].second);
m_animationController.Reset();
}
else
{
m_currentStep = 0;
m_animationController.SetPoses(m_steps.back().first, m_steps.front().first);
m_animationController.SetDuration(m_resetTime);
m_animationController.Reset();
}
}
else
{
OnSequenceCompleted.NotifyAll(this);
}
}
}
void SequenceAnimationController::Tick()
{
if(m_steps.empty())
return;
m_animationController.Tick();
}
void SequenceAnimationController::Restart()
{
m_currentStep = 0;
if(!m_steps.empty())
{
m_animationController.SetPoses(m_animationController.GetTargetPose(), m_steps[m_currentStep].first);
m_animationController.SetDuration(m_steps[m_currentStep].second);
}
m_animationController.Reset();
}
bool SequenceAnimationController::IsFinished() const
{
if(m_loop)
return false;
return m_currentStep >= m_steps.size();
}
void SequenceAnimationController::AddAnimationStep(const Math::PoseF &pose, double duration)
{
m_steps.emplace_back(pose, duration);
if(m_steps.size() > 1)
{
m_currentStep = 1;
m_animationController.SetPoses(m_steps[0].first, m_steps[1].first);
m_animationController.SetDuration(m_steps[1].second);
m_animationController.Reset();
}
}
void SequenceAnimationController::AddAnimationSteps(const std::initializer_list<Math::PoseF> poses, double duration)
{
for(const auto& pose : poses)
{
m_steps.emplace_back(pose, duration);
}
if(m_steps.size() > 1)
{
m_currentStep = 1;
m_animationController.SetPoses(m_steps[0].first, m_steps[1].first);
m_animationController.SetDuration(m_steps[1].second);
m_animationController.Reset();
}
}
void SequenceAnimationController::AddAnimationSteps(const std::initializer_list<PoseDurationPair> steps)
{
for(const auto& step : steps)
{
m_steps.emplace_back(step);
}
if(m_steps.size() > 1)
{
m_currentStep = 1;
m_animationController.SetPoses(m_steps[0].first, m_steps[1].first);
m_animationController.SetDuration(m_steps[1].second);
m_animationController.Reset();
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "SimpleAnimationController.hpp"
#include "Base/Event.hpp"
#include "Base/ITickable.hpp"
#include "Math/Math.hpp"
#include "Math/Pose.hpp"
#include <vector>
#include <utility>
#include <initializer_list>
namespace OpenVulkano::Scene
{
class SequenceAnimationController : public ITickable
{
public:
using PoseDurationPair = std::pair<Math::PoseF, double>;
private:
SimpleAnimationController m_animationController;
std::vector<PoseDurationPair> m_steps;
size_t m_currentStep = 0;
bool m_loop = false;
double m_resetTime = 0;
void SequenceCompletedCallback(SimpleAnimationController *animationController);
public:
Event<SequenceAnimationController*> OnSequenceCompleted;
SequenceAnimationController();
/**
* Enables or disables looping of the animation sequence.
*
* When looping is enabled, the sequence will restart from the first step after the last step is completed.
* If the start and end poses of the step list are equal or the reset time is 0, the sequence will jump
* directly to the first step. Otherwise, it will animate the transition back to the first step using the
* reset time set by the user.
*
* @param loop A boolean value to enable or disable looping.
*/
void EnableLoop(const bool loop) { m_loop = loop; }
void SetNode(Node* node) { m_animationController.SetNode(node); }
[[nodiscard]] Node* GetNode() const { return m_animationController.GetNode(); }
/**
* Sets the time to transition back to the first pose when looping is enabled.
*
* If the reset time is set to 0, the sequence will jump directly to the first step. If the start and end poses
* of the step list are equal, the sequence will also jump directly to the first step regardless of the reset time.
* Otherwise, the sequence will animate the transition back to the first step using the reset time.
*
* @param resetTime The time to transition back to the first pose.
* @see GetAnimationPoseResetTime
*/
void SetAnimationPoseResetTime(const double resetTime) { m_resetTime = resetTime; }
/**
* Gets the current reset time for transitioning back to the first pose.
*
* @return The current reset time.
* @see SetAnimationPoseResetTime
*/
double GetAnimationPoseResetTime() const { return m_resetTime; }
void Restart();
[[nodiscard]] bool IsFinished() const;
void AddAnimationStep(const Math::PoseF &pose, double duration);
void AddAnimationSteps(std::initializer_list<Math::PoseF> poses, double duration);
void AddAnimationSteps(std::initializer_list<PoseDurationPair> steps);
[[nodiscard]] const PoseDurationPair& GetStep(int index) const;
[[nodiscard]] const std::vector<PoseDurationPair>& GetSteps() const { return m_steps; }
void Tick() override;
};
}

View File

@@ -0,0 +1,34 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "SimpleAnimationController.hpp"
#include "Base/FrameMetadata.hpp"
namespace OpenVulkano::Scene
{
double SimpleAnimationController::GetProgress()
{
double progress = m_elapsed / m_duration;
if(progress >= 1.0)
progress = 1;
return progress;
}
void SimpleAnimationController::Tick()
{
if(!m_node || m_duration <= 0 || m_elapsed > m_duration)
return;
m_elapsed += CURRENT_FRAME.frameTime;
double progress = GetProgress();
Math::Pose<float> currentPose = m_initialPose.Interpolate(m_targetPose, progress);
m_node->SetMatrix(currentPose.ToMatrix());
if(m_elapsed > m_duration)
OnCompletion(this);
}
}

View File

@@ -0,0 +1,49 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Base/ITickable.hpp"
#include "Base/Event.hpp"
#include "Math/Math.hpp"
#include "Math/Pose.hpp"
#include "Scene/Node.hpp"
#include <utility>
namespace OpenVulkano::Scene
{
class SimpleAnimationController : public ITickable
{
Node *m_node = nullptr;
Math::PoseF m_targetPose;
Math::PoseF m_initialPose;
double m_duration = 0;
double m_elapsed = 0;
public:
Event<SimpleAnimationController*> OnCompletion;
SimpleAnimationController() = default;
void Reset() { m_elapsed = 0; }
void SwapPoses() { std::swap(m_initialPose, m_targetPose); }
[[nodiscard]] Node* GetNode() const { return m_node; }
void SetNode(Node* node) { m_node = node; }
[[nodiscard]] const Math::PoseF& GetInitialPose() const { return m_initialPose; }
[[nodiscard]] const Math::PoseF& GetTargetPose() const { return m_targetPose; }
void SetPoses(const Math::PoseF& initialPose, const Math::PoseF& targetPose) { m_initialPose = initialPose; m_targetPose = targetPose; }
[[nodiscard]] double GetDuration() const { return m_duration; }
void SetDuration(const double duration) { m_duration = duration; }
[[nodiscard]] double GetProgress();
void Tick() override;
};
}