1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
//! A simple library for animation in Rust
//!
//! ## Usage
//!
//! Tweening between two values is done with [`ease(function, from, to, time)`](fn.ease.html). 
//! `from` and `to` can be any type that implements [`CanTween`](trait.CanTween.html), such as `f64` or `mint::Vector2`, while `time` needs to be a floating-point value between zero and one. 
//! `function` specifies the transition between `from` and `to` and is any type that implements [`EasingFunction`](trait.EasingFunction.html).
//!
//! [`AnimationSequence`](struct.AnimationSequence.html) can be used to create more complex animations that keep track of keyframes, time, etc.
//! You can create animation sequences with the [`keyframes![...]`](macro.keyframes.html) macro, from an iterator or from a vector.
//! 
//! ## Examples
//! 
//! An example visualizer is included in `examples/`. Run `cargo run --example visualizer --release` to start it. (ggez is really slow in debug mode!)
//! 
//! Tweening:
//! 
//! ```rust
//! use keyframe::{ease, functions::*};
//! 
//! fn example() -> f64 {
//!     let a = 0.0;
//!     let b = 2.0;
//!     let time = 0.5;
//! 
//!     ease(EaseInOut, a, b, time)
//! }
//! ```
//! 
//! Animation sequences:
//! 
//! ```rust 
//! #[macro_use]
//! extern crate keyframe;
//! 
//! use keyframe::{Keyframe, AnimationSequence};
//! 
//! fn example() {
//!     // (value, time) or (value, time, function)
//!     let sequence = keyframes![
//!         (0.5, 0.0), // <-- EaseInOut used from 0.0 to 0.3
//!         (1.5, 0.3, EaseIn), // <-- EaseIn used from 0.3 to 1.0
//!         (2.5, 1.0, Linear) // <-- Linear never used, since we're at the end
//!     ];
//!
//!     sequence.advance_by(0.65);
//!
//!     assert_eq!(sequence.now(), 2.0);
//!     assert_eq!(sequence.duration(), 1.0);
//! }
//! ```

pub(crate) use num_traits::Float;
#[cfg(feature = "mint_types")]
pub(crate) use mint::{Vector2, Vector3, Vector4, Point2, Point3};

use std::fmt;

pub(crate) fn as_f64(value: impl Float) -> f64 { value.to_f64().expect(&format!("Value not representable in f64")) }
pub(crate) fn as_t<T: Float>(value: f64) -> T { 
	match value {
		_ if value > as_f64(T::max_value()) => T::max_value(),
		_ if value < as_f64(T::min_value()) => T::min_value(),
		_ => T::from(value).expect(&format!("{} not representable in chosen float type", value)) 
	}
}

/// Definitions for various easing functions
/// 
/// <div class="function-preview" data-function="t" data-struct="Linear"></div>
/// <div class="function-preview" data-function="t * t * t" data-struct="EaseIn"></div>
/// <div class="function-preview" data-function="(--t) * t * t + 1" data-struct="EaseOut"></div>
/// <div class="function-preview" data-function="t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1" data-struct="EaseInOut"></div>
pub mod functions;
use functions::*;

mod easing;
pub use easing::*;

/// Intermediate step in an animation sequence
pub struct Keyframe<T: CanTween + Copy> {
	value: T,
	time: f64,
	function: Box<dyn EasingFunction + Send + Sync>
}

impl<T: CanTween + Copy> Keyframe<T> {
	/// Creates a new keyframe from the specified values.
	/// If the time value is negative the keyframe will start at 0.0.
	/// 
	/// # Arguments
	/// * `value` - The value that this keyframe will be tweened to/from
	/// * `time` - The start time in seconds of this keyframe
	/// * `function` - The easing function to use from the start of this keyframe to the start of the next keyframe
	#[inline]
	pub fn new<F: Float>(value: T, time: F, function: impl EasingFunction + 'static + Send + Sync) -> Self {
		Keyframe::<T> {
			value: value,
			time: if time < F::zero() { 0.0 } else { as_f64(time) },
			function: Box::new(function)
		}
	}

	/// The value of this keyframe
	#[inline]
	pub fn value(&self) -> T { self.value }

	/// The time in seconds at which this keyframe starts in a sequence
	#[inline]
	pub fn time(&self) -> f64 { self.time }

	/// The easing function that will be used when tweening to another keyframe
	#[inline]
	pub fn function(&self) -> &dyn EasingFunction { self.function.as_ref() }

	/// Returns the value between this keyframe and the next keyframe at the specified time
	/// 
	/// # Note
	/// 
	/// The following applies if:
	/// * The requested time is before the start time of this keyframe: the value of this keyframe is returned
	/// * The requested time is after the start time of next keyframe: the value of the next keyframe is returned
	/// * The start time of the next keyframe is before the start time of this keyframe: the value of the next keyframe is returned
	#[inline]
	pub fn tween_to(&self, next: &Keyframe<T>, time: impl Float) -> T {
		match as_f64(time) {
			// If the requested time starts before this keyframe
			time if time < self.time => self.value,
			// If the requested time starts after the next keyframe
			time if time > next.time => next.value,
			// If the next keyframe starts before this keyframe
			_ if next.time < self.time => next.value,

			time => T::ease(self.value, next.value, self.function.y(ease_with_scaled_time(Linear, 0.0, 1.0, time - self.time, next.time - self.time)))
		}
	}
}

impl<V: CanTween + Copy, T: Float> From<(V, T)> for Keyframe<V> {
	/// Creates a new keyframe from a tuple of (value, time).
	/// `EaseInOut` will be used as the easing function.
	/// If the time value is negative the keyframe will start at 0.0.
	#[inline]
	fn from(tuple: (V, T)) -> Self { Keyframe::new(tuple.0, as_f64(tuple.1), EaseInOut) }
}

impl<V: CanTween + Copy, T: Float, F: EasingFunction + 'static + Send + Sync> From<(V, T, F)> for Keyframe<V> {
	/// Creates a new keyframe from a tuple of (value, time, function).
	/// If the time value is negative the keyframe will start at 0.0.
	#[inline]
	fn from(tuple: (V, T, F)) -> Self { Keyframe::new(tuple.0, as_f64(tuple.1), tuple.2) }
}

impl<T: CanTween + Copy + fmt::Display> fmt::Display for Keyframe<T> {
	#[inline]
	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		write!(f, "Keyframe at {} s: {}", self.time, self.value)
	}
}

impl<T: CanTween + Copy + fmt::Debug> fmt::Debug for Keyframe<T> {
	#[inline]
	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		write!(f, "Keyframe {{ value: {:?}, time: {:?} }}", self.value, self.time)
	}
}

impl Default for Keyframe<f32> {
	#[inline]
	fn default() -> Self { Keyframe::new(0.0, 0.0, Linear) }
}

impl Default for Keyframe<Vector2<f32>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Vector3<f32>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Vector4<f32>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Point2<f32>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Point3<f32>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<f64> {
	#[inline]
	fn default() -> Self { Keyframe::new(0.0, 0.0, Linear) }
}

impl Default for Keyframe<Vector2<f64>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Vector3<f64>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Vector4<f64>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Point2<f64>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0].into(), 0.0, Linear) }
}

impl Default for Keyframe<Point3<f64>> {
	#[inline]
	fn default() -> Self { Keyframe::new([0.0, 0.0, 0.0].into(), 0.0, Linear) }
}

mod sequence;
pub use sequence::*;