//! Keyframes of animation clips. use core::{ any::TypeId, fmt::{self, Debug, Formatter}, }; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{component::Component, world::Mut}; use bevy_math::{Quat, Vec3}; use bevy_reflect::{FromReflect, Reflect, Reflectable, TypePath}; use bevy_render::mesh::morph::MorphWeights; use bevy_transform::prelude::Transform; use crate::{ animatable, prelude::{Animatable, GetKeyframe}, AnimationEntityMut, AnimationEvaluationError, Interpolation, }; /// A value on a component that Bevy can animate. /// /// You can implement this trait on a unit struct in order to support animating /// custom components other than transforms and morph weights. Use that type in /// conjunction with [`AnimatablePropertyKeyframes`]. For example, in order to /// animate font size of a text section from 24 pt. to 80 pt., you might use: /// /// # use bevy_animation::prelude::AnimatableProperty; /// # use bevy_reflect::Reflect; /// # use bevy_text::Text; /// #[derive(Reflect)] /// struct FontSizeProperty; /// /// impl AnimatableProperty for FontSizeProperty { /// type Component = Text; /// type Property = f32; /// fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property> { /// Some(&mut component.sections.get_mut(0)?.style.font_size) /// } /// } /// /// You can then create a [`crate::AnimationClip`] to animate this property like so: /// /// # use bevy_animation::{AnimationClip, AnimationTargetId, Interpolation, VariableCurve}; /// # use bevy_animation::prelude::{AnimatableProperty, AnimatablePropertyKeyframes}; /// # use bevy_core::Name; /// # use bevy_reflect::Reflect; /// # use bevy_text::Text; /// # let animation_target_id = AnimationTargetId::from(&Name::new("Test")); /// # #[derive(Reflect)] /// # struct FontSizeProperty; /// # impl AnimatableProperty for FontSizeProperty { /// # type Component = Text; /// # type Property = f32; /// # fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property> { /// # Some(&mut component.sections.get_mut(0)?.style.font_size) /// # } /// # } /// let mut animation_clip = AnimationClip::default(); /// animation_clip.add_curve_to_target( /// animation_target_id, /// VariableCurve::linear::>( /// [0.0, 1.0], /// [24.0, 80.0], /// ), /// ); pub trait AnimatableProperty: Reflect + TypePath + 'static { /// The type of the component that the property lives on. type Component: Component; /// The type of the property to be animated. type Property: Animatable + FromReflect + Reflectable + Clone + Sync + Debug + 'static; /// Given a reference to the component, returns a reference to the property. /// /// If the property couldn't be found, returns `None`. fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property>; } /// Keyframes in a [`crate::VariableCurve`] that animate an /// [`AnimatableProperty`]. /// /// This is the a generic type of [`Keyframes`] that can animate any /// [`AnimatableProperty`]. See the documentation for [`AnimatableProperty`] for /// more information as to how to use this type. /// /// If you're animating scale, rotation, or translation of a [`Transform`], /// [`ScaleKeyframes`], [`RotationKeyframes`], and [`TranslationKeyframes`] are /// faster, and simpler, alternatives to this type. #[derive(Reflect, Deref, DerefMut)] pub struct AnimatablePropertyKeyframes

(pub Vec) where P: AnimatableProperty; impl

Clone for AnimatablePropertyKeyframes

where P: AnimatableProperty, { fn clone(&self) -> Self { Self(self.0.clone()) } } impl

Debug for AnimatablePropertyKeyframes

