fyrox_animation/pose.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//! Pose is a set of property values of a node ([`NodePose`]) or a set of nodes ([`AnimationPose`]).
22
23use crate::{value::BoundValue, value::BoundValueCollection, EntityId, RootMotion};
24use fxhash::FxHashMap;
25use std::collections::hash_map::Entry;
26
27/// A "captured" state of properties of some animated scene node. The pose can be considered as container of values of some
28/// properties.
29#[derive(Clone, Debug, PartialEq, Default)]
30pub struct NodePose<T: EntityId> {
31 /// A handle of an animated node.
32 pub node: T,
33
34 /// A set of property values.
35 pub values: BoundValueCollection,
36}
37
38impl<T: EntityId> NodePose<T> {
39 /// Performs a blending of the current with some other pose. See [`super::value::TrackValue::blend_with`] docs for more
40 /// info.
41 pub fn blend_with(&mut self, other: &NodePose<T>, weight: f32) {
42 self.values.blend_with(&other.values, weight)
43 }
44}
45
46/// Animations pose is a set of node poses. See [`NodePose`] docs for more info.
47#[derive(Default, Debug, Clone, PartialEq)]
48pub struct AnimationPose<T: EntityId> {
49 poses: FxHashMap<T, NodePose<T>>,
50 root_motion: Option<RootMotion>,
51}
52
53impl<T: EntityId> AnimationPose<T> {
54 /// Clears the set of node poses in the given animation pose and clones poses from the current animation pose to the given.
55 pub fn clone_into(&self, dest: &mut AnimationPose<T>) {
56 dest.reset();
57 for (handle, local_pose) in self.poses.iter() {
58 dest.poses.insert(*handle, local_pose.clone());
59 }
60 dest.root_motion.clone_from(&self.root_motion);
61 }
62
63 /// Sets root motion for the animation pose; the root motion will be blended with other motions
64 /// and the result can be obtained on a final pose.
65 pub fn set_root_motion(&mut self, root_motion: Option<RootMotion>) {
66 self.root_motion = root_motion;
67 }
68
69 /// Returns current root motion (if any).
70 pub fn root_motion(&self) -> Option<&RootMotion> {
71 self.root_motion.as_ref()
72 }
73
74 /// Blends current animation pose with another using a weight coefficient. Missing node poses (from either animation poses)
75 /// will become a simple copies of a respective node pose.
76 pub fn blend_with(&mut self, other: &AnimationPose<T>, weight: f32) {
77 for (handle, other_pose) in other.poses.iter() {
78 if let Some(current_pose) = self.poses.get_mut(handle) {
79 current_pose.blend_with(other_pose, weight);
80 } else {
81 self.add_node_pose(other_pose.clone());
82 }
83 }
84
85 self.root_motion
86 .get_or_insert_with(Default::default)
87 .blend_with(&other.root_motion.clone().unwrap_or_default(), weight);
88 }
89
90 fn add_node_pose(&mut self, local_pose: NodePose<T>) {
91 self.poses.insert(local_pose.node, local_pose);
92 }
93
94 pub(super) fn add_to_node_pose(&mut self, node: T, bound_value: BoundValue) {
95 match self.poses.entry(node) {
96 Entry::Occupied(entry) => {
97 entry.into_mut().values.values.push(bound_value);
98 }
99 Entry::Vacant(entry) => {
100 entry.insert(NodePose {
101 node,
102 values: BoundValueCollection {
103 values: vec![bound_value],
104 },
105 });
106 }
107 }
108 }
109
110 /// Clears the pose.
111 pub fn reset(&mut self) {
112 self.poses.clear();
113 }
114
115 /// Returns a reference to inner node pose map.
116 pub fn poses(&self) -> &FxHashMap<T, NodePose<T>> {
117 &self.poses
118 }
119
120 /// Returns a reference to inner node pose map.
121 pub fn poses_mut(&mut self) -> &mut FxHashMap<T, NodePose<T>> {
122 &mut self.poses
123 }
124}