use core::borrow::Borrow;
use core::mem::MaybeUninit;
pub(crate) use crate::*;
#[cfg(feature = "mint_types")]
pub use mint_type_impls::*;
pub trait EasingFunction {
fn y(&self, x: f64) -> f64;
}
pub trait CanTween {
fn ease(from: Self, to: Self, time: impl Float) -> Self;
}
impl CanTween for f32 {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
as_t(as_f64(from) + as_f64(to - from) * as_f64(time))
}
}
impl CanTween for f64 {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
as_t(as_f64(from) + as_f64(to - from) * as_f64(time))
}
}
impl<T: CanTween, const N: usize> CanTween for [T; N] {
fn ease(from: Self, to: Self, time: impl Float) -> Self {
let mut result_uninit: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
for (i, (f, t)) in IntoIterator::into_iter(from)
.zip(IntoIterator::into_iter(to))
.enumerate()
{
result_uninit[i].write(T::ease(f, t, time));
}
unsafe {
let ptr = result_uninit.as_mut_ptr() as *mut [T; N];
let result = ptr.read();
core::mem::forget(result_uninit);
result
}
}
}
#[inline]
pub fn ease_with_unbounded_time<V: CanTween, F: EasingFunction>(
function: impl Borrow<F>,
from: V,
to: V,
time: impl Float,
) -> V {
V::ease(from, to, function.borrow().y(as_f64(time)))
}
#[inline]
pub fn ease<V: CanTween, T: Float, F: EasingFunction>(function: impl Borrow<F>, from: V, to: V, time: T) -> V {
ease_with_unbounded_time(
function,
from,
to,
match time {
_ if time < T::zero() => T::zero(),
_ if time > T::one() => T::one(),
_ => time,
},
)
}
#[inline]
pub fn ease_with_scaled_time<V: CanTween, T: Float, F: EasingFunction>(
function: impl Borrow<F>,
from: V,
to: V,
time: T,
max_time: T,
) -> V {
ease(
function,
from,
to,
match time {
_ if time < T::zero() => T::zero(),
_ if time > max_time => T::one(),
_ => time / max_time,
},
)
}
#[cfg(feature = "mint_types")]
mod mint_type_impls {
use crate::easing::*;
impl<V: CanTween> CanTween for Vector2<V> {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
Self {
x: V::ease(from.x, to.x, time),
y: V::ease(from.y, to.y, time),
}
}
}
impl<V: CanTween> CanTween for Vector3<V> {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
Self {
x: V::ease(from.x, to.x, time),
y: V::ease(from.y, to.y, time),
z: V::ease(from.z, to.z, time),
}
}
}
impl<V: CanTween> CanTween for Vector4<V> {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
Self {
x: V::ease(from.x, to.x, time),
y: V::ease(from.y, to.y, time),
z: V::ease(from.z, to.z, time),
w: V::ease(from.w, to.w, time),
}
}
}
impl<V: CanTween> CanTween for Point2<V> {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
Self {
x: V::ease(from.x, to.x, time),
y: V::ease(from.y, to.y, time),
}
}
}
impl<V: CanTween> CanTween for Point3<V> {
#[inline]
fn ease(from: Self, to: Self, time: impl Float) -> Self {
Self {
x: V::ease(from.x, to.x, time),
y: V::ease(from.y, to.y, time),
z: V::ease(from.z, to.z, time),
}
}
}
}