where P: AnimatableProperty, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_tuple("AnimatablePropertyKeyframes") .field(&self.0) .finish() } } /// A low-level trait for use in [`crate::VariableCurve`] that provides fine /// control over how animations are evaluated. /// /// You can implement this trait when the generic /// [`AnimatablePropertyKeyframes`] isn't sufficiently-expressive for your /// needs. For example, [`MorphWeights`] implements this trait instead of using /// [`AnimatablePropertyKeyframes`] because it needs to animate arbitrarily many /// weights at once, which can't be done with [`Animatable`] as that works on /// fixed-size values only. pub trait Keyframes: Reflect + Debug + Send + Sync { /// Returns a boxed clone of this value. fn clone_value(&self) -> Box; /// Interpolates between the existing value and the value of the first /// keyframe, and writes the value into `transform` and/or `entity` as /// appropriate. /// /// Arguments: /// /// * `transform`: The transform of the entity, if present. /// /// * `entity`: Allows access to the rest of the components of the entity. /// /// * `weight`: The blend weight between the existing component value (0.0) /// and the one computed from the keyframes (1.0). fn apply_single_keyframe<'a>( &self, transform: Option>, entity: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError>; /// Interpolates between the existing value and the value of the two nearest /// keyframes, and writes the value into `transform` and/or `entity` as /// appropriate. /// /// Arguments: /// /// * `transform`: The transform of the entity, if present. /// /// * `entity`: Allows access to the rest of the components of the entity. /// /// * `interpolation`: The type of interpolation to use. /// /// * `step_start`: The index of the first keyframe. /// /// * `time`: The blend weight between the first keyframe (0.0) and the next /// keyframe (1.0). /// /// * `weight`: The blend weight between the existing component value (0.0) /// and the one computed from the keyframes (1.0). /// /// If `interpolation` is `Interpolation::Linear`, then pseudocode for this /// function could be `property = lerp(property, lerp(keyframes[step_start], /// keyframes[step_start + 1], time), weight)`. #[allow(clippy::too_many_arguments)] fn apply_tweened_keyframes<'a>( &self, transform: Option>, entity: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError>; } /// Keyframes for animating [`Transform::translation`]. /// /// An example of a [`crate::AnimationClip`] that animates translation: /// /// # use bevy_animation::{AnimationClip, AnimationTargetId, Interpolation}; /// # use bevy_animation::{VariableCurve, prelude::TranslationKeyframes}; /// # use bevy_core::Name; /// # use bevy_math::Vec3; /// # let animation_target_id = AnimationTargetId::from(&Name::new("Test")); /// let mut animation_clip = AnimationClip::default(); /// animation_clip.add_curve_to_target( /// animation_target_id, /// VariableCurve::linear::( /// [0.0, 1.0], /// [Vec3::ZERO, Vec3::ONE], /// ), /// ); #[derive(Clone, Reflect, Debug, Deref, DerefMut)] pub struct TranslationKeyframes(pub Vec); /// Keyframes for animating [`Transform::scale`]. /// /// An example of a [`crate::AnimationClip`] that animates translation: /// /// # use bevy_animation::{AnimationClip, AnimationTargetId, Interpolation}; /// # use bevy_animation::{VariableCurve, prelude::ScaleKeyframes}; /// # use bevy_core::Name; /// # use bevy_math::Vec3; /// # let animation_target_id = AnimationTargetId::from(&Name::new("Test")); /// let mut animation_clip = AnimationClip::default(); /// animation_clip.add_curve_to_target( /// animation_target_id, /// VariableCurve::linear::( /// [0.0, 1.0], /// [Vec3::ONE, Vec3::splat(2.0)], /// ), /// ); #[derive(Clone, Reflect, Debug, Deref, DerefMut)] pub struct ScaleKeyframes(pub Vec); /// Keyframes for animating [`Transform::rotation`]. /// /// An example of a [`crate::AnimationClip`] that animates translation: /// /// # use bevy_animation::{AnimationClip, AnimationTargetId, Interpolation}; /// # use bevy_animation::{VariableCurve, prelude::RotationKeyframes}; /// # use bevy_core::Name; /// # use bevy_math::Quat; /// # use std::f32::consts::FRAC_PI_2; /// # let animation_target_id = AnimationTargetId::from(&Name::new("Test")); /// let mut animation_clip = AnimationClip::default(); /// animation_clip.add_curve_to_target( /// animation_target_id, /// VariableCurve::linear::( /// [0.0, 1.0], /// [Quat::from_rotation_x(FRAC_PI_2), Quat::from_rotation_y(FRAC_PI_2)], /// ), /// ); #[derive(Clone, Reflect, Debug, Deref, DerefMut)] pub struct RotationKeyframes(pub Vec); /// Keyframes for animating [`MorphWeights`]. #[derive(Clone, Debug, Reflect)] pub struct MorphWeightsKeyframes { /// The total number of morph weights. pub morph_target_count: usize, /// The morph weights. /// /// The length of this vector should be the total number of morph weights /// times the number of keyframes. pub weights: Vec, } impl From for TranslationKeyframes where T: Into>, { fn from(value: T) -> Self { Self(value.into()) } } impl Keyframes for TranslationKeyframes { fn clone_value(&self) -> Box { Box::new(self.clone()) } fn apply_single_keyframe<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; let value = self .first() .ok_or(AnimationEvaluationError::KeyframeNotPresent(0))?; component.translation = Animatable::interpolate(&component.translation, value, weight); Ok(()) } fn apply_tweened_keyframes<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; animatable::interpolate_keyframes( &mut component.translation, &(*self)[..], interpolation, step_start, time, weight, duration, ) } } impl From for ScaleKeyframes where T: Into>, { fn from(value: T) -> Self { Self(value.into()) } } impl Keyframes for ScaleKeyframes { fn clone_value(&self) -> Box { Box::new(self.clone()) } fn apply_single_keyframe<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; let value = self .first() .ok_or(AnimationEvaluationError::KeyframeNotPresent(0))?; component.scale = Animatable::interpolate(&component.scale, value, weight); Ok(()) } fn apply_tweened_keyframes<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; animatable::interpolate_keyframes( &mut component.scale, &(*self)[..], interpolation, step_start, time, weight, duration, ) } } impl From for RotationKeyframes where T: Into>, { fn from(value: T) -> Self { Self(value.into()) } } impl Keyframes for RotationKeyframes { fn clone_value(&self) -> Box { Box::new(self.clone()) } fn apply_single_keyframe<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; let value = self .first() .ok_or(AnimationEvaluationError::KeyframeNotPresent(0))?; component.rotation = Animatable::interpolate(&component.rotation, value, weight); Ok(()) } fn apply_tweened_keyframes<'a>( &self, transform: Option>, _: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = transform.ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; animatable::interpolate_keyframes( &mut component.rotation, &(*self)[..], interpolation, step_start, time, weight, duration, ) } } impl From for AnimatablePropertyKeyframes

