1use crate::{Curve, CurveExt, FunctionCurve, Interval};
74use bevy_math::{
75 Dir2, Dir3, Dir3A, Isometry2d, Isometry3d, Quat, Rot2, Sum, Vec2, Vec3, Vec3A, Vec4,
76 VectorSpace,
77};
78
79#[cfg(feature = "bevy_reflect")]
80use bevy_reflect::std_traits::ReflectDefault;
81
82use variadics_please::all_tuples_enumerated;
83
84pub trait Ease: Sized {
93 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self>;
101}
102
103pub trait EaseVectorSpace: VectorSpace<Scalar = f32> {}
115
116impl EaseVectorSpace for Vec2 {}
117impl EaseVectorSpace for Vec3 {}
118impl EaseVectorSpace for Vec4 {}
119impl EaseVectorSpace for Vec3A {}
120impl EaseVectorSpace for f32 {}
121impl<V, W> EaseVectorSpace for Sum<V, W>
122where
123 V: EaseVectorSpace,
124 W: EaseVectorSpace,
125{
126}
127
128impl<V: EaseVectorSpace> Ease for V {
129 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
130 FunctionCurve::new(Interval::EVERYWHERE, move |t| V::lerp(start, end, t))
131 }
132}
133
134impl Ease for Rot2 {
135 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
136 FunctionCurve::new(Interval::EVERYWHERE, move |t| Rot2::slerp(start, end, t))
137 }
138}
139
140impl Ease for Quat {
141 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
142 let dot = start.dot(end);
143 let end_adjusted = if dot < 0.0 { -end } else { end };
144 let difference = end_adjusted * start.inverse();
145 let (axis, angle) = difference.to_axis_angle();
146 FunctionCurve::new(Interval::EVERYWHERE, move |s| {
147 Quat::from_axis_angle(axis, angle * s) * start
148 })
149 }
150}
151
152impl Ease for Dir2 {
153 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
154 FunctionCurve::new(Interval::EVERYWHERE, move |t| Dir2::slerp(start, end, t))
155 }
156}
157
158impl Ease for Dir3 {
159 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
160 let difference_quat = Quat::from_rotation_arc(start.as_vec3(), end.as_vec3());
161 Quat::interpolating_curve_unbounded(Quat::IDENTITY, difference_quat).map(move |q| q * start)
162 }
163}
164
165impl Ease for Dir3A {
166 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
167 let difference_quat =
168 Quat::from_rotation_arc(start.as_vec3a().into(), end.as_vec3a().into());
169 Quat::interpolating_curve_unbounded(Quat::IDENTITY, difference_quat).map(move |q| q * start)
170 }
171}
172
173impl Ease for Isometry3d {
174 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
175 FunctionCurve::new(Interval::EVERYWHERE, move |t| {
176 Isometry3d {
179 rotation: Quat::interpolating_curve_unbounded(start.rotation, end.rotation)
180 .sample_unchecked(t),
181 translation: Vec3A::interpolating_curve_unbounded(
182 start.translation,
183 end.translation,
184 )
185 .sample_unchecked(t),
186 }
187 })
188 }
189}
190
191impl Ease for Isometry2d {
192 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
193 FunctionCurve::new(Interval::EVERYWHERE, move |t| {
194 Isometry2d {
197 rotation: Rot2::interpolating_curve_unbounded(start.rotation, end.rotation)
198 .sample_unchecked(t),
199 translation: Vec2::interpolating_curve_unbounded(
200 start.translation,
201 end.translation,
202 )
203 .sample_unchecked(t),
204 }
205 })
206 }
207}
208
209macro_rules! impl_ease_tuple {
210 ($(#[$meta:meta])* $(($n:tt, $T:ident)),*) => {
211 $(#[$meta])*
212 impl<$($T: Ease),*> Ease for ($($T,)*) {
213 fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
214 let curve_tuple =
215 (
216 $(
217 <$T as Ease>::interpolating_curve_unbounded(start.$n, end.$n),
218 )*
219 );
220
221 FunctionCurve::new(Interval::EVERYWHERE, move |t|
222 (
223 $(
224 curve_tuple.$n.sample_unchecked(t),
225 )*
226 )
227 )
228 }
229 }
230 };
231}
232
233all_tuples_enumerated!(
234 #[doc(fake_variadic)]
235 impl_ease_tuple,
236 1,
237 11,
238 T
239);
240
241#[derive(Clone, Debug, PartialEq)]
333#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
334#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
335pub struct EasingCurve<T> {
336 start: T,
337 end: T,
338 ease_fn: EaseFunction,
339}
340
341impl<T> EasingCurve<T> {
342 pub const fn new(start: T, end: T, ease_fn: EaseFunction) -> Self {
349 Self {
350 start,
351 end,
352 ease_fn,
353 }
354 }
355}
356
357impl<T> Curve<T> for EasingCurve<T>
358where
359 T: Ease + Clone,
360{
361 #[inline]
362 fn domain(&self) -> Interval {
363 Interval::UNIT
364 }
365
366 #[inline]
367 fn sample_unchecked(&self, t: f32) -> T {
368 let remapped_t = self.ease_fn.eval(t);
369 T::interpolating_curve_unbounded(self.start.clone(), self.end.clone())
370 .sample_unchecked(remapped_t)
371 }
372}
373
374#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
379#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
380#[cfg_attr(
381 feature = "bevy_reflect",
382 derive(bevy_reflect::Reflect),
383 reflect(Clone, Default, PartialEq)
384)]
385pub enum JumpAt {
386 #[doc = include_str!("../images/easefunction/StartSteps.svg")]
389 Start,
390 #[doc = include_str!("../images/easefunction/EndSteps.svg")]
393 #[default]
394 End,
395 #[doc = include_str!("../images/easefunction/NoneSteps.svg")]
398 None,
399 #[doc = include_str!("../images/easefunction/BothSteps.svg")]
402 Both,
403}
404
405impl JumpAt {
406 #[inline]
407 pub(crate) fn eval(self, num_steps: usize, t: f32) -> f32 {
408 use bevy_math::ops;
409
410 let (a, b) = match self {
411 JumpAt::Start => (1.0, 0),
412 JumpAt::End => (0.0, 0),
413 JumpAt::None => (0.0, -1),
414 JumpAt::Both => (1.0, 1),
415 };
416
417 let current_step = ops::floor(t * num_steps as f32) + a;
418 let step_size = (num_steps as isize + b).max(1) as f32;
419
420 (current_step / step_size).clamp(0.0, 1.0)
421 }
422}
423
424#[non_exhaustive]
465#[derive(Debug, Copy, Clone, PartialEq)]
466#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
467#[cfg_attr(
468 feature = "bevy_reflect",
469 derive(bevy_reflect::Reflect),
470 reflect(Clone, PartialEq)
471)]
472pub enum EaseFunction {
474 #[doc = include_str!("../images/easefunction/Linear.svg")]
477 Linear,
478
479 #[doc = include_str!("../images/easefunction/QuadraticIn.svg")]
487 QuadraticIn,
488 #[doc = include_str!("../images/easefunction/QuadraticOut.svg")]
496 QuadraticOut,
497 #[doc = include_str!("../images/easefunction/QuadraticInOut.svg")]
504 QuadraticInOut,
505
506 #[doc = include_str!("../images/easefunction/CubicIn.svg")]
515 CubicIn,
516 #[doc = include_str!("../images/easefunction/CubicOut.svg")]
519 CubicOut,
520 #[doc = include_str!("../images/easefunction/CubicInOut.svg")]
530 CubicInOut,
531
532 #[doc = include_str!("../images/easefunction/QuarticIn.svg")]
535 QuarticIn,
536 #[doc = include_str!("../images/easefunction/QuarticOut.svg")]
539 QuarticOut,
540 #[doc = include_str!("../images/easefunction/QuarticInOut.svg")]
543 QuarticInOut,
544
545 #[doc = include_str!("../images/easefunction/QuinticIn.svg")]
548 QuinticIn,
549 #[doc = include_str!("../images/easefunction/QuinticOut.svg")]
552 QuinticOut,
553 #[doc = include_str!("../images/easefunction/QuinticInOut.svg")]
561 QuinticInOut,
562
563 #[doc = include_str!("../images/easefunction/SmoothStepIn.svg")]
568 SmoothStepIn,
569 #[doc = include_str!("../images/easefunction/SmoothStepOut.svg")]
574 SmoothStepOut,
575 #[doc = include_str!("../images/easefunction/SmoothStep.svg")]
588 SmoothStep,
589
590 #[doc = include_str!("../images/easefunction/SmootherStepIn.svg")]
595 SmootherStepIn,
596 #[doc = include_str!("../images/easefunction/SmootherStepOut.svg")]
601 SmootherStepOut,
602 #[doc = include_str!("../images/easefunction/SmootherStep.svg")]
613 SmootherStep,
614
615 #[doc = include_str!("../images/easefunction/SineIn.svg")]
618 SineIn,
619 #[doc = include_str!("../images/easefunction/SineOut.svg")]
622 SineOut,
623 #[doc = include_str!("../images/easefunction/SineInOut.svg")]
626 SineInOut,
627
628 #[doc = include_str!("../images/easefunction/CircularIn.svg")]
631 CircularIn,
632 #[doc = include_str!("../images/easefunction/CircularOut.svg")]
635 CircularOut,
636 #[doc = include_str!("../images/easefunction/CircularInOut.svg")]
639 CircularInOut,
640
641 #[doc = include_str!("../images/easefunction/ExponentialIn.svg")]
647 ExponentialIn,
648 #[doc = include_str!("../images/easefunction/ExponentialOut.svg")]
654 ExponentialOut,
655 #[doc = include_str!("../images/easefunction/ExponentialInOut.svg")]
658 ExponentialInOut,
659
660 #[doc = include_str!("../images/easefunction/ElasticIn.svg")]
663 ElasticIn,
664 #[doc = include_str!("../images/easefunction/ElasticOut.svg")]
667 ElasticOut,
668 #[doc = include_str!("../images/easefunction/ElasticInOut.svg")]
671 ElasticInOut,
672
673 #[doc = include_str!("../images/easefunction/BackIn.svg")]
676 BackIn,
677 #[doc = include_str!("../images/easefunction/BackOut.svg")]
680 BackOut,
681 #[doc = include_str!("../images/easefunction/BackInOut.svg")]
684 BackInOut,
685
686 #[doc = include_str!("../images/easefunction/BounceIn.svg")]
689 BounceIn,
690 #[doc = include_str!("../images/easefunction/BounceOut.svg")]
693 BounceOut,
694 #[doc = include_str!("../images/easefunction/BounceInOut.svg")]
697 BounceInOut,
698
699 Steps(usize, JumpAt),
702
703 #[doc = include_str!("../images/easefunction/Elastic.svg")]
706 Elastic(f32),
707}
708
709#[doc = include_str!("../images/easefunction/Linear.svg")]
712#[derive(Copy, Clone)]
713pub struct LinearCurve;
714
715#[doc = include_str!("../images/easefunction/QuadraticIn.svg")]
723#[derive(Copy, Clone)]
724pub struct QuadraticInCurve;
725
726#[doc = include_str!("../images/easefunction/QuadraticOut.svg")]
734#[derive(Copy, Clone)]
735pub struct QuadraticOutCurve;
736
737#[doc = include_str!("../images/easefunction/QuadraticInOut.svg")]
744#[derive(Copy, Clone)]
745pub struct QuadraticInOutCurve;
746
747#[doc = include_str!("../images/easefunction/CubicIn.svg")]
756#[derive(Copy, Clone)]
757pub struct CubicInCurve;
758
759#[doc = include_str!("../images/easefunction/CubicOut.svg")]
762#[derive(Copy, Clone)]
763pub struct CubicOutCurve;
764
765#[doc = include_str!("../images/easefunction/CubicInOut.svg")]
775#[derive(Copy, Clone)]
776pub struct CubicInOutCurve;
777
778#[doc = include_str!("../images/easefunction/QuarticIn.svg")]
781#[derive(Copy, Clone)]
782pub struct QuarticInCurve;
783
784#[doc = include_str!("../images/easefunction/QuarticOut.svg")]
787#[derive(Copy, Clone)]
788pub struct QuarticOutCurve;
789
790#[doc = include_str!("../images/easefunction/QuarticInOut.svg")]
793#[derive(Copy, Clone)]
794pub struct QuarticInOutCurve;
795
796#[doc = include_str!("../images/easefunction/QuinticIn.svg")]
799#[derive(Copy, Clone)]
800pub struct QuinticInCurve;
801
802#[doc = include_str!("../images/easefunction/QuinticOut.svg")]
805#[derive(Copy, Clone)]
806pub struct QuinticOutCurve;
807
808#[doc = include_str!("../images/easefunction/QuinticInOut.svg")]
816#[derive(Copy, Clone)]
817pub struct QuinticInOutCurve;
818
819#[doc = include_str!("../images/easefunction/SmoothStepIn.svg")]
824#[derive(Copy, Clone)]
825pub struct SmoothStepInCurve;
826
827#[doc = include_str!("../images/easefunction/SmoothStepOut.svg")]
832#[derive(Copy, Clone)]
833pub struct SmoothStepOutCurve;
834
835#[doc = include_str!("../images/easefunction/SmoothStep.svg")]
848#[derive(Copy, Clone)]
849pub struct SmoothStepCurve;
850
851#[doc = include_str!("../images/easefunction/SmootherStepIn.svg")]
856#[derive(Copy, Clone)]
857pub struct SmootherStepInCurve;
858
859#[doc = include_str!("../images/easefunction/SmootherStepOut.svg")]
864#[derive(Copy, Clone)]
865pub struct SmootherStepOutCurve;
866
867#[doc = include_str!("../images/easefunction/SmootherStep.svg")]
878#[derive(Copy, Clone)]
879pub struct SmootherStepCurve;
880
881#[doc = include_str!("../images/easefunction/SineIn.svg")]
884#[derive(Copy, Clone)]
885pub struct SineInCurve;
886
887#[doc = include_str!("../images/easefunction/SineOut.svg")]
890#[derive(Copy, Clone)]
891pub struct SineOutCurve;
892
893#[doc = include_str!("../images/easefunction/SineInOut.svg")]
896#[derive(Copy, Clone)]
897pub struct SineInOutCurve;
898
899#[doc = include_str!("../images/easefunction/CircularIn.svg")]
902#[derive(Copy, Clone)]
903pub struct CircularInCurve;
904
905#[doc = include_str!("../images/easefunction/CircularOut.svg")]
908#[derive(Copy, Clone)]
909pub struct CircularOutCurve;
910
911#[doc = include_str!("../images/easefunction/CircularInOut.svg")]
914#[derive(Copy, Clone)]
915pub struct CircularInOutCurve;
916
917#[doc = include_str!("../images/easefunction/ExponentialIn.svg")]
923#[derive(Copy, Clone)]
924pub struct ExponentialInCurve;
925
926#[doc = include_str!("../images/easefunction/ExponentialOut.svg")]
932#[derive(Copy, Clone)]
933pub struct ExponentialOutCurve;
934
935#[doc = include_str!("../images/easefunction/ExponentialInOut.svg")]
938#[derive(Copy, Clone)]
939pub struct ExponentialInOutCurve;
940
941#[doc = include_str!("../images/easefunction/ElasticIn.svg")]
944#[derive(Copy, Clone)]
945pub struct ElasticInCurve;
946
947#[doc = include_str!("../images/easefunction/ElasticOut.svg")]
950#[derive(Copy, Clone)]
951pub struct ElasticOutCurve;
952
953#[doc = include_str!("../images/easefunction/ElasticInOut.svg")]
956#[derive(Copy, Clone)]
957pub struct ElasticInOutCurve;
958
959#[doc = include_str!("../images/easefunction/BackIn.svg")]
962#[derive(Copy, Clone)]
963pub struct BackInCurve;
964
965#[doc = include_str!("../images/easefunction/BackOut.svg")]
968#[derive(Copy, Clone)]
969pub struct BackOutCurve;
970
971#[doc = include_str!("../images/easefunction/BackInOut.svg")]
974#[derive(Copy, Clone)]
975pub struct BackInOutCurve;
976
977#[doc = include_str!("../images/easefunction/BounceIn.svg")]
980#[derive(Copy, Clone)]
981pub struct BounceInCurve;
982
983#[doc = include_str!("../images/easefunction/BounceOut.svg")]
986#[derive(Copy, Clone)]
987pub struct BounceOutCurve;
988
989#[doc = include_str!("../images/easefunction/BounceInOut.svg")]
992#[derive(Copy, Clone)]
993pub struct BounceInOutCurve;
994
995#[derive(Copy, Clone)]
998pub struct StepsCurve(pub usize, pub JumpAt);
999
1000#[doc = include_str!("../images/easefunction/Elastic.svg")]
1003#[derive(Copy, Clone)]
1004pub struct ElasticCurve(pub f32);
1005
1006macro_rules! impl_ease_unit_struct {
1008 ($ty: ty, $fn: ident) => {
1009 impl Curve<f32> for $ty {
1010 #[inline]
1011 fn domain(&self) -> Interval {
1012 Interval::UNIT
1013 }
1014
1015 #[inline]
1016 fn sample_unchecked(&self, t: f32) -> f32 {
1017 easing_functions::$fn(t)
1018 }
1019 }
1020 };
1021}
1022
1023impl_ease_unit_struct!(LinearCurve, linear);
1024impl_ease_unit_struct!(QuadraticInCurve, quadratic_in);
1025impl_ease_unit_struct!(QuadraticOutCurve, quadratic_out);
1026impl_ease_unit_struct!(QuadraticInOutCurve, quadratic_in_out);
1027impl_ease_unit_struct!(CubicInCurve, cubic_in);
1028impl_ease_unit_struct!(CubicOutCurve, cubic_out);
1029impl_ease_unit_struct!(CubicInOutCurve, cubic_in_out);
1030impl_ease_unit_struct!(QuarticInCurve, quartic_in);
1031impl_ease_unit_struct!(QuarticOutCurve, quartic_out);
1032impl_ease_unit_struct!(QuarticInOutCurve, quartic_in_out);
1033impl_ease_unit_struct!(QuinticInCurve, quintic_in);
1034impl_ease_unit_struct!(QuinticOutCurve, quintic_out);
1035impl_ease_unit_struct!(QuinticInOutCurve, quintic_in_out);
1036impl_ease_unit_struct!(SmoothStepInCurve, smoothstep_in);
1037impl_ease_unit_struct!(SmoothStepOutCurve, smoothstep_out);
1038impl_ease_unit_struct!(SmoothStepCurve, smoothstep);
1039impl_ease_unit_struct!(SmootherStepInCurve, smootherstep_in);
1040impl_ease_unit_struct!(SmootherStepOutCurve, smootherstep_out);
1041impl_ease_unit_struct!(SmootherStepCurve, smootherstep);
1042impl_ease_unit_struct!(SineInCurve, sine_in);
1043impl_ease_unit_struct!(SineOutCurve, sine_out);
1044impl_ease_unit_struct!(SineInOutCurve, sine_in_out);
1045impl_ease_unit_struct!(CircularInCurve, circular_in);
1046impl_ease_unit_struct!(CircularOutCurve, circular_out);
1047impl_ease_unit_struct!(CircularInOutCurve, circular_in_out);
1048impl_ease_unit_struct!(ExponentialInCurve, exponential_in);
1049impl_ease_unit_struct!(ExponentialOutCurve, exponential_out);
1050impl_ease_unit_struct!(ExponentialInOutCurve, exponential_in_out);
1051impl_ease_unit_struct!(ElasticInCurve, elastic_in);
1052impl_ease_unit_struct!(ElasticOutCurve, elastic_out);
1053impl_ease_unit_struct!(ElasticInOutCurve, elastic_in_out);
1054impl_ease_unit_struct!(BackInCurve, back_in);
1055impl_ease_unit_struct!(BackOutCurve, back_out);
1056impl_ease_unit_struct!(BackInOutCurve, back_in_out);
1057impl_ease_unit_struct!(BounceInCurve, bounce_in);
1058impl_ease_unit_struct!(BounceOutCurve, bounce_out);
1059impl_ease_unit_struct!(BounceInOutCurve, bounce_in_out);
1060
1061impl Curve<f32> for StepsCurve {
1062 #[inline]
1063 fn domain(&self) -> Interval {
1064 Interval::UNIT
1065 }
1066
1067 #[inline]
1068 fn sample_unchecked(&self, t: f32) -> f32 {
1069 easing_functions::steps(self.0, self.1, t)
1070 }
1071}
1072
1073impl Curve<f32> for ElasticCurve {
1074 #[inline]
1075 fn domain(&self) -> Interval {
1076 Interval::UNIT
1077 }
1078
1079 #[inline]
1080 fn sample_unchecked(&self, t: f32) -> f32 {
1081 easing_functions::elastic(self.0, t)
1082 }
1083}
1084
1085mod easing_functions {
1086 use core::f32::consts::{FRAC_PI_2, FRAC_PI_3, PI};
1087
1088 use bevy_math::{ops, FloatPow};
1089
1090 #[inline]
1091 pub(crate) const fn linear(t: f32) -> f32 {
1092 t
1093 }
1094
1095 #[inline]
1096 pub(crate) fn quadratic_in(t: f32) -> f32 {
1097 t.squared()
1098 }
1099 #[inline]
1100 pub(crate) fn quadratic_out(t: f32) -> f32 {
1101 1.0 - (1.0 - t).squared()
1102 }
1103 #[inline]
1104 pub(crate) fn quadratic_in_out(t: f32) -> f32 {
1105 if t < 0.5 {
1106 2.0 * t.squared()
1107 } else {
1108 1.0 - (-2.0 * t + 2.0).squared() / 2.0
1109 }
1110 }
1111
1112 #[inline]
1113 pub(crate) fn cubic_in(t: f32) -> f32 {
1114 t.cubed()
1115 }
1116 #[inline]
1117 pub(crate) fn cubic_out(t: f32) -> f32 {
1118 1.0 - (1.0 - t).cubed()
1119 }
1120 #[inline]
1121 pub(crate) fn cubic_in_out(t: f32) -> f32 {
1122 if t < 0.5 {
1123 4.0 * t.cubed()
1124 } else {
1125 1.0 - (-2.0 * t + 2.0).cubed() / 2.0
1126 }
1127 }
1128
1129 #[inline]
1130 pub(crate) const fn quartic_in(t: f32) -> f32 {
1131 t * t * t * t
1132 }
1133 #[inline]
1134 pub(crate) const fn quartic_out(t: f32) -> f32 {
1135 1.0 - (1.0 - t) * (1.0 - t) * (1.0 - t) * (1.0 - t)
1136 }
1137 #[inline]
1138 pub(crate) const fn quartic_in_out(t: f32) -> f32 {
1139 if t < 0.5 {
1140 8.0 * t * t * t * t
1141 } else {
1142 1.0 - (-2.0 * t + 2.0) * (-2.0 * t + 2.0) * (-2.0 * t + 2.0) * (-2.0 * t + 2.0) / 2.0
1143 }
1144 }
1145
1146 #[inline]
1147 pub(crate) const fn quintic_in(t: f32) -> f32 {
1148 t * t * t * t * t
1149 }
1150 #[inline]
1151 pub(crate) const fn quintic_out(t: f32) -> f32 {
1152 1.0 - (1.0 - t) * (1.0 - t) * (1.0 - t) * (1.0 - t) * (1.0 - t)
1153 }
1154 #[inline]
1155 pub(crate) const fn quintic_in_out(t: f32) -> f32 {
1156 if t < 0.5 {
1157 16.0 * t * t * t * t * t
1158 } else {
1159 1.0 - (-2.0 * t + 2.0)
1160 * (-2.0 * t + 2.0)
1161 * (-2.0 * t + 2.0)
1162 * (-2.0 * t + 2.0)
1163 * (-2.0 * t + 2.0)
1164 / 2.0
1165 }
1166 }
1167
1168 #[inline]
1169 pub(crate) const fn smoothstep_in(t: f32) -> f32 {
1170 ((1.5 - 0.5 * t) * t) * t
1171 }
1172
1173 #[inline]
1174 pub(crate) const fn smoothstep_out(t: f32) -> f32 {
1175 (1.5 + (-0.5 * t) * t) * t
1176 }
1177
1178 #[inline]
1179 pub(crate) const fn smoothstep(t: f32) -> f32 {
1180 ((3.0 - 2.0 * t) * t) * t
1181 }
1182
1183 #[inline]
1184 pub(crate) const fn smootherstep_in(t: f32) -> f32 {
1185 (((2.5 + (-1.875 + 0.375 * t) * t) * t) * t) * t
1186 }
1187
1188 #[inline]
1189 pub(crate) const fn smootherstep_out(t: f32) -> f32 {
1190 (1.875 + ((-1.25 + (0.375 * t) * t) * t) * t) * t
1191 }
1192
1193 #[inline]
1194 pub(crate) const fn smootherstep(t: f32) -> f32 {
1195 (((10.0 + (-15.0 + 6.0 * t) * t) * t) * t) * t
1196 }
1197
1198 #[inline]
1199 pub(crate) fn sine_in(t: f32) -> f32 {
1200 1.0 - ops::cos(t * FRAC_PI_2)
1201 }
1202 #[inline]
1203 pub(crate) fn sine_out(t: f32) -> f32 {
1204 ops::sin(t * FRAC_PI_2)
1205 }
1206 #[inline]
1207 pub(crate) fn sine_in_out(t: f32) -> f32 {
1208 -(ops::cos(PI * t) - 1.0) / 2.0
1209 }
1210
1211 #[inline]
1212 pub(crate) fn circular_in(t: f32) -> f32 {
1213 1.0 - ops::sqrt(1.0 - t.squared())
1214 }
1215 #[inline]
1216 pub(crate) fn circular_out(t: f32) -> f32 {
1217 ops::sqrt(1.0 - (t - 1.0).squared())
1218 }
1219 #[inline]
1220 pub(crate) fn circular_in_out(t: f32) -> f32 {
1221 if t < 0.5 {
1222 (1.0 - ops::sqrt(1.0 - (2.0 * t).squared())) / 2.0
1223 } else {
1224 (ops::sqrt(1.0 - (-2.0 * t + 2.0).squared()) + 1.0) / 2.0
1225 }
1226 }
1227
1228 #[expect(
1233 clippy::excessive_precision,
1234 reason = "This is deliberately more precise than an f32 will allow, as truncating the value might imply that the value is carefully chosen."
1235 )]
1236 const LOG2_1023: f32 = 9.998590429745328646459226;
1237 #[expect(
1238 clippy::excessive_precision,
1239 reason = "This is deliberately more precise than an f32 will allow, as truncating the value might imply that the value is carefully chosen."
1240 )]
1241 const FRAC_1_1023: f32 = 0.00097751710654936461388074291;
1242 #[inline]
1243 pub(crate) fn exponential_in(t: f32) -> f32 {
1244 ops::exp2(10.0 * t - LOG2_1023) - FRAC_1_1023
1247 }
1248 #[inline]
1249 pub(crate) fn exponential_out(t: f32) -> f32 {
1250 (FRAC_1_1023 + 1.0) - ops::exp2(-10.0 * t - (LOG2_1023 - 10.0))
1251 }
1252 #[inline]
1253 pub(crate) fn exponential_in_out(t: f32) -> f32 {
1254 if t < 0.5 {
1255 ops::exp2(20.0 * t - (LOG2_1023 + 1.0)) - (FRAC_1_1023 / 2.0)
1256 } else {
1257 (FRAC_1_1023 / 2.0 + 1.0) - ops::exp2(-20.0 * t - (LOG2_1023 - 19.0))
1258 }
1259 }
1260
1261 #[inline]
1262 pub(crate) fn back_in(t: f32) -> f32 {
1263 let c = 1.70158;
1264
1265 (c + 1.0) * t.cubed() - c * t.squared()
1266 }
1267 #[inline]
1268 pub(crate) fn back_out(t: f32) -> f32 {
1269 let c = 1.70158;
1270
1271 1.0 + (c + 1.0) * (t - 1.0).cubed() + c * (t - 1.0).squared()
1272 }
1273 #[inline]
1274 pub(crate) fn back_in_out(t: f32) -> f32 {
1275 let c1 = 1.70158;
1276 let c2 = c1 + 1.525;
1277
1278 if t < 0.5 {
1279 (2.0 * t).squared() * ((c2 + 1.0) * 2.0 * t - c2) / 2.0
1280 } else {
1281 ((2.0 * t - 2.0).squared() * ((c2 + 1.0) * (2.0 * t - 2.0) + c2) + 2.0) / 2.0
1282 }
1283 }
1284
1285 #[inline]
1286 pub(crate) fn elastic_in(t: f32) -> f32 {
1287 -ops::powf(2.0, 10.0 * t - 10.0) * ops::sin((t * 10.0 - 10.75) * 2.0 * FRAC_PI_3)
1288 }
1289 #[inline]
1290 pub(crate) fn elastic_out(t: f32) -> f32 {
1291 ops::powf(2.0, -10.0 * t) * ops::sin((t * 10.0 - 0.75) * 2.0 * FRAC_PI_3) + 1.0
1292 }
1293 #[inline]
1294 pub(crate) fn elastic_in_out(t: f32) -> f32 {
1295 let c = (2.0 * PI) / 4.5;
1296
1297 if t < 0.5 {
1298 -ops::powf(2.0, 20.0 * t - 10.0) * ops::sin((t * 20.0 - 11.125) * c) / 2.0
1299 } else {
1300 ops::powf(2.0, -20.0 * t + 10.0) * ops::sin((t * 20.0 - 11.125) * c) / 2.0 + 1.0
1301 }
1302 }
1303
1304 #[inline]
1305 pub(crate) fn bounce_in(t: f32) -> f32 {
1306 1.0 - bounce_out(1.0 - t)
1307 }
1308 #[inline]
1309 pub(crate) fn bounce_out(t: f32) -> f32 {
1310 if t < 4.0 / 11.0 {
1311 (121.0 * t.squared()) / 16.0
1312 } else if t < 8.0 / 11.0 {
1313 (363.0 / 40.0 * t.squared()) - (99.0 / 10.0 * t) + 17.0 / 5.0
1314 } else if t < 9.0 / 10.0 {
1315 (4356.0 / 361.0 * t.squared()) - (35442.0 / 1805.0 * t) + 16061.0 / 1805.0
1316 } else {
1317 (54.0 / 5.0 * t.squared()) - (513.0 / 25.0 * t) + 268.0 / 25.0
1318 }
1319 }
1320 #[inline]
1321 pub(crate) fn bounce_in_out(t: f32) -> f32 {
1322 if t < 0.5 {
1323 (1.0 - bounce_out(1.0 - 2.0 * t)) / 2.0
1324 } else {
1325 (1.0 + bounce_out(2.0 * t - 1.0)) / 2.0
1326 }
1327 }
1328
1329 #[inline]
1330 pub(crate) fn steps(num_steps: usize, jump_at: super::JumpAt, t: f32) -> f32 {
1331 jump_at.eval(num_steps, t)
1332 }
1333
1334 #[inline]
1335 pub(crate) fn elastic(omega: f32, t: f32) -> f32 {
1336 1.0 - (1.0 - t).squared() * (2.0 * ops::sin(omega * t) / omega + ops::cos(omega * t))
1337 }
1338}
1339
1340impl EaseFunction {
1341 fn eval(&self, t: f32) -> f32 {
1342 match self {
1343 EaseFunction::Linear => easing_functions::linear(t),
1344 EaseFunction::QuadraticIn => easing_functions::quadratic_in(t),
1345 EaseFunction::QuadraticOut => easing_functions::quadratic_out(t),
1346 EaseFunction::QuadraticInOut => easing_functions::quadratic_in_out(t),
1347 EaseFunction::CubicIn => easing_functions::cubic_in(t),
1348 EaseFunction::CubicOut => easing_functions::cubic_out(t),
1349 EaseFunction::CubicInOut => easing_functions::cubic_in_out(t),
1350 EaseFunction::QuarticIn => easing_functions::quartic_in(t),
1351 EaseFunction::QuarticOut => easing_functions::quartic_out(t),
1352 EaseFunction::QuarticInOut => easing_functions::quartic_in_out(t),
1353 EaseFunction::QuinticIn => easing_functions::quintic_in(t),
1354 EaseFunction::QuinticOut => easing_functions::quintic_out(t),
1355 EaseFunction::QuinticInOut => easing_functions::quintic_in_out(t),
1356 EaseFunction::SmoothStepIn => easing_functions::smoothstep_in(t),
1357 EaseFunction::SmoothStepOut => easing_functions::smoothstep_out(t),
1358 EaseFunction::SmoothStep => easing_functions::smoothstep(t),
1359 EaseFunction::SmootherStepIn => easing_functions::smootherstep_in(t),
1360 EaseFunction::SmootherStepOut => easing_functions::smootherstep_out(t),
1361 EaseFunction::SmootherStep => easing_functions::smootherstep(t),
1362 EaseFunction::SineIn => easing_functions::sine_in(t),
1363 EaseFunction::SineOut => easing_functions::sine_out(t),
1364 EaseFunction::SineInOut => easing_functions::sine_in_out(t),
1365 EaseFunction::CircularIn => easing_functions::circular_in(t),
1366 EaseFunction::CircularOut => easing_functions::circular_out(t),
1367 EaseFunction::CircularInOut => easing_functions::circular_in_out(t),
1368 EaseFunction::ExponentialIn => easing_functions::exponential_in(t),
1369 EaseFunction::ExponentialOut => easing_functions::exponential_out(t),
1370 EaseFunction::ExponentialInOut => easing_functions::exponential_in_out(t),
1371 EaseFunction::ElasticIn => easing_functions::elastic_in(t),
1372 EaseFunction::ElasticOut => easing_functions::elastic_out(t),
1373 EaseFunction::ElasticInOut => easing_functions::elastic_in_out(t),
1374 EaseFunction::BackIn => easing_functions::back_in(t),
1375 EaseFunction::BackOut => easing_functions::back_out(t),
1376 EaseFunction::BackInOut => easing_functions::back_in_out(t),
1377 EaseFunction::BounceIn => easing_functions::bounce_in(t),
1378 EaseFunction::BounceOut => easing_functions::bounce_out(t),
1379 EaseFunction::BounceInOut => easing_functions::bounce_in_out(t),
1380 EaseFunction::Steps(num_steps, jump_at) => {
1381 easing_functions::steps(*num_steps, *jump_at, t)
1382 }
1383 EaseFunction::Elastic(omega) => easing_functions::elastic(*omega, t),
1384 }
1385 }
1386}
1387
1388impl Curve<f32> for EaseFunction {
1389 #[inline]
1390 fn domain(&self) -> Interval {
1391 Interval::UNIT
1392 }
1393
1394 #[inline]
1395 fn sample_unchecked(&self, t: f32) -> f32 {
1396 self.eval(t)
1397 }
1398}
1399
1400#[cfg(test)]
1401#[cfg(feature = "approx")]
1402mod tests {
1403
1404 use approx::assert_abs_diff_eq;
1405 use bevy_math::{Vec2, Vec3, Vec3A};
1406
1407 use super::*;
1408 const MONOTONIC_IN_OUT_INOUT: &[[EaseFunction; 3]] = {
1409 use EaseFunction::*;
1410 &[
1411 [QuadraticIn, QuadraticOut, QuadraticInOut],
1412 [CubicIn, CubicOut, CubicInOut],
1413 [QuarticIn, QuarticOut, QuarticInOut],
1414 [QuinticIn, QuinticOut, QuinticInOut],
1415 [SmoothStepIn, SmoothStepOut, SmoothStep],
1416 [SmootherStepIn, SmootherStepOut, SmootherStep],
1417 [SineIn, SineOut, SineInOut],
1418 [CircularIn, CircularOut, CircularInOut],
1419 [ExponentialIn, ExponentialOut, ExponentialInOut],
1420 ]
1421 };
1422
1423 const TOLERANCE: f32 = 1.0e-6;
1426 const _: () = const {
1427 assert!(1.0 - TOLERANCE != 1.0);
1428 };
1429
1430 #[test]
1431 fn ease_functions_zero_to_one() {
1432 for ef in MONOTONIC_IN_OUT_INOUT.iter().flatten() {
1433 let start = ef.eval(0.0);
1434 assert!(
1435 (0.0..=TOLERANCE).contains(&start),
1436 "EaseFunction.{ef:?}(0) was {start:?}",
1437 );
1438
1439 let finish = ef.eval(1.0);
1440 assert!(
1441 (1.0 - TOLERANCE..=1.0).contains(&finish),
1442 "EaseFunction.{ef:?}(1) was {start:?}",
1443 );
1444 }
1445 }
1446
1447 #[test]
1448 fn ease_function_inout_deciles() {
1449 for [ef_in, ef_out, ef_inout] in MONOTONIC_IN_OUT_INOUT {
1451 for x in [0.1, 0.2, 0.3, 0.4] {
1452 let y = ef_inout.eval(x);
1453 assert!(y < x, "EaseFunction.{ef_inout:?}({x:?}) was {y:?}");
1454
1455 let iny = ef_in.eval(2.0 * x) / 2.0;
1456 assert!(
1457 (y - TOLERANCE..y + TOLERANCE).contains(&iny),
1458 "EaseFunction.{ef_inout:?}({x:?}) was {y:?}, but \
1459 EaseFunction.{ef_in:?}(2 * {x:?}) / 2 was {iny:?}",
1460 );
1461 }
1462
1463 for x in [0.6, 0.7, 0.8, 0.9] {
1464 let y = ef_inout.eval(x);
1465 assert!(y > x, "EaseFunction.{ef_inout:?}({x:?}) was {y:?}");
1466
1467 let outy = ef_out.eval(2.0 * x - 1.0) / 2.0 + 0.5;
1468 assert!(
1469 (y - TOLERANCE..y + TOLERANCE).contains(&outy),
1470 "EaseFunction.{ef_inout:?}({x:?}) was {y:?}, but \
1471 EaseFunction.{ef_out:?}(2 * {x:?} - 1) / 2 + ½ was {outy:?}",
1472 );
1473 }
1474 }
1475 }
1476
1477 #[test]
1478 fn ease_function_midpoints() {
1479 for [ef_in, ef_out, ef_inout] in MONOTONIC_IN_OUT_INOUT {
1480 let mid = ef_in.eval(0.5);
1481 assert!(
1482 mid < 0.5 - TOLERANCE,
1483 "EaseFunction.{ef_in:?}(½) was {mid:?}",
1484 );
1485
1486 let mid = ef_out.eval(0.5);
1487 assert!(
1488 mid > 0.5 + TOLERANCE,
1489 "EaseFunction.{ef_out:?}(½) was {mid:?}",
1490 );
1491
1492 let mid = ef_inout.eval(0.5);
1493 assert!(
1494 (0.5 - TOLERANCE..=0.5 + TOLERANCE).contains(&mid),
1495 "EaseFunction.{ef_inout:?}(½) was {mid:?}",
1496 );
1497 }
1498 }
1499
1500 #[test]
1501 fn ease_quats() {
1502 let quat_start = Quat::from_axis_angle(Vec3::Z, 0.0);
1503 let quat_end = Quat::from_axis_angle(Vec3::Z, 90.0_f32.to_radians());
1504
1505 let quat_curve = Quat::interpolating_curve_unbounded(quat_start, quat_end);
1506
1507 assert_abs_diff_eq!(
1508 quat_curve.sample(0.0).unwrap(),
1509 Quat::from_axis_angle(Vec3::Z, 0.0)
1510 );
1511 {
1512 let (before_mid_axis, before_mid_angle) =
1513 quat_curve.sample(0.25).unwrap().to_axis_angle();
1514 assert_abs_diff_eq!(before_mid_axis, Vec3::Z);
1515 assert_abs_diff_eq!(before_mid_angle, 22.5_f32.to_radians());
1516 }
1517 {
1518 let (mid_axis, mid_angle) = quat_curve.sample(0.5).unwrap().to_axis_angle();
1519 assert_abs_diff_eq!(mid_axis, Vec3::Z);
1520 assert_abs_diff_eq!(mid_angle, 45.0_f32.to_radians());
1521 }
1522 {
1523 let (after_mid_axis, after_mid_angle) =
1524 quat_curve.sample(0.75).unwrap().to_axis_angle();
1525 assert_abs_diff_eq!(after_mid_axis, Vec3::Z);
1526 assert_abs_diff_eq!(after_mid_angle, 67.5_f32.to_radians());
1527 }
1528 assert_abs_diff_eq!(
1529 quat_curve.sample(1.0).unwrap(),
1530 Quat::from_axis_angle(Vec3::Z, 90.0_f32.to_radians())
1531 );
1532 }
1533
1534 #[test]
1535 fn ease_isometries_2d() {
1536 let angle = 90.0;
1537 let iso_2d_start = Isometry2d::new(Vec2::ZERO, Rot2::degrees(0.0));
1538 let iso_2d_end = Isometry2d::new(Vec2::ONE, Rot2::degrees(angle));
1539
1540 let iso_2d_curve = Isometry2d::interpolating_curve_unbounded(iso_2d_start, iso_2d_end);
1541
1542 [-1.0, 0.0, 0.5, 1.0, 2.0].into_iter().for_each(|t| {
1543 assert_abs_diff_eq!(
1544 iso_2d_curve.sample(t).unwrap(),
1545 Isometry2d::new(Vec2::ONE * t, Rot2::degrees(angle * t))
1546 );
1547 });
1548 }
1549
1550 #[test]
1551 fn ease_isometries_3d() {
1552 let angle = 90.0_f32.to_radians();
1553 let iso_3d_start = Isometry3d::new(Vec3A::ZERO, Quat::from_axis_angle(Vec3::Z, 0.0));
1554 let iso_3d_end = Isometry3d::new(Vec3A::ONE, Quat::from_axis_angle(Vec3::Z, angle));
1555
1556 let iso_3d_curve = Isometry3d::interpolating_curve_unbounded(iso_3d_start, iso_3d_end);
1557
1558 [-1.0, 0.0, 0.5, 1.0, 2.0].into_iter().for_each(|t| {
1559 assert_abs_diff_eq!(
1560 iso_3d_curve.sample(t).unwrap(),
1561 Isometry3d::new(Vec3A::ONE * t, Quat::from_axis_angle(Vec3::Z, angle * t))
1562 );
1563 });
1564 }
1565
1566 #[test]
1567 fn jump_at_start() {
1568 let jump_at = JumpAt::Start;
1569 let num_steps = 4;
1570
1571 [
1572 (0.0, 0.25),
1573 (0.249, 0.25),
1574 (0.25, 0.5),
1575 (0.499, 0.5),
1576 (0.5, 0.75),
1577 (0.749, 0.75),
1578 (0.75, 1.0),
1579 (1.0, 1.0),
1580 ]
1581 .into_iter()
1582 .for_each(|(t, expected)| {
1583 assert_abs_diff_eq!(jump_at.eval(num_steps, t), expected);
1584 });
1585 }
1586
1587 #[test]
1588 fn jump_at_end() {
1589 let jump_at = JumpAt::End;
1590 let num_steps = 4;
1591
1592 [
1593 (0.0, 0.0),
1594 (0.249, 0.0),
1595 (0.25, 0.25),
1596 (0.499, 0.25),
1597 (0.5, 0.5),
1598 (0.749, 0.5),
1599 (0.75, 0.75),
1600 (0.999, 0.75),
1601 (1.0, 1.0),
1602 ]
1603 .into_iter()
1604 .for_each(|(t, expected)| {
1605 assert_abs_diff_eq!(jump_at.eval(num_steps, t), expected);
1606 });
1607 }
1608
1609 #[test]
1610 fn jump_at_none() {
1611 let jump_at = JumpAt::None;
1612 let num_steps = 5;
1613
1614 [
1615 (0.0, 0.0),
1616 (0.199, 0.0),
1617 (0.2, 0.25),
1618 (0.399, 0.25),
1619 (0.4, 0.5),
1620 (0.599, 0.5),
1621 (0.6, 0.75),
1622 (0.799, 0.75),
1623 (0.8, 1.0),
1624 (0.999, 1.0),
1625 (1.0, 1.0),
1626 ]
1627 .into_iter()
1628 .for_each(|(t, expected)| {
1629 assert_abs_diff_eq!(jump_at.eval(num_steps, t), expected);
1630 });
1631 }
1632
1633 #[test]
1634 fn jump_at_both() {
1635 let jump_at = JumpAt::Both;
1636 let num_steps = 4;
1637
1638 [
1639 (0.0, 0.2),
1640 (0.249, 0.2),
1641 (0.25, 0.4),
1642 (0.499, 0.4),
1643 (0.5, 0.6),
1644 (0.749, 0.6),
1645 (0.75, 0.8),
1646 (0.999, 0.8),
1647 (1.0, 1.0),
1648 ]
1649 .into_iter()
1650 .for_each(|(t, expected)| {
1651 assert_abs_diff_eq!(jump_at.eval(num_steps, t), expected);
1652 });
1653 }
1654
1655 #[test]
1656 fn ease_function_curve() {
1657 let f0 = SmoothStepCurve;
1661 let f1 = EaseFunction::SmoothStep;
1662 let f2 = EasingCurve::new(0.0, 1.0, EaseFunction::SmoothStep);
1663
1664 assert_eq!(f0.domain(), f1.domain());
1665 assert_eq!(f0.domain(), f2.domain());
1666
1667 [
1668 -1.0,
1669 -f32::MIN_POSITIVE,
1670 0.0,
1671 0.5,
1672 1.0,
1673 1.0 + f32::EPSILON,
1674 2.0,
1675 ]
1676 .into_iter()
1677 .for_each(|t| {
1678 assert_eq!(f0.sample(t), f1.sample(t));
1679 assert_eq!(f0.sample(t), f2.sample(t));
1680
1681 assert_eq!(f0.sample_clamped(t), f1.sample_clamped(t));
1682 assert_eq!(f0.sample_clamped(t), f2.sample_clamped(t));
1683 });
1684 }
1685
1686 #[test]
1687 fn unit_structs_match_function() {
1688 fn test(f1: impl Curve<f32>, f2: impl Curve<f32>, t: f32) {
1692 assert_eq!(f1.sample(t), f2.sample(t));
1693 }
1694
1695 for t in [-1.0, 0.0, 0.25, 0.5, 0.75, 1.0, 2.0] {
1696 test(LinearCurve, EaseFunction::Linear, t);
1697 test(QuadraticInCurve, EaseFunction::QuadraticIn, t);
1698 test(QuadraticOutCurve, EaseFunction::QuadraticOut, t);
1699 test(QuadraticInOutCurve, EaseFunction::QuadraticInOut, t);
1700 test(CubicInCurve, EaseFunction::CubicIn, t);
1701 test(CubicOutCurve, EaseFunction::CubicOut, t);
1702 test(CubicInOutCurve, EaseFunction::CubicInOut, t);
1703 test(QuarticInCurve, EaseFunction::QuarticIn, t);
1704 test(QuarticOutCurve, EaseFunction::QuarticOut, t);
1705 test(QuarticInOutCurve, EaseFunction::QuarticInOut, t);
1706 test(QuinticInCurve, EaseFunction::QuinticIn, t);
1707 test(QuinticOutCurve, EaseFunction::QuinticOut, t);
1708 test(QuinticInOutCurve, EaseFunction::QuinticInOut, t);
1709 test(SmoothStepInCurve, EaseFunction::SmoothStepIn, t);
1710 test(SmoothStepOutCurve, EaseFunction::SmoothStepOut, t);
1711 test(SmoothStepCurve, EaseFunction::SmoothStep, t);
1712 test(SmootherStepInCurve, EaseFunction::SmootherStepIn, t);
1713 test(SmootherStepOutCurve, EaseFunction::SmootherStepOut, t);
1714 test(SmootherStepCurve, EaseFunction::SmootherStep, t);
1715 test(SineInCurve, EaseFunction::SineIn, t);
1716 test(SineOutCurve, EaseFunction::SineOut, t);
1717 test(SineInOutCurve, EaseFunction::SineInOut, t);
1718 test(CircularInCurve, EaseFunction::CircularIn, t);
1719 test(CircularOutCurve, EaseFunction::CircularOut, t);
1720 test(CircularInOutCurve, EaseFunction::CircularInOut, t);
1721 test(ExponentialInCurve, EaseFunction::ExponentialIn, t);
1722 test(ExponentialOutCurve, EaseFunction::ExponentialOut, t);
1723 test(ExponentialInOutCurve, EaseFunction::ExponentialInOut, t);
1724 test(ElasticInCurve, EaseFunction::ElasticIn, t);
1725 test(ElasticOutCurve, EaseFunction::ElasticOut, t);
1726 test(ElasticInOutCurve, EaseFunction::ElasticInOut, t);
1727 test(BackInCurve, EaseFunction::BackIn, t);
1728 test(BackOutCurve, EaseFunction::BackOut, t);
1729 test(BackInOutCurve, EaseFunction::BackInOut, t);
1730 test(BounceInCurve, EaseFunction::BounceIn, t);
1731 test(BounceOutCurve, EaseFunction::BounceOut, t);
1732 test(BounceInOutCurve, EaseFunction::BounceInOut, t);
1733
1734 test(
1735 StepsCurve(4, JumpAt::Start),
1736 EaseFunction::Steps(4, JumpAt::Start),
1737 t,
1738 );
1739
1740 test(ElasticCurve(50.0), EaseFunction::Elastic(50.0), t);
1741 }
1742 }
1743}