fyrox_animation/machine/node/
blend.rs1use crate::{
24 core::{
25 pool::{Handle, Pool},
26 reflect::prelude::*,
27 visitor::{Visit, VisitResult, Visitor},
28 },
29 machine::{
30 node::AnimationEventCollectionStrategy, node::BasePoseNode, AnimationPoseSource, Parameter,
31 ParameterContainer, PoseNode, PoseWeight,
32 },
33 Animation, AnimationContainer, AnimationEvent, AnimationPose, EntityId,
34};
35use fyrox_core::uuid::{uuid, Uuid};
36use fyrox_core::TypeUuidProvider;
37use std::cmp::Ordering;
38use std::{
39 cell::{Cell, Ref, RefCell},
40 ops::{Deref, DerefMut},
41};
42
43#[derive(Default, Debug, Visit, Clone, Reflect, PartialEq)]
46pub struct BlendPose<T: EntityId> {
47 pub weight: PoseWeight,
49
50 #[reflect(hidden)]
52 pub pose_source: Handle<PoseNode<T>>,
53}
54
55impl<T: EntityId> TypeUuidProvider for BlendPose<T> {
56 fn type_uuid() -> Uuid {
57 uuid!("b01d7639-7b39-4eaf-87e6-29fd5221951b")
58 }
59}
60
61impl<T: EntityId> BlendPose<T> {
62 pub fn new(weight: PoseWeight, pose_source: Handle<PoseNode<T>>) -> Self {
64 Self {
65 weight,
66 pose_source,
67 }
68 }
69
70 pub fn with_constant_weight(weight: f32, pose_source: Handle<PoseNode<T>>) -> Self {
73 Self {
74 weight: PoseWeight::Constant(weight),
75 pose_source,
76 }
77 }
78
79 pub fn with_param_weight(param_id: &str, pose_source: Handle<PoseNode<T>>) -> Self {
82 Self {
83 weight: PoseWeight::Parameter(param_id.to_owned()),
84 pose_source,
85 }
86 }
87}
88
89#[derive(Default, Debug, Visit, Clone, Reflect, PartialEq)]
97pub struct BlendAnimations<T: EntityId> {
98 pub base: BasePoseNode<T>,
100
101 pub pose_sources: Vec<BlendPose<T>>,
103
104 #[visit(skip)]
106 #[reflect(hidden)]
107 pub output_pose: RefCell<AnimationPose<T>>,
108}
109
110impl<T: EntityId> Deref for BlendAnimations<T> {
111 type Target = BasePoseNode<T>;
112
113 fn deref(&self) -> &Self::Target {
114 &self.base
115 }
116}
117
118impl<T: EntityId> DerefMut for BlendAnimations<T> {
119 fn deref_mut(&mut self) -> &mut Self::Target {
120 &mut self.base
121 }
122}
123
124impl<T: EntityId> BlendAnimations<T> {
125 pub fn new(poses: Vec<BlendPose<T>>) -> Self {
127 Self {
128 base: Default::default(),
129 pose_sources: poses,
130 output_pose: Default::default(),
131 }
132 }
133
134 pub fn children(&self) -> Vec<Handle<PoseNode<T>>> {
136 self.pose_sources.iter().map(|s| s.pose_source).collect()
137 }
138}
139
140impl<T: EntityId> AnimationPoseSource<T> for BlendAnimations<T> {
141 fn eval_pose(
142 &self,
143 nodes: &Pool<PoseNode<T>>,
144 params: &ParameterContainer,
145 animations: &AnimationContainer<T>,
146 dt: f32,
147 ) -> Ref<AnimationPose<T>> {
148 self.output_pose.borrow_mut().reset();
149 for blend_pose in self.pose_sources.iter() {
150 let weight = match blend_pose.weight {
151 PoseWeight::Constant(value) => value,
152 PoseWeight::Parameter(ref param_id) => {
153 if let Some(Parameter::Weight(weight)) = params.get(param_id) {
154 *weight
155 } else {
156 0.0
157 }
158 }
159 };
160
161 if let Ok(pose_source) = nodes
162 .try_borrow(blend_pose.pose_source)
163 .map(|pose_source| pose_source.eval_pose(nodes, params, animations, dt))
164 {
165 self.output_pose
166 .borrow_mut()
167 .blend_with(&pose_source, weight);
168 }
169 }
170 self.output_pose.borrow()
171 }
172
173 fn pose(&self) -> Ref<AnimationPose<T>> {
174 self.output_pose.borrow()
175 }
176
177 fn collect_animation_events(
178 &self,
179 nodes: &Pool<PoseNode<T>>,
180 params: &ParameterContainer,
181 animations: &AnimationContainer<T>,
182 strategy: AnimationEventCollectionStrategy,
183 ) -> Vec<(Handle<Animation<T>>, AnimationEvent)> {
184 match strategy {
185 AnimationEventCollectionStrategy::All => {
186 let mut events = Vec::new();
187 for pose in self.pose_sources.iter() {
188 if let Ok(source) = nodes.try_borrow(pose.pose_source) {
189 events.extend(
190 source.collect_animation_events(nodes, params, animations, strategy),
191 );
192 }
193 }
194 events
195 }
196 AnimationEventCollectionStrategy::MaxWeight => {
197 if let Some((pose, _)) = self
198 .pose_sources
199 .iter()
200 .filter_map(|s| s.weight.value(params).map(|w| (s, w)))
201 .max_by(|(_, w1), (_, w2)| w1.partial_cmp(w2).unwrap_or(Ordering::Equal))
202 {
203 if let Ok(pose_source) = nodes.try_borrow(pose.pose_source) {
204 return pose_source
205 .collect_animation_events(nodes, params, animations, strategy);
206 }
207 }
208
209 Default::default()
210 }
211 AnimationEventCollectionStrategy::MinWeight => {
212 if let Some((pose, _)) = self
213 .pose_sources
214 .iter()
215 .filter_map(|s| s.weight.value(params).map(|w| (s, w)))
216 .min_by(|(_, w1), (_, w2)| w1.partial_cmp(w2).unwrap_or(Ordering::Equal))
217 {
218 if let Ok(pose_source) = nodes.try_borrow(pose.pose_source) {
219 return pose_source
220 .collect_animation_events(nodes, params, animations, strategy);
221 }
222 }
223
224 Default::default()
225 }
226 }
227 }
228}
229
230#[derive(Default, Debug, Visit, Clone, Reflect, PartialEq)]
233pub struct IndexedBlendInput<T: EntityId> {
234 pub blend_time: f32,
236
237 #[reflect(hidden)]
239 pub pose_source: Handle<PoseNode<T>>,
240}
241
242impl<T: EntityId> TypeUuidProvider for IndexedBlendInput<T> {
243 fn type_uuid() -> Uuid {
244 uuid!("92fcc992-9a68-4152-8449-657546faa286")
245 }
246}
247
248#[derive(Default, Debug, Visit, Clone, Reflect, PartialEq)]
257pub struct BlendAnimationsByIndex<T: EntityId> {
258 pub base: BasePoseNode<T>,
260
261 pub index_parameter: String,
263
264 pub inputs: Vec<IndexedBlendInput<T>>,
266
267 #[reflect(hidden)]
269 pub prev_index: Cell<Option<u32>>,
270
271 #[reflect(hidden)]
273 pub blend_time: Cell<f32>,
274
275 #[visit(skip)]
277 #[reflect(hidden)]
278 pub output_pose: RefCell<AnimationPose<T>>,
279}
280
281impl<T: EntityId> Deref for BlendAnimationsByIndex<T> {
282 type Target = BasePoseNode<T>;
283
284 fn deref(&self) -> &Self::Target {
285 &self.base
286 }
287}
288
289impl<T: EntityId> DerefMut for BlendAnimationsByIndex<T> {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 &mut self.base
292 }
293}
294
295impl<T: EntityId> BlendAnimationsByIndex<T> {
296 pub fn new(index_parameter: String, inputs: Vec<IndexedBlendInput<T>>) -> Self {
298 Self {
299 base: Default::default(),
300 index_parameter,
301 inputs,
302 output_pose: RefCell::new(Default::default()),
303 prev_index: Cell::new(None),
304 blend_time: Cell::new(0.0),
305 }
306 }
307
308 pub fn children(&self) -> Vec<Handle<PoseNode<T>>> {
310 self.inputs.iter().map(|s| s.pose_source).collect()
311 }
312}
313
314impl<T: EntityId> AnimationPoseSource<T> for BlendAnimationsByIndex<T> {
315 fn eval_pose(
316 &self,
317 nodes: &Pool<PoseNode<T>>,
318 params: &ParameterContainer,
319 animations: &AnimationContainer<T>,
320 dt: f32,
321 ) -> Ref<AnimationPose<T>> {
322 self.output_pose.borrow_mut().reset();
323
324 if let Some(&Parameter::Index(current_index)) = params.get(&self.index_parameter) {
325 let mut applied = false;
326
327 if let Some(prev_index) = self.prev_index.get() {
328 if prev_index != current_index {
329 if let (Some(prev_input), Some(current_input)) = (
330 self.inputs.get(prev_index as usize),
331 self.inputs.get(current_index as usize),
332 ) {
333 self.blend_time
334 .set((self.blend_time.get() + dt).min(current_input.blend_time));
335
336 let interpolator = self.blend_time.get() / current_input.blend_time;
337
338 self.output_pose.borrow_mut().blend_with(
339 &nodes[prev_input.pose_source].eval_pose(nodes, params, animations, dt),
340 1.0 - interpolator,
341 );
342 self.output_pose.borrow_mut().blend_with(
343 &nodes[current_input.pose_source]
344 .eval_pose(nodes, params, animations, dt),
345 interpolator,
346 );
347
348 if interpolator >= 1.0 {
349 self.prev_index.set(Some(current_index));
350 self.blend_time.set(0.0);
351 }
352
353 applied = true;
354 }
355 }
356 } else {
357 self.prev_index.set(Some(current_index));
358 }
359
360 if !applied {
361 self.blend_time.set(0.0);
363
364 if let Some(current_input) = self.inputs.get(current_index as usize) {
365 nodes[current_input.pose_source]
366 .eval_pose(nodes, params, animations, dt)
367 .clone_into(&mut self.output_pose.borrow_mut());
368 }
369 }
370 }
371
372 self.output_pose.borrow()
373 }
374
375 fn pose(&self) -> Ref<AnimationPose<T>> {
376 self.output_pose.borrow()
377 }
378
379 fn collect_animation_events(
380 &self,
381 nodes: &Pool<PoseNode<T>>,
382 params: &ParameterContainer,
383 animations: &AnimationContainer<T>,
384 strategy: AnimationEventCollectionStrategy,
385 ) -> Vec<(Handle<Animation<T>>, AnimationEvent)> {
386 if let Some(&Parameter::Index(current_index)) = params.get(&self.index_parameter) {
387 if let Some(prev_index) = self.prev_index.get() {
388 if prev_index != current_index {
389 if let (Some(prev_input), Some(current_input)) = (
390 self.inputs.get(prev_index as usize),
391 self.inputs.get(current_index as usize),
392 ) {
393 let interpolator = self.blend_time.get() / current_input.blend_time;
394
395 match strategy {
396 AnimationEventCollectionStrategy::All => {
397 let mut events = Vec::new();
398 for input in [prev_input, current_input] {
399 if let Ok(source) = nodes.try_borrow(input.pose_source) {
400 events.extend(source.collect_animation_events(
401 nodes, params, animations, strategy,
402 ));
403 }
404 }
405 return events;
406 }
407 AnimationEventCollectionStrategy::MaxWeight => {
408 let input = if interpolator < 0.5 {
409 prev_input
410 } else {
411 current_input
412 };
413
414 if let Ok(pose_source) = nodes.try_borrow(input.pose_source) {
415 return pose_source.collect_animation_events(
416 nodes, params, animations, strategy,
417 );
418 }
419 }
420 AnimationEventCollectionStrategy::MinWeight => {
421 let input = if interpolator < 0.5 {
422 current_input
423 } else {
424 prev_input
425 };
426
427 if let Ok(pose_source) = nodes.try_borrow(input.pose_source) {
428 return pose_source.collect_animation_events(
429 nodes, params, animations, strategy,
430 );
431 }
432 }
433 }
434 }
435 } else {
436 if let Some(current_input) = self.inputs.get(current_index as usize) {
439 if let Ok(pose_source) = nodes.try_borrow(current_input.pose_source) {
440 return pose_source
441 .collect_animation_events(nodes, params, animations, strategy);
442 }
443 }
444 }
445 }
446 }
447
448 Default::default()
449 }
450}