1use super::cores::{EvenCore, EvenCoreError, UnevenCore, UnevenCoreError};
4use super::{Curve, Interval};
5
6use crate::StableInterpolate;
7use core::any::type_name;
8use core::fmt::{self, Debug};
9
10#[cfg(feature = "bevy_reflect")]
11use bevy_reflect::{utility::GenericTypePathCell, Reflect, TypePath};
12
13#[cfg(feature = "bevy_reflect")]
14mod paths {
15 pub(super) const THIS_MODULE: &str = "bevy_math::curve::sample_curves";
16 pub(super) const THIS_CRATE: &str = "bevy_math";
17}
18
19#[derive(Clone)]
21#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(
23 feature = "bevy_reflect",
24 derive(Reflect),
25 reflect(where T: TypePath),
26 reflect(from_reflect = false, type_path = false),
27)]
28pub struct SampleCurve<T, I> {
29 pub(crate) core: EvenCore<T>,
30 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
31 pub(crate) interpolation: I,
32}
33
34impl<T, I> Debug for SampleCurve<T, I>
35where
36 EvenCore<T>: Debug,
37{
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("SampleCurve")
40 .field("core", &self.core)
41 .field("interpolation", &type_name::<I>())
42 .finish()
43 }
44}
45
46#[cfg(feature = "bevy_reflect")]
49impl<T, I> TypePath for SampleCurve<T, I>
50where
51 T: TypePath,
52 I: 'static,
53{
54 fn type_path() -> &'static str {
55 static CELL: GenericTypePathCell = GenericTypePathCell::new();
56 CELL.get_or_insert::<Self, _>(|| {
57 format!(
58 "{}::SampleCurve<{},{}>",
59 paths::THIS_MODULE,
60 T::type_path(),
61 type_name::<I>()
62 )
63 })
64 }
65
66 fn short_type_path() -> &'static str {
67 static CELL: GenericTypePathCell = GenericTypePathCell::new();
68 CELL.get_or_insert::<Self, _>(|| {
69 format!("SampleCurve<{},{}>", T::type_path(), type_name::<I>())
70 })
71 }
72
73 fn type_ident() -> Option<&'static str> {
74 Some("SampleCurve")
75 }
76
77 fn crate_name() -> Option<&'static str> {
78 Some(paths::THIS_CRATE)
79 }
80
81 fn module_path() -> Option<&'static str> {
82 Some(paths::THIS_MODULE)
83 }
84}
85
86impl<T, I> Curve<T> for SampleCurve<T, I>
87where
88 T: Clone,
89 I: Fn(&T, &T, f32) -> T,
90{
91 #[inline]
92 fn domain(&self) -> Interval {
93 self.core.domain()
94 }
95
96 #[inline]
97 fn sample_clamped(&self, t: f32) -> T {
98 self.core.sample_with(t, &self.interpolation)
100 }
101
102 #[inline]
103 fn sample_unchecked(&self, t: f32) -> T {
104 self.sample_clamped(t)
105 }
106}
107
108impl<T, I> SampleCurve<T, I> {
109 pub fn new(
117 domain: Interval,
118 samples: impl IntoIterator<Item = T>,
119 interpolation: I,
120 ) -> Result<Self, EvenCoreError>
121 where
122 I: Fn(&T, &T, f32) -> T,
123 {
124 Ok(Self {
125 core: EvenCore::new(domain, samples)?,
126 interpolation,
127 })
128 }
129}
130
131#[derive(Clone, Debug)]
136#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
137#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
138pub struct SampleAutoCurve<T> {
139 pub(crate) core: EvenCore<T>,
140}
141
142impl<T> Curve<T> for SampleAutoCurve<T>
143where
144 T: StableInterpolate,
145{
146 #[inline]
147 fn domain(&self) -> Interval {
148 self.core.domain()
149 }
150
151 #[inline]
152 fn sample_clamped(&self, t: f32) -> T {
153 self.core
155 .sample_with(t, <T as StableInterpolate>::interpolate_stable)
156 }
157
158 #[inline]
159 fn sample_unchecked(&self, t: f32) -> T {
160 self.sample_clamped(t)
161 }
162}
163
164impl<T> SampleAutoCurve<T> {
165 pub fn new(
169 domain: Interval,
170 samples: impl IntoIterator<Item = T>,
171 ) -> Result<Self, EvenCoreError> {
172 Ok(Self {
173 core: EvenCore::new(domain, samples)?,
174 })
175 }
176}
177
178#[derive(Clone)]
181#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
182#[cfg_attr(
183 feature = "bevy_reflect",
184 derive(Reflect),
185 reflect(where T: TypePath),
186 reflect(from_reflect = false, type_path = false),
187)]
188pub struct UnevenSampleCurve<T, I> {
189 pub(crate) core: UnevenCore<T>,
190 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
191 pub(crate) interpolation: I,
192}
193
194impl<T, I> Debug for UnevenSampleCurve<T, I>
195where
196 UnevenCore<T>: Debug,
197{
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 f.debug_struct("SampleCurve")
200 .field("core", &self.core)
201 .field("interpolation", &type_name::<I>())
202 .finish()
203 }
204}
205
206#[cfg(feature = "bevy_reflect")]
209impl<T, I> TypePath for UnevenSampleCurve<T, I>
210where
211 T: TypePath,
212 I: 'static,
213{
214 fn type_path() -> &'static str {
215 static CELL: GenericTypePathCell = GenericTypePathCell::new();
216 CELL.get_or_insert::<Self, _>(|| {
217 format!(
218 "{}::UnevenSampleCurve<{},{}>",
219 paths::THIS_MODULE,
220 T::type_path(),
221 type_name::<I>()
222 )
223 })
224 }
225
226 fn short_type_path() -> &'static str {
227 static CELL: GenericTypePathCell = GenericTypePathCell::new();
228 CELL.get_or_insert::<Self, _>(|| {
229 format!("UnevenSampleCurve<{},{}>", T::type_path(), type_name::<I>())
230 })
231 }
232
233 fn type_ident() -> Option<&'static str> {
234 Some("UnevenSampleCurve")
235 }
236
237 fn crate_name() -> Option<&'static str> {
238 Some(paths::THIS_CRATE)
239 }
240
241 fn module_path() -> Option<&'static str> {
242 Some(paths::THIS_MODULE)
243 }
244}
245
246impl<T, I> Curve<T> for UnevenSampleCurve<T, I>
247where
248 T: Clone,
249 I: Fn(&T, &T, f32) -> T,
250{
251 #[inline]
252 fn domain(&self) -> Interval {
253 self.core.domain()
254 }
255
256 #[inline]
257 fn sample_clamped(&self, t: f32) -> T {
258 self.core.sample_with(t, &self.interpolation)
260 }
261
262 #[inline]
263 fn sample_unchecked(&self, t: f32) -> T {
264 self.sample_clamped(t)
265 }
266}
267
268impl<T, I> UnevenSampleCurve<T, I> {
269 pub fn new(
278 timed_samples: impl IntoIterator<Item = (f32, T)>,
279 interpolation: I,
280 ) -> Result<Self, UnevenCoreError> {
281 Ok(Self {
282 core: UnevenCore::new(timed_samples)?,
283 interpolation,
284 })
285 }
286
287 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleCurve<T, I> {
294 Self {
295 core: self.core.map_sample_times(f),
296 interpolation: self.interpolation,
297 }
298 }
299}
300
301#[derive(Clone, Debug)]
306#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
307#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
308pub struct UnevenSampleAutoCurve<T> {
309 pub(crate) core: UnevenCore<T>,
310}
311
312impl<T> Curve<T> for UnevenSampleAutoCurve<T>
313where
314 T: StableInterpolate,
315{
316 #[inline]
317 fn domain(&self) -> Interval {
318 self.core.domain()
319 }
320
321 #[inline]
322 fn sample_clamped(&self, t: f32) -> T {
323 self.core
325 .sample_with(t, <T as StableInterpolate>::interpolate_stable)
326 }
327
328 #[inline]
329 fn sample_unchecked(&self, t: f32) -> T {
330 self.sample_clamped(t)
331 }
332}
333
334impl<T> UnevenSampleAutoCurve<T> {
335 pub fn new(timed_samples: impl IntoIterator<Item = (f32, T)>) -> Result<Self, UnevenCoreError> {
340 Ok(Self {
341 core: UnevenCore::new(timed_samples)?,
342 })
343 }
344
345 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleAutoCurve<T> {
352 Self {
353 core: self.core.map_sample_times(f),
354 }
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::{SampleCurve, UnevenSampleCurve};
366 use crate::{curve::Interval, VectorSpace};
367 use bevy_reflect::Reflect;
368
369 #[test]
370 fn reflect_sample_curve() {
371 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
372 x.lerp(*y, t)
373 }
374 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
375 let baz: fn(&f32, &f32, f32) -> f32 = bar;
376
377 let samples = [0.0, 1.0, 2.0];
378
379 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, foo).unwrap());
380 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, bar).unwrap());
381 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, baz).unwrap());
382 }
383
384 #[test]
385 fn reflect_uneven_sample_curve() {
386 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
387 x.lerp(*y, t)
388 }
389 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
390 let baz: fn(&f32, &f32, f32) -> f32 = bar;
391
392 let keyframes = [(0.0, 1.0), (1.0, 0.0), (2.0, -1.0)];
393
394 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, foo).unwrap());
395 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, bar).unwrap());
396 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, baz).unwrap());
397 }
398}