eazy_core/
easing.rs

1//! Each functions is grouped by context:
2//!
3//! #### easing functions.
4//!
5//! |               |                                   |
6//! |:--------------|:----------------------------------|
7//! | polynomial    | linear, quadratic, cubic, etc.    |
8//! | trigonometric | sine, circle.                     |
9//! | exponential   | expo2, expoe.                     |
10//! | logarithmic   | log10.                            |
11//! | root          | sqrt.                             |
12//! | oscillatory   | elastic, bounce.                  |
13//! | backtracking  | back.                             |
14//!
15//! #### notes.
16//!
17//! *Time is a normalized percentage of the elapsed time [0,1] i.e a range
18//! between 0.0 and 1.0 (both inclusively).*
19
20pub mod backtracking;
21pub mod bezier;
22pub mod exponential;
23pub mod logarithmic;
24pub mod oscillatory;
25pub mod polynomial;
26pub mod root;
27pub mod trigonometric;
28
29use wide::f32x8;
30
31/// ### The [`Curve`] Parabola Interface.
32///
33/// A curve that has an axis of symmetry parallel to the `y-axis`.
34pub trait Curve {
35  /// Computes the `y-axis` of the curve from a progress value.
36  ///     
37  /// #### params.
38  ///   
39  /// |     |               |
40  /// |:----|:--------------|
41  /// | `p` | The progress. |
42  ///   
43  /// #### returns.
44  ///
45  /// `f32` — The progress of the `y-axis` value.
46  ///   
47  /// #### examples.
48  ///   
49  /// ```rust
50  /// use eazy::Curve;
51  ///
52  /// struct Linear;
53  ///  
54  /// impl Curve for Linear {
55  ///   fn y(&self, p: f32) -> f32 {
56  ///     -f32::INFINITY
57  ///   }
58  /// }
59  ///  
60  /// assert_eq!(Linear.y(0.0), -f32::INFINITY);
61  /// ```
62  fn y(&self, p: f32) -> f32;
63}
64
65/// Blanket impl for references, enabling `&dyn Curve` to work with `ease()`.
66impl<T: Curve + ?Sized> Curve for &T {
67  #[inline(always)]
68  fn y(&self, p: f32) -> f32 {
69    (**self).y(p)
70  }
71}
72
73/// ### The [`Curve`] Parabola Interface using SIMD.
74pub trait CurveSIMD {
75  /// Computes the `y-axis` of the curve from a progress value.
76  ///     
77  /// #### params.
78  ///   
79  /// |     |               |
80  /// |:----|:--------------|
81  /// | `p` | The progress. |
82  ///   
83  /// #### returns.
84  ///
85  /// `f32` — The progress of the `y-axis` value.
86  ///   
87  /// #### examples.
88  ///   
89  /// ```rust
90  /// use eazy::CurveSIMD;
91  ///
92  /// struct Constant;
93  ///  
94  /// impl CurveSIMD for Constant {
95  ///   fn y(&self, p: f32x8) -> f32x8 {
96  ///     -f32x8::ZERO
97  ///   }
98  /// }
99  ///  
100  /// assert_eq!(Constant.y(0.0), -f32::INFINITY);
101  /// ```
102  fn y(&self, p: f32x8) -> f32x8;
103}
104
105/// ### The [`Ease`] Function Interface.
106pub trait Ease {
107  /// Computes the `y-axis` of the curve from a progress value.
108  ///     
109  /// #### params.
110  ///   
111  /// |     |                   |
112  /// |:----|:------------------|
113  /// | `p` | The elapsed time. |
114  /// | `a` | The start.        |
115  /// | `b` | The end.          |
116  ///
117  /// #### returns.
118  ///
119  /// `f32` — The progress of the `y-axis` value.
120  ///
121  /// ```
122  /// use eazy::ease;
123  ///
124  /// ease(0.5 / 4.0, 0.0, 1.0);
125  /// ```
126  fn ease(p: f32, a: f32, b: f32) -> f32;
127}
128
129/// ### The [`Easing`] Function User Access.
130///
131/// Wraps all easing functions in one place.
132#[derive(Debug, Default, Clone)]
133pub enum Easing {
134  // constant.
135  None,
136  // polynomial:linear.
137  #[default]
138  Linear,
139  // polynomial:in.
140  InQuadratic,
141  InCubic,
142  InQuartic,
143  InQuintic,
144  InSextic,
145  InSeptic,
146  InOctic,
147  InNonic,
148  InDecic,
149  InHectic,
150  // polynomial:out.
151  OutQuadratic,
152  OutCubic,
153  OutQuartic,
154  OutQuintic,
155  OutSextic,
156  OutSeptic,
157  OutOctic,
158  OutNonic,
159  OutDecic,
160  OutHectic,
161  // polynomial:in-out.
162  InOutQuadratic,
163  InOutCubic,
164  InOutQuartic,
165  InOutQuintic,
166  InOutSextic,
167  InOutSeptic,
168  InOutOctic,
169  InOutNonic,
170  InOutDecic,
171  InOutHectic,
172  // trigonometric:in.
173  InSine,
174  InCircle,
175  // trigonometric:out.
176  OutSine,
177  OutCircle,
178  // trigonometric:in-out.
179  InOutSine,
180  InOutCircle,
181  // exponential:in.
182  InExpo2,
183  InExpoE,
184  // exponential:out.
185  OutExpo2,
186  OutExpoE,
187  // exponential:in-out.
188  InOutExpo2,
189  InOutExpoE,
190  // logarithmic:in.
191  InLog10,
192  // logarithmic:out.
193  OutLog10,
194  // logarithmic:in-out.
195  InOutLog10,
196  // root:in.
197  InSqrt,
198  // root:out.
199  OutSqrt,
200  // root:in-out.
201  InOutSqrt,
202  // oscillatory:in.
203  InElastic,
204  InBounce,
205  // oscillatory:out.
206  OutElastic,
207  OutBounce,
208  // oscillatory:in-out.
209  InOutElastic,
210  InOutBounce,
211  // oscillatory:spring.
212  Spring,
213  // backtracking:in.
214  InBack,
215  // backtracking:out.
216  OutBack,
217  // backtracking:in-out.
218  InOutBack,
219  // cubic bezier.
220  CubicBezier(bezier::Bezier),
221  // interpolation.
222  Interpolation(crate::interpolation::Interpolation),
223  // custom easing function.
224  // Custom(dyn Curve),
225}
226
227impl Curve for Easing {
228  #[inline(always)]
229  fn y(&self, p: f32) -> f32 {
230    match self {
231      Self::None => polynomial::none::None.y(p),
232      Self::Linear => polynomial::linear::Linear.y(p),
233      Self::InQuadratic => polynomial::quadratic::InQuadratic.y(p),
234      Self::InCubic => polynomial::cubic::InCubic.y(p),
235      Self::InQuartic => polynomial::quartic::InQuartic.y(p),
236      Self::InQuintic => polynomial::quintic::InQuintic.y(p),
237      Self::InSextic => polynomial::sextic::InSextic.y(p),
238      Self::InSeptic => polynomial::septic::InSeptic.y(p),
239      Self::InOctic => polynomial::octic::InOctic.y(p),
240      Self::InNonic => polynomial::nonic::InNonic.y(p),
241      Self::InDecic => polynomial::decic::InDecic.y(p),
242      Self::InHectic => polynomial::hectic::InHectic.y(p),
243      Self::OutQuadratic => polynomial::quadratic::OutQuadratic.y(p),
244      Self::OutCubic => polynomial::cubic::OutCubic.y(p),
245      Self::OutQuartic => polynomial::quartic::OutQuartic.y(p),
246      Self::OutQuintic => polynomial::quintic::OutQuintic.y(p),
247      Self::OutSextic => polynomial::sextic::OutSextic.y(p),
248      Self::OutSeptic => polynomial::septic::OutSeptic.y(p),
249      Self::OutOctic => polynomial::octic::OutOctic.y(p),
250      Self::OutNonic => polynomial::nonic::OutNonic.y(p),
251      Self::OutDecic => polynomial::decic::OutDecic.y(p),
252      Self::OutHectic => polynomial::hectic::OutHectic.y(p),
253      Self::InOutQuadratic => polynomial::quadratic::InOutQuadratic.y(p),
254      Self::InOutCubic => polynomial::cubic::InOutCubic.y(p),
255      Self::InOutQuartic => polynomial::quartic::InOutQuartic.y(p),
256      Self::InOutQuintic => polynomial::quintic::InOutQuintic.y(p),
257      Self::InOutSextic => polynomial::sextic::InOutSextic.y(p),
258      Self::InOutSeptic => polynomial::septic::InOutSeptic.y(p),
259      Self::InOutOctic => polynomial::octic::InOutOctic.y(p),
260      Self::InOutNonic => polynomial::nonic::InOutNonic.y(p),
261      Self::InOutDecic => polynomial::decic::InOutDecic.y(p),
262      Self::InOutHectic => polynomial::hectic::InOutHectic.y(p),
263      Self::InSine => trigonometric::sine::InSine.y(p),
264      Self::InCircle => trigonometric::circle::InCircle.y(p),
265      Self::OutSine => trigonometric::sine::OutSine.y(p),
266      Self::OutCircle => trigonometric::circle::OutCircle.y(p),
267      Self::InOutSine => trigonometric::sine::InOutSine.y(p),
268      Self::InOutCircle => trigonometric::circle::InOutCircle.y(p),
269      Self::InExpo2 => exponential::expo2::InExpo2.y(p),
270      Self::InExpoE => exponential::expoe::InExpoE.y(p),
271      Self::OutExpo2 => exponential::expo2::OutExpo2.y(p),
272      Self::OutExpoE => exponential::expoe::InExpoE.y(p),
273      Self::InOutExpo2 => exponential::expo2::InOutExpo2.y(p),
274      Self::InOutExpoE => exponential::expoe::InOutExpoE.y(p),
275      Self::InLog10 => logarithmic::log10::InLog10.y(p),
276      Self::OutLog10 => logarithmic::log10::OutLog10.y(p),
277      Self::InOutLog10 => logarithmic::log10::InOutLog10.y(p),
278      Self::InSqrt => root::sqrt::InSqrt.y(p),
279      Self::OutSqrt => root::sqrt::OutSqrt.y(p),
280      Self::InOutSqrt => root::sqrt::InOutSqrt.y(p),
281      Self::InElastic => oscillatory::elastic::InElastic.y(p),
282      Self::InBounce => oscillatory::bounce::InBounce.y(p),
283      Self::OutElastic => oscillatory::elastic::OutElastic.y(p),
284      Self::OutBounce => oscillatory::bounce::OutBounce.y(p),
285      Self::InOutElastic => oscillatory::elastic::InOutElastic.y(p),
286      Self::InOutBounce => oscillatory::bounce::InOutBounce.y(p),
287      Self::Spring => oscillatory::spring::Spring.y(p),
288      Self::InBack => backtracking::back::InBack.y(p),
289      Self::OutBack => backtracking::back::OutBack.y(p),
290      Self::InOutBack => backtracking::back::InOutBack.y(p),
291      Self::CubicBezier(bezier) => bezier.y(p),
292      Self::Interpolation(interpolation) => interpolation.y(p),
293      // shoud stay at the last place. New ones must be place above it.
294      // Self::Custom(curve) => curve.y(p),
295    }
296  }
297}
298
299/// ### The Ease Function.
300///
301/// Interpolates between `start` and `end` using the given easing curve.
302///
303/// Zero-cost for static easing types (monomorphized at compile time).
304/// Also works with trait objects thanks to the blanket impl for `&T`.
305///
306/// #### examples.
307///
308/// ```rust
309/// use eazy::{ease, Curve, Easing};
310/// use eazy::polynomial::quadratic::InQuadratic;
311///
312/// // Static type (zero-cost, inlined).
313/// let value = ease(InQuadratic, 0.5, 0.0, 100.0);
314///
315/// // Easing enum.
316/// let value = ease(Easing::InQuadratic, 0.5, 0.0, 100.0);
317///
318/// // Reference.
319/// let easing = Easing::OutBounce;
320/// let value = ease(&easing, 0.5, 0.0, 100.0);
321///
322/// // Trait object.
323/// let curve: &dyn Curve = &Easing::InElastic;
324/// let value = ease(curve, 0.5, 0.0, 100.0);
325/// ```
326#[inline(always)]
327pub fn ease(curve: impl Curve, time: f32, start: f32, end: f32) -> f32 {
328  start + (end - start) * curve.y(time)
329}