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 Ok(Self {
284 core: UnevenCore::new(timed_samples)?,
285 interpolation,
286 })
287 }
288
289 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleCurve<T, I> {
298 Self {
299 core: self.core.map_sample_times(f),
300 interpolation: self.interpolation,
301 }
302 }
303}
304
305#[derive(Clone, Debug)]
310#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
311#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
312pub struct UnevenSampleAutoCurve<T> {
313 pub(crate) core: UnevenCore<T>,
314}
315
316impl<T> Curve<T> for UnevenSampleAutoCurve<T>
317where
318 T: StableInterpolate,
319{
320 #[inline]
321 fn domain(&self) -> Interval {
322 self.core.domain()
323 }
324
325 #[inline]
326 fn sample_clamped(&self, t: f32) -> T {
327 self.core
329 .sample_with(t, <T as StableInterpolate>::interpolate_stable)
330 }
331
332 #[inline]
333 fn sample_unchecked(&self, t: f32) -> T {
334 self.sample_clamped(t)
335 }
336}
337
338impl<T> UnevenSampleAutoCurve<T> {
339 pub fn new(timed_samples: impl IntoIterator<Item = (f32, T)>) -> Result<Self, UnevenCoreError> {
344 Ok(Self {
345 core: UnevenCore::new(timed_samples)?,
346 })
347 }
348
349 pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleAutoCurve<T> {
358 Self {
359 core: self.core.map_sample_times(f),
360 }
361 }
362}
363
364#[cfg(test)]
365#[cfg(feature = "bevy_reflect")]
366mod tests {
367 use super::{SampleCurve, UnevenSampleCurve};
373 use crate::{curve::Interval, VectorSpace};
374 use alloc::boxed::Box;
375 use bevy_reflect::Reflect;
376
377 #[test]
378 fn reflect_sample_curve() {
379 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
380 x.lerp(*y, t)
381 }
382 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
383 let baz: fn(&f32, &f32, f32) -> f32 = bar;
384
385 let samples = [0.0, 1.0, 2.0];
386
387 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, foo).unwrap());
388 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, bar).unwrap());
389 let _: Box<dyn Reflect> = Box::new(SampleCurve::new(Interval::UNIT, samples, baz).unwrap());
390 }
391
392 #[test]
393 fn reflect_uneven_sample_curve() {
394 fn foo(x: &f32, y: &f32, t: f32) -> f32 {
395 x.lerp(*y, t)
396 }
397 let bar = |x: &f32, y: &f32, t: f32| x.lerp(*y, t);
398 let baz: fn(&f32, &f32, f32) -> f32 = bar;
399
400 let keyframes = [(0.0, 1.0), (1.0, 0.0), (2.0, -1.0)];
401
402 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, foo).unwrap());
403 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, bar).unwrap());
404 let _: Box<dyn Reflect> = Box::new(UnevenSampleCurve::new(keyframes, baz).unwrap());
405 }
406}