use super::easing::EasingFunction;
use nalgebra_glm::{Vec2, Vec3, Vec4};
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum TweenValue {
F32(f32),
Vec2(Vec2),
Vec3(Vec3),
Vec4(Vec4),
}
impl TweenValue {
pub fn lerp(from: &Self, to: &Self, t: f32) -> Self {
match (from, to) {
(Self::F32(a), Self::F32(b)) => Self::F32(a + (b - a) * t),
(Self::Vec2(a), Self::Vec2(b)) => Self::Vec2(nalgebra_glm::lerp(a, b, t)),
(Self::Vec3(a), Self::Vec3(b)) => Self::Vec3(nalgebra_glm::lerp(a, b, t)),
(Self::Vec4(a), Self::Vec4(b)) => Self::Vec4(nalgebra_glm::lerp(a, b, t)),
_ => *from,
}
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize,
)]
pub enum TweenState {
#[default]
Playing,
Paused,
Completed,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize,
)]
pub enum TweenLoopMode {
#[default]
Once,
Loop,
PingPong,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TweenTrack {
pub tag: u32,
pub from: TweenValue,
pub to: TweenValue,
pub duration: f32,
pub elapsed: f32,
pub easing: EasingFunction,
pub loop_mode: TweenLoopMode,
pub state: TweenState,
pub current: TweenValue,
pub speed: f32,
pub ping_pong_forward: bool,
pub delay: f32,
pub delay_remaining: f32,
}
impl TweenTrack {
pub fn new(from: TweenValue, to: TweenValue, duration: f32) -> Self {
Self {
tag: 0,
from,
to,
duration,
elapsed: 0.0,
easing: EasingFunction::default(),
loop_mode: TweenLoopMode::default(),
state: TweenState::Playing,
current: from,
speed: 1.0,
ping_pong_forward: true,
delay: 0.0,
delay_remaining: 0.0,
}
}
pub fn with_easing(mut self, easing: EasingFunction) -> Self {
self.easing = easing;
self
}
pub fn with_loop_mode(mut self, loop_mode: TweenLoopMode) -> Self {
self.loop_mode = loop_mode;
self
}
pub fn with_tag(mut self, tag: u32) -> Self {
self.tag = tag;
self
}
pub fn with_delay(mut self, delay: f32) -> Self {
self.delay = delay;
self.delay_remaining = delay;
self
}
pub fn with_speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
pub fn value_f32(&self) -> f32 {
match self.current {
TweenValue::F32(value) => value,
_ => 0.0,
}
}
pub fn value_vec2(&self) -> Vec2 {
match self.current {
TweenValue::Vec2(value) => value,
_ => Vec2::zeros(),
}
}
pub fn value_vec3(&self) -> Vec3 {
match self.current {
TweenValue::Vec3(value) => value,
_ => Vec3::zeros(),
}
}
pub fn value_vec4(&self) -> Vec4 {
match self.current {
TweenValue::Vec4(value) => value,
_ => Vec4::zeros(),
}
}
pub fn progress(&self) -> f32 {
if self.duration <= 0.0 {
1.0
} else {
(self.elapsed / self.duration).clamp(0.0, 1.0)
}
}
pub fn is_completed(&self) -> bool {
self.state == TweenState::Completed
}
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct Tween {
pub tracks: Vec<TweenTrack>,
}
impl Tween {
pub fn new() -> Self {
Self { tracks: Vec::new() }
}
pub fn add_track(&mut self, track: TweenTrack) {
self.tracks.push(track);
}
pub fn track_by_tag(&self, tag: u32) -> Option<&TweenTrack> {
self.tracks.iter().find(|track| track.tag == tag)
}
pub fn track_by_tag_mut(&mut self, tag: u32) -> Option<&mut TweenTrack> {
self.tracks.iter_mut().find(|track| track.tag == tag)
}
pub fn all_completed(&self) -> bool {
self.tracks.iter().all(|track| track.is_completed())
}
pub fn remove_completed(&mut self) {
self.tracks.retain(|track| !track.is_completed());
}
}