where P: AnimatableProperty, T: Into>, { fn from(value: T) -> Self { Self(value.into()) } } impl

Keyframes for AnimatablePropertyKeyframes

where P: AnimatableProperty, { fn clone_value(&self) -> Box { Box::new((*self).clone()) } fn apply_single_keyframe<'a>( &self, _: Option>, mut entity: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = entity.get_mut::().ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; let property = P::get_mut(&mut component) .ok_or_else(|| AnimationEvaluationError::PropertyNotPresent(TypeId::of::

()))?; let value = self .first() .ok_or(AnimationEvaluationError::KeyframeNotPresent(0))?; ::interpolate(property, value, weight); Ok(()) } fn apply_tweened_keyframes<'a>( &self, _: Option>, mut entity: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError> { let mut component = entity.get_mut::().ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; let property = P::get_mut(&mut component) .ok_or_else(|| AnimationEvaluationError::PropertyNotPresent(TypeId::of::

()))?; animatable::interpolate_keyframes( property, self, interpolation, step_start, time, weight, duration, )?; Ok(()) } } impl GetKeyframe for [A] where A: Animatable, { type Output = A; fn get_keyframe(&self, index: usize) -> Option<&Self::Output> { self.get(index) } } impl

GetKeyframe for AnimatablePropertyKeyframes

where P: AnimatableProperty, { type Output = P::Property; fn get_keyframe(&self, index: usize) -> Option<&Self::Output> { self.get(index) } } /// Information needed to look up morph weight values in the flattened morph /// weight keyframes vector. struct GetMorphWeightKeyframe<'k> { /// The morph weights keyframe structure that we're animating. keyframes: &'k MorphWeightsKeyframes, /// The index of the morph target in that structure. morph_target_index: usize, } impl Keyframes for MorphWeightsKeyframes { fn clone_value(&self) -> Box { Box::new(self.clone()) } fn apply_single_keyframe<'a>( &self, _: Option>, mut entity: AnimationEntityMut<'a>, weight: f32, ) -> Result<(), AnimationEvaluationError> { let mut dest = entity.get_mut::().ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; // TODO: Go 4 weights at a time to make better use of SIMD. for (morph_target_index, morph_weight) in dest.weights_mut().iter_mut().enumerate() { *morph_weight = f32::interpolate(morph_weight, &self.weights[morph_target_index], weight); } Ok(()) } fn apply_tweened_keyframes<'a>( &self, _: Option>, mut entity: AnimationEntityMut<'a>, interpolation: Interpolation, step_start: usize, time: f32, weight: f32, duration: f32, ) -> Result<(), AnimationEvaluationError> { let mut dest = entity.get_mut::().ok_or_else(|| { AnimationEvaluationError::ComponentNotPresent(TypeId::of::()) })?; // TODO: Go 4 weights at a time to make better use of SIMD. for (morph_target_index, morph_weight) in dest.weights_mut().iter_mut().enumerate() { animatable::interpolate_keyframes( morph_weight, &GetMorphWeightKeyframe { keyframes: self, morph_target_index, }, interpolation, step_start, time, weight, duration, )?; } Ok(()) } } impl GetKeyframe for GetMorphWeightKeyframe<'_> { type Output = f32; fn get_keyframe(&self, keyframe_index: usize) -> Option<&Self::Output> { self.keyframes .weights .as_slice() .get(keyframe_index * self.keyframes.morph_target_count + self.morph_target_index) } }