fyrox_animation/machine/
layer.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//! Layer is a separate state graph that usually animates only a part of nodes from animations. See docs of [`MachineLayer`]
22//! for more info.
23
24use crate::{
25    core::{
26        log::{Log, MessageKind},
27        pool::{Handle, Pool},
28        reflect::prelude::*,
29        visitor::prelude::*,
30    },
31    machine::{
32        event::FixedEventQueue, node::AnimationEventCollectionStrategy, AnimationPoseSource, Event,
33        LayerMask, ParameterContainer, PoseNode, State, Transition,
34    },
35    Animation, AnimationContainer, AnimationEvent, AnimationPose, EntityId,
36};
37use fyrox_core::{find_by_name_mut, find_by_name_ref, NameProvider};
38
39/// Layer is a separate state graph. Layers mainly used to animate different parts of humanoid (but not only) characters. For
40/// example there could a layer for upper body and a layer for lower body. Upper body layer could contain animations for aiming,
41/// melee attacks while lower body layer could contain animations for standing, running, crouching, etc. This gives you an
42/// ability to have running character that could aim or melee attack, or crouching and aiming, and so on with any combination.
43/// Both layers use the same set of parameters, so a change in a parameter will affect all layers that use it.
44///
45/// # Example
46///
47/// ```rust
48/// use fyrox_animation::{
49///     machine::{
50///         State, Transition, PoseNode, MachineLayer,
51///         Parameter, PlayAnimation, PoseWeight, BlendAnimations, BlendPose
52///     },
53///     core::pool::Handle
54/// };
55/// use fyrox_core::pool::ErasedHandle;
56///
57/// // Assume that these are correct handles.
58/// let idle_animation = Handle::default();
59/// let walk_animation = Handle::default();
60/// let aim_animation = Handle::default();
61///
62/// let mut root_layer = MachineLayer::<ErasedHandle>::new();
63///
64/// let aim = root_layer.add_node(PoseNode::PlayAnimation(PlayAnimation::new(aim_animation)));
65/// let walk = root_layer.add_node(PoseNode::PlayAnimation(PlayAnimation::new(walk_animation)));
66///
67/// // Blend two animations together
68/// let blend_aim_walk = root_layer.add_node(PoseNode::BlendAnimations(
69///     BlendAnimations::new(vec![
70///         BlendPose::new(PoseWeight::Constant(0.75), aim),
71///         BlendPose::new(PoseWeight::Constant(0.25), walk)
72///     ])
73/// ));
74///
75/// let walk_state = root_layer.add_state(State::new("Walk", blend_aim_walk));
76///
77/// let idle = root_layer.add_node(PoseNode::PlayAnimation(PlayAnimation::new(idle_animation)));
78/// let idle_state = root_layer.add_state(State::new("Idle", idle));
79///
80/// root_layer.add_transition(Transition::new("Walk->Idle", walk_state, idle_state, 1.0, "WalkToIdle"));
81/// root_layer.add_transition(Transition::new("Idle->Walk", idle_state, walk_state, 1.0, "IdleToWalk"));
82///
83/// ```
84#[derive(Default, Debug, Visit, Reflect, Clone, PartialEq)]
85pub struct MachineLayer<T: EntityId> {
86    name: String,
87
88    weight: f32,
89
90    mask: LayerMask<T>,
91
92    #[reflect(hidden)]
93    nodes: Pool<PoseNode<T>>,
94
95    #[reflect(hidden)]
96    transitions: Pool<Transition<T>>,
97
98    #[reflect(hidden)]
99    states: Pool<State<T>>,
100
101    #[reflect(hidden)]
102    active_state: Handle<State<T>>,
103
104    #[reflect(hidden)]
105    entry_state: Handle<State<T>>,
106
107    #[reflect(hidden)]
108    active_transition: Handle<Transition<T>>,
109
110    #[visit(skip)]
111    #[reflect(hidden)]
112    final_pose: AnimationPose<T>,
113
114    #[visit(skip)]
115    #[reflect(hidden)]
116    events: FixedEventQueue<T>,
117
118    #[visit(skip)]
119    #[reflect(hidden)]
120    debug: bool,
121}
122
123impl<T: EntityId> NameProvider for MachineLayer<T> {
124    fn name(&self) -> &str {
125        &self.name
126    }
127}
128
129/// A source of animation events coming from a layer.
130#[derive(Default)]
131pub enum AnimationEventsSource<T: EntityId> {
132    /// Layer is malformed and no events were gathered.
133    #[default]
134    Unknown,
135    /// Animation events were gathered from a state.
136    State {
137        /// A handle of a state, from which the events were collected.
138        handle: Handle<State<T>>,
139        /// A name of a state, from which the events were collected.
140        name: String,
141    },
142    /// Animation events were gathered from both states of a transition.
143    Transition {
144        /// A handle of an active transition.
145        handle: Handle<Transition<T>>,
146        /// A handle of a source state of an active transition.
147        source_state_handle: Handle<State<T>>,
148        /// A handle of a destination state of an active transition.
149        dest_state_handle: Handle<State<T>>,
150        /// A name of a source state of an active transition.
151        source_state_name: String,
152        /// A name of a destination state of an active transition.
153        dest_state_name: String,
154    },
155}
156
157/// A collection of events gathered from an active state (or a transition between states). See docs of [`MachineLayer::collect_active_animations_events`]
158/// for more info and usage examples.
159#[derive(Default)]
160pub struct LayerAnimationEventsCollection<T: EntityId> {
161    /// A source of events.
162    pub source: AnimationEventsSource<T>,
163    /// Actual animation events, defined as a tuple `(animation handle, event)`.
164    pub events: Vec<(Handle<Animation<T>>, AnimationEvent)>,
165}
166
167impl<T: EntityId> MachineLayer<T> {
168    /// Creates a new machine layer. See examples in [`MachineLayer`] docs.
169    #[inline]
170    pub fn new() -> Self {
171        Self {
172            name: Default::default(),
173            nodes: Default::default(),
174            states: Default::default(),
175            transitions: Default::default(),
176            final_pose: Default::default(),
177            active_state: Default::default(),
178            entry_state: Default::default(),
179            active_transition: Default::default(),
180            weight: 1.0,
181            events: FixedEventQueue::new(2048),
182            debug: false,
183            mask: Default::default(),
184        }
185    }
186
187    /// Sets new name for the layer. The name can then be used to find a layer in a parent state machine.
188    #[inline]
189    pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
190        name.as_ref().clone_into(&mut self.name);
191    }
192
193    /// Returns a current name of the layer.
194    #[inline]
195    pub fn name(&self) -> &str {
196        &self.name
197    }
198
199    /// Adds a new node to the layer and returns its handle.
200    #[inline]
201    pub fn add_node(&mut self, node: PoseNode<T>) -> Handle<PoseNode<T>> {
202        self.nodes.spawn(node)
203    }
204
205    /// Sets new entry state of the layer. Entry state will always be active on the first frame and will remain active
206    /// until some transition won't change it.
207    #[inline]
208    pub fn set_entry_state(&mut self, entry_state: Handle<State<T>>) {
209        self.active_state = entry_state;
210        self.entry_state = entry_state;
211    }
212
213    /// Returns a handle of current entry state.
214    #[inline]
215    pub fn entry_state(&self) -> Handle<State<T>> {
216        self.entry_state
217    }
218
219    /// Turns on/off the debug mode. Debug mode forces to log all events happening in the layer. For example when a
220    /// state changes, there will be a respective message in the log.
221    #[inline]
222    pub fn debug(&mut self, state: bool) {
223        self.debug = state;
224    }
225
226    /// Adds a new state to the layer and returns its handle.
227    #[inline]
228    pub fn add_state(&mut self, state: State<T>) -> Handle<State<T>> {
229        let state = self.states.spawn(state);
230        if self.active_state.is_none() {
231            self.active_state = state;
232        }
233        state
234    }
235
236    /// Adds a new transition to the layer and returns its handle.
237    #[inline]
238    pub fn add_transition(&mut self, transition: Transition<T>) -> Handle<Transition<T>> {
239        self.transitions.spawn(transition)
240    }
241
242    /// Borrows a state using its handle, panics if the handle is invalid.
243    #[inline]
244    pub fn get_state(&self, state: Handle<State<T>>) -> &State<T> {
245        &self.states[state]
246    }
247
248    /// Borrows a transition using its handle, panics if the handle is invalid.
249    #[inline]
250    pub fn get_transition(&self, transition: Handle<Transition<T>>) -> &Transition<T> {
251        &self.transitions[transition]
252    }
253
254    /// Tries to extract a next event from the inner event queue. You should use this method if you need to react
255    /// to layer events somehow. For example you might want to do some action when `jump` state had become active.
256    ///
257    /// # Example
258    ///
259    /// ```rust
260    /// use fyrox_animation::machine::{Event, MachineLayer};
261    /// use fyrox_core::pool::ErasedHandle;
262    ///
263    /// let mut layer = MachineLayer::<ErasedHandle>::new();
264    ///
265    /// while let Some(event) = layer.pop_event() {
266    ///     match event {
267    ///         Event::StateEnter(state_handle) => {
268    ///             // Occurs when a state is just entered.
269    ///         }
270    ///         Event::StateLeave(state_handle) => {
271    ///             // Occurs when a state is just left.
272    ///         }
273    ///         Event::ActiveStateChanged { prev, new } => {
274    ///             // Occurs when active state has changed.
275    ///         }
276    ///         Event::ActiveTransitionChanged(transition_handle) => {
277    ///             // Occurs when active transition has changed.
278    ///         }
279    ///     }
280    /// }
281    /// ```
282    #[inline]
283    pub fn pop_event(&mut self) -> Option<Event<T>> {
284        self.events.pop()
285    }
286
287    /// Resets layer state; deactivates all active transitions and sets active state to entry state.
288    #[inline]
289    pub fn reset(&mut self) {
290        for transition in self.transitions.iter_mut() {
291            transition.reset();
292        }
293
294        self.active_state = self.entry_state;
295    }
296
297    /// Fetches animation events from an active state (or a transition). It could be used to fetch animation events from a layer
298    /// and receive events only from active state (or transition) without a need to manually fetching the events from a dozens
299    /// of animations. Additionally, it provides a way of weight filtering of events - you can pick one of
300    /// [`AnimationEventCollectionStrategy`]. For example, [`AnimationEventCollectionStrategy::MaxWeight`] could be used to fetch
301    /// events from the animations with the largest weight (when blending them together).
302    ///
303    /// ## Important notes
304    ///
305    /// This method does **not** remove the events from events queue of respective animations, so you need to clear the queue
306    /// manually each frame.
307    pub fn collect_active_animations_events(
308        &self,
309        params: &ParameterContainer,
310        animations: &AnimationContainer<T>,
311        strategy: AnimationEventCollectionStrategy,
312    ) -> LayerAnimationEventsCollection<T> {
313        if let Some(state) = self.states.try_borrow(self.active_state) {
314            return LayerAnimationEventsCollection {
315                source: AnimationEventsSource::State {
316                    handle: self.active_state,
317                    name: state.name.clone(),
318                },
319                events: self
320                    .nodes
321                    .try_borrow(state.root)
322                    .map(|root| {
323                        root.collect_animation_events(&self.nodes, params, animations, strategy)
324                    })
325                    .unwrap_or_default(),
326            };
327        } else if let Some(transition) = self.transitions.try_borrow(self.active_transition) {
328            if let (Some(source_state), Some(dest_state)) = (
329                self.states.try_borrow(transition.source()),
330                self.states.try_borrow(transition.dest()),
331            ) {
332                let mut events = Vec::new();
333                match strategy {
334                    AnimationEventCollectionStrategy::All => {
335                        for state in [source_state, dest_state] {
336                            if let Some(root) = self.nodes.try_borrow(state.root) {
337                                events.extend(root.collect_animation_events(
338                                    &self.nodes,
339                                    params,
340                                    animations,
341                                    strategy,
342                                ));
343                            }
344                        }
345                    }
346                    AnimationEventCollectionStrategy::MaxWeight => {
347                        let input = if transition.blend_factor() < 0.5 {
348                            source_state
349                        } else {
350                            dest_state
351                        };
352
353                        if let Some(pose_source) = self.nodes.try_borrow(input.root) {
354                            events = pose_source.collect_animation_events(
355                                &self.nodes,
356                                params,
357                                animations,
358                                strategy,
359                            );
360                        }
361                    }
362                    AnimationEventCollectionStrategy::MinWeight => {
363                        let input = if transition.blend_factor() < 0.5 {
364                            dest_state
365                        } else {
366                            source_state
367                        };
368
369                        if let Some(pose_source) = self.nodes.try_borrow(input.root) {
370                            events = pose_source.collect_animation_events(
371                                &self.nodes,
372                                params,
373                                animations,
374                                strategy,
375                            );
376                        }
377                    }
378                }
379
380                return LayerAnimationEventsCollection {
381                    source: AnimationEventsSource::Transition {
382                        handle: self.active_transition,
383                        source_state_handle: transition.source,
384                        dest_state_handle: transition.dest,
385                        source_state_name: self
386                            .states
387                            .try_borrow(transition.source)
388                            .map(|s| s.name.clone())
389                            .unwrap_or_default(),
390                        dest_state_name: self
391                            .states
392                            .try_borrow(transition.dest)
393                            .map(|s| s.name.clone())
394                            .unwrap_or_default(),
395                    },
396                    events,
397                };
398            }
399        }
400        Default::default()
401    }
402
403    /// Tries to borrow a node by its handle, panics if the handle is invalid.
404    #[inline]
405    pub fn node(&self, handle: Handle<PoseNode<T>>) -> &PoseNode<T> {
406        &self.nodes[handle]
407    }
408
409    /// Tries to borrow a node by its handle, panics if the handle is invalid.
410    #[inline]
411    pub fn node_mut(&mut self, handle: Handle<PoseNode<T>>) -> &mut PoseNode<T> {
412        &mut self.nodes[handle]
413    }
414
415    /// Returns a reference to inner node container.
416    #[inline]
417    pub fn nodes(&self) -> &Pool<PoseNode<T>> {
418        &self.nodes
419    }
420
421    /// Returns a reference to inner node container.
422    #[inline]
423    pub fn nodes_mut(&mut self) -> &mut Pool<PoseNode<T>> {
424        &mut self.nodes
425    }
426
427    /// Returns a handle of active state. It could be used if you need to perform some action only if some
428    /// state is active. For example jumping could be done only from `idle` and `run` state, and not from
429    /// `crouch` and other states.
430    #[inline]
431    pub fn active_state(&self) -> Handle<State<T>> {
432        self.active_state
433    }
434
435    /// Returns a handle of active transition. It is not empty only while a transition is active (doing blending
436    /// between states).
437    #[inline]
438    pub fn active_transition(&self) -> Handle<Transition<T>> {
439        self.active_transition
440    }
441
442    /// Tries to borrow a transition using its handle, panics if the handle is invalid.
443    #[inline]
444    pub fn transition(&self, handle: Handle<Transition<T>>) -> &Transition<T> {
445        &self.transitions[handle]
446    }
447
448    /// Tries to borrow a transition using its handle, panics if the handle is invalid.
449    #[inline]
450    pub fn transition_mut(&mut self, handle: Handle<Transition<T>>) -> &mut Transition<T> {
451        &mut self.transitions[handle]
452    }
453
454    /// Returns a reference to inner transitions container.
455    #[inline]
456    pub fn transitions(&self) -> &Pool<Transition<T>> {
457        &self.transitions
458    }
459
460    /// Returns a reference to inner transitions container.
461    #[inline]
462    pub fn transitions_mut(&mut self) -> &mut Pool<Transition<T>> {
463        &mut self.transitions
464    }
465
466    /// Tries to find a transition by its name.
467    #[inline]
468    pub fn find_transition_by_name_ref<S: AsRef<str>>(
469        &self,
470        name: S,
471    ) -> Option<(Handle<Transition<T>>, &Transition<T>)> {
472        find_by_name_ref(self.transitions.pair_iter(), name)
473    }
474
475    /// Tries to find a transition by its name.
476    #[inline]
477    pub fn find_transition_by_name_mut<S: AsRef<str>>(
478        &mut self,
479        name: S,
480    ) -> Option<(Handle<Transition<T>>, &mut Transition<T>)> {
481        find_by_name_mut(self.transitions.pair_iter_mut(), name)
482    }
483
484    /// Tries to borrow a state using its handle, panics if the handle is invalid.
485    #[inline]
486    pub fn state(&self, handle: Handle<State<T>>) -> &State<T> {
487        &self.states[handle]
488    }
489
490    /// Tries to borrow a state using its handle, panics if the handle is invalid.
491    #[inline]
492    pub fn state_mut(&mut self, handle: Handle<State<T>>) -> &mut State<T> {
493        &mut self.states[handle]
494    }
495
496    /// Tries to find a state by its name.
497    #[inline]
498    pub fn find_state_by_name_ref<S: AsRef<str>>(
499        &self,
500        name: S,
501    ) -> Option<(Handle<State<T>>, &State<T>)> {
502        find_by_name_ref(self.states.pair_iter(), name)
503    }
504
505    /// Tries to find a state by its name.
506    #[inline]
507    pub fn find_state_by_name_mut<S: AsRef<str>>(
508        &mut self,
509        name: S,
510    ) -> Option<(Handle<State<T>>, &mut State<T>)> {
511        find_by_name_mut(self.states.pair_iter_mut(), name)
512    }
513
514    /// Returns a reference to inner states container.
515    #[inline]
516    pub fn states(&self) -> &Pool<State<T>> {
517        &self.states
518    }
519
520    /// Returns a reference to inner states container.
521    #[inline]
522    pub fn states_mut(&mut self) -> &mut Pool<State<T>> {
523        &mut self.states
524    }
525
526    /// Sets layer weight. The weight will be used by parent state machine to blend into final pose. By default
527    /// the weight is 1.0.
528    #[inline]
529    pub fn set_weight(&mut self, weight: f32) {
530        self.weight = weight;
531    }
532
533    /// Returns the layer weight.
534    #[inline]
535    pub fn weight(&self) -> f32 {
536        self.weight
537    }
538
539    /// Sets new layer mask. See docs of [`LayerMask`] for more info about layer masks.
540    #[inline]
541    pub fn set_mask(&mut self, mask: LayerMask<T>) -> LayerMask<T> {
542        std::mem::replace(&mut self.mask, mask)
543    }
544
545    /// Returns a reference to current layer mask.
546    #[inline]
547    pub fn mask(&self) -> &LayerMask<T> {
548        &self.mask
549    }
550
551    /// Returns final pose of the layer.
552    #[inline]
553    pub fn pose(&self) -> &AnimationPose<T> {
554        &self.final_pose
555    }
556
557    /// Returns an iterator over all animations of a given state. It fetches the animations from [`PoseNode::PlayAnimation`]
558    /// nodes and returns them. This method could be useful to extract all animations used by a particular state. For example,
559    /// to listen for animation events and react to them.
560    pub fn animations_of_state(
561        &self,
562        state: Handle<State<T>>,
563    ) -> impl Iterator<Item = Handle<Animation<T>>> + '_ {
564        self.nodes.iter().filter_map(move |node| {
565            if node.parent_state == state {
566                if let PoseNode::PlayAnimation(play_animation) = node {
567                    Some(play_animation.animation)
568                } else {
569                    None
570                }
571            } else {
572                None
573            }
574        })
575    }
576
577    /// Returns `true` if all animations of the given state has ended, `false` - otherwise.
578    pub fn is_all_animations_of_state_ended(
579        &self,
580        state: Handle<State<T>>,
581        animations: &AnimationContainer<T>,
582    ) -> bool {
583        self.animations_of_state(state)
584            .filter_map(|a| animations.try_get(a))
585            .all(|a| a.has_ended())
586    }
587
588    #[inline]
589    pub(super) fn evaluate_pose(
590        &mut self,
591        animations: &mut AnimationContainer<T>,
592        parameters: &ParameterContainer,
593        dt: f32,
594    ) -> &AnimationPose<T> {
595        self.final_pose.reset();
596
597        if self.active_state.is_some() || self.active_transition.is_some() {
598            // Gather actual poses for each state.
599            for state in self.states.iter_mut() {
600                state.update(&self.nodes, parameters, animations, dt);
601            }
602
603            if self.active_transition.is_none() {
604                // Find transition.
605                for (handle, transition) in self.transitions.pair_iter_mut() {
606                    if transition.dest() == self.active_state
607                        || transition.source() != self.active_state
608                    {
609                        continue;
610                    }
611
612                    if transition.condition.calculate_value(parameters, animations) {
613                        if let Some(active_state) = self.states.try_borrow(self.active_state) {
614                            for action in active_state.on_leave_actions.iter() {
615                                action.apply(animations);
616                            }
617                        }
618
619                        self.events.push(Event::StateLeave(self.active_state));
620                        if self.debug {
621                            Log::writeln(
622                                MessageKind::Information,
623                                format!("Leaving state: {}", self.states[self.active_state].name),
624                            );
625                        }
626
627                        if let Some(source) = self.states.try_borrow(transition.dest()) {
628                            for action in source.on_enter_actions.iter() {
629                                action.apply(animations);
630                            }
631                        }
632
633                        self.events.push(Event::StateEnter(transition.dest()));
634                        if self.debug {
635                            Log::writeln(
636                                MessageKind::Information,
637                                format!("Entering state: {}", self.states[transition.dest()].name),
638                            );
639                        }
640
641                        self.active_state = Handle::NONE;
642
643                        self.active_transition = handle;
644                        self.events
645                            .push(Event::ActiveTransitionChanged(self.active_transition));
646
647                        break;
648                    }
649                }
650            }
651
652            // Double check for active transition because we can have empty machine.
653            if self.active_transition.is_some() {
654                let transition = &mut self.transitions[self.active_transition];
655
656                // Blend between source and dest states.
657                if let Some(source_pose) = self.states[transition.source()].pose(&self.nodes) {
658                    self.final_pose
659                        .blend_with(&source_pose, 1.0 - transition.blend_factor());
660                }
661                if let Some(dest_pose) = self.states[transition.dest()].pose(&self.nodes) {
662                    self.final_pose
663                        .blend_with(&dest_pose, transition.blend_factor());
664                }
665
666                transition.update(dt);
667
668                if transition.is_done() {
669                    transition.reset();
670
671                    self.active_transition = Handle::NONE;
672                    self.events
673                        .push(Event::ActiveTransitionChanged(self.active_transition));
674
675                    self.active_state = transition.dest();
676                    self.events.push(Event::ActiveStateChanged {
677                        prev: transition.source(),
678                        new: transition.dest(),
679                    });
680
681                    if self.debug {
682                        Log::writeln(
683                            MessageKind::Information,
684                            format!(
685                                "Active state changed: {}",
686                                self.states[self.active_state].name
687                            ),
688                        );
689                    }
690                }
691            } else {
692                // We must have active state all the time when we do not have any active transition.
693                // Just get pose from active state.
694                if let Some(active_state_pose) = self.states[self.active_state].pose(&self.nodes) {
695                    active_state_pose.clone_into(&mut self.final_pose);
696                }
697            }
698        }
699
700        self.final_pose
701            .poses_mut()
702            .retain(|h, _| self.mask.should_animate(*h));
703
704        &self.final_pose
705    }
706}