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}