use crate::math::round;
use core::any::Any;
pub trait Interpolate: Sized {
fn lerp(&self, other: &Self, t: f32) -> Self;
}
pub trait Animatable: Interpolate + Clone + 'static {}
impl<T: Interpolate + Clone + 'static> Animatable for T {}
pub trait Update {
fn update(&mut self, dt: f32) -> bool;
}
pub trait Playable: Update + Any {
fn duration(&self) -> f32;
fn reset(&mut self);
fn seek_to(&mut self, progress: f32);
fn is_complete(&self) -> bool;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl Interpolate for f32 {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
self + (other - self) * t
}
}
impl Interpolate for f64 {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
let t64 = t as f64;
self + (other - self) * t64
}
}
impl Interpolate for [f32; 2] {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
[
self[0] + (other[0] - self[0]) * t,
self[1] + (other[1] - self[1]) * t,
]
}
}
impl Interpolate for [f32; 3] {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
[
self[0] + (other[0] - self[0]) * t,
self[1] + (other[1] - self[1]) * t,
self[2] + (other[2] - self[2]) * t,
]
}
}
impl Interpolate for [f32; 4] {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
[
self[0] + (other[0] - self[0]) * t,
self[1] + (other[1] - self[1]) * t,
self[2] + (other[2] - self[2]) * t,
self[3] + (other[3] - self[3]) * t,
]
}
}
impl Interpolate for i32 {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
let a = *self as f32;
let b = *other as f32;
(round(a + (b - a) * t)) as i32
}
}
impl Interpolate for u8 {
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
let a = *self as f32;
let b = *other as f32;
round(a + (b - a) * t).clamp(0.0, 255.0) as u8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn f32_lerp_start() {
assert_eq!(0.0_f32.lerp(&100.0, 0.0), 0.0);
}
#[test]
fn f32_lerp_end() {
assert_eq!(0.0_f32.lerp(&100.0, 1.0), 100.0);
}
#[test]
fn f32_lerp_mid() {
assert_eq!(0.0_f32.lerp(&100.0, 0.5), 50.0);
}
#[test]
fn f64_lerp_precision() {
let result = 0.0_f64.lerp(&1.0, 0.5);
assert!((result - 0.5).abs() < 1e-10);
}
#[test]
fn vec2_lerp() {
let a = [0.0_f32, 0.0];
let b = [10.0_f32, 20.0];
let mid = a.lerp(&b, 0.5);
assert_eq!(mid, [5.0, 10.0]);
}
#[test]
fn vec3_lerp_endpoints() {
let a = [1.0_f32, 2.0, 3.0];
let b = [4.0_f32, 5.0, 6.0];
assert_eq!(a.lerp(&b, 0.0), a);
assert_eq!(a.lerp(&b, 1.0), b);
}
#[test]
fn vec4_components_independent() {
let a = [0.0_f32; 4];
let b = [1.0_f32, 2.0, 3.0, 4.0];
let mid = a.lerp(&b, 0.5);
assert_eq!(mid, [0.5, 1.0, 1.5, 2.0]);
}
#[test]
fn i32_rounds_correctly() {
assert_eq!(0_i32.lerp(&10, 0.55), 6); assert_eq!(0_i32.lerp(&10, 0.44), 4); }
#[test]
fn u8_clamps_at_255() {
assert_eq!(200_u8.lerp(&255, 2.0), 255); }
#[test]
fn u8_clamps_at_0() {
assert_eq!(50_u8.lerp(&0, 2.0), 0); }
#[test]
fn update_returns_false_when_done() {
struct OneShot {
done: bool,
}
impl Update for OneShot {
fn update(&mut self, _dt: f32) -> bool {
if self.done {
return false;
}
self.done = true;
false
}
}
let mut s = OneShot { done: false };
assert!(!s.update(0.016));
assert!(!s.update(0.016)); }
}