Skip to main content

token_value_map/
animated_data.rs

1use crate::{
2    macros::{impl_animated_data_insert, impl_data_type_ops, impl_sample_for_animated_data},
3    time_data_map::TimeDataMapControl,
4    *,
5};
6
7use crate::Result;
8use core::num::NonZeroU16;
9use enum_dispatch::enum_dispatch;
10use smallvec::SmallVec;
11use std::hash::Hasher;
12
13/// Time-indexed data with interpolation support.
14///
15/// [`AnimatedData`] `enum` stores a collection of time-value pairs for a
16/// specific data type and provides interpolation between keyframes. Each
17/// variant contains a [`TimeDataMap`] for the corresponding data type.
18#[enum_dispatch(AnimatedDataOps)]
19#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21#[cfg_attr(feature = "facet", derive(Facet))]
22#[cfg_attr(feature = "facet", facet(opaque))]
23#[cfg_attr(feature = "facet", repr(u8))]
24#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
25pub enum AnimatedData {
26    /// Animated boolean values.
27    Boolean(TimeDataMap<Boolean>),
28    /// Animated integer values.
29    Integer(TimeDataMap<Integer>),
30    /// Animated real values.
31    Real(TimeDataMap<Real>),
32    /// Animated string values.
33    String(TimeDataMap<String>),
34    /// Animated color values.
35    Color(TimeDataMap<Color>),
36    /// Animated 2D vectors.
37    #[cfg(feature = "vector2")]
38    Vector2(TimeDataMap<Vector2>),
39    /// Animated 3D vectors.
40    #[cfg(feature = "vector3")]
41    Vector3(TimeDataMap<Vector3>),
42    /// Animated transformation matrices.
43    #[cfg(feature = "matrix3")]
44    Matrix3(TimeDataMap<Matrix3>),
45    /// Animated 3D normal vectors.
46    #[cfg(feature = "normal3")]
47    Normal3(TimeDataMap<Normal3>),
48    /// Animated 3D points.
49    #[cfg(feature = "point3")]
50    Point3(TimeDataMap<Point3>),
51    /// Animated 4×4 transformation matrices.
52    #[cfg(feature = "matrix4")]
53    Matrix4(TimeDataMap<Matrix4>),
54    /// Animated boolean vectors.
55    BooleanVec(TimeDataMap<BooleanVec>),
56    /// Animated integer vectors.
57    IntegerVec(TimeDataMap<IntegerVec>),
58    /// Animated real vectors.
59    RealVec(TimeDataMap<RealVec>),
60    /// Animated color vectors.
61    ColorVec(TimeDataMap<ColorVec>),
62    /// Animated string vectors.
63    StringVec(TimeDataMap<StringVec>),
64    /// Animated 2D vector arrays.
65    #[cfg(all(feature = "vector2", feature = "vec_variants"))]
66    Vector2Vec(TimeDataMap<Vector2Vec>),
67    /// Animated 3D vector arrays.
68    #[cfg(all(feature = "vector3", feature = "vec_variants"))]
69    Vector3Vec(TimeDataMap<Vector3Vec>),
70    /// Animated matrix arrays.
71    #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
72    Matrix3Vec(TimeDataMap<Matrix3Vec>),
73    /// Animated 3D normal arrays.
74    #[cfg(all(feature = "normal3", feature = "vec_variants"))]
75    Normal3Vec(TimeDataMap<Normal3Vec>),
76    /// Animated 3D point arrays.
77    #[cfg(all(feature = "point3", feature = "vec_variants"))]
78    Point3Vec(TimeDataMap<Point3Vec>),
79    /// Animated 4×4 matrix arrays.
80    #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
81    Matrix4Vec(TimeDataMap<Matrix4Vec>),
82    /// Animated real curve.
83    #[cfg(feature = "curves")]
84    RealCurve(TimeDataMap<RealCurve>),
85    /// Animated color curve.
86    #[cfg(feature = "curves")]
87    ColorCurve(TimeDataMap<ColorCurve>),
88}
89
90/// Common operations `trait` for animated data types.
91#[enum_dispatch]
92pub trait AnimatedDataOps {
93    /// Returns the number of time samples.
94    fn len(&self) -> usize;
95    /// Returns `true` if there are no time samples.
96    fn is_empty(&self) -> bool;
97    /// Returns `true` if there is more than one time sample.
98    fn is_animated(&self) -> bool;
99}
100
101impl<T> AnimatedDataOps for TimeDataMap<T> {
102    fn len(&self) -> usize {
103        self.values.len()
104    }
105
106    fn is_empty(&self) -> bool {
107        self.values.is_empty()
108    }
109
110    fn is_animated(&self) -> bool {
111        self.values.len() > 1
112    }
113}
114
115impl_data_type_ops!(AnimatedData);
116
117// Interpolation-specific methods (when feature enabled)
118#[cfg(all(feature = "interpolation", feature = "egui-keyframe"))]
119impl AnimatedData {
120    /// Get bezier handles at a given time.
121    ///
122    /// Returns handles for scalar types (Real, Integer). Other types return None.
123    pub fn bezier_handles(&self, time: &Time) -> Option<egui_keyframe::BezierHandles> {
124        match self {
125            AnimatedData::Real(map) => map.interpolation(time).map(crate::key_to_bezier_handles),
126            AnimatedData::Integer(map) => map.interpolation(time).map(crate::key_to_bezier_handles),
127            // Vector/matrix types don't support scalar bezier handles
128            _ => None,
129        }
130    }
131
132    /// Set bezier handles at a given time.
133    ///
134    /// Works for scalar types (Real, Integer). Other types return an error.
135    pub fn set_bezier_handles(
136        &mut self,
137        time: &Time,
138        handles: egui_keyframe::BezierHandles,
139    ) -> Result<()> {
140        match self {
141            AnimatedData::Real(map) => {
142                map.set_interpolation_at(time, crate::bezier_handles_to_key(&handles))
143            }
144            AnimatedData::Integer(map) => {
145                map.set_interpolation_at(time, crate::bezier_handles_to_key(&handles))
146            }
147            _ => Err(Error::BezierNotSupported {
148                got: self.data_type(),
149            }),
150        }
151    }
152
153    /// Set the interpolation type at a given time.
154    ///
155    /// Works for scalar types (Real, Integer). Other types return an error.
156    pub fn set_keyframe_type(
157        &mut self,
158        time: &Time,
159        keyframe_type: egui_keyframe::KeyframeType,
160    ) -> Result<()> {
161        use crate::interpolation::{Interpolation, Key};
162
163        match keyframe_type {
164            egui_keyframe::KeyframeType::Hold => match self {
165                AnimatedData::Real(map) => map.set_interpolation_at(
166                    time,
167                    Key {
168                        interpolation_in: Interpolation::Hold,
169                        interpolation_out: Interpolation::Hold,
170                    },
171                ),
172                AnimatedData::Integer(map) => map.set_interpolation_at(
173                    time,
174                    Key {
175                        interpolation_in: Interpolation::Hold,
176                        interpolation_out: Interpolation::Hold,
177                    },
178                ),
179                _ => Err(Error::BezierNotSupported {
180                    got: self.data_type(),
181                }),
182            },
183            egui_keyframe::KeyframeType::Linear => match self {
184                AnimatedData::Real(map) => map.set_interpolation_at(
185                    time,
186                    Key {
187                        interpolation_in: Interpolation::Linear,
188                        interpolation_out: Interpolation::Linear,
189                    },
190                ),
191                AnimatedData::Integer(map) => map.set_interpolation_at(
192                    time,
193                    Key {
194                        interpolation_in: Interpolation::Linear,
195                        interpolation_out: Interpolation::Linear,
196                    },
197                ),
198                _ => Err(Error::BezierNotSupported {
199                    got: self.data_type(),
200                }),
201            },
202            egui_keyframe::KeyframeType::Bezier => {
203                // Default bezier handles (smooth curve)
204                self.set_bezier_handles(time, egui_keyframe::BezierHandles::default())
205            }
206        }
207    }
208}
209
210impl AnimatedData {
211    /// Get all time samples from this animated data.
212    pub fn times(&self) -> SmallVec<[Time; 10]> {
213        match self {
214            AnimatedData::Boolean(map) => map.iter().map(|(t, _)| *t).collect(),
215            AnimatedData::Integer(map) => map.iter().map(|(t, _)| *t).collect(),
216            AnimatedData::Real(map) => map.iter().map(|(t, _)| *t).collect(),
217            AnimatedData::String(map) => map.iter().map(|(t, _)| *t).collect(),
218            AnimatedData::Color(map) => map.iter().map(|(t, _)| *t).collect(),
219            #[cfg(feature = "vector2")]
220            AnimatedData::Vector2(map) => map.iter().map(|(t, _)| *t).collect(),
221            #[cfg(feature = "vector3")]
222            AnimatedData::Vector3(map) => map.iter().map(|(t, _)| *t).collect(),
223            #[cfg(feature = "matrix3")]
224            AnimatedData::Matrix3(map) => map.iter().map(|(t, _)| *t).collect(),
225            #[cfg(feature = "normal3")]
226            AnimatedData::Normal3(map) => map.iter().map(|(t, _)| *t).collect(),
227            #[cfg(feature = "point3")]
228            AnimatedData::Point3(map) => map.iter().map(|(t, _)| *t).collect(),
229            #[cfg(feature = "matrix4")]
230            AnimatedData::Matrix4(map) => map.iter().map(|(t, _)| *t).collect(),
231            AnimatedData::BooleanVec(map) => map.iter().map(|(t, _)| *t).collect(),
232            AnimatedData::IntegerVec(map) => map.iter().map(|(t, _)| *t).collect(),
233            AnimatedData::RealVec(map) => map.iter().map(|(t, _)| *t).collect(),
234            AnimatedData::ColorVec(map) => map.iter().map(|(t, _)| *t).collect(),
235            AnimatedData::StringVec(map) => map.iter().map(|(t, _)| *t).collect(),
236            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
237            AnimatedData::Vector2Vec(map) => map.iter().map(|(t, _)| *t).collect(),
238            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
239            AnimatedData::Vector3Vec(map) => map.iter().map(|(t, _)| *t).collect(),
240            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
241            AnimatedData::Matrix3Vec(map) => map.iter().map(|(t, _)| *t).collect(),
242            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
243            AnimatedData::Normal3Vec(map) => map.iter().map(|(t, _)| *t).collect(),
244            #[cfg(all(feature = "point3", feature = "vec_variants"))]
245            AnimatedData::Point3Vec(map) => map.iter().map(|(t, _)| *t).collect(),
246            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
247            AnimatedData::Matrix4Vec(map) => map.iter().map(|(t, _)| *t).collect(),
248            #[cfg(feature = "curves")]
249            AnimatedData::RealCurve(map) => map.iter().map(|(t, _)| *t).collect(),
250            #[cfg(feature = "curves")]
251            AnimatedData::ColorCurve(map) => map.iter().map(|(t, _)| *t).collect(),
252        }
253    }
254}
255
256impl From<(Time, Value)> for AnimatedData {
257    fn from((time, value): (Time, Value)) -> Self {
258        match value {
259            Value::Uniform(data) => AnimatedData::from((time, data)),
260            Value::Animated(animated_data) => {
261                // If the value is already animated, we need to insert this time
262                // sample For simplicity, we'll just return the
263                // animated data as-is In a more sophisticated
264                // implementation, we might want to merge or replace samples
265                animated_data
266            }
267        }
268    }
269}
270
271impl From<(Time, Data)> for AnimatedData {
272    fn from((time, data): (Time, Data)) -> Self {
273        match data {
274            Data::Boolean(v) => AnimatedData::Boolean(TimeDataMap::from((time, v))),
275            Data::Integer(v) => AnimatedData::Integer(TimeDataMap::from((time, v))),
276            Data::Real(v) => AnimatedData::Real(TimeDataMap::from((time, v))),
277            Data::String(v) => AnimatedData::String(TimeDataMap::from((time, v))),
278            Data::Color(v) => AnimatedData::Color(TimeDataMap::from((time, v))),
279            #[cfg(feature = "vector2")]
280            Data::Vector2(v) => AnimatedData::Vector2(TimeDataMap::from((time, v))),
281            #[cfg(feature = "vector3")]
282            Data::Vector3(v) => AnimatedData::Vector3(TimeDataMap::from((time, v))),
283            #[cfg(feature = "matrix3")]
284            Data::Matrix3(v) => AnimatedData::Matrix3(TimeDataMap::from((time, v))),
285            #[cfg(feature = "normal3")]
286            Data::Normal3(v) => AnimatedData::Normal3(TimeDataMap::from((time, v))),
287            #[cfg(feature = "point3")]
288            Data::Point3(v) => AnimatedData::Point3(TimeDataMap::from((time, v))),
289            #[cfg(feature = "matrix4")]
290            Data::Matrix4(v) => AnimatedData::Matrix4(TimeDataMap::from((time, v))),
291            Data::BooleanVec(v) => AnimatedData::BooleanVec(TimeDataMap::from((time, v))),
292            Data::IntegerVec(v) => AnimatedData::IntegerVec(TimeDataMap::from((time, v))),
293            Data::RealVec(v) => AnimatedData::RealVec(TimeDataMap::from((time, v))),
294            Data::ColorVec(v) => AnimatedData::ColorVec(TimeDataMap::from((time, v))),
295            Data::StringVec(v) => AnimatedData::StringVec(TimeDataMap::from((time, v))),
296            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
297            Data::Vector2Vec(v) => AnimatedData::Vector2Vec(TimeDataMap::from((time, v))),
298            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
299            Data::Vector3Vec(v) => AnimatedData::Vector3Vec(TimeDataMap::from((time, v))),
300            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
301            Data::Matrix3Vec(v) => AnimatedData::Matrix3Vec(TimeDataMap::from((time, v))),
302            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
303            Data::Normal3Vec(v) => AnimatedData::Normal3Vec(TimeDataMap::from((time, v))),
304            #[cfg(all(feature = "point3", feature = "vec_variants"))]
305            Data::Point3Vec(v) => AnimatedData::Point3Vec(TimeDataMap::from((time, v))),
306            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
307            Data::Matrix4Vec(v) => AnimatedData::Matrix4Vec(TimeDataMap::from((time, v))),
308            #[cfg(feature = "curves")]
309            Data::RealCurve(v) => AnimatedData::RealCurve(TimeDataMap::from((time, v))),
310            #[cfg(feature = "curves")]
311            Data::ColorCurve(v) => AnimatedData::ColorCurve(TimeDataMap::from((time, v))),
312        }
313    }
314}
315
316impl_animated_data_insert!(
317    insert_boolean, Boolean, Boolean;
318    insert_integer, Integer, Integer;
319    insert_real, Real, Real;
320    insert_string, String, String;
321    insert_color, Color, Color;
322);
323
324#[cfg(feature = "vector2")]
325impl_animated_data_insert!(
326    insert_vector2, Vector2, Vector2;
327);
328
329#[cfg(feature = "vector3")]
330impl_animated_data_insert!(
331    insert_vector3, Vector3, Vector3;
332);
333
334#[cfg(feature = "matrix3")]
335impl_animated_data_insert!(
336    insert_matrix3, Matrix3, Matrix3;
337);
338
339#[cfg(feature = "normal3")]
340impl_animated_data_insert!(
341    insert_normal3, Normal3, Normal3;
342);
343
344#[cfg(feature = "point3")]
345impl_animated_data_insert!(
346    insert_point3, Point3, Point3;
347);
348
349#[cfg(feature = "matrix4")]
350impl_animated_data_insert!(
351    insert_matrix4, Matrix4, Matrix4;
352);
353
354impl AnimatedData {
355    /// Generic insert method that takes `Data` and matches the type to the
356    /// `AnimatedData` variant.
357    pub fn try_insert(&mut self, time: Time, value: Data) -> Result<()> {
358        match (self, value) {
359            (AnimatedData::Boolean(map), Data::Boolean(v)) => {
360                map.insert(time, v);
361                Ok(())
362            }
363            (AnimatedData::Integer(map), Data::Integer(v)) => {
364                map.insert(time, v);
365                Ok(())
366            }
367            (AnimatedData::Real(map), Data::Real(v)) => {
368                map.insert(time, v);
369                Ok(())
370            }
371            (AnimatedData::String(map), Data::String(v)) => {
372                map.insert(time, v);
373                Ok(())
374            }
375            (AnimatedData::Color(map), Data::Color(v)) => {
376                map.insert(time, v);
377                Ok(())
378            }
379            #[cfg(feature = "vector2")]
380            (AnimatedData::Vector2(map), Data::Vector2(v)) => {
381                map.insert(time, v);
382                Ok(())
383            }
384            #[cfg(feature = "vector3")]
385            (AnimatedData::Vector3(map), Data::Vector3(v)) => {
386                map.insert(time, v);
387                Ok(())
388            }
389            #[cfg(feature = "matrix3")]
390            (AnimatedData::Matrix3(map), Data::Matrix3(v)) => {
391                map.insert(time, v);
392                Ok(())
393            }
394            #[cfg(feature = "normal3")]
395            (AnimatedData::Normal3(map), Data::Normal3(v)) => {
396                map.insert(time, v);
397                Ok(())
398            }
399            #[cfg(feature = "point3")]
400            (AnimatedData::Point3(map), Data::Point3(v)) => {
401                map.insert(time, v);
402                Ok(())
403            }
404            #[cfg(feature = "matrix4")]
405            (AnimatedData::Matrix4(map), Data::Matrix4(v)) => {
406                map.insert(time, v);
407                Ok(())
408            }
409            (AnimatedData::BooleanVec(map), Data::BooleanVec(v)) => {
410                map.insert(time, v);
411                Ok(())
412            }
413            (AnimatedData::IntegerVec(map), Data::IntegerVec(v)) => {
414                map.insert(time, v);
415                Ok(())
416            }
417            (AnimatedData::RealVec(map), Data::RealVec(v)) => {
418                map.insert(time, v);
419                Ok(())
420            }
421            (AnimatedData::ColorVec(map), Data::ColorVec(v)) => {
422                map.insert(time, v);
423                Ok(())
424            }
425            (AnimatedData::StringVec(map), Data::StringVec(v)) => {
426                map.insert(time, v);
427                Ok(())
428            }
429            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
430            (AnimatedData::Vector2Vec(map), Data::Vector2Vec(v)) => {
431                map.insert(time, v);
432                Ok(())
433            }
434            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
435            (AnimatedData::Vector3Vec(map), Data::Vector3Vec(v)) => {
436                map.insert(time, v);
437                Ok(())
438            }
439            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
440            (AnimatedData::Matrix3Vec(map), Data::Matrix3Vec(v)) => {
441                map.insert(time, v);
442                Ok(())
443            }
444            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
445            (AnimatedData::Normal3Vec(map), Data::Normal3Vec(v)) => {
446                map.insert(time, v);
447                Ok(())
448            }
449            #[cfg(all(feature = "point3", feature = "vec_variants"))]
450            (AnimatedData::Point3Vec(map), Data::Point3Vec(v)) => {
451                map.insert(time, v);
452                Ok(())
453            }
454            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
455            (AnimatedData::Matrix4Vec(map), Data::Matrix4Vec(v)) => {
456                map.insert(time, v);
457                Ok(())
458            }
459            #[cfg(feature = "curves")]
460            (AnimatedData::RealCurve(map), Data::RealCurve(v)) => {
461                map.insert(time, v);
462                Ok(())
463            }
464            #[cfg(feature = "curves")]
465            (AnimatedData::ColorCurve(map), Data::ColorCurve(v)) => {
466                map.insert(time, v);
467                Ok(())
468            }
469            (s, v) => Err(Error::SampleTypeMismatch {
470                expected: s.data_type(),
471                got: v.data_type(),
472            }),
473        }
474    }
475
476    /// Remove a sample at the given time.
477    ///
478    /// Returns the removed value as `Data` if it existed.
479    pub fn remove_at(&mut self, time: &Time) -> Option<Data> {
480        match self {
481            AnimatedData::Boolean(map) => map.remove(time).map(Data::Boolean),
482            AnimatedData::Integer(map) => map.remove(time).map(Data::Integer),
483            AnimatedData::Real(map) => map.remove(time).map(Data::Real),
484            AnimatedData::String(map) => map.remove(time).map(Data::String),
485            AnimatedData::Color(map) => map.remove(time).map(Data::Color),
486            #[cfg(feature = "vector2")]
487            AnimatedData::Vector2(map) => map.remove(time).map(Data::Vector2),
488            #[cfg(feature = "vector3")]
489            AnimatedData::Vector3(map) => map.remove(time).map(Data::Vector3),
490            #[cfg(feature = "matrix3")]
491            AnimatedData::Matrix3(map) => map.remove(time).map(Data::Matrix3),
492            #[cfg(feature = "normal3")]
493            AnimatedData::Normal3(map) => map.remove(time).map(Data::Normal3),
494            #[cfg(feature = "point3")]
495            AnimatedData::Point3(map) => map.remove(time).map(Data::Point3),
496            #[cfg(feature = "matrix4")]
497            AnimatedData::Matrix4(map) => map.remove(time).map(Data::Matrix4),
498            AnimatedData::BooleanVec(map) => map.remove(time).map(Data::BooleanVec),
499            AnimatedData::IntegerVec(map) => map.remove(time).map(Data::IntegerVec),
500            AnimatedData::RealVec(map) => map.remove(time).map(Data::RealVec),
501            AnimatedData::ColorVec(map) => map.remove(time).map(Data::ColorVec),
502            AnimatedData::StringVec(map) => map.remove(time).map(Data::StringVec),
503            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
504            AnimatedData::Vector2Vec(map) => map.remove(time).map(Data::Vector2Vec),
505            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
506            AnimatedData::Vector3Vec(map) => map.remove(time).map(Data::Vector3Vec),
507            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
508            AnimatedData::Matrix3Vec(map) => map.remove(time).map(Data::Matrix3Vec),
509            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
510            AnimatedData::Normal3Vec(map) => map.remove(time).map(Data::Normal3Vec),
511            #[cfg(all(feature = "point3", feature = "vec_variants"))]
512            AnimatedData::Point3Vec(map) => map.remove(time).map(Data::Point3Vec),
513            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
514            AnimatedData::Matrix4Vec(map) => map.remove(time).map(Data::Matrix4Vec),
515            #[cfg(feature = "curves")]
516            AnimatedData::RealCurve(map) => map.remove(time).map(Data::RealCurve),
517            #[cfg(feature = "curves")]
518            AnimatedData::ColorCurve(map) => map.remove(time).map(Data::ColorCurve),
519        }
520    }
521
522    pub fn sample_at(&self, time: Time) -> Option<Data> {
523        match self {
524            AnimatedData::Boolean(map) => map.get(&time).map(|v| Data::Boolean(v.clone())),
525            AnimatedData::Integer(map) => map.get(&time).map(|v| Data::Integer(v.clone())),
526            AnimatedData::Real(map) => map.get(&time).map(|v| Data::Real(v.clone())),
527            AnimatedData::String(map) => map.get(&time).map(|v| Data::String(v.clone())),
528            AnimatedData::Color(map) => map.get(&time).map(|v| Data::Color(*v)),
529            #[cfg(feature = "vector2")]
530            AnimatedData::Vector2(map) => map.get(&time).map(|v| Data::Vector2(v.clone())),
531            #[cfg(feature = "vector3")]
532            AnimatedData::Vector3(map) => map.get(&time).map(|v| Data::Vector3(v.clone())),
533            #[cfg(feature = "matrix3")]
534            AnimatedData::Matrix3(map) => map.get(&time).map(|v| Data::Matrix3(v.clone())),
535            #[cfg(feature = "normal3")]
536            AnimatedData::Normal3(map) => map.get(&time).map(|v| Data::Normal3(v.clone())),
537            #[cfg(feature = "point3")]
538            AnimatedData::Point3(map) => map.get(&time).map(|v| Data::Point3(v.clone())),
539            #[cfg(feature = "matrix4")]
540            AnimatedData::Matrix4(map) => map.get(&time).map(|v| Data::Matrix4(v.clone())),
541            AnimatedData::BooleanVec(map) => map.get(&time).map(|v| Data::BooleanVec(v.clone())),
542            AnimatedData::IntegerVec(map) => map.get(&time).map(|v| Data::IntegerVec(v.clone())),
543            AnimatedData::RealVec(map) => map.get(&time).map(|v| Data::RealVec(v.clone())),
544            AnimatedData::ColorVec(map) => map.get(&time).map(|v| Data::ColorVec(v.clone())),
545            AnimatedData::StringVec(map) => map.get(&time).map(|v| Data::StringVec(v.clone())),
546            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
547            AnimatedData::Vector2Vec(map) => map.get(&time).map(|v| Data::Vector2Vec(v.clone())),
548            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
549            AnimatedData::Vector3Vec(map) => map.get(&time).map(|v| Data::Vector3Vec(v.clone())),
550            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
551            AnimatedData::Matrix3Vec(map) => map.get(&time).map(|v| Data::Matrix3Vec(v.clone())),
552            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
553            AnimatedData::Normal3Vec(map) => map.get(&time).map(|v| Data::Normal3Vec(v.clone())),
554            #[cfg(all(feature = "point3", feature = "vec_variants"))]
555            AnimatedData::Point3Vec(map) => map.get(&time).map(|v| Data::Point3Vec(v.clone())),
556            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
557            AnimatedData::Matrix4Vec(map) => map.get(&time).map(|v| Data::Matrix4Vec(v.clone())),
558            #[cfg(feature = "curves")]
559            AnimatedData::RealCurve(map) => map.get(&time).map(|v| Data::RealCurve(v.clone())),
560            #[cfg(feature = "curves")]
561            AnimatedData::ColorCurve(map) => map.get(&time).map(|v| Data::ColorCurve(v.clone())),
562        }
563    }
564
565    pub fn interpolate(&self, time: Time) -> Data {
566        match self {
567            AnimatedData::Boolean(map) => Data::Boolean(map.closest_sample(time).clone()),
568            AnimatedData::Integer(map) => {
569                if TimeDataMapControl::is_animated(map) {
570                    Data::Integer(map.interpolate(time))
571                } else {
572                    Data::Integer(map.iter().next().unwrap().1.clone())
573                }
574            }
575            AnimatedData::Real(map) => {
576                if TimeDataMapControl::is_animated(map) {
577                    Data::Real(map.interpolate(time))
578                } else {
579                    Data::Real(map.iter().next().unwrap().1.clone())
580                }
581            }
582            AnimatedData::String(map) => Data::String(map.closest_sample(time).clone()),
583            AnimatedData::Color(map) => {
584                if TimeDataMapControl::is_animated(map) {
585                    Data::Color(map.interpolate(time))
586                } else {
587                    Data::Color(*map.iter().next().unwrap().1)
588                }
589            }
590            #[cfg(feature = "vector2")]
591            AnimatedData::Vector2(map) => {
592                if TimeDataMapControl::is_animated(map) {
593                    Data::Vector2(map.interpolate(time))
594                } else {
595                    Data::Vector2(map.iter().next().unwrap().1.clone())
596                }
597            }
598            #[cfg(feature = "vector3")]
599            AnimatedData::Vector3(map) => {
600                if TimeDataMapControl::is_animated(map) {
601                    Data::Vector3(map.interpolate(time))
602                } else {
603                    Data::Vector3(map.iter().next().unwrap().1.clone())
604                }
605            }
606            #[cfg(feature = "matrix3")]
607            AnimatedData::Matrix3(map) => {
608                if TimeDataMapControl::is_animated(map) {
609                    Data::Matrix3(map.interpolate(time))
610                } else {
611                    Data::Matrix3(map.iter().next().unwrap().1.clone())
612                }
613            }
614            #[cfg(feature = "normal3")]
615            AnimatedData::Normal3(map) => {
616                if TimeDataMapControl::is_animated(map) {
617                    Data::Normal3(map.interpolate(time))
618                } else {
619                    Data::Normal3(map.iter().next().unwrap().1.clone())
620                }
621            }
622            #[cfg(feature = "point3")]
623            AnimatedData::Point3(map) => {
624                if TimeDataMapControl::is_animated(map) {
625                    Data::Point3(map.interpolate(time))
626                } else {
627                    Data::Point3(map.iter().next().unwrap().1.clone())
628                }
629            }
630            #[cfg(feature = "matrix4")]
631            AnimatedData::Matrix4(map) => {
632                if TimeDataMapControl::is_animated(map) {
633                    Data::Matrix4(map.interpolate(time))
634                } else {
635                    Data::Matrix4(map.iter().next().unwrap().1.clone())
636                }
637            }
638            AnimatedData::BooleanVec(map) => Data::BooleanVec(map.closest_sample(time).clone()),
639            AnimatedData::IntegerVec(map) => {
640                if TimeDataMapControl::is_animated(map) {
641                    Data::IntegerVec(map.interpolate(time))
642                } else {
643                    Data::IntegerVec(map.iter().next().unwrap().1.clone())
644                }
645            }
646            AnimatedData::RealVec(map) => {
647                if TimeDataMapControl::is_animated(map) {
648                    Data::RealVec(map.interpolate(time))
649                } else {
650                    Data::RealVec(map.iter().next().unwrap().1.clone())
651                }
652            }
653            AnimatedData::ColorVec(map) => {
654                if TimeDataMapControl::is_animated(map) {
655                    Data::ColorVec(map.interpolate(time))
656                } else {
657                    Data::ColorVec(map.iter().next().unwrap().1.clone())
658                }
659            }
660            AnimatedData::StringVec(map) => Data::StringVec(map.closest_sample(time).clone()),
661            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
662            AnimatedData::Vector2Vec(map) => {
663                if TimeDataMapControl::is_animated(map) {
664                    Data::Vector2Vec(map.interpolate(time))
665                } else {
666                    Data::Vector2Vec(map.iter().next().unwrap().1.clone())
667                }
668            }
669            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
670            AnimatedData::Vector3Vec(map) => {
671                if TimeDataMapControl::is_animated(map) {
672                    Data::Vector3Vec(map.interpolate(time))
673                } else {
674                    Data::Vector3Vec(map.iter().next().unwrap().1.clone())
675                }
676            }
677            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
678            AnimatedData::Matrix3Vec(map) => {
679                if TimeDataMapControl::is_animated(map) {
680                    Data::Matrix3Vec(map.interpolate(time))
681                } else {
682                    Data::Matrix3Vec(map.iter().next().unwrap().1.clone())
683                }
684            }
685            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
686            AnimatedData::Normal3Vec(map) => {
687                if TimeDataMapControl::is_animated(map) {
688                    Data::Normal3Vec(map.interpolate(time))
689                } else {
690                    Data::Normal3Vec(map.iter().next().unwrap().1.clone())
691                }
692            }
693            #[cfg(all(feature = "point3", feature = "vec_variants"))]
694            AnimatedData::Point3Vec(map) => {
695                if TimeDataMapControl::is_animated(map) {
696                    Data::Point3Vec(map.interpolate(time))
697                } else {
698                    Data::Point3Vec(map.iter().next().unwrap().1.clone())
699                }
700            }
701            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
702            AnimatedData::Matrix4Vec(map) => {
703                if TimeDataMapControl::is_animated(map) {
704                    Data::Matrix4Vec(map.interpolate(time))
705                } else {
706                    Data::Matrix4Vec(map.iter().next().unwrap().1.clone())
707                }
708            }
709            #[cfg(feature = "curves")]
710            AnimatedData::RealCurve(map) => Data::RealCurve(map.closest_sample(time).clone()),
711            #[cfg(feature = "curves")]
712            AnimatedData::ColorCurve(map) => Data::ColorCurve(map.closest_sample(time).clone()),
713        }
714    }
715}
716
717impl Hash for AnimatedData {
718    fn hash<H: Hasher>(&self, state: &mut H) {
719        std::mem::discriminant(self).hash(state);
720        match self {
721            AnimatedData::Boolean(map) => {
722                map.len().hash(state);
723                #[cfg(not(feature = "interpolation"))]
724                for (time, value) in &map.values {
725                    time.hash(state);
726                    value.0.hash(state);
727                }
728                #[cfg(feature = "interpolation")]
729                for (time, (value, spec)) in &map.values {
730                    time.hash(state);
731                    value.0.hash(state);
732                    spec.hash(state);
733                }
734            }
735            AnimatedData::Integer(map) => {
736                map.len().hash(state);
737                #[cfg(not(feature = "interpolation"))]
738                for (time, value) in &map.values {
739                    time.hash(state);
740                    value.0.hash(state);
741                }
742                #[cfg(feature = "interpolation")]
743                for (time, (value, spec)) in &map.values {
744                    time.hash(state);
745                    value.0.hash(state);
746                    spec.hash(state);
747                }
748            }
749            AnimatedData::Real(map) => {
750                map.len().hash(state);
751                #[cfg(not(feature = "interpolation"))]
752                for (time, value) in &map.values {
753                    time.hash(state);
754                    value.0.to_bits().hash(state);
755                }
756                #[cfg(feature = "interpolation")]
757                for (time, (value, spec)) in &map.values {
758                    time.hash(state);
759                    value.0.to_bits().hash(state);
760                    spec.hash(state);
761                }
762            }
763            AnimatedData::String(map) => {
764                map.len().hash(state);
765                #[cfg(not(feature = "interpolation"))]
766                for (time, value) in &map.values {
767                    time.hash(state);
768                    value.0.hash(state);
769                }
770                #[cfg(feature = "interpolation")]
771                for (time, (value, spec)) in &map.values {
772                    time.hash(state);
773                    value.0.hash(state);
774                    spec.hash(state);
775                }
776            }
777            AnimatedData::Color(map) => {
778                map.len().hash(state);
779                #[cfg(not(feature = "interpolation"))]
780                for (time, value) in &map.values {
781                    time.hash(state);
782                    value.0.iter().for_each(|v| v.to_bits().hash(state));
783                }
784                #[cfg(feature = "interpolation")]
785                for (time, (value, spec)) in &map.values {
786                    time.hash(state);
787                    value.0.iter().for_each(|v| v.to_bits().hash(state));
788                    spec.hash(state);
789                }
790            }
791            #[cfg(feature = "vector2")]
792            AnimatedData::Vector2(map) => {
793                map.len().hash(state);
794                #[cfg(not(feature = "interpolation"))]
795                for (time, value) in &map.values {
796                    time.hash(state);
797                    crate::math::vec2_as_slice(&value.0)
798                        .iter()
799                        .for_each(|v| v.to_bits().hash(state));
800                }
801                #[cfg(feature = "interpolation")]
802                for (time, (value, spec)) in &map.values {
803                    time.hash(state);
804                    crate::math::vec2_as_slice(&value.0)
805                        .iter()
806                        .for_each(|v| v.to_bits().hash(state));
807                    spec.hash(state);
808                }
809            }
810            #[cfg(feature = "vector3")]
811            AnimatedData::Vector3(map) => {
812                map.len().hash(state);
813                #[cfg(not(feature = "interpolation"))]
814                for (time, value) in &map.values {
815                    time.hash(state);
816                    crate::math::vec3_as_slice(&value.0)
817                        .iter()
818                        .for_each(|v| v.to_bits().hash(state));
819                }
820                #[cfg(feature = "interpolation")]
821                for (time, (value, spec)) in &map.values {
822                    time.hash(state);
823                    crate::math::vec3_as_slice(&value.0)
824                        .iter()
825                        .for_each(|v| v.to_bits().hash(state));
826                    spec.hash(state);
827                }
828            }
829            #[cfg(feature = "matrix3")]
830            AnimatedData::Matrix3(map) => {
831                map.len().hash(state);
832                #[cfg(not(feature = "interpolation"))]
833                for (time, value) in &map.values {
834                    time.hash(state);
835                    crate::math::mat3_iter(&value.0).for_each(|v| v.to_bits().hash(state));
836                }
837                #[cfg(feature = "interpolation")]
838                for (time, (value, spec)) in &map.values {
839                    time.hash(state);
840                    crate::math::mat3_iter(&value.0).for_each(|v| v.to_bits().hash(state));
841                    spec.hash(state);
842                }
843            }
844            #[cfg(feature = "normal3")]
845            AnimatedData::Normal3(map) => {
846                map.len().hash(state);
847                #[cfg(not(feature = "interpolation"))]
848                for (time, value) in &map.values {
849                    time.hash(state);
850                    crate::math::vec3_as_slice(&value.0)
851                        .iter()
852                        .for_each(|v| v.to_bits().hash(state));
853                }
854                #[cfg(feature = "interpolation")]
855                for (time, (value, spec)) in &map.values {
856                    time.hash(state);
857                    crate::math::vec3_as_slice(&value.0)
858                        .iter()
859                        .for_each(|v| v.to_bits().hash(state));
860                    spec.hash(state);
861                }
862            }
863            #[cfg(feature = "point3")]
864            AnimatedData::Point3(map) => {
865                map.len().hash(state);
866                #[cfg(not(feature = "interpolation"))]
867                for (time, value) in &map.values {
868                    time.hash(state);
869                    crate::math::point3_as_slice(&value.0)
870                        .iter()
871                        .for_each(|v| v.to_bits().hash(state));
872                }
873                #[cfg(feature = "interpolation")]
874                for (time, (value, spec)) in &map.values {
875                    time.hash(state);
876                    crate::math::point3_as_slice(&value.0)
877                        .iter()
878                        .for_each(|v| v.to_bits().hash(state));
879                    spec.hash(state);
880                }
881            }
882            #[cfg(feature = "matrix4")]
883            AnimatedData::Matrix4(map) => {
884                map.len().hash(state);
885                #[cfg(not(feature = "interpolation"))]
886                for (time, value) in &map.values {
887                    time.hash(state);
888                    crate::math::mat4_iter(&value.0).for_each(|v| v.to_bits().hash(state));
889                }
890                #[cfg(feature = "interpolation")]
891                for (time, (value, spec)) in &map.values {
892                    time.hash(state);
893                    crate::math::mat4_iter(&value.0).for_each(|v| v.to_bits().hash(state));
894                    spec.hash(state);
895                }
896            }
897            AnimatedData::BooleanVec(map) => {
898                map.len().hash(state);
899                #[cfg(not(feature = "interpolation"))]
900                for (time, value) in &map.values {
901                    time.hash(state);
902                    value.0.hash(state);
903                }
904                #[cfg(feature = "interpolation")]
905                for (time, (value, spec)) in &map.values {
906                    time.hash(state);
907                    value.0.hash(state);
908                    spec.hash(state);
909                }
910            }
911            AnimatedData::IntegerVec(map) => {
912                map.len().hash(state);
913                #[cfg(not(feature = "interpolation"))]
914                for (time, value) in &map.values {
915                    time.hash(state);
916                    value.0.hash(state);
917                }
918                #[cfg(feature = "interpolation")]
919                for (time, (value, spec)) in &map.values {
920                    time.hash(state);
921                    value.0.hash(state);
922                    spec.hash(state);
923                }
924            }
925            AnimatedData::RealVec(map) => {
926                map.len().hash(state);
927                #[cfg(not(feature = "interpolation"))]
928                for (time, value) in &map.values {
929                    time.hash(state);
930                    value.0.len().hash(state);
931                    value.0.iter().for_each(|v| v.to_bits().hash(state));
932                }
933                #[cfg(feature = "interpolation")]
934                for (time, (value, spec)) in &map.values {
935                    time.hash(state);
936                    value.0.len().hash(state);
937                    value.0.iter().for_each(|v| v.to_bits().hash(state));
938                    spec.hash(state);
939                }
940            }
941            AnimatedData::ColorVec(map) => {
942                map.len().hash(state);
943                #[cfg(not(feature = "interpolation"))]
944                for (time, value) in &map.values {
945                    time.hash(state);
946                    value.0.len().hash(state);
947                    value.0.iter().for_each(|c| {
948                        c.iter().for_each(|v| v.to_bits().hash(state));
949                    });
950                }
951                #[cfg(feature = "interpolation")]
952                for (time, (value, spec)) in &map.values {
953                    time.hash(state);
954                    value.0.len().hash(state);
955                    value.0.iter().for_each(|c| {
956                        c.iter().for_each(|v| v.to_bits().hash(state));
957                    });
958                    spec.hash(state);
959                }
960            }
961            AnimatedData::StringVec(map) => {
962                map.len().hash(state);
963                #[cfg(not(feature = "interpolation"))]
964                for (time, value) in &map.values {
965                    time.hash(state);
966                    value.0.hash(state);
967                }
968                #[cfg(feature = "interpolation")]
969                for (time, (value, spec)) in &map.values {
970                    time.hash(state);
971                    value.0.hash(state);
972                    spec.hash(state);
973                }
974            }
975            #[cfg(all(feature = "vector2", feature = "vec_variants"))]
976            AnimatedData::Vector2Vec(map) => {
977                map.len().hash(state);
978                #[cfg(not(feature = "interpolation"))]
979                for (time, value) in &map.values {
980                    time.hash(state);
981                    value.0.len().hash(state);
982                    value.0.iter().for_each(|v| {
983                        crate::math::vec2_as_slice(v)
984                            .iter()
985                            .for_each(|f| f.to_bits().hash(state));
986                    });
987                }
988                #[cfg(feature = "interpolation")]
989                for (time, (value, spec)) in &map.values {
990                    time.hash(state);
991                    value.0.len().hash(state);
992                    value.0.iter().for_each(|v| {
993                        crate::math::vec2_as_slice(v)
994                            .iter()
995                            .for_each(|f| f.to_bits().hash(state));
996                    });
997                    spec.hash(state);
998                }
999            }
1000            #[cfg(all(feature = "vector3", feature = "vec_variants"))]
1001            AnimatedData::Vector3Vec(map) => {
1002                map.len().hash(state);
1003                #[cfg(not(feature = "interpolation"))]
1004                for (time, value) in &map.values {
1005                    time.hash(state);
1006                    value.0.len().hash(state);
1007                    value.0.iter().for_each(|v| {
1008                        crate::math::vec3_as_slice(v)
1009                            .iter()
1010                            .for_each(|f| f.to_bits().hash(state));
1011                    });
1012                }
1013                #[cfg(feature = "interpolation")]
1014                for (time, (value, spec)) in &map.values {
1015                    time.hash(state);
1016                    value.0.len().hash(state);
1017                    value.0.iter().for_each(|v| {
1018                        crate::math::vec3_as_slice(v)
1019                            .iter()
1020                            .for_each(|f| f.to_bits().hash(state));
1021                    });
1022                    spec.hash(state);
1023                }
1024            }
1025            #[cfg(all(feature = "matrix3", feature = "vec_variants"))]
1026            AnimatedData::Matrix3Vec(map) => {
1027                map.len().hash(state);
1028                #[cfg(not(feature = "interpolation"))]
1029                for (time, value) in &map.values {
1030                    time.hash(state);
1031                    value.0.len().hash(state);
1032                    value.0.iter().for_each(|m| {
1033                        crate::math::mat3_iter(m).for_each(|f| f.to_bits().hash(state));
1034                    });
1035                }
1036                #[cfg(feature = "interpolation")]
1037                for (time, (value, spec)) in &map.values {
1038                    time.hash(state);
1039                    value.0.len().hash(state);
1040                    value.0.iter().for_each(|m| {
1041                        crate::math::mat3_iter(m).for_each(|f| f.to_bits().hash(state));
1042                    });
1043                    spec.hash(state);
1044                }
1045            }
1046            #[cfg(all(feature = "normal3", feature = "vec_variants"))]
1047            AnimatedData::Normal3Vec(map) => {
1048                map.len().hash(state);
1049                #[cfg(not(feature = "interpolation"))]
1050                for (time, value) in &map.values {
1051                    time.hash(state);
1052                    value.0.len().hash(state);
1053                    value.0.iter().for_each(|v| {
1054                        crate::math::vec3_as_slice(v)
1055                            .iter()
1056                            .for_each(|f| f.to_bits().hash(state));
1057                    });
1058                }
1059                #[cfg(feature = "interpolation")]
1060                for (time, (value, spec)) in &map.values {
1061                    time.hash(state);
1062                    value.0.len().hash(state);
1063                    value.0.iter().for_each(|v| {
1064                        crate::math::vec3_as_slice(v)
1065                            .iter()
1066                            .for_each(|f| f.to_bits().hash(state));
1067                    });
1068                    spec.hash(state);
1069                }
1070            }
1071            #[cfg(all(feature = "point3", feature = "vec_variants"))]
1072            AnimatedData::Point3Vec(map) => {
1073                map.len().hash(state);
1074                #[cfg(not(feature = "interpolation"))]
1075                for (time, value) in &map.values {
1076                    time.hash(state);
1077                    value.0.len().hash(state);
1078                    value.0.iter().for_each(|p| {
1079                        crate::math::point3_as_slice(p)
1080                            .iter()
1081                            .for_each(|f| f.to_bits().hash(state));
1082                    });
1083                }
1084                #[cfg(feature = "interpolation")]
1085                for (time, (value, spec)) in &map.values {
1086                    time.hash(state);
1087                    value.0.len().hash(state);
1088                    value.0.iter().for_each(|p| {
1089                        crate::math::point3_as_slice(p)
1090                            .iter()
1091                            .for_each(|f| f.to_bits().hash(state));
1092                    });
1093                    spec.hash(state);
1094                }
1095            }
1096            #[cfg(all(feature = "matrix4", feature = "vec_variants"))]
1097            AnimatedData::Matrix4Vec(map) => {
1098                map.len().hash(state);
1099                #[cfg(not(feature = "interpolation"))]
1100                for (time, value) in &map.values {
1101                    time.hash(state);
1102                    value.0.len().hash(state);
1103                    value.0.iter().for_each(|m| {
1104                        crate::math::mat4_iter(m).for_each(|f| f.to_bits().hash(state));
1105                    });
1106                }
1107                #[cfg(feature = "interpolation")]
1108                for (time, (value, spec)) in &map.values {
1109                    time.hash(state);
1110                    value.0.len().hash(state);
1111                    value.0.iter().for_each(|m| {
1112                        crate::math::mat4_iter(m).for_each(|f| f.to_bits().hash(state));
1113                    });
1114                    spec.hash(state);
1115                }
1116            }
1117            #[cfg(feature = "curves")]
1118            AnimatedData::RealCurve(map) => {
1119                map.len().hash(state);
1120                #[cfg(not(feature = "interpolation"))]
1121                for (time, value) in &map.values {
1122                    time.hash(state);
1123                    value.hash(state);
1124                }
1125                #[cfg(feature = "interpolation")]
1126                for (time, (value, spec)) in &map.values {
1127                    time.hash(state);
1128                    value.hash(state);
1129                    spec.hash(state);
1130                }
1131            }
1132            #[cfg(feature = "curves")]
1133            AnimatedData::ColorCurve(map) => {
1134                map.len().hash(state);
1135                #[cfg(not(feature = "interpolation"))]
1136                for (time, value) in &map.values {
1137                    time.hash(state);
1138                    value.hash(state);
1139                }
1140                #[cfg(feature = "interpolation")]
1141                for (time, (value, spec)) in &map.values {
1142                    time.hash(state);
1143                    value.hash(state);
1144                    spec.hash(state);
1145                }
1146            }
1147        }
1148    }
1149}
1150
1151// Sample trait implementations for AnimatedData
1152impl_sample_for_animated_data!(
1153    Real, Real;
1154    Integer, Integer;
1155    Color, Color;
1156);
1157
1158impl_sample_for_animated_data!(
1159    Vector2, Vector2, "vector2";
1160    Vector3, Vector3, "vector3";
1161    Matrix3, Matrix3, "matrix3";
1162    Normal3, Normal3, "normal3";
1163    Point3, Point3, "point3";
1164    Matrix4, Matrix4, "matrix4";
1165);
1166
1167impl AnimatedData {
1168    /// Hash the animated data with shutter context for better cache coherency.
1169    ///
1170    /// Samples the animation at standardized points within the shutter range
1171    /// and hashes the interpolated values. If all samples are identical,
1172    /// only one value is hashed for efficiency.
1173    pub fn hash_with_shutter<H: Hasher>(&self, state: &mut H, shutter: &Shutter) {
1174        use smallvec::SmallVec;
1175
1176        // Sample at 5 standardized points within the shutter.
1177        const SAMPLE_POSITIONS: [f32; 5] = [0.0, 0.25, 0.5, 0.75, 1.0];
1178
1179        // Collect interpolated samples using SmallVec to avoid heap allocation.
1180        let samples: SmallVec<[Data; 5]> = SAMPLE_POSITIONS
1181            .iter()
1182            .map(|&pos| {
1183                let time = shutter.evaluate(pos);
1184                self.interpolate(time)
1185            })
1186            .collect();
1187
1188        // Check if all samples are identical.
1189        let all_same = samples.windows(2).all(|w| w[0] == w[1]);
1190
1191        // Hash the data type discriminant.
1192        std::mem::discriminant(self).hash(state);
1193
1194        if all_same {
1195            // If all samples are the same, just hash one.
1196            1usize.hash(state); // Indicate single sample.
1197            samples[0].hash(state);
1198        } else {
1199            // Hash all samples.
1200            samples.len().hash(state); // Indicate multiple samples.
1201            for sample in &samples {
1202                sample.hash(state);
1203            }
1204        }
1205    }
1206}
1207
1208// Implement AnimatedDataSystem trait for the built-in AnimatedData type.
1209impl crate::traits::AnimatedDataSystem for AnimatedData {
1210    type Data = Data;
1211
1212    fn keyframe_count(&self) -> usize {
1213        AnimatedDataOps::len(self)
1214    }
1215
1216    fn is_keyframes_empty(&self) -> bool {
1217        AnimatedDataOps::is_empty(self)
1218    }
1219
1220    fn has_animation(&self) -> bool {
1221        AnimatedDataOps::is_animated(self)
1222    }
1223
1224    fn times(&self) -> SmallVec<[Time; 10]> {
1225        AnimatedData::times(self)
1226    }
1227
1228    fn interpolate(&self, time: Time) -> Data {
1229        AnimatedData::interpolate(self, time)
1230    }
1231
1232    fn sample_at(&self, time: Time) -> Option<Data> {
1233        AnimatedData::sample_at(self, time)
1234    }
1235
1236    fn try_insert(&mut self, time: Time, value: Data) -> Result<()> {
1237        AnimatedData::try_insert(self, time, value)
1238    }
1239
1240    fn remove_at(&mut self, time: &Time) -> Option<Data> {
1241        AnimatedData::remove_at(self, time)
1242    }
1243
1244    fn discriminant(&self) -> DataType {
1245        DataTypeOps::data_type(self)
1246    }
1247
1248    fn from_single(time: Time, value: Data) -> Self {
1249        AnimatedData::from((time, value))
1250    }
1251
1252    fn variant_name(&self) -> &'static str {
1253        DataTypeOps::type_name(self)
1254    }
1255}