1use super::cores::{EvenCore, EvenCoreError, UnevenCore, UnevenCoreError};
4use super::{Curve, Interval};
5
6use crate::StableInterpolate;
7#[cfg(feature = "bevy_reflect")]
8use alloc::format;
9use core::any::type_name;
10use core::fmt::{self, Debug};
11
12#[cfg(feature = "bevy_reflect")]
13use bevy_reflect::{utility::GenericTypePathCell, Reflect, TypePath};
14
15#[cfg(feature = "bevy_reflect")]
16mod paths {
17 pub(super) const THIS_MODULE: &str = "bevy_math::curve::sample_curves";
18 pub(super) const THIS_CRATE: &str = "bevy_math";
19}
20
21#[derive(Clone)]
23#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(
25 feature = "bevy_reflect",
26 derive(Reflect),
27 reflect(where T: TypePath),
28 reflect(from_reflect = false, type_path = false),
29)]
30pub struct SampleCurve<T, I> {
31 pub(crate) core: EvenCore<T>,
32 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
33 pub(crate) interpolation: I,
34}
35
36impl<T, I> Debug for SampleCurve<T, I>
37where
38 EvenCore<T>: Debug,
39{
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 f.debug_struct("SampleCurve")
42 .field("core", &self.core)
43 .field("interpolation", &type_name::<I>())
44 .finish()
45 }
46}
47
48#[cfg(feature = "bevy_reflect")]
51impl<T, I> TypePath for SampleCurve<T, I>
52where
53 T: TypePath,
54 I: 'static,
55{
56 fn type_path() -> &'static str {
57 static CELL: GenericTypePathCell = GenericTypePathCell::new();
58 CELL.get_or_insert::<Self, _>(|| {
59 format!(
60 "{}::SampleCurve<{},{}>",
61 paths::THIS_MODULE,
62 T::type_path(),
63 type_name::<I>()
64 )
65 })
66 }
67
68 fn short_type_path() -> &'static str {
69 static CELL: GenericTypePathCell = GenericTypePathCell::new();
70 CELL.get_or_insert::<Self, _>(|| {
71 format!("SampleCurve<{},{}>", T::type_path(), type_name::<I>())
72 })
73 }
74
75 fn type_ident() -> Option<&'static str> {
76 Some("SampleCurve")
77 }
78
79 fn crate_name() -> Option<&'static str> {
80 Some(paths::THIS_CRATE)
81 }
82
83 fn module_path() -> Option<&'static str> {
84 Some(paths::THIS_MODULE)
85 }
86}
87
88impl<T, I> Curve<T> for SampleCurve<T, I>
89where
90 T: Clone,
91 I: Fn(&T, &T, f32) -> T,
92{
93 #[inline]
94 fn domain(&self) -> Interval {
95 self.core.domain()
96 }
97
98 #[inline]
99 fn sample_clamped(&self, t: f32) -> T {
100 self.core.sample_with(t, &self.interpolation)
102 }
103
104 #[inline]
105 fn sample_unchecked(&self, t: f32) -> T {
106 self.sample_clamped(t)
107 }
108}
109
110impl<T, I> SampleCurve<T, I> {
111 pub fn new(
119 domain: Interval,
120 samples: impl IntoIterator<Item = T>,
121 interpolation: I,
122 ) -> Result<Self, EvenCoreError>
123 where
124 I: Fn(&T, &T, f32) -> T,
125 {
126 Ok(Self {
127 core: EvenCore::new(domain, samples)?,
128 interpolation,
129 })
130 }
131}
132
133#[derive(Clone, Debug)]
138#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
139#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
140pub struct SampleAutoCurve<T> {
141 pub(crate) core: EvenCore<T>,
142}
143
144impl<T> Curve<T> for SampleAutoCurve<T>
145where
146 T: StableInterpolate,
147{
148 #[inline]
149 fn domain(&self) -> Interval {
150 self.core.domain()
151 }
152
153 #[inline]
154 fn sample_clamped(&self, t: f32) -> T {
155 self.core
157 .sample_with(t, <T as StableInterpolate>::interpolate_stable)
158 }
159
160 #[inline]
161 fn sample_unchecked(&self, t: f32) -> T {
162 self.sample_clamped(t)
163 }
164}
165
166impl<T> SampleAutoCurve<T> {
167 pub fn new(
171 domain: Interval,
172 samples: impl IntoIterator<Item = T>,
173 ) -> Result<Self, EvenCoreError> {
174 Ok(Self {
175 core: EvenCore::new(domain, samples)?,
176 })
177 }
178}
179
180#[derive(Clone)]
183#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
184#[cfg_attr(
185 feature = "bevy_reflect",
186 derive(Reflect),
187 reflect(where T: TypePath),
188 reflect(from_reflect = false, type_path = false),
189)]
190pub struct UnevenSampleCurve<T, I> {
191 pub(crate) core: UnevenCore<T>,
192 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
193 pub(crate) interpolation: I,
194}
195
196impl<T, I> Debug for UnevenSampleCurve<T, I>
197where
198 UnevenCore<T>: Debug,
199{
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("SampleCurve")
202 .field("core", &self.core)
203 .field("interpolation", &type_name::<I>())
204 .finish()
205 }
206}
207
208#[cfg(feature = "bevy_reflect")]
211impl<T, I> TypePath for UnevenSampleCurve<T, I>
212where
213 T: TypePath,
214 I: 'static,
215{
216 fn type_path() -> &'static str {
217 static CELL: GenericTypePathCell = GenericTypePathCell::new();
218 CELL.get_or_insert::<Self, _>(|| {
219 format!(
220 "{}::UnevenSampleCurve<{},{}>",
221 paths::THIS_MODULE,
222 T::type_path(),
223 type_name::<I>()
224 )
225 })
226 }
227
228 fn short_type_path() -> &'static str {
229 static CELL: GenericTypePathCell = GenericTypePathCell::new();
230 CELL.get_or_insert::<Self, _>(|| {
231 format!("UnevenSampleCurve<{},{}>", T::type_path(), type_name::<I>())
232 })
233 }
234
235 fn type_ident() -> Option<&'static str> {
236 Some("UnevenSampleCurve")
237 }
238
239 fn crate_name() -> Option<&'static str> {
240 Some(paths::THIS_CRATE)
241 }
242
243 fn module_path() -> Option<&'static str> {
244 Some(paths::THIS_MODULE)
245 }
246}
247
248impl<T, I> Curve<T> for UnevenSampleCurve<T, I>
249where
250 T: Clone,
251 I: Fn(&T, &T, f32) -> T,
252{
253 #[inline]
254 fn domain(&self) -> Interval {
255 self.core.domain()
256 }
257
258 #[inline]
259 fn sample_clamped(&self, t: f32) -> T {
260 self.core.sample_with(t, &self.interpolation)
262 }
263
264 #[inline]
265 fn sample_unchecked(&self, t: f32) -> T {
266 self.sample_clamped(t)
267 }
268}
269
270impl<T, I> UnevenSampleCurve<T, I> {
271 pub fn new(
280 timed_samples: impl IntoIterator<Item = (f32, T)>,
281 interpolation: I,
282 ) -> Result<Self, UnevenCoreError>
283 where
284 I: Fn(&T, &T, f32) -> T,
285 {
286 Ok(Self {
287 core: UnevenCore::new(timed_samples)?,
288 interpolation,
289 })
290 }
291
292 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleCurve<T, I> {
301 Self {
302 core: self.core.map_sample_times(f),
303 interpolation: self.interpolation,
304 }
305 }
306}
307
308#[derive(Clone, Debug)]
313#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
314#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
315pub struct UnevenSampleAutoCurve<T> {
316 pub(crate) core: UnevenCore<T>,
317}
318
319impl<T> Curve<T> for UnevenSampleAutoCurve<T>
320where
321 T: StableInterpolate,
322{
323 #[inline]
324 fn domain(&self) -> Interval {
325 self.core.domain()
326 }
327
328 #[inline]
329 fn sample_clamped(&self, t: f32) -> T {
330 self.core
332 .sample_with(t, <T as StableInterpolate>::interpolate_stable)
333 }
334
335 #[inline]
336 fn sample_unchecked(&self, t: f32) -> T {
337 self.sample_clamped(t)
338 }
339}
340
341impl<T> UnevenSampleAutoCurve<T> {
342 pub fn new(timed_samples: impl IntoIterator<Item = (f32, T)>) -> Result<Self, UnevenCoreError> {
347 Ok(Self {
348 core: UnevenCore::new(timed_samples)?,
349 })
350 }
351
352 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleAutoCurve<T> {
361 Self {
362 core: self.core.map_sample_times(f),
363 }
364 }
365}
366
367#[cfg(test)]
368#[cfg(feature = "bevy_reflect")]
369mod tests {
370 use super::{SampleCurve, UnevenSampleCurve};
376 use crate::{curve::Interval, VectorSpace};
377 use alloc::boxed::Box;
378 use bevy_reflect::Reflect;
379
380 #[test]
381 fn reflect_sample_curve() {
382 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
383 x.lerp(*y, t)
384 }
385 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
386 let baz: fn(&f32, &f32, f32) -> f32 = bar;
387
388 let samples = [0.0, 1.0, 2.0];
389
390 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, foo).unwrap());
391 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, bar).unwrap());
392 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, baz).unwrap());
393 }
394
395 #[test]
396 fn reflect_uneven_sample_curve() {
397 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
398 x.lerp(*y, t)
399 }
400 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
401 let baz: fn(&f32, &f32, f32) -> f32 = bar;
402
403 let keyframes = [(0.0, 1.0), (1.0, 0.0), (2.0, -1.0)];
404
405 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, foo).unwrap());
406 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, bar).unwrap());
407 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, baz).unwrap());
408 }
409 #[test]
410 fn test_infer_interp_arguments() {
411 SampleCurve::new(Interval::UNIT, [0.0, 1.0], |x, y, t| x.lerp(*y, t)).ok();
414 UnevenSampleCurve::new([(0.1, 1.0), (1.0, 3.0)], |x, y, t| x.lerp(*y, t)).ok();
415 }
416}