fyrox_impl/scene/animation/
mod.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//! Animation player is a node that contains multiple animations. It updates and plays all the animations.
22//! See [`AnimationPlayer`] docs for more info.
23
24use crate::scene::node::constructor::NodeConstructor;
25use crate::{
26    core::{
27        log::{Log, MessageKind},
28        math::aabb::AxisAlignedBoundingBox,
29        pool::Handle,
30        reflect::prelude::*,
31        type_traits::prelude::*,
32        uuid::{uuid, Uuid},
33        variable::InheritableVariable,
34        visitor::prelude::*,
35    },
36    generic_animation::value::{BoundValueCollection, TrackValue, ValueBinding},
37    scene::{
38        base::{Base, BaseBuilder},
39        graph::{Graph, NodePool},
40        node::{Node, NodeTrait, UpdateContext},
41    },
42};
43use fyrox_graph::constructor::ConstructorProvider;
44use fyrox_graph::BaseSceneGraph;
45use std::ops::{Deref, DerefMut};
46
47pub mod absm;
48pub mod spritesheet;
49
50/// Scene specific animation.
51pub type Animation = crate::generic_animation::Animation<Handle<Node>>;
52/// Scene specific animation track.
53pub type Track = crate::generic_animation::track::Track;
54/// Scene specific animation container.
55pub type AnimationContainer = crate::generic_animation::AnimationContainer<Handle<Node>>;
56/// Scene specific animation pose.
57pub type AnimationPose = crate::generic_animation::AnimationPose<Handle<Node>>;
58/// Scene specific animation node pose.
59pub type NodePose = crate::generic_animation::NodePose<Handle<Node>>;
60
61/// Standard prelude for animations, that contains all most commonly used types and traits.
62pub mod prelude {
63    pub use super::{
64        Animation, AnimationContainer, AnimationContainerExt, AnimationPlayer,
65        AnimationPlayerBuilder, AnimationPose, AnimationPoseExt, BoundValueCollectionExt, NodePose,
66        Track,
67    };
68    pub use crate::generic_animation::{
69        container::{TrackDataContainer, TrackValueKind},
70        signal::AnimationSignal,
71        value::{BoundValueCollection, TrackValue, ValueBinding, ValueType},
72        AnimationEvent,
73    };
74}
75
76/// Extension trait for [`AnimationContainer`].
77pub trait AnimationContainerExt {
78    /// Updates all animations in the container and applies their poses to respective nodes. This method is intended to
79    /// be used only by the internals of the engine!
80    fn update_animations(&mut self, nodes: &mut NodePool, dt: f32);
81}
82
83impl AnimationContainerExt for AnimationContainer {
84    fn update_animations(&mut self, nodes: &mut NodePool, dt: f32) {
85        for animation in self.iter_mut().filter(|anim| anim.is_enabled()) {
86            animation.tick(dt);
87            animation.pose().apply_internal(nodes);
88        }
89    }
90}
91
92/// Extension trait for [`AnimationPose`].
93pub trait AnimationPoseExt {
94    /// Tries to set each value to the each property from the animation pose to respective scene nodes.
95    fn apply_internal(&self, nodes: &mut NodePool);
96
97    /// Tries to set each value to the each property from the animation pose to respective scene nodes.
98    fn apply(&self, graph: &mut Graph);
99
100    /// Calls given callback function for each node and allows you to apply pose with your own
101    /// rules. This could be useful if you need to ignore transform some part of pose for a node.
102    fn apply_with<C>(&self, graph: &mut Graph, callback: C)
103    where
104        C: FnMut(&mut Node, Handle<Node>, &NodePose);
105}
106
107impl AnimationPoseExt for AnimationPose {
108    fn apply_internal(&self, nodes: &mut NodePool) {
109        for (node, local_pose) in self.poses() {
110            if node.is_none() {
111                Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
112            } else if let Some(node) = nodes.try_borrow_mut(*node) {
113                local_pose.values.apply(node);
114            }
115        }
116    }
117
118    fn apply(&self, graph: &mut Graph) {
119        for (node, local_pose) in self.poses() {
120            if node.is_none() {
121                Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
122            } else if let Some(node) = graph.try_get_mut(*node) {
123                local_pose.values.apply(node);
124            }
125        }
126    }
127
128    fn apply_with<C>(&self, graph: &mut Graph, mut callback: C)
129    where
130        C: FnMut(&mut Node, Handle<Node>, &NodePose),
131    {
132        for (node, local_pose) in self.poses() {
133            if node.is_none() {
134                Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!");
135            } else if let Some(node_ref) = graph.try_get_mut(*node) {
136                callback(node_ref, *node, local_pose);
137            }
138        }
139    }
140}
141
142/// Extension trait for [`BoundValueCollection`].
143pub trait BoundValueCollectionExt {
144    /// Tries to set each value from the collection to the respective property (by binding) of the given scene node.
145    fn apply(&self, node_ref: &mut Node);
146}
147
148impl BoundValueCollectionExt for BoundValueCollection {
149    fn apply(&self, node_ref: &mut Node) {
150        for bound_value in self.values.iter() {
151            match bound_value.binding {
152                ValueBinding::Position => {
153                    if let TrackValue::Vector3(v) = bound_value.value {
154                        node_ref.local_transform_mut().set_position(v);
155                    } else {
156                        Log::err(
157                            "Unable to apply position, because underlying type is not Vector3!",
158                        )
159                    }
160                }
161                ValueBinding::Scale => {
162                    if let TrackValue::Vector3(v) = bound_value.value {
163                        node_ref.local_transform_mut().set_scale(v);
164                    } else {
165                        Log::err("Unable to apply scaling, because underlying type is not Vector3!")
166                    }
167                }
168                ValueBinding::Rotation => {
169                    if let TrackValue::UnitQuaternion(v) = bound_value.value {
170                        node_ref.local_transform_mut().set_rotation(v);
171                    } else {
172                        Log::err("Unable to apply rotation, because underlying type is not UnitQuaternion!")
173                    }
174                }
175                ValueBinding::Property {
176                    name: ref property_name,
177                    value_type,
178                } => bound_value.apply_to_object(node_ref, property_name, value_type),
179            }
180        }
181    }
182}
183
184/// Animation player is a node that contains multiple animations. It updates and plays all the animations.
185/// The node could be a source of animations for animation blending state machines. To learn more about
186/// animations, see [`Animation`] docs.
187///
188/// # Examples
189///
190/// Always prefer using animation editor to create animation player nodes. It has rich functionality and
191/// an ability to preview the result of animations. If you need to create an animation procedurally, the
192/// next code snippet is for you.
193///
194/// ```rust
195/// # use fyrox_animation::track::TrackBinding;
196/// # use fyrox_impl::{
197/// #     core::{
198/// #         math::curve::{Curve, CurveKey, CurveKeyKind},
199/// #         pool::Handle,
200/// #     },
201/// #     scene::{animation::prelude::*, base::BaseBuilder, graph::Graph, node::Node},
202/// # };
203///
204/// fn create_bounce_animation(animated_node: Handle<Node>) -> Animation {
205///     let mut frames_container = TrackDataContainer::new(TrackValueKind::Vector3);
206///
207///     // We'll animate only Y coordinate (at index 1).
208///     frames_container.curves_mut()[1] = Curve::from(vec![
209///         CurveKey::new(0.1, 1.0, CurveKeyKind::Linear),
210///         CurveKey::new(0.2, 0.0, CurveKeyKind::Linear),
211///         CurveKey::new(0.3, 0.75, CurveKeyKind::Linear),
212///         CurveKey::new(0.4, 0.0, CurveKeyKind::Linear),
213///         CurveKey::new(0.5, 0.25, CurveKeyKind::Linear),
214///         CurveKey::new(0.6, 0.0, CurveKeyKind::Linear),
215///     ]);
216///
217///     // Create a track that will animate the node using the curve above.
218///     let mut track = Track::new(frames_container, ValueBinding::Position);
219///     // Finally create an animation and set its time slice and turn it on.
220///     let mut animation = Animation::default();
221///     animation.add_track_with_binding(TrackBinding::new(animated_node),track);
222///     animation.set_time_slice(0.0..0.6);
223///     animation.set_enabled(true);
224///     animation
225/// }
226///
227/// fn create_bounce_animation_player(
228///     animated_node: Handle<Node>,
229///     graph: &mut Graph,
230/// ) -> Handle<Node> {
231///     let mut animations = AnimationContainer::new();
232///
233///     // Create a bounce animation.
234///     animations.add(create_bounce_animation(animated_node));
235///
236///     AnimationPlayerBuilder::new(BaseBuilder::new())
237///         .with_animations(animations)
238///         .build(graph)
239/// }
240/// ```
241///
242/// As you can see, the example is quite big. That's why you should always prefer using the editor to create animations.
243/// The example creates a bounce animation first - it is a simple animation that animates position of a given node
244/// (`animated_node`). Only then it creates an animation player node with an animation container with a single animation.
245/// To understand why this is so complicated, see the docs of [`Animation`].
246#[derive(Visit, Reflect, Clone, Debug, ComponentProvider)]
247pub struct AnimationPlayer {
248    base: Base,
249    #[component(include)]
250    animations: InheritableVariable<AnimationContainer>,
251    #[component(include)]
252    auto_apply: bool,
253}
254
255impl Default for AnimationPlayer {
256    fn default() -> Self {
257        Self {
258            base: Default::default(),
259            animations: Default::default(),
260            auto_apply: true,
261        }
262    }
263}
264
265impl AnimationPlayer {
266    /// Enables or disables automatic animations update and pose applying. If auto applying is enabled,
267    /// then every animation in this node is updated first, and then their output pose could be applied
268    /// to the graph, so the animation takes effect. Automatic applying is useful when you need your
269    /// animations to be applied immediately to the graph, but in some cases (if you're using animation
270    /// blending state machines for example) this functionality is undesired.
271    ///
272    /// Animation blending machines hijacks control over the animation container and updates only
273    /// active animations, instead of all available. This is much better for performance than updating
274    /// all at once.
275    pub fn set_auto_apply(&mut self, auto_apply: bool) {
276        self.auto_apply = auto_apply;
277    }
278
279    /// Returns `true` if the node is automatically applying output poses of animations to the graph, `false` -
280    /// otherwise.
281    pub fn is_auto_apply(&self) -> bool {
282        self.auto_apply
283    }
284
285    /// Returns a reference to internal animations container.
286    pub fn animations(&self) -> &InheritableVariable<AnimationContainer> {
287        &self.animations
288    }
289
290    /// Returns a reference to internal animations container. Keep in mind that mutable access to [`InheritableVariable`]
291    /// may have side effects if used inappropriately. Checks docs for [`InheritableVariable`] for more info.
292    pub fn animations_mut(&mut self) -> &mut InheritableVariable<AnimationContainer> {
293        &mut self.animations
294    }
295
296    /// Sets new animations container of the animation player.
297    pub fn set_animations(&mut self, animations: AnimationContainer) {
298        self.animations.set_value_and_mark_modified(animations);
299    }
300}
301
302impl TypeUuidProvider for AnimationPlayer {
303    fn type_uuid() -> Uuid {
304        uuid!("44d1c94e-354f-4f9a-b918-9d31c28aa16a")
305    }
306}
307
308impl Deref for AnimationPlayer {
309    type Target = Base;
310
311    fn deref(&self) -> &Self::Target {
312        &self.base
313    }
314}
315
316impl DerefMut for AnimationPlayer {
317    fn deref_mut(&mut self) -> &mut Self::Target {
318        &mut self.base
319    }
320}
321
322impl ConstructorProvider<Node, Graph> for AnimationPlayer {
323    fn constructor() -> NodeConstructor {
324        NodeConstructor::new::<Self>()
325            .with_variant("Animation Player", |_| {
326                AnimationPlayerBuilder::new(BaseBuilder::new().with_name("Animation Player"))
327                    .build_node()
328                    .into()
329            })
330            .with_group("Animation")
331    }
332}
333
334impl NodeTrait for AnimationPlayer {
335    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
336        self.base.local_bounding_box()
337    }
338
339    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
340        self.base.world_bounding_box()
341    }
342
343    fn id(&self) -> Uuid {
344        Self::type_uuid()
345    }
346
347    fn update(&mut self, context: &mut UpdateContext) {
348        if self.auto_apply {
349            self.animations
350                .get_value_mut_silent()
351                .update_animations(context.nodes, context.dt);
352        }
353    }
354}
355
356/// A builder for [`AnimationPlayer`] node.
357pub struct AnimationPlayerBuilder {
358    base_builder: BaseBuilder,
359    animations: AnimationContainer,
360    auto_apply: bool,
361}
362
363impl AnimationPlayerBuilder {
364    /// Creates new builder instance.
365    pub fn new(base_builder: BaseBuilder) -> Self {
366        Self {
367            base_builder,
368            animations: AnimationContainer::new(),
369            auto_apply: true,
370        }
371    }
372
373    /// Sets a container with desired animations.
374    pub fn with_animations(mut self, animations: AnimationContainer) -> Self {
375        self.animations = animations;
376        self
377    }
378
379    /// Enables or disables automatic pose applying. See [`AnimationPlayer::set_auto_apply`] docs for more info.
380    pub fn with_auto_apply(mut self, auto_apply: bool) -> Self {
381        self.auto_apply = auto_apply;
382        self
383    }
384
385    /// Creates an instance of [`AnimationPlayer`] node.
386    pub fn build_node(self) -> Node {
387        Node::new(AnimationPlayer {
388            base: self.base_builder.build_base(),
389            animations: self.animations.into(),
390            auto_apply: self.auto_apply,
391        })
392    }
393
394    /// Creates an instance of [`AnimationPlayer`] node and adds it to the given scene graph.
395    pub fn build(self, graph: &mut Graph) -> Handle<Node> {
396        graph.add_node(self.build_node())
397    }
398}