use num_traits::{Zero, One};
use std::ops::Range;
use crate::ops::{Lerp, Clamp};
pub trait ProgressMapper<Progress=f32> {
fn map_progress(&self, progress: Progress) -> Progress;
}
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct IdentityProgressMapper;
impl<Progress> ProgressMapper<Progress> for IdentityProgressMapper {
#[inline]
fn map_progress(&self, progress: Progress) -> Progress {
progress
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ProgressMapperFn<T>(pub fn(T) -> T);
impl<T> Default for ProgressMapperFn<T> {
fn default() -> Self {
fn identity<T>(x: T) -> T { x }
ProgressMapperFn(identity)
}
}
impl<T> From<fn(T) -> T> for ProgressMapperFn<T> {
fn from(f: fn(T) -> T) -> Self {
ProgressMapperFn(f)
}
}
impl<Progress> ProgressMapper<Progress> for ProgressMapperFn<Progress> {
fn map_progress(&self, progress: Progress) -> Progress {
self.0(progress)
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Transition<T, F, Progress=f32> {
pub start: T,
pub end: T,
pub progress: Progress,
pub progress_mapper: F,
}
impl<T: Default, F: Default, Progress: Zero> Default for Transition<T, F, Progress> {
fn default() -> Self {
Self {
start: T::default(),
end: T::default(),
progress: Progress::zero(),
progress_mapper: F::default(),
}
}
}
impl<T, F: Default, Progress: Zero> From<Range<T>> for Transition<T, F, Progress> {
fn from(r: Range<T>) -> Self {
Transition { start: r.start, end: r.end, progress: Zero::zero(), progress_mapper: F::default() }
}
}
impl<T, F, Progress> Transition<T, F, Progress> {
pub fn with_mapper(start: T, end: T, progress_mapper: F) -> Self where Progress: Zero {
Self { start, end, progress_mapper, progress: Zero::zero() }
}
pub fn with_mapper_and_progress(start: T, end: T, progress_mapper: F, progress: Progress) -> Self {
Self { start, end, progress_mapper, progress }
}
pub fn into_range(self) -> Range<T> {
let Self { start, end, .. } = self;
Range { start, end }
}
}
impl<T, F, Progress> Transition<T, F, Progress> where F: ProgressMapper<Progress> {
pub fn into_current(self) -> T where T: Lerp<Progress,Output=T>, Progress: Clamp + Zero + One {
Lerp::lerp(self.start, self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn into_current_unclamped(self) -> T where T: Lerp<Progress,Output=T> {
Lerp::lerp_unclamped(self.start, self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn into_current_precise(self) -> T where T: Lerp<Progress,Output=T>, Progress: Clamp + Zero + One {
Lerp::lerp_precise(self.start, self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn into_current_unclamped_precise(self) -> T where T: Lerp<Progress,Output=T> {
Lerp::lerp_unclamped_precise(self.start, self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn current<'a>(&'a self) -> T where &'a T: Lerp<Progress,Output=T>, Progress: Copy + Clamp + Zero + One {
Lerp::lerp(&self.start, &self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn current_unclamped<'a>(&'a self) -> T where &'a T: Lerp<Progress,Output=T>, Progress: Copy {
Lerp::lerp_unclamped(&self.start, &self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn current_precise<'a>(&'a self) -> T where &'a T: Lerp<Progress,Output=T>, Progress: Copy + Clamp + Zero + One {
Lerp::lerp_precise(&self.start, &self.end, self.progress_mapper.map_progress(self.progress))
}
pub fn current_unclamped_precise<'a>(&'a self) -> T where &'a T: Lerp<Progress,Output=T>, Progress: Copy {
Lerp::lerp_unclamped_precise(&self.start, &self.end, self.progress_mapper.map_progress(self.progress))
}
}
pub type LinearTransition<T,Progress=f32> = Transition<T, IdentityProgressMapper, Progress>;
impl<T, Progress> LinearTransition<T, Progress> {
pub fn new(start: T, end: T) -> Self where Progress: Zero {
Self { start, end, progress: Zero::zero(), progress_mapper: Default::default() }
}
pub fn with_progress(start: T, end: T, progress: Progress) -> Self {
Self { start, end, progress, progress_mapper: Default::default() }
}
}