kaliber/src/engine/animator.cc

304 lines
8.4 KiB
C++
Raw Normal View History

2020-04-13 11:24:53 +00:00
#include "animator.h"
#include "../base/interpolation.h"
#include "../base/log.h"
#include "animatable.h"
using namespace base;
namespace eng {
void Animator::Attach(Animatable* animatable) {
elements_.push_back({animatable,
{0, 0},
0,
animatable->GetColor(),
(int)animatable->GetFrame()});
}
void Animator::Play(int animation, bool loop) {
play_flags_ |= animation;
loop_flags_ |= loop ? animation : 0;
}
void Animator::Pause(int animation) {
play_flags_ &= ~animation;
}
void Animator::Stop(int animation) {
if ((animation & kMovement) != 0)
movement_time_ = 0;
if ((animation & kRotation) != 0)
rotation_time_ = 0;
if ((animation & kBlending) != 0)
blending_time_ = 0;
if ((animation & kFrames) != 0)
frame_time_ = 0;
if ((animation & kTimer) != 0)
timer_time_ = 0;
play_flags_ |= animation;
Update(0);
play_flags_ &= ~animation;
loop_flags_ &= ~animation;
}
float Animator::GetTime(int animation) {
if ((animation & kMovement) != 0)
return movement_time_;
if ((animation & kRotation) != 0)
return rotation_time_;
if ((animation & kBlending) != 0)
return blending_time_;
if ((animation & kFrames) != 0)
return frame_time_;
return timer_time_;
}
void Animator::SetTime(int animation, float time) {
DCHECK(time >= 0 && time <= 1);
if ((animation & kMovement) != 0)
movement_time_ = time;
if ((animation & kRotation) != 0)
rotation_time_ = time;
if ((animation & kBlending) != 0)
blending_time_ = time;
if ((animation & kFrames) != 0)
frame_time_ = time;
if ((animation & kTimer) != 0)
timer_time_ = time;
}
2020-04-13 11:24:53 +00:00
void Animator::SetEndCallback(int animation, base::Closure cb) {
if ((inside_cb_ & animation) != 0) {
has_pending_cb_ = true;
pending_cb_ = std::move(cb);
}
if ((animation & kMovement) != 0 && inside_cb_ != kMovement)
movement_cb_ = std::move(cb);
if ((animation & kRotation) != 0 && inside_cb_ != kRotation)
rotation_cb_ = std::move(cb);
if ((animation & kBlending) != 0 && inside_cb_ != kBlending)
blending_cb_ = std::move(cb);
if ((animation & kFrames) != 0 && inside_cb_ != kFrames)
frame_cb_ = std::move(cb);
if ((animation & kTimer) != 0 && inside_cb_ != kTimer)
timer_cb_ = std::move(cb);
}
void Animator::SetMovement(Vector2 direction,
float duration,
Interpolator interpolator) {
movement_direction_ = direction;
movement_speed_ = 1.0f / duration;
movement_interpolator_ = std::move(interpolator);
for (auto& a : elements_)
a.movement_last_offset = {0, 0};
}
void Animator::SetRotation(float trget,
float duration,
Interpolator interpolator) {
rotation_target_ = trget;
rotation_speed_ = 1.0f / duration;
rotation_interpolator_ = std::move(interpolator);
for (auto& a : elements_)
a.rotation_last_theta = 0;
}
void Animator::SetBlending(Vector4 target,
float duration,
Interpolator interpolator) {
blending_target_ = target;
blending_speed_ = 1.0f / duration;
for (auto& a : elements_)
a.blending_start = a.animatable->GetColor();
blending_interpolator_ = std::move(interpolator);
}
void Animator::SetFrames(int count,
int frames_per_second,
Interpolator interpolator) {
frame_count_ = count;
frame_speed_ = (float)frames_per_second / (float)count;
for (auto& a : elements_)
a.frame_start_ = a.animatable->GetFrame();
frame_interpolator_ = std::move(interpolator);
}
void Animator::SetTimer(float duration) {
timer_speed_ = 1.0f / duration;
}
void Animator::SetVisible(bool visible) {
for (auto& a : elements_)
a.animatable->SetVisible(visible);
}
void Animator::Update(float delta_time) {
if (play_flags_ & kMovement)
UpdateMovement(delta_time);
if (play_flags_ & kRotation)
UpdateRotation(delta_time);
if (play_flags_ & kBlending)
UpdateBlending(delta_time);
if (play_flags_ & kFrames)
UpdateFrame(delta_time);
if (play_flags_ & kTimer)
UpdateTimer(delta_time);
for (auto& a : elements_) {
if (play_flags_ & kMovement) {
float interpolated_time = movement_interpolator_
? movement_interpolator_(movement_time_)
: movement_time_;
Vector2 offset =
base::Lerp({0, 0}, movement_direction_, interpolated_time);
a.animatable->Translate(offset - a.movement_last_offset);
a.movement_last_offset = offset;
}
if (play_flags_ & kRotation) {
float interpolated_time = rotation_interpolator_
? rotation_interpolator_(rotation_time_)
: rotation_time_;
float theta = base::Lerp(0.0f, rotation_target_, interpolated_time);
a.animatable->Rotate(theta - a.rotation_last_theta);
a.rotation_last_theta = theta;
}
if (play_flags_ & kBlending) {
float interpolated_time = blending_interpolator_
? blending_interpolator_(blending_time_)
: blending_time_;
Vector4 r =
base::Lerp(a.blending_start, blending_target_, interpolated_time);
a.animatable->SetColor(r);
}
if (play_flags_ & kFrames) {
float interpolated_time =
frame_interpolator_ ? frame_interpolator_(frame_time_) : frame_time_;
int target = a.frame_start_ + frame_count_;
int r = base::Lerp(a.frame_start_, target, interpolated_time);
if (r < target)
a.animatable->SetFrame(r);
}
}
}
void Animator::UpdateMovement(float delta_time) {
if ((loop_flags_ & kMovement) == 0 && movement_time_ == 1.0f) {
movement_time_ = 0;
play_flags_ &= ~kMovement;
if (movement_cb_) {
inside_cb_ = kMovement;
movement_cb_();
inside_cb_ = kNone;
if (has_pending_cb_) {
has_pending_cb_ = false;
movement_cb_ = std::move(pending_cb_);
}
}
return;
}
movement_time_ += movement_speed_ * delta_time;
if (movement_time_ > 1)
movement_time_ =
(loop_flags_ & kMovement) == 0 ? 1 : fmod(movement_time_, 1.0f);
}
void Animator::UpdateRotation(float delta_time) {
if ((loop_flags_ & kRotation) == 0 && rotation_time_ == 1.0f) {
rotation_time_ = 0;
play_flags_ &= ~kRotation;
if (rotation_cb_) {
inside_cb_ = kRotation;
rotation_cb_();
inside_cb_ = kNone;
if (has_pending_cb_) {
has_pending_cb_ = false;
rotation_cb_ = std::move(pending_cb_);
}
}
return;
}
rotation_time_ += rotation_speed_ * delta_time;
if (rotation_time_ > 1)
rotation_time_ =
(loop_flags_ & kRotation) == 0 ? 1 : fmod(rotation_time_, 1.0f);
}
void Animator::UpdateBlending(float delta_time) {
if ((loop_flags_ & kBlending) == 0 && blending_time_ == 1.0f) {
blending_time_ = 0;
play_flags_ &= ~kBlending;
if (blending_cb_) {
inside_cb_ = kBlending;
blending_cb_();
inside_cb_ = kNone;
if (has_pending_cb_) {
has_pending_cb_ = false;
blending_cb_ = std::move(pending_cb_);
}
}
return;
}
blending_time_ += blending_speed_ * delta_time;
if (blending_time_ > 1)
blending_time_ =
(loop_flags_ & kBlending) == 0 ? 1 : fmod(blending_time_, 1.0f);
}
void Animator::UpdateFrame(float delta_time) {
if ((loop_flags_ & kFrames) == 0 && frame_time_ == 1.0f) {
frame_time_ = 0;
play_flags_ &= ~kFrames;
if (frame_cb_) {
inside_cb_ = kFrames;
frame_cb_();
inside_cb_ = kNone;
if (has_pending_cb_) {
has_pending_cb_ = false;
frame_cb_ = std::move(pending_cb_);
}
}
return;
} else if ((loop_flags_ & kFrames) != 0 && frame_time_ == 1.0f) {
frame_time_ = 0;
}
frame_time_ += frame_speed_ * delta_time;
if (frame_time_ > 1)
frame_time_ = 1;
}
void Animator::UpdateTimer(float delta_time) {
if (timer_time_ == 1.0f) {
timer_time_ = 0;
play_flags_ &= ~kTimer;
if (timer_cb_) {
inside_cb_ = kTimer;
timer_cb_();
inside_cb_ = kNone;
if (has_pending_cb_) {
has_pending_cb_ = false;
timer_cb_ = std::move(pending_cb_);
}
}
return;
}
timer_time_ += timer_speed_ * delta_time;
if (timer_time_ > 1)
timer_time_ = 1;
}
} // namespace eng