Skip to content

Instantly share code, notes, and snippets.

@yongkyuns
Created July 31, 2020 04:31
Show Gist options
  • Save yongkyuns/808ea328987737c28f491b15420106ed to your computer and use it in GitHub Desktop.
Save yongkyuns/808ea328987737c28f491b15420106ed to your computer and use it in GitHub Desktop.
//! A suite of common interpolation functions often referred to as "easing" and "tweening"
//! functions. This API is provided by the [pennereq crate](https://docs.rs/pennereq).
pub use crate::geom::{self, pt2, Point2};
use crate::math::BaseFloat;
pub use pennereq::*;
type EaseFn<S> = fn(t: S, b: S, c: S, d: S) -> S;
#[derive(Debug, Copy, Clone)]
pub enum EaseType {
Quad,
QuadIn,
QuadOut,
Cubic,
CubicIn,
CubicOut,
Quart,
QuartIn,
QuartOut,
Quint,
QuintIn,
QuintOut,
Sine,
SineIn,
SineOut,
Expo,
ExpoIn,
ExpoOut,
Circ,
CircIn,
CircOut,
Elastic,
ElasticIn,
ElasticOut,
Back,
BackIn,
BackOut,
Bounce,
BounceIn,
BounceOut,
}
pub trait Tween {
// Update the current value, according to progress and final target
fn update(&self, progress: f32, target: &Self) -> Self;
}
#[derive(Debug, Clone, Copy)]
pub struct Arrow<S = geom::scalar::Default> {
pub start: Point2<S>,
pub end: Point2<S>,
}
impl<S> Tween for Arrow<S>
where
S: BaseFloat,
{
// Iterate through registered attributes, update tween values
fn update(&self, progress: f32, target: &Self) -> Self {
println!("{}", progress);
let p = S::from(progress).unwrap();
let start = self.start;
let end = self.end * (S::one() - p) + target.end * p;
Arrow { start, end }
}
}
pub struct TweenPair<T>
where
T: Tween,
{
pub current: T,
pub target: T,
}
impl<T> TweenPair<T>
where
T: Tween,
{
fn set_target(&mut self, target: T) {
self.target = target;
}
}
pub struct Tweener<T: Tween, S = geom::scalar::Default> {
pub start_time: S,
pub run_time: S,
pub progress: S,
pub entities: Vec<TweenPair<T>>,
pub ease_type: EaseType,
}
impl<T, S> Tweener<T, S>
where
S: BaseFloat + From<f32> + Into<f32>,
T: Tween + Copy,
{
pub fn new() -> Self {
Self::default()
}
pub fn start(&mut self, ease_type: EaseType, target: T, time_now: S, run_time: S) {
self.ease_type = ease_type;
self.start_time = time_now;
self.progress = S::zero();
self.run_time = run_time;
for pair in &mut self.entities {
pair.set_target(target);
}
}
pub fn update(&mut self, time_now: S) {
let start_time = self.start_time;
let run_time = self.run_time;
let time_passed: S = time_now - start_time;
let t = time_passed.min(run_time) / run_time;
self.progress = self.calculate_ease(t);
for pair in &mut self.entities {
pair.current = pair.current.update(self.progress.into(), &pair.target);
}
}
pub fn clear(&mut self) {
self.entities = Vec::new();
}
pub fn register(&mut self, start: T, end: T) {
self.entities.push(TweenPair {
current: start,
target: end,
});
}
fn calculate_ease(&mut self, t: S) -> S {
let ease_func: EaseFn<S> = match self.ease_type {
EaseType::Quad => quad::ease_in_out,
EaseType::QuadIn => quad::ease_in,
EaseType::QuadOut => quad::ease_out,
EaseType::Cubic => cubic::ease_in_out,
EaseType::CubicIn => cubic::ease_in,
EaseType::CubicOut => cubic::ease_out,
EaseType::Quart => quart::ease_in_out,
EaseType::QuartIn => quart::ease_in,
EaseType::QuartOut => quart::ease_out,
EaseType::Quint => quint::ease_in_out,
EaseType::QuintIn => quint::ease_in,
EaseType::QuintOut => quint::ease_out,
EaseType::Sine => sine::ease_in_out,
EaseType::SineIn => sine::ease_in,
EaseType::SineOut => sine::ease_out,
EaseType::Expo => expo::ease_in_out,
EaseType::ExpoIn => expo::ease_in,
EaseType::ExpoOut => expo::ease_out,
EaseType::Circ => circ::ease_in_out,
EaseType::CircIn => circ::ease_in,
EaseType::CircOut => circ::ease_out,
EaseType::Elastic => elastic::ease_in_out,
EaseType::ElasticIn => elastic::ease_in,
EaseType::ElasticOut => elastic::ease_out,
EaseType::Back => back::ease_in_out,
EaseType::BackIn => back::ease_in,
EaseType::BackOut => back::ease_out,
EaseType::Bounce => bounce::ease_in_out,
EaseType::BounceIn => bounce::ease_in,
EaseType::BounceOut => bounce::ease_out,
};
ease_func(t, S::zero(), S::one(), S::one())
}
}
impl<T, S> Default for Tweener<T, S>
where
S: BaseFloat,
T: Tween,
{
fn default() -> Self {
let start_time = S::zero();
let run_time = S::one();
let progress = S::zero();
let ease_type = EaseType::BounceOut;
let entities: Vec<TweenPair<T>> = Vec::new();
Tweener {
start_time,
run_time,
progress,
entities,
ease_type,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment