Summary:
- In MovingCubeApp animations are now allocated on stack - m_sequenceAnimationController now uses SetAnimationPoseResetTime() - Removed OnSequenceAnimationCompleted() - Pose::GetOrientation() now returns by value(without it my code doesn't compile) - GetStep() getter - In if(m_loop) checking for m_resetTime to be zero or last step to be equal to the first - Tick now ticks only if there are at least one element in m_steps - IsFinished() function - AddAnimationSteps() functions that take initializer_lists - Getters in SimpleAnimationController are now const
This commit is contained in:
@@ -40,8 +40,8 @@ namespace OpenVulkano
|
|||||||
Scene::Material m_material;
|
Scene::Material m_material;
|
||||||
Scene::Shader m_shader;
|
Scene::Shader m_shader;
|
||||||
|
|
||||||
std::unique_ptr<Scene::SimpleAnimationController> m_simpleAnimationController;
|
Scene::SimpleAnimationController m_simpleAnimationController;
|
||||||
std::unique_ptr<Scene::SequenceAnimationController> m_sequenceAnimationController;
|
Scene::SequenceAnimationController m_sequenceAnimationController;
|
||||||
|
|
||||||
SceneElement m_whiteBox;
|
SceneElement m_whiteBox;
|
||||||
SceneElement m_redBox;
|
SceneElement m_redBox;
|
||||||
@@ -79,24 +79,22 @@ namespace OpenVulkano
|
|||||||
CreateSceneElement(&m_whiteBox, Math::Vector4f(1, 1, 1, 1), 1);
|
CreateSceneElement(&m_whiteBox, Math::Vector4f(1, 1, 1, 1), 1);
|
||||||
CreateSceneElement(&m_redBox, Math::Vector4f(1, 0.2, 0.2, 1.0), 0.3);
|
CreateSceneElement(&m_redBox, Math::Vector4f(1, 0.2, 0.2, 1.0), 0.3);
|
||||||
|
|
||||||
m_simpleAnimationController = std::make_unique<Scene::SimpleAnimationController>();
|
m_simpleAnimationController.SetNode(&m_whiteBox.m_node);
|
||||||
m_simpleAnimationController->SetNode(&m_whiteBox.m_node);
|
m_simpleAnimationController.SetDuration(3);
|
||||||
m_simpleAnimationController->SetDuration(3);
|
|
||||||
Math::Pose srcPose(Math::Quaternion<float>(), Math::Vector3f_SIMD(-3, 0, 0));
|
Math::Pose srcPose(Math::Quaternion<float>(), Math::Vector3f_SIMD(-3, 0, 0));
|
||||||
Math::Pose destPose(Math::Quaternion<float>(), Math::Vector3f_SIMD(3, 0, 0));
|
Math::Pose destPose(Math::Quaternion<float>(), Math::Vector3f_SIMD(3, 0, 0));
|
||||||
m_simpleAnimationController->SetPoses(srcPose, destPose);
|
m_simpleAnimationController.SetPoses(srcPose, destPose);
|
||||||
m_simpleAnimationController->m_completionEvent += EventHandler(this, &MovingCubeAppImpl::OnSimpleAnimationCompleted);
|
m_simpleAnimationController.m_completionEvent += EventHandler(this, &MovingCubeAppImpl::OnSimpleAnimationCompleted);
|
||||||
|
|
||||||
m_sequenceAnimationController = std::make_unique<Scene::SequenceAnimationController>();
|
m_sequenceAnimationController.EnableLoop(true);
|
||||||
m_sequenceAnimationController->EnableLoop(false);
|
m_sequenceAnimationController.SetNode(&m_redBox.m_node);
|
||||||
m_sequenceAnimationController->SetNode(&m_redBox.m_node);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(1, 0, 0, 1)), Math::Vector3f_SIMD(0, 0, 1)), 5);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(1, 0, 0, 1)), Math::Vector3f_SIMD(0, 0, 1)), 5);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(2, 1, 0, 1)), Math::Vector3f_SIMD(1, 1, -1)), 3);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(2, 1, 0, 1)), Math::Vector3f_SIMD(1, 1, -1)), 3);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(1, 1, 1, 1)), Math::Vector3f_SIMD(2, 1, -2)), 3);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(1, 1, 1, 1)), Math::Vector3f_SIMD(2, 1, -2)), 3);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(0, 1, 1, 0)), Math::Vector3f_SIMD(2, 1, -1)), 3);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(0, 1, 1, 0)), Math::Vector3f_SIMD(2, 1, -1)), 3);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(3, 2, 1, 1)), Math::Vector3f_SIMD(1, 1, -1)), 3);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(3, 2, 1, 1)), Math::Vector3f_SIMD(1, 1, -1)), 3);
|
m_sequenceAnimationController.AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(0, 0, 1, 1)), Math::Vector3f_SIMD(0, 1, 0)), 1);
|
||||||
m_sequenceAnimationController->AddAnimationStep(Math::PoseF(Math::Utils::normalize(Math::QuaternionF(0, 0, 1, 1)), Math::Vector3f_SIMD(0, 1, 0)), 1);
|
m_sequenceAnimationController.SetAnimationPoseResetTime(10);
|
||||||
m_sequenceAnimationController->m_sequenceCompletionEvent += EventHandler(this, &MovingCubeAppImpl::OnSequenceAnimationCompleted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSimpleAnimationCompleted(Scene::SimpleAnimationController *anim)
|
void OnSimpleAnimationCompleted(Scene::SimpleAnimationController *anim)
|
||||||
@@ -105,17 +103,11 @@ namespace OpenVulkano
|
|||||||
anim->Reset();
|
anim->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSequenceAnimationCompleted(Scene::SequenceAnimationController *anim)
|
|
||||||
{
|
|
||||||
Logger::APP->info("Animation sequence completed - restarting...");
|
|
||||||
m_sequenceAnimationController->Restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tick() override
|
void Tick() override
|
||||||
{
|
{
|
||||||
m_cameraControl.Tick();
|
m_cameraControl.Tick();
|
||||||
m_simpleAnimationController->Tick();
|
m_simpleAnimationController.Tick();
|
||||||
m_sequenceAnimationController->Tick();
|
m_sequenceAnimationController.Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Close() override
|
void Close() override
|
||||||
|
|||||||
@@ -44,7 +44,12 @@ namespace OpenVulkano::Math
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Quaternion<T>& GetOrientation() const { return m_orientation; }
|
bool operator==(const Math::Pose<T> &otherPose)
|
||||||
|
{
|
||||||
|
return (GetOrientation() == otherPose.GetOrientation()) && (GetPosition() == otherPose.GetPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Quaternion<T> GetOrientation() const { return m_orientation; }
|
||||||
|
|
||||||
[[nodiscard]] Vector3_SIMD<T> GetPosition() const { return m_position; }
|
[[nodiscard]] Vector3_SIMD<T> GetPosition() const { return m_position; }
|
||||||
|
|
||||||
|
|||||||
@@ -10,31 +10,47 @@ namespace OpenVulkano::Scene
|
|||||||
{
|
{
|
||||||
SequenceAnimationController::SequenceAnimationController()
|
SequenceAnimationController::SequenceAnimationController()
|
||||||
{
|
{
|
||||||
// m_animationController.m_completionEvent += EventHandler(this, &SequenceAnimationController::OnCurrentFrameFinished);
|
m_animationController.m_completionEvent += EventHandler(this, &SequenceAnimationController::OnCurrentFrameFinished);
|
||||||
m_completionEvent += EventHandler(this, &SequenceAnimationController::OnCurrentFrameFinished);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceAnimationController::AdvanceToNextStep()
|
SequenceAnimationController::PoseDurationPair SequenceAnimationController::GetStep(int index)
|
||||||
|
{
|
||||||
|
if(index >= 0 && index < m_steps.size())
|
||||||
|
return m_steps[index];
|
||||||
|
return PoseDurationPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceAnimationController::OnCurrentFrameFinished(SimpleAnimationController *ignored)
|
||||||
{
|
{
|
||||||
if(m_steps.empty())
|
if(m_steps.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(m_currentStep < m_steps.size() - 1)
|
if(m_currentStep < m_steps.size() - 1)
|
||||||
{
|
{
|
||||||
++m_currentStep;
|
m_currentStep++;
|
||||||
SetPoses(GetTargetPose(), m_steps[m_currentStep].first);
|
m_animationController.SetPoses(m_animationController.GetTargetPose(), m_steps[m_currentStep].first);
|
||||||
SetDuration(m_steps[m_currentStep-1].second);
|
m_animationController.SetDuration(m_steps[m_currentStep].second);
|
||||||
SimpleAnimationController::Reset();
|
m_animationController.Reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(m_loop)
|
if(m_loop)
|
||||||
{
|
{
|
||||||
m_currentStep = 0;
|
// NOTE(vb): Maybe compare steps with some epsilon value
|
||||||
SetPoses(GetTargetPose(), m_steps[m_currentStep].first);
|
if(m_steps.size() > 1 && ((m_steps.front().first == m_steps.back().first) || m_resetTime == 0))
|
||||||
// We don't set the duration because transition from the last step to the first
|
{
|
||||||
// requires to use duration of the last step
|
m_currentStep = 1;
|
||||||
SimpleAnimationController::Reset();
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -45,7 +61,9 @@ namespace OpenVulkano::Scene
|
|||||||
|
|
||||||
void SequenceAnimationController::Tick()
|
void SequenceAnimationController::Tick()
|
||||||
{
|
{
|
||||||
SimpleAnimationController::Tick();
|
if(m_steps.empty())
|
||||||
|
return;
|
||||||
|
m_animationController.Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceAnimationController::Restart()
|
void SequenceAnimationController::Restart()
|
||||||
@@ -53,26 +71,60 @@ namespace OpenVulkano::Scene
|
|||||||
m_currentStep = 0;
|
m_currentStep = 0;
|
||||||
if(!m_steps.empty())
|
if(!m_steps.empty())
|
||||||
{
|
{
|
||||||
SetPoses(GetTargetPose(), m_steps[m_currentStep].first);
|
m_animationController.SetPoses(m_animationController.GetTargetPose(), m_steps[m_currentStep].first);
|
||||||
SetDuration(m_steps.back().second);
|
m_animationController.SetDuration(m_steps[m_currentStep].second);
|
||||||
}
|
}
|
||||||
SimpleAnimationController::Reset();
|
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)
|
void SequenceAnimationController::AddAnimationStep(const Math::PoseF &pose, double duration)
|
||||||
{
|
{
|
||||||
m_steps.emplace_back(pose, duration);
|
m_steps.emplace_back(pose, duration);
|
||||||
if(m_steps.size() == 2)
|
if(m_steps.size() > 1)
|
||||||
{
|
{
|
||||||
m_currentStep = 1;
|
m_currentStep = 1;
|
||||||
SetPoses(m_steps[0].first, m_steps[1].first);
|
m_animationController.SetPoses(m_steps[0].first, m_steps[1].first);
|
||||||
SetDuration(m_steps[0].second);
|
m_animationController.SetDuration(m_steps[1].second);
|
||||||
Reset();
|
m_animationController.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceAnimationController::OnCurrentFrameFinished(SimpleAnimationController *animationController)
|
void SequenceAnimationController::AddAnimationSteps(std::initializer_list<Math::PoseF> poses, double duration)
|
||||||
{
|
{
|
||||||
AdvanceToNextStep();
|
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(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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,32 +14,60 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
namespace OpenVulkano::Scene
|
namespace OpenVulkano::Scene
|
||||||
{
|
{
|
||||||
class SequenceAnimationController : public SimpleAnimationController
|
class SequenceAnimationController : public ITickable
|
||||||
{
|
{
|
||||||
using PoseDurationPair = std::pair<Math::PoseF, double>;
|
|
||||||
|
|
||||||
std::vector<PoseDurationPair> m_steps;
|
|
||||||
int m_currentStep = 0;
|
|
||||||
bool m_loop = false;
|
|
||||||
|
|
||||||
void AdvanceToNextStep();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceAnimationController();
|
using PoseDurationPair = std::pair<Math::PoseF, double>;
|
||||||
|
|
||||||
Event<SequenceAnimationController *> m_sequenceCompletionEvent;
|
private:
|
||||||
|
SimpleAnimationController m_animationController;
|
||||||
void EnableLoop(bool value) { m_loop = value; }
|
std::vector<PoseDurationPair> m_steps;
|
||||||
|
size_t m_currentStep = 0;
|
||||||
void Restart();
|
bool m_loop = false;
|
||||||
void AddAnimationStep(const Math::PoseF &pose, double duration);
|
double m_resetTime = 0;
|
||||||
bool IsFinished() { if(m_loop) return false; return m_currentStep >= m_steps.size(); }
|
|
||||||
|
|
||||||
void OnCurrentFrameFinished(SimpleAnimationController *animationController);
|
void OnCurrentFrameFinished(SimpleAnimationController *animationController);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Event<SequenceAnimationController *> m_sequenceCompletionEvent;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
void EnableLoop(bool value) { m_loop = value; }
|
||||||
|
|
||||||
|
void SetNode(Node *node) { m_animationController.SetNode(node); }
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
void SetAnimationPoseResetTime(double resetTime) { m_resetTime = resetTime; }
|
||||||
|
double GetAnimationPoseResetTime() const { return m_resetTime; }
|
||||||
|
|
||||||
|
void Restart();
|
||||||
|
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);
|
||||||
|
PoseDurationPair GetStep(int index);
|
||||||
|
|
||||||
void Tick() override;
|
void Tick() override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -32,14 +32,14 @@ namespace OpenVulkano::Scene
|
|||||||
void Reset() { m_elapsed = 0; }
|
void Reset() { m_elapsed = 0; }
|
||||||
void SwapPoses() { std::swap(m_initialPose, m_targetPose); }
|
void SwapPoses() { std::swap(m_initialPose, m_targetPose); }
|
||||||
|
|
||||||
Node* GetNode() { return m_node; }
|
Node* GetNode() const { return m_node; }
|
||||||
void SetNode(Node *node) { m_node = node; }
|
void SetNode(Node *node) { m_node = node; }
|
||||||
|
|
||||||
const Math::PoseF& GetInitialPose() { return m_initialPose; }
|
const Math::PoseF& GetInitialPose() const { return m_initialPose; }
|
||||||
const Math::PoseF& GetTargetPose() { return m_targetPose; }
|
const Math::PoseF& GetTargetPose() const { return m_targetPose; }
|
||||||
void SetPoses(const Math::PoseF &initialPose, const Math::PoseF &targetPose) { m_initialPose = initialPose; m_targetPose = targetPose; }
|
void SetPoses(const Math::PoseF &initialPose, const Math::PoseF &targetPose) { m_initialPose = initialPose; m_targetPose = targetPose; }
|
||||||
|
|
||||||
double GetDuration() { return m_duration; }
|
double GetDuration() const { return m_duration; }
|
||||||
void SetDuration(double duration) { m_duration = duration; }
|
void SetDuration(double duration) { m_duration = duration; }
|
||||||
|
|
||||||
double GetProgress();
|
double GetProgress();
|
||||||
|
|||||||
Reference in New Issue
Block a user