Skip to main content

fyrox_animation/
value.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! A module that contains everything related to numeric values of animation tracks. See [`TrackValue`] docs
22//! for more info.
23
24use crate::core::{
25    algebra::{Unit, UnitQuaternion, Vector2, Vector3, Vector4},
26    log::Log,
27    math::lerpf,
28    num_traits::AsPrimitive,
29    reflect::prelude::*,
30    visitor::prelude::*,
31    ImmutableString,
32};
33use std::any::TypeId;
34use std::{
35    any,
36    any::Any,
37    fmt::{Debug, Display, Formatter},
38};
39
40/// An actual type of a property value.
41#[derive(Visit, Reflect, Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
42pub enum ValueType {
43    /// `bool`
44    Bool,
45    /// `f32`
46    #[default]
47    F32,
48    /// `f64`
49    F64,
50    /// `u64`
51    U64,
52    /// `i64`
53    I64,
54    /// `u32`
55    U32,
56    /// `i32`
57    I32,
58    /// `u16`
59    U16,
60    /// `i16`
61    I16,
62    /// `u8`
63    U8,
64    /// `i8`
65    I8,
66
67    /// `Vector2<bool>`
68    Vector2Bool,
69    /// `Vector2<f32>`
70    Vector2F32,
71    /// `Vector2<f64>`
72    Vector2F64,
73    /// `Vector2<u64>`
74    Vector2U64,
75    /// `Vector2<i64>`
76    Vector2I64,
77    /// `Vector2<u32>`
78    Vector2U32,
79    /// `Vector2<i32>`
80    Vector2I32,
81    /// `Vector2<u16>`
82    Vector2U16,
83    /// `Vector2<i16>`
84    Vector2I16,
85    /// `Vector2<u8>`
86    Vector2U8,
87    /// `Vector2<i8>`
88    Vector2I8,
89
90    /// `Vector3<bool>`
91    Vector3Bool,
92    /// `Vector3<f32>`
93    Vector3F32,
94    /// `Vector3<f64>`
95    Vector3F64,
96    /// `Vector3<u64>`
97    Vector3U64,
98    /// `Vector3<i64>`
99    Vector3I64,
100    /// `Vector3<u32>`
101    Vector3U32,
102    /// `Vector3<i32>`
103    Vector3I32,
104    /// `Vector3<u16>`
105    Vector3U16,
106    /// `Vector3<i16>`
107    Vector3I16,
108    /// `Vector3<u8>`
109    Vector3U8,
110    /// `Vector3<i8>`
111    Vector3I8,
112
113    /// `Vector4<bool>`
114    Vector4Bool,
115    /// `Vector4<f32>`
116    Vector4F32,
117    /// `Vector4<f64>`
118    Vector4F64,
119    /// `Vector4<u64>`
120    Vector4U64,
121    /// `Vector4<i64>`
122    Vector4I64,
123    /// `Vector4<u32>`
124    Vector4U32,
125    /// `Vector4<i32>`
126    Vector4I32,
127    /// `Vector4<u16>`
128    Vector4U16,
129    /// `Vector4<i16>`
130    Vector4I16,
131    /// `Vector4<u8>`
132    Vector4U8,
133    /// `Vector4<i8>`
134    Vector4I8,
135
136    /// `UnitQuaternion<f32>`
137    UnitQuaternionF32,
138    /// `UnitQuaternion<f64>`
139    UnitQuaternionF64,
140}
141
142impl ValueType {
143    /// Converts the value type into its respective type id.
144    pub fn into_type_id(self) -> TypeId {
145        match self {
146            ValueType::Bool => TypeId::of::<bool>(),
147            ValueType::F32 => TypeId::of::<f32>(),
148            ValueType::F64 => TypeId::of::<f64>(),
149            ValueType::U64 => TypeId::of::<u64>(),
150            ValueType::I64 => TypeId::of::<i64>(),
151            ValueType::U32 => TypeId::of::<u32>(),
152            ValueType::I32 => TypeId::of::<i32>(),
153            ValueType::U16 => TypeId::of::<u16>(),
154            ValueType::I16 => TypeId::of::<i16>(),
155            ValueType::U8 => TypeId::of::<u8>(),
156            ValueType::I8 => TypeId::of::<i8>(),
157            ValueType::Vector2Bool => TypeId::of::<Vector2<bool>>(),
158            ValueType::Vector2F32 => TypeId::of::<Vector2<f32>>(),
159            ValueType::Vector2F64 => TypeId::of::<Vector2<f64>>(),
160            ValueType::Vector2U64 => TypeId::of::<Vector2<u64>>(),
161            ValueType::Vector2I64 => TypeId::of::<Vector2<i64>>(),
162            ValueType::Vector2U32 => TypeId::of::<Vector2<u32>>(),
163            ValueType::Vector2I32 => TypeId::of::<Vector2<i32>>(),
164            ValueType::Vector2U16 => TypeId::of::<Vector2<u16>>(),
165            ValueType::Vector2I16 => TypeId::of::<Vector2<i16>>(),
166            ValueType::Vector2U8 => TypeId::of::<Vector2<u8>>(),
167            ValueType::Vector2I8 => TypeId::of::<Vector2<i8>>(),
168            ValueType::Vector3Bool => TypeId::of::<Vector3<bool>>(),
169            ValueType::Vector3F32 => TypeId::of::<Vector3<f32>>(),
170            ValueType::Vector3F64 => TypeId::of::<Vector3<f64>>(),
171            ValueType::Vector3U64 => TypeId::of::<Vector3<u64>>(),
172            ValueType::Vector3I64 => TypeId::of::<Vector3<i64>>(),
173            ValueType::Vector3U32 => TypeId::of::<Vector3<u32>>(),
174            ValueType::Vector3I32 => TypeId::of::<Vector3<i32>>(),
175            ValueType::Vector3U16 => TypeId::of::<Vector3<u16>>(),
176            ValueType::Vector3I16 => TypeId::of::<Vector3<i16>>(),
177            ValueType::Vector3U8 => TypeId::of::<Vector3<u8>>(),
178            ValueType::Vector3I8 => TypeId::of::<Vector3<i8>>(),
179            ValueType::Vector4Bool => TypeId::of::<Vector4<bool>>(),
180            ValueType::Vector4F32 => TypeId::of::<Vector4<f32>>(),
181            ValueType::Vector4F64 => TypeId::of::<Vector4<f64>>(),
182            ValueType::Vector4U64 => TypeId::of::<Vector4<u64>>(),
183            ValueType::Vector4I64 => TypeId::of::<Vector4<i64>>(),
184            ValueType::Vector4U32 => TypeId::of::<Vector4<u32>>(),
185            ValueType::Vector4I32 => TypeId::of::<Vector4<i32>>(),
186            ValueType::Vector4U16 => TypeId::of::<Vector4<u16>>(),
187            ValueType::Vector4I16 => TypeId::of::<Vector4<i16>>(),
188            ValueType::Vector4U8 => TypeId::of::<Vector4<u8>>(),
189            ValueType::Vector4I8 => TypeId::of::<Vector4<i8>>(),
190            ValueType::UnitQuaternionF32 => TypeId::of::<UnitQuaternion<f32>>(),
191            ValueType::UnitQuaternionF64 => TypeId::of::<UnitQuaternion<f64>>(),
192        }
193    }
194}
195
196/// A real value that can be produced by an animation track. Animations always operate on real numbers (`f32`) for any kind
197/// of machine numeric types (including `bool`). This is needed to be able to blend values; final blending result is then
198/// converted to an actual machine type of a target property.
199#[derive(Clone, Debug, PartialEq)]
200pub enum TrackValue {
201    /// A real number.
202    Real(f32),
203
204    /// A 2-dimensional vector of real values.
205    Vector2(Vector2<f32>),
206
207    /// A 3-dimensional vector of real values.
208    Vector3(Vector3<f32>),
209
210    /// A 4-dimensional vector of real values.
211    Vector4(Vector4<f32>),
212
213    /// A quaternion that represents some rotation.
214    UnitQuaternion(UnitQuaternion<f32>),
215}
216
217impl TrackValue {
218    /// Mixes (blends) the current value with an other value using the given weight. Blending is possible only if the types
219    /// are the same.
220    pub fn blend_with(&mut self, other: &Self, weight: f32) {
221        match (self, other) {
222            (Self::Real(a), Self::Real(b)) => *a = lerpf(*a, *b, weight),
223            (Self::Vector2(a), Self::Vector2(b)) => *a = a.lerp(b, weight),
224            (Self::Vector3(a), Self::Vector3(b)) => *a = a.lerp(b, weight),
225            (Self::Vector4(a), Self::Vector4(b)) => *a = a.lerp(b, weight),
226            (Self::UnitQuaternion(a), Self::UnitQuaternion(b)) => *a = nlerp(*a, b, weight),
227            _ => (),
228        }
229    }
230
231    /// Tries to perform a numeric type casting of the current value to some other and returns a boxed value, that can
232    /// be used to set the value using reflection.
233    pub fn apply_to_any(&self, any: &mut dyn Any, value_type: ValueType) -> bool {
234        fn convert_vec2<T>(vec2: &Vector2<f32>) -> Vector2<T>
235        where
236            f32: AsPrimitive<T>,
237            T: Copy + 'static,
238        {
239            Vector2::new(vec2.x.as_(), vec2.y.as_())
240        }
241
242        fn convert_vec3<T>(vec3: &Vector3<f32>) -> Vector3<T>
243        where
244            f32: AsPrimitive<T>,
245            T: Copy + 'static,
246        {
247            Vector3::new(vec3.x.as_(), vec3.y.as_(), vec3.z.as_())
248        }
249
250        fn convert_vec4<T>(vec4: &Vector4<f32>) -> Vector4<T>
251        where
252            f32: AsPrimitive<T>,
253            T: Copy + 'static,
254        {
255            Vector4::new(vec4.x.as_(), vec4.y.as_(), vec4.z.as_(), vec4.w.as_())
256        }
257
258        fn set<T>(any: &mut dyn Any, value: T) -> bool
259        where
260            T: Any + Copy,
261        {
262            if let Some(any_val) = any.downcast_mut::<T>() {
263                *any_val = value;
264                true
265            } else {
266                Log::err(format!(
267                    "Animation: unable to set value of type {}! Types mismatch!",
268                    any::type_name::<T>()
269                ));
270                false
271            }
272        }
273
274        match self {
275            TrackValue::Real(real) => match value_type {
276                ValueType::Bool => set(any, real.ne(&0.0)),
277                ValueType::F32 => set(any, *real),
278                ValueType::F64 => set(any, *real as f64),
279                ValueType::U64 => set(any, *real as u64),
280                ValueType::I64 => set(any, *real as i64),
281                ValueType::U32 => set(any, *real as u32),
282                ValueType::I32 => set(any, *real as i32),
283                ValueType::U16 => set(any, *real as u16),
284                ValueType::I16 => set(any, *real as i16),
285                ValueType::U8 => set(any, *real as u8),
286                ValueType::I8 => set(any, *real as i8),
287                _ => false,
288            },
289            TrackValue::Vector2(vec2) => match value_type {
290                ValueType::Vector2Bool => set(any, Vector2::new(vec2.x.ne(&0.0), vec2.y.ne(&0.0))),
291                ValueType::Vector2F32 => set(any, *vec2),
292                ValueType::Vector2F64 => set(any, convert_vec2::<f64>(vec2)),
293                ValueType::Vector2U64 => set(any, convert_vec2::<u64>(vec2)),
294                ValueType::Vector2I64 => set(any, convert_vec2::<i64>(vec2)),
295                ValueType::Vector2U32 => set(any, convert_vec2::<u32>(vec2)),
296                ValueType::Vector2I32 => set(any, convert_vec2::<i32>(vec2)),
297                ValueType::Vector2U16 => set(any, convert_vec2::<u16>(vec2)),
298                ValueType::Vector2I16 => set(any, convert_vec2::<i16>(vec2)),
299                ValueType::Vector2U8 => set(any, convert_vec2::<u8>(vec2)),
300                ValueType::Vector2I8 => set(any, convert_vec2::<i8>(vec2)),
301                _ => false,
302            },
303            TrackValue::Vector3(vec3) => match value_type {
304                ValueType::Vector3Bool => set(
305                    any,
306                    Vector3::new(vec3.x.ne(&0.0), vec3.y.ne(&0.0), vec3.z.ne(&0.0)),
307                ),
308                ValueType::Vector3F32 => set(any, *vec3),
309                ValueType::Vector3F64 => set(any, convert_vec3::<f64>(vec3)),
310                ValueType::Vector3U64 => set(any, convert_vec3::<u64>(vec3)),
311                ValueType::Vector3I64 => set(any, convert_vec3::<i64>(vec3)),
312                ValueType::Vector3U32 => set(any, convert_vec3::<u32>(vec3)),
313                ValueType::Vector3I32 => set(any, convert_vec3::<i32>(vec3)),
314                ValueType::Vector3U16 => set(any, convert_vec3::<u16>(vec3)),
315                ValueType::Vector3I16 => set(any, convert_vec3::<i16>(vec3)),
316                ValueType::Vector3U8 => set(any, convert_vec3::<u8>(vec3)),
317                ValueType::Vector3I8 => set(any, convert_vec3::<i8>(vec3)),
318                _ => false,
319            },
320            TrackValue::Vector4(vec4) => match value_type {
321                ValueType::Vector4Bool => set(
322                    any,
323                    Vector4::new(
324                        vec4.x.ne(&0.0),
325                        vec4.y.ne(&0.0),
326                        vec4.z.ne(&0.0),
327                        vec4.w.ne(&0.0),
328                    ),
329                ),
330                ValueType::Vector4F32 => set(any, *vec4),
331                ValueType::Vector4F64 => set(any, convert_vec4::<f64>(vec4)),
332                ValueType::Vector4U64 => set(any, convert_vec4::<u64>(vec4)),
333                ValueType::Vector4I64 => set(any, convert_vec4::<i64>(vec4)),
334                ValueType::Vector4U32 => set(any, convert_vec4::<u32>(vec4)),
335                ValueType::Vector4I32 => set(any, convert_vec4::<i32>(vec4)),
336                ValueType::Vector4U16 => set(any, convert_vec4::<u16>(vec4)),
337                ValueType::Vector4I16 => set(any, convert_vec4::<i16>(vec4)),
338                ValueType::Vector4U8 => set(any, convert_vec4::<u8>(vec4)),
339                ValueType::Vector4I8 => set(any, convert_vec4::<i8>(vec4)),
340                _ => false,
341            },
342            TrackValue::UnitQuaternion(quat) => match value_type {
343                ValueType::UnitQuaternionF32 => set(any, *quat),
344                ValueType::UnitQuaternionF64 => set(any, quat.cast::<f64>()),
345                _ => false,
346            },
347        }
348    }
349}
350
351/// Value binding tells the animation system to which of the many properties to set track's value. It has special
352/// cases for the most used properties and a generic one for arbitrary properties. Arbitrary properties are set using
353/// reflection system, while the special cases handles bindings to standard properties (such as position, scaling, or
354/// rotation) for optimization. Reflection is quite slow to be used as the universal property setting mechanism.  
355#[derive(Default, Clone, Visit, Reflect, Debug, PartialEq, Eq)]
356pub enum ValueBinding {
357    /// A binding to position of a scene node.
358    #[default]
359    Position,
360    /// A binding to scale of a scene node.
361    Scale,
362    /// A binding to rotation of a scene node.
363    Rotation,
364    /// A binding to an arbitrary property of a scene node.
365    Property {
366        /// A path to a property (`foo.bar.baz[1].foobar@EnumVariant.stuff`)
367        name: ImmutableString,
368        /// Actual property type (only numeric properties are supported).
369        value_type: ValueType,
370    },
371}
372
373impl Display for ValueBinding {
374    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
375        match self {
376            ValueBinding::Position => write!(f, "Position"),
377            ValueBinding::Scale => write!(f, "Scale"),
378            ValueBinding::Rotation => write!(f, "Rotation"),
379            ValueBinding::Property { name, .. } => write!(f, "{name}"),
380        }
381    }
382}
383
384/// A value that is bound to a property.
385#[derive(Clone, Debug, PartialEq)]
386pub struct BoundValue {
387    /// A property to which the value is bound to.
388    pub binding: ValueBinding,
389    /// The new value for the property the binding points to.
390    pub value: TrackValue,
391}
392
393impl BoundValue {
394    /// Blends the current value with an other value using the given weight. See [`TrackValue::blend_with`] for
395    /// more info.
396    pub fn blend_with(&mut self, other: &Self, weight: f32) {
397        assert_eq!(self.binding, other.binding);
398        self.value.blend_with(&other.value, weight);
399    }
400
401    /// Sets a property of the given object.
402    pub fn apply_to_object(
403        &self,
404        object: &mut dyn Reflect,
405        property_path: &str,
406        value_type: ValueType,
407    ) {
408        object.as_reflect_mut(&mut |object_ref| {
409            object_ref.resolve_path_mut(property_path, &mut |result| match result {
410                Ok(property) => {
411                    let mut applied = false;
412                    property.as_any_mut(&mut |any| {
413                        applied = self.value.apply_to_any(any, value_type);
414                    });
415                    if applied {
416                        property.as_inheritable_variable_mut(&mut |var| {
417                            if let Some(var) = var {
418                                var.mark_modified();
419                            }
420                        });
421                    }
422                }
423                Err(err) => {
424                    Log::err(format!(
425                        "Failed to set property {property_path}! Reason: {err:?}"
426                    ));
427                }
428            });
429        })
430    }
431}
432
433/// A collection of values that are bounds to some properties.
434#[derive(Clone, Debug, Default, PartialEq)]
435pub struct BoundValueCollection {
436    /// Actual values collection.
437    pub values: Vec<BoundValue>,
438}
439
440impl BoundValueCollection {
441    /// Tries to blend each value of the current collection with a respective (by binding) value in the other collection.
442    /// See [`TrackValue::blend_with`] docs for more info.
443    pub fn blend_with(&mut self, other: &Self, weight: f32) {
444        for value in self.values.iter_mut() {
445            if let Some(other_value) = other.values.iter().find(|v| v.binding == value.binding) {
446                value.blend_with(other_value, weight);
447            }
448        }
449    }
450}
451
452/// Interpolates from `a` to `b` using nlerp, including an additional check to ensure
453/// that the a.dot(b) is positive to prevent the interpolation from going around the long way.
454pub fn nlerp(mut a: UnitQuaternion<f32>, b: &UnitQuaternion<f32>, w: f32) -> UnitQuaternion<f32> {
455    if a.dot(b) < 0.0 {
456        a = negate_unit_quaternion(&a)
457    }
458    a.nlerp(b, w)
459}
460
461/// Negate the given quaternion by negating each of its components.
462pub fn negate_unit_quaternion(a: &UnitQuaternion<f32>) -> UnitQuaternion<f32> {
463    Unit::new_unchecked(-a.as_ref())
464}
465
466#[cfg(test)]
467mod test {
468    use crate::value::{BoundValue, TrackValue, ValueBinding, ValueType};
469    use fyrox_core::{reflect::prelude::*, variable::InheritableVariable};
470
471    #[derive(Reflect, Debug, Clone, PartialEq)]
472    struct OtherStruct {
473        field: u32,
474        inheritable_variable: InheritableVariable<u32>,
475    }
476
477    impl Default for OtherStruct {
478        fn default() -> Self {
479            Self {
480                field: 0,
481                inheritable_variable: InheritableVariable::new_non_modified(0),
482            }
483        }
484    }
485
486    #[derive(Default, Reflect, Clone, Debug, PartialEq)]
487    struct MyStruct {
488        some_bool: bool,
489        some_property: f32,
490        other_struct: OtherStruct,
491    }
492
493    #[test]
494    fn test_apply_value() {
495        let some_bool_value = BoundValue {
496            binding: ValueBinding::Property {
497                name: "some_bool".into(),
498                value_type: ValueType::Bool,
499            },
500            value: TrackValue::Real(1.0),
501        };
502
503        let some_property_value = BoundValue {
504            binding: ValueBinding::Property {
505                name: "some_property".into(),
506                value_type: ValueType::F32,
507            },
508            value: TrackValue::Real(123.0),
509        };
510
511        let field_value = BoundValue {
512            binding: ValueBinding::Property {
513                name: "field".into(),
514                value_type: ValueType::U32,
515            },
516            value: TrackValue::Real(123.0),
517        };
518
519        let inheritable_variable_value = BoundValue {
520            binding: ValueBinding::Property {
521                name: "inheritable_variable".into(),
522                value_type: ValueType::U32,
523            },
524            value: TrackValue::Real(123.0),
525        };
526
527        let mut object = MyStruct::default();
528
529        some_bool_value.apply_to_object(&mut object, "some_bool", ValueType::Bool);
530        assert!(object.some_bool);
531
532        some_property_value.apply_to_object(&mut object, "some_property", ValueType::F32);
533        assert_eq!(object.some_property, 123.0);
534
535        field_value.apply_to_object(&mut object, "other_struct.field", ValueType::U32);
536        assert_eq!(object.other_struct.field, 123);
537
538        assert!(!object.other_struct.inheritable_variable.is_modified());
539        inheritable_variable_value.apply_to_object(
540            &mut object,
541            "other_struct.inheritable_variable",
542            ValueType::U32,
543        );
544        assert_eq!(object.other_struct.field, 123);
545        assert!(object.other_struct.inheritable_variable.is_modified());
546    }
547}