fyrox_animation/lib.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 allows you to change properties of arbitrary objects at runtime using a set of key frames.
22//! See [`Animation`] docs for more info.
23
24#![warn(missing_docs)]
25#![allow(clippy::doc_lazy_continuation)]
26#![allow(mismatched_lifetime_syntaxes)]
27
28use crate::track::TrackBinding;
29use crate::{
30 core::{
31 algebra::{UnitQuaternion, Vector3},
32 math::wrapf,
33 pool::{ErasedHandle, Handle, Pool, Ticket},
34 reflect::prelude::*,
35 type_traits::prelude::*,
36 uuid::{uuid, Uuid},
37 visitor::{Visit, VisitResult, Visitor},
38 ImmutableString, NameProvider,
39 },
40 track::Track,
41};
42use fxhash::FxHashMap;
43pub use fyrox_core as core;
44use fyrox_core::pool::PoolError;
45use fyrox_resource::untyped::ResourceKind;
46use fyrox_resource::{Resource, ResourceData};
47pub use pose::{AnimationPose, NodePose};
48pub use signal::{AnimationEvent, AnimationSignal};
49use std::{
50 collections::VecDeque,
51 error::Error,
52 fmt::Debug,
53 hash::Hash,
54 ops::{Index, IndexMut, Range},
55 path::Path,
56};
57use value::{nlerp, TrackValue, ValueBinding};
58
59pub mod container;
60pub mod machine;
61pub mod pose;
62pub mod signal;
63pub mod spritesheet;
64pub mod track;
65pub mod value;
66
67/// A container for animation tracks. Multiple animations can share the same container to reduce
68/// memory consumption. It could be extremely useful in case of many instances of a little amount
69/// of kinds of animated models.
70#[derive(Default, Debug, Reflect, Clone, PartialEq, TypeUuidProvider)]
71#[type_uuid(id = "044d9f7c-5c6c-4b29-8de9-d0d975a48256")]
72pub struct AnimationTracksData {
73 /// Tracks of the animation. See [`Track`] docs for more info.
74 pub tracks: Vec<Track>,
75}
76
77impl AnimationTracksData {
78 /// Adds new track to the animation. Animation can have unlimited number of tracks, each track is responsible
79 /// for animation of a single scene node.
80 pub fn add_track(&mut self, track: Track) {
81 self.tracks.push(track);
82 }
83
84 /// Removes a track at given index.
85 pub fn remove_track(&mut self, index: usize) -> Track {
86 self.tracks.remove(index)
87 }
88
89 /// Inserts a track at given index.
90 pub fn insert_track(&mut self, index: usize, track: Track) {
91 self.tracks.insert(index, track)
92 }
93
94 /// Removes last track from the list of tracks of the animation.
95 pub fn pop_track(&mut self) -> Option<Track> {
96 self.tracks.pop()
97 }
98
99 /// Returns a reference to tracks container.
100 pub fn tracks(&self) -> &[Track] {
101 &self.tracks
102 }
103
104 /// Returns a mutable reference to the track container.
105 pub fn tracks_mut(&mut self) -> &mut [Track] {
106 &mut self.tracks
107 }
108
109 /// Removes all tracks from the animation for which the given `filter` closure returns `false`. Could be useful
110 /// to remove undesired animation tracks.
111 pub fn retain_tracks<F>(&mut self, filter: F)
112 where
113 F: FnMut(&Track) -> bool,
114 {
115 self.tracks.retain(filter)
116 }
117}
118
119impl Visit for AnimationTracksData {
120 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
121 self.tracks.visit(name, visitor)
122 }
123}
124
125impl ResourceData for AnimationTracksData {
126 fn type_uuid(&self) -> Uuid {
127 <AnimationTracksData as TypeUuidProvider>::type_uuid()
128 }
129
130 fn save(&mut self, _path: &Path) -> Result<(), Box<dyn Error>> {
131 // TODO
132 Ok(())
133 }
134
135 fn can_be_saved(&self) -> bool {
136 true
137 }
138
139 fn try_clone_box(&self) -> Option<Box<dyn ResourceData>> {
140 Some(Box::new(self.clone()))
141 }
142}
143
144/// A resource that holds animation tracks. This resource can be shared across multiple animations.
145pub type AnimationTracksDataResource = Resource<AnimationTracksData>;
146
147/// # Overview
148///
149/// Animation allows you to change properties of arbitrary entities at runtime using a set of key frames. Animation
150/// consists of multiple tracks, where each track is bound to a property of an entity. A track can animate
151/// any numeric properties, starting from numbers (including `bool`) end ending by 2/3/4 dimensional vectors.
152/// Each component (number, x/y/z/w vector components) is stored in a _parametric curve_ (see
153/// [`crate::core::math::curve::Curve`] docs for more info). Every parametric curve contains zero or more _key frames_.
154/// Graphically this could be represented like so:
155///
156/// ```text
157/// Timeline
158/// v
159/// Time > |---------------|------------------------------------>
160/// | |
161/// Track1 > | node.position |
162/// | X curve |..1..........5...........10..........
163/// | Y curve |..2.........-2..................1.... < Curve key frames
164/// | Z curve |..1..........9......................4
165/// |_______________|
166/// Track2 | node.property |
167/// | ............ |.....................................
168/// | ............ |.....................................
169/// | ............ |.....................................
170/// ```
171///
172/// Each key frame is just a real number with interpolation mode. Interpolation mode tells the engine how to
173/// calculate intermediate values between key frames. There are three kinds of interpolation used in animations
174/// (you can skip "boring math" if you want):
175///
176/// - **Constant** - intermediate value will be calculated using leftmost value of two. Constant "interpolation" is
177/// usually used to create step-like behaviour, the most common case is to "interpolate" two boolean values.
178/// - **Linear** - intermediate value will be calculated using linear interpolation `i = left + (right - left) / t`,
179/// where `t = (time_position - left) / (right - left)`. `t` is always in `0..1` range. Linear interpolation is usually
180/// used to create "straight" transitions between two values.
181/// - **Cubic** - intermediate value will be calculated using Hermite cubic spline:
182/// `i = (2t^3 - 3t^2 + 1) * left + (t^3 - 2t^2 + t) * left_tangent + (-2t^3 + 3t^2) * right + (t^3 - t^2) * right_tangent`,
183/// where `t = (time_position - left) / (right - left)` (`t` is always in `0..1` range), `left_tangent` and `right_tangent`
184/// is usually a `tan(angle)`. Cubic interpolation is usually used to create "smooth" transitions between two values.
185///
186/// # Track binding
187///
188/// Each track is always bound to a property in a node, either by its name or by a special binding. The name is used to fetch the
189/// property using reflection, the special binding is a faster way of fetching built-in properties. It is usually used to animate
190/// position, scale and rotation (these are the most common properties available in every scene node).
191///
192/// # Time slice and looping
193///
194/// While key frames on the curves can be located at arbitrary position in time, animations usually plays a specific time slice.
195/// By default, each animation will play on a given time slice infinitely - it is called _animation looping_, it works in both
196/// playback directions.
197///
198/// # Speed
199///
200/// You can vary playback speed in wide range, by default every animation has playback speed multiplier set to 1.0. The multiplier
201/// tells how faster (>1) or slower (<1) the animation needs to be played. Negative speed multiplier values will reverse playback.
202///
203/// # Enabling or disabling animations
204///
205/// Sometimes there's a need to disable/enable an animation or check if it is enabled or not, you can do this by using the pair
206/// of respective methods - [`Animation::set_enabled`] and [`Animation::is_enabled`].
207///
208/// # Signals
209///
210/// Signal is a named marker on specific time position on the animation timeline. Signal will emit an event if the animation playback
211/// time passes signal's position from left-to-right (or vice versa depending on playback direction). Signals are usually used to
212/// attach some specific actions to a position in time. For example, you can have a walking animation and you want to emit sounds
213/// when character's feet touch ground. In this case you need to add a few signals at times when each foot touches the ground.
214/// After that all you need to do is to fetch animation events one-by-one and emit respective sounds. See [`AnimationSignal`] docs
215/// for more info and examples.
216///
217/// # Examples
218///
219/// Usually, animations are created from the editor or some external tool and then imported in the engine.
220/// However, sometimes there's a need for procedural animations. Use the following example code as
221/// a guide **only** if you need to create procedural animations:
222///
223/// ```rust
224/// # use fyrox_animation::{
225/// # container::{TrackDataContainer, TrackValueKind},
226/// # track::Track,
227/// # value::ValueBinding,
228/// # Animation,
229/// # core::{
230/// # math::curve::{Curve, CurveKey, CurveKeyKind},
231/// # pool::Handle,
232/// # },
233/// # };
234/// # use fyrox_animation::track::TrackBinding;
235/// # use fyrox_core::pool::ErasedHandle;
236/// fn create_animation(target: ErasedHandle) -> Animation<ErasedHandle> {
237/// let mut frames_container = TrackDataContainer::new(TrackValueKind::Vector3);
238///
239/// // We'll animate only X coordinate (at index 0).
240/// frames_container.curves_mut()[0] = Curve::from(vec![
241/// CurveKey::new(0.5, 2.0, CurveKeyKind::Linear),
242/// CurveKey::new(0.75, 1.0, CurveKeyKind::Linear),
243/// CurveKey::new(1.0, 3.0, CurveKeyKind::Linear),
244/// ]);
245///
246/// // Create a track that will animate the node using the curve above.
247/// let mut track = Track::new(frames_container, ValueBinding::Position);
248///
249/// // Finally create an animation and set its time slice and turn it on.
250/// let mut animation = Animation::default();
251/// animation.add_track_with_binding(TrackBinding::new(target), track);
252/// animation.set_time_slice(0.0..1.0);
253/// animation.set_enabled(true);
254///
255/// animation
256/// }
257///
258/// // Create the animation.
259/// let mut animation = create_animation(Default::default());
260///
261/// // Emulate some ticks (like it was updated from the main loop of your game).
262/// for _ in 0..10 {
263/// animation.tick(1.0 / 60.0);
264/// }
265/// ```
266///
267/// The code above creates a simple animation that moves a node along X axis in various ways. The usage of the animation
268/// is only for the sake of completeness of the example. In the real games you need to add the animation to an animation
269/// player scene node and it will do the job for you.
270#[derive(Debug, Reflect, Visit, PartialEq)]
271pub struct Animation<T: EntityId> {
272 name: ImmutableString,
273 tracks_data: AnimationTracksDataResource,
274 track_bindings: FxHashMap<Uuid, TrackBinding<T>>,
275 time_position: f32,
276 time_slice: Range<f32>,
277 speed: f32,
278 looped: bool,
279 enabled: bool,
280 signals: Vec<AnimationSignal>,
281 root_motion_settings: Option<RootMotionSettings<T>>,
282 max_event_capacity: usize,
283
284 #[reflect(hidden)]
285 #[visit(skip)]
286 root_motion: Option<RootMotion>,
287 #[reflect(hidden)]
288 #[visit(skip)]
289 pose: AnimationPose<T>,
290 #[reflect(hidden)]
291 #[visit(skip)]
292 events: VecDeque<AnimationEvent>,
293}
294
295impl<T: EntityId> TypeUuidProvider for Animation<T> {
296 fn type_uuid() -> Uuid {
297 uuid!("aade8e9d-e2cf-401d-a4d1-59c6943645f3")
298 }
299}
300
301/// Identifier of an entity, that can be animated.
302pub trait EntityId:
303 Default + Send + Copy + Reflect + Visit + PartialEq + Eq + Hash + Debug + Ord + PartialEq + 'static
304{
305}
306
307impl<T: Reflect> EntityId for Handle<T> {}
308impl EntityId for ErasedHandle {}
309
310/// Root motion settings. It allows you to set a node (root) from which the motion will be taken
311/// as well as filter out some unnecessary parts of the motion (i.e. do not extract motion on
312/// Y axis).
313#[derive(Default, Debug, Clone, PartialEq, Reflect, Visit)]
314pub struct RootMotionSettings<T: EntityId> {
315 /// A handle to a node which movement will be extracted and put in root motion field of an animation
316 /// to which these settings were set to.
317 pub node: T,
318 /// Keeps X part of the translational part of the motion.
319 pub ignore_x_movement: bool,
320 /// Keeps Y part of the translational part of the motion.
321 pub ignore_y_movement: bool,
322 /// Keeps Z part of the translational part of the motion.
323 pub ignore_z_movement: bool,
324 /// Keeps rotational part of the motion.
325 pub ignore_rotations: bool,
326}
327
328/// Motion of a root node of an hierarchy of nodes. It contains relative rotation and translation in local
329/// space of the node. To transform this data into velocity and orientation you need to multiply these
330/// parts with some global transform, usually with the global transform of the mesh that is being animated.
331#[derive(Default, Debug, Clone, PartialEq)]
332pub struct RootMotion {
333 /// Relative offset between current and a previous frame of an animation.
334 pub delta_position: Vector3<f32>,
335 /// Relative rotation between current and a previous frame of an animation.
336 pub delta_rotation: UnitQuaternion<f32>,
337
338 prev_position: Vector3<f32>,
339 position_offset_remainder: Option<Vector3<f32>>,
340
341 prev_rotation: UnitQuaternion<f32>,
342 rotation_remainder: Option<UnitQuaternion<f32>>,
343}
344
345impl RootMotion {
346 /// Blend this motion with some other using `weight` as a proportion.
347 pub fn blend_with(&mut self, other: &RootMotion, weight: f32) {
348 self.delta_position = self.delta_position.lerp(&other.delta_position, weight);
349 self.delta_rotation = nlerp(self.delta_rotation, &other.delta_rotation, weight);
350 }
351}
352
353impl<T: EntityId> NameProvider for Animation<T> {
354 fn name(&self) -> &str {
355 &self.name
356 }
357}
358
359impl<T: EntityId> Clone for Animation<T> {
360 fn clone(&self) -> Self {
361 Self {
362 name: self.name.clone(),
363 tracks_data: self.tracks_data.clone(),
364 speed: self.speed,
365 time_position: self.time_position,
366 looped: self.looped,
367 enabled: self.enabled,
368 pose: Default::default(),
369 signals: self.signals.clone(),
370 root_motion_settings: self.root_motion_settings.clone(),
371 events: Default::default(),
372 time_slice: self.time_slice.clone(),
373 root_motion: self.root_motion.clone(),
374 max_event_capacity: 32,
375 track_bindings: self.track_bindings.clone(),
376 }
377 }
378}
379
380impl<T: EntityId> Animation<T> {
381 /// Gets the maximum capacity of events.
382 pub fn get_max_event_capacity(&self) -> usize {
383 self.max_event_capacity
384 }
385
386 /// Sets the maximum capacity of events.
387 pub fn set_max_event_capacity(&mut self, max_event_capacity: usize) {
388 self.max_event_capacity = max_event_capacity;
389 }
390
391 /// Sets a new name for the animation. The name then could be used to find the animation in a container.
392 pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
393 self.name = ImmutableString::new(name);
394 }
395
396 /// Returns current name of the animation.
397 pub fn name(&self) -> &str {
398 self.name.as_ref()
399 }
400
401 /// Sets a new source of data for animation tracks. Keep in mind, that all existing track bindings
402 /// stored in the animation could become invalid, if the new resource does not have tracks with
403 /// the same ids that the bindings has.
404 pub fn set_tracks_data(&mut self, resource: AnimationTracksDataResource) {
405 self.tracks_data = resource;
406 }
407
408 /// Returns a reference to the current animation tracks resource.
409 pub fn tracks_data(&self) -> &AnimationTracksDataResource {
410 &self.tracks_data
411 }
412
413 /// Calculates new length of the animation based on the content of its tracks. It looks for the most "right"
414 /// curve key in all curves of all tracks and treats it as length of the animation. The method could be used
415 /// in case if you formed animation from code using just curves and don't know the actual length of the
416 /// animation.
417 pub fn fit_length_to_content(&mut self) {
418 let state = self.tracks_data.state();
419 let Some(tracks_data) = state.data_ref() else {
420 return;
421 };
422 self.time_slice.start = 0.0;
423 for track in tracks_data.tracks.iter() {
424 if track.time_length() > self.time_slice.end {
425 self.time_slice.end = track.time_length();
426 }
427 }
428 }
429
430 /// Sets new time position of the animation. The actual time position the animation will have after the call,
431 /// can be different in two reasons:
432 ///
433 /// - If the animation is looping and the new time position is outside of the time slice of the animation, then
434 /// the actual time position will be wrapped to fit the time slice. For example, if you have an animation that has
435 /// `0.0..5.0s` time slice and you trying to set `7.5s` position, the actual time position will be `2.5s` (it
436 /// wraps the input value on the given time slice).
437 /// - If the animation is **not** looping and the new time position is outside of the time slice of the animation,
438 /// then the actual time position will be clamped to the time clice of the animation.
439 pub fn set_time_position(&mut self, time: f32) -> &mut Self {
440 if self.looped {
441 self.time_position = wrapf(time, self.time_slice.start, self.time_slice.end);
442 } else {
443 self.time_position = time.clamp(self.time_slice.start, self.time_slice.end);
444 }
445
446 self
447 }
448
449 /// Sets new time slice of the animation in seconds. It defines a time interval in which the animation will
450 /// be played. Current playback position will be clamped (or wrapped if the animation is looping) to fit to new
451 /// bounds.
452 pub fn set_time_slice(&mut self, time_slice: Range<f32>) {
453 assert!(time_slice.start <= time_slice.end);
454
455 self.time_slice = time_slice;
456
457 // Ensure time position is in given time slice.
458 self.set_time_position(self.time_position);
459 }
460
461 /// Returns current time slice of the animation.
462 pub fn time_slice(&self) -> Range<f32> {
463 self.time_slice.clone()
464 }
465
466 /// Rewinds the animation to the beginning.
467 pub fn rewind(&mut self) -> &mut Self {
468 self.set_time_position(self.time_slice.start)
469 }
470
471 /// Returns length of the animation in seconds.
472 pub fn length(&self) -> f32 {
473 self.time_slice.end - self.time_slice.start
474 }
475
476 /// Performs a single update tick and calculates an output pose. This method is low level, you should not use it
477 /// in normal circumstances - the engine will call it for you.
478 pub fn tick(&mut self, dt: f32) {
479 self.update_pose();
480
481 let current_time_position = self.time_position();
482 let new_time_position = current_time_position + dt * self.speed();
483
484 for signal in self.signals.iter_mut().filter(|s| s.enabled) {
485 if self.speed >= 0.0
486 && (current_time_position < signal.time && new_time_position >= signal.time)
487 || self.speed < 0.0
488 && (current_time_position > signal.time && new_time_position <= signal.time)
489 && self.events.len() < self.max_event_capacity
490 {
491 self.events.push_back(AnimationEvent {
492 signal_id: signal.id,
493 name: signal.name.clone(),
494 });
495 }
496 }
497
498 let prev_time_position = current_time_position;
499
500 self.set_time_position(new_time_position);
501
502 self.update_root_motion(prev_time_position);
503 }
504
505 fn update_root_motion(&mut self, prev_time_position: f32) {
506 let state = self.tracks_data.state();
507 let Some(tracks_data) = state.data_ref() else {
508 return;
509 };
510 let tracks = &tracks_data.tracks;
511
512 fn fetch_position_at_time(tracks: &[Track], time: f32) -> Vector3<f32> {
513 tracks
514 .iter()
515 .find(|track| track.value_binding() == &ValueBinding::Position)
516 .and_then(|track| track.fetch(time))
517 .and_then(|value| {
518 if let TrackValue::Vector3(position) = value.value {
519 Some(position)
520 } else {
521 None
522 }
523 })
524 .unwrap_or_default()
525 }
526
527 fn fetch_rotation_at_time(tracks: &[Track], time: f32) -> UnitQuaternion<f32> {
528 tracks
529 .iter()
530 .find(|track| track.value_binding() == &ValueBinding::Rotation)
531 .and_then(|track| track.fetch(time))
532 .and_then(|value| {
533 if let TrackValue::UnitQuaternion(rotation) = value.value {
534 Some(rotation)
535 } else {
536 None
537 }
538 })
539 .unwrap_or_default()
540 }
541
542 // If we have root motion enabled, try to extract the actual motion values. We'll take only relative motion
543 // here, relative to the previous values.
544 if let Some(root_motion_settings) = self.root_motion_settings.as_ref() {
545 let mut prev_root_motion = self.root_motion.clone().unwrap_or_default();
546
547 // Check if we've started another loop cycle.
548 let new_loop_cycle_started = self.looped
549 && (self.speed > 0.0 && self.time_position < prev_time_position
550 || self.speed < 0.0 && self.time_position > prev_time_position);
551
552 let cycle_start_time = if self.speed > 0.0 {
553 self.time_slice.start
554 } else {
555 self.time_slice.end
556 };
557
558 let cycle_end_time = if self.speed > 0.0 {
559 self.time_slice.end
560 } else {
561 self.time_slice.start
562 };
563
564 let mut root_motion = RootMotion::default();
565 if let Some(root_pose) = self.pose.poses_mut().get_mut(&root_motion_settings.node) {
566 for bound_value in root_pose.values.values.iter_mut() {
567 match bound_value.binding {
568 ValueBinding::Position => {
569 if let TrackValue::Vector3(pose_position) = bound_value.value {
570 if new_loop_cycle_started {
571 root_motion.prev_position =
572 fetch_position_at_time(tracks, cycle_start_time);
573 root_motion.position_offset_remainder = Some(
574 fetch_position_at_time(tracks, cycle_end_time)
575 - pose_position,
576 );
577 } else {
578 root_motion.prev_position = pose_position;
579 }
580
581 let remainder = prev_root_motion
582 .position_offset_remainder
583 .take()
584 .unwrap_or_default();
585 let current_offset = pose_position - prev_root_motion.prev_position;
586 let delta = current_offset + remainder;
587
588 root_motion.delta_position.x =
589 if root_motion_settings.ignore_x_movement {
590 0.0
591 } else {
592 delta.x
593 };
594 root_motion.delta_position.y =
595 if root_motion_settings.ignore_y_movement {
596 0.0
597 } else {
598 delta.y
599 };
600 root_motion.delta_position.z =
601 if root_motion_settings.ignore_z_movement {
602 0.0
603 } else {
604 delta.z
605 };
606
607 // Reset position so the root won't move.
608 let start_position =
609 fetch_position_at_time(tracks, self.time_slice.start);
610
611 bound_value.value = TrackValue::Vector3(Vector3::new(
612 if root_motion_settings.ignore_x_movement {
613 pose_position.x
614 } else {
615 start_position.x
616 },
617 if root_motion_settings.ignore_y_movement {
618 pose_position.y
619 } else {
620 start_position.y
621 },
622 if root_motion_settings.ignore_z_movement {
623 pose_position.z
624 } else {
625 start_position.z
626 },
627 ));
628 }
629 }
630 ValueBinding::Rotation => {
631 if let TrackValue::UnitQuaternion(pose_rotation) = bound_value.value {
632 if !root_motion_settings.ignore_rotations {
633 if new_loop_cycle_started {
634 root_motion.prev_rotation =
635 fetch_rotation_at_time(tracks, cycle_start_time);
636 root_motion.rotation_remainder = Some(
637 fetch_rotation_at_time(tracks, cycle_end_time)
638 .inverse()
639 * pose_rotation,
640 );
641 } else {
642 root_motion.prev_rotation = pose_rotation;
643 }
644
645 // Compute relative rotation that can be used to "turn" a node later on.
646 let remainder = prev_root_motion
647 .rotation_remainder
648 .take()
649 .unwrap_or_else(UnitQuaternion::identity);
650 let current_relative_rotation =
651 prev_root_motion.prev_rotation.inverse() * pose_rotation;
652 root_motion.delta_rotation =
653 remainder * current_relative_rotation;
654
655 // Reset rotation so the root won't rotate.
656 bound_value.value = TrackValue::UnitQuaternion(
657 fetch_rotation_at_time(tracks, self.time_slice.start),
658 );
659 }
660 }
661 }
662 _ => (),
663 }
664 }
665 }
666 self.root_motion = Some(root_motion);
667 }
668 }
669
670 /// Sets new root motion settings.
671 pub fn set_root_motion_settings(&mut self, settings: Option<RootMotionSettings<T>>) {
672 self.root_motion_settings = settings;
673 }
674
675 /// Returns a reference to the root motion settings (if any).
676 pub fn root_motion_settings_ref(&self) -> Option<&RootMotionSettings<T>> {
677 self.root_motion_settings.as_ref()
678 }
679
680 /// Returns a reference to the root motion settings (if any).
681 pub fn root_motion_settings_mut(&mut self) -> Option<&mut RootMotionSettings<T>> {
682 self.root_motion_settings.as_mut()
683 }
684
685 /// Returns a reference to the root motion (if any).
686 pub fn root_motion(&self) -> Option<&RootMotion> {
687 self.root_motion.as_ref()
688 }
689
690 /// Extracts a first event from the events queue of the animation.
691 pub fn pop_event(&mut self) -> Option<AnimationEvent> {
692 self.events.pop_front()
693 }
694
695 /// Returns a reference to inner events queue. It is useful when you need to iterate over the events, but
696 /// don't extract them from the queue.
697 pub fn events_ref(&self) -> &VecDeque<AnimationEvent> {
698 &self.events
699 }
700
701 /// Return a mutable reference to inner events queue. Provides you a full controls over animation events,
702 /// you can even manually inject events in the queue.
703 pub fn events_mut(&mut self) -> &mut VecDeque<AnimationEvent> {
704 &mut self.events
705 }
706
707 /// Takes the events queue and returns it to the caller, leaving the internal queue empty.
708 pub fn take_events(&mut self) -> VecDeque<AnimationEvent> {
709 std::mem::take(&mut self.events)
710 }
711
712 /// Returns current time position of the animation. The time position is guaranteed to be in the range of
713 /// current time slice of the animation.
714 pub fn time_position(&self) -> f32 {
715 self.time_position
716 }
717
718 /// Sets new speed multiplier for the animation. By default it is set to 1.0. Negative values can be used
719 /// to play the animation in reverse.
720 pub fn set_speed(&mut self, speed: f32) -> &mut Self {
721 self.speed = speed;
722 self
723 }
724
725 /// Returns speed multiplier of the animation.
726 pub fn speed(&self) -> f32 {
727 self.speed
728 }
729
730 /// Enables or disables looping of the animation.
731 pub fn set_loop(&mut self, state: bool) -> &mut Self {
732 self.looped = state;
733 self
734 }
735
736 /// Returns `true` if the animation is looping, `false` - otherwise.
737 pub fn is_loop(&self) -> bool {
738 self.looped
739 }
740
741 /// Returns `true` if the animation was played until the end of current time slice of the animation, `false` -
742 /// otherwise. Looping animations will always return `false`.
743 pub fn has_ended(&self) -> bool {
744 !self.looped && (self.time_position - self.time_slice.end).abs() <= f32::EPSILON
745 }
746
747 /// Enables or disables the animation, disabled animations does not updated and their output pose will remain
748 /// the same. By default every animation is enabled.
749 pub fn set_enabled(&mut self, enabled: bool) -> &mut Self {
750 self.enabled = enabled;
751 self
752 }
753
754 /// Returns `true` if the animation is enabled, `false` - otherwise.
755 pub fn is_enabled(&self) -> bool {
756 self.enabled
757 }
758
759 /// Adds a new track to the animation track data container and binds it with the specified target.
760 /// Keep in mind, that this method will modify potentially shared track data container, which might
761 /// affect other animations using it.
762 pub fn add_track_with_binding(&mut self, binding: TrackBinding<T>, track: Track) {
763 let mut state = self.tracks_data.state();
764 let Some(tracks_data) = state.data() else {
765 return;
766 };
767 let id = track.id();
768 tracks_data.tracks.push(track);
769 self.track_bindings.insert(id, binding);
770 }
771
772 /// Removes last track from the current tracks data resource and the respective binding to it
773 /// from the animation. This method will fail if the resource is not loaded, or if there's no
774 /// tracks in it. It will also fail if there's no respective binding to the track in the
775 /// animation.
776 ///
777 /// Keep in mind, that this method modifies the tracks data resource, which might be used by
778 /// some other animation.
779 pub fn pop_track_with_binding(&mut self) -> Option<(TrackBinding<T>, Track)> {
780 let mut state = self.tracks_data.state();
781 let tracks_data = state.data()?;
782 let track = tracks_data.tracks.pop()?;
783 let binding = self.track_bindings.remove(&track.id())?;
784 Some((binding, track))
785 }
786
787 /// Removes the specified track from the current tracks data resource and the respective binding
788 /// to it from the animation. This method will fail if the resource is not loaded, or if there's
789 /// no tracks in it. It will also fail if there's no respective binding to the track in the
790 /// animation.
791 ///
792 /// Keep in mind, that this method modifies the tracks data resource, which might be used by
793 /// some other animation.
794 pub fn remove_track_with_binding(&mut self, index: usize) -> Option<(TrackBinding<T>, Track)> {
795 let mut state = self.tracks_data.state();
796 let tracks_data = state.data()?;
797 let track = tracks_data.tracks.remove(index);
798 let binding = self.track_bindings.remove(&track.id())?;
799 Some((binding, track))
800 }
801
802 /// Inserts a new track in the tracks data resource and creates a new binding to it.
803 ///
804 /// Keep in mind, that this method modifies the tracks data resource, which might be used by
805 /// some other animation.
806 pub fn insert_track_with_binding(
807 &mut self,
808 index: usize,
809 binding: TrackBinding<T>,
810 track: Track,
811 ) {
812 let mut state = self.tracks_data.state();
813 let Some(tracks_data) = state.data() else {
814 return;
815 };
816 assert!(self.track_bindings.insert(track.id(), binding).is_none());
817 tracks_data.tracks.insert(index, track);
818 }
819
820 /// Adds a new animation signal to the animation. See [`AnimationSignal`] docs for more info and examples.
821 pub fn add_signal(&mut self, signal: AnimationSignal) -> &mut Self {
822 self.signals.push(signal);
823 self
824 }
825
826 /// Removes last animation signal from the container of the animation.
827 pub fn pop_signal(&mut self) -> Option<AnimationSignal> {
828 self.signals.pop()
829 }
830
831 /// Inserts a new animation signal at given position.
832 pub fn insert_signal(&mut self, index: usize, signal: AnimationSignal) {
833 self.signals.insert(index, signal)
834 }
835
836 /// Removes an animation signal at given index.
837 pub fn remove_signal(&mut self, index: usize) -> AnimationSignal {
838 self.signals.remove(index)
839 }
840
841 /// Returns a reference to the animation signals container.
842 pub fn signals(&self) -> &[AnimationSignal] {
843 &self.signals
844 }
845
846 /// Returns a mutable reference to the inner animation signals container, allowing you to modify the signals.
847 pub fn signals_mut(&mut self) -> &mut [AnimationSignal] {
848 &mut self.signals
849 }
850
851 /// Tries to find all tracks that refer to a given node and enables or disables them.
852 pub fn set_node_track_enabled(&mut self, handle: T, enabled: bool) {
853 for track in self.track_bindings.values_mut() {
854 if track.target() == handle {
855 track.set_enabled(enabled);
856 }
857 }
858 }
859
860 /// Returns a reference to the current set of track bindings used by the animation. The returned
861 /// hash map contains `(track_id -> binding)` pairs.
862 pub fn track_bindings(&self) -> &FxHashMap<Uuid, TrackBinding<T>> {
863 &self.track_bindings
864 }
865
866 /// Returns a reference to the current set of track bindings used by the animation. The returned
867 /// hash map contains `(track_id -> binding)` pairs.
868 pub fn track_bindings_mut(&mut self) -> &mut FxHashMap<Uuid, TrackBinding<T>> {
869 &mut self.track_bindings
870 }
871
872 /// Tries to find a layer by its name. Returns index of the signal and its reference.
873 #[inline]
874 pub fn find_signal_by_name_ref<S: AsRef<str>>(
875 &self,
876 name: S,
877 ) -> Option<(usize, &AnimationSignal)> {
878 core::find_by_name_ref(self.signals.iter().enumerate(), name)
879 }
880
881 /// Tries to find a signal by its name. Returns index of the signal and its reference.
882 #[inline]
883 pub fn find_signal_by_name_mut<S: AsRef<str>>(
884 &mut self,
885 name: S,
886 ) -> Option<(usize, &mut AnimationSignal)> {
887 core::find_by_name_mut(self.signals.iter_mut().enumerate(), name)
888 }
889
890 /// Returns `true` if there's a signal with given name and id.
891 #[inline]
892 pub fn has_signal<S: AsRef<str>>(&self, name: S, id: Uuid) -> bool {
893 self.find_signal_by_name_ref(name)
894 .is_some_and(|(_, s)| s.id == id)
895 }
896
897 /// Removes all tracks from the animation.
898 pub fn remove_tracks(&mut self) {
899 self.track_bindings.clear();
900 }
901
902 fn update_pose(&mut self) {
903 let state = self.tracks_data.state();
904 let Some(tracks_data) = state.data_ref() else {
905 return;
906 };
907
908 self.pose.reset();
909 for track in tracks_data.tracks.iter() {
910 let Some(binding) = self.track_bindings.get(&track.id()) else {
911 continue;
912 };
913
914 if binding.is_enabled() {
915 if let Some(bound_value) = track.fetch(self.time_position) {
916 self.pose.add_to_node_pose(binding.target(), bound_value);
917 }
918 }
919 }
920 }
921
922 /// Returns current pose of the animation (a final result that can be applied to a scene graph).
923 pub fn pose(&self) -> &AnimationPose<T> {
924 &self.pose
925 }
926}
927
928impl<T: EntityId> Default for Animation<T> {
929 fn default() -> Self {
930 Self {
931 name: Default::default(),
932 tracks_data: Resource::new_ok(
933 Uuid::default(),
934 ResourceKind::Embedded,
935 AnimationTracksData::default(),
936 ),
937 speed: 1.0,
938 time_position: 0.0,
939 enabled: true,
940 looped: true,
941 pose: Default::default(),
942 signals: Default::default(),
943 root_motion_settings: None,
944 events: Default::default(),
945 time_slice: Default::default(),
946 root_motion: None,
947 max_event_capacity: 32,
948 track_bindings: Default::default(),
949 }
950 }
951}
952
953/// A container for animations. It is a tiny wrapper around [`Pool`], you should never create the container yourself,
954/// it is managed by the engine.
955#[derive(Debug, Clone, Reflect, PartialEq)]
956pub struct AnimationContainer<T: EntityId> {
957 pool: Pool<Animation<T>>,
958}
959
960impl<T: EntityId> Default for AnimationContainer<T> {
961 fn default() -> Self {
962 Self::new()
963 }
964}
965
966impl<T: EntityId> AnimationContainer<T> {
967 /// Creates an empty animation container.
968 pub fn new() -> Self {
969 Self { pool: Pool::new() }
970 }
971
972 /// Returns a total amount of animations in the container.
973 #[inline]
974 pub fn alive_count(&self) -> u32 {
975 self.pool.alive_count()
976 }
977
978 /// Returns an iterator yielding a references to animations in the container.
979 #[inline]
980 pub fn iter(&self) -> impl Iterator<Item = &Animation<T>> {
981 self.pool.iter()
982 }
983
984 /// Returns an iterator yielding a pair (handle, reference) to animations in the container.
985 #[inline]
986 pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<Animation<T>>, &Animation<T>)> {
987 self.pool.pair_iter()
988 }
989
990 /// Returns an iterator yielding a pair (handle, reference) to animations in the container.
991 #[inline]
992 pub fn pair_iter_mut(
993 &mut self,
994 ) -> impl Iterator<Item = (Handle<Animation<T>>, &mut Animation<T>)> {
995 self.pool.pair_iter_mut()
996 }
997
998 /// Returns an iterator yielding a references to animations in the container.
999 #[inline]
1000 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Animation<T>> {
1001 self.pool.iter_mut()
1002 }
1003
1004 /// Adds a new animation to the container and returns its handle.
1005 #[inline]
1006 pub fn add(&mut self, animation: Animation<T>) -> Handle<Animation<T>> {
1007 self.pool.spawn(animation)
1008 }
1009
1010 /// Tries to remove an animation from the container by its handle.
1011 #[inline]
1012 pub fn remove(&mut self, handle: Handle<Animation<T>>) -> Result<Animation<T>, PoolError> {
1013 self.pool.try_free(handle)
1014 }
1015
1016 /// Extracts animation from container and reserves its handle. It is used to temporarily take
1017 /// ownership over animation, and then put animation back using given ticket.
1018 pub fn take_reserve(
1019 &mut self,
1020 handle: Handle<Animation<T>>,
1021 ) -> (Ticket<Animation<T>>, Animation<T>) {
1022 self.pool.take_reserve(handle)
1023 }
1024
1025 /// Puts animation back by given ticket.
1026 pub fn put_back(
1027 &mut self,
1028 ticket: Ticket<Animation<T>>,
1029 animation: Animation<T>,
1030 ) -> Handle<Animation<T>> {
1031 self.pool.put_back(ticket, animation)
1032 }
1033
1034 /// Makes animation handle vacant again.
1035 pub fn forget_ticket(&mut self, ticket: Ticket<Animation<T>>) {
1036 self.pool.forget_ticket(ticket)
1037 }
1038
1039 /// Removes all animations.
1040 #[inline]
1041 pub fn clear(&mut self) {
1042 self.pool.clear()
1043 }
1044
1045 /// Tries to borrow a reference to an animation in the container. Panics if the handle is invalid.
1046 #[inline]
1047 pub fn get(&self, handle: Handle<Animation<T>>) -> &Animation<T> {
1048 self.pool.borrow(handle)
1049 }
1050
1051 /// Tries to borrow a mutable reference to an animation in the container. Panics if the handle is invalid.
1052 #[inline]
1053 pub fn get_mut(&mut self, handle: Handle<Animation<T>>) -> &mut Animation<T> {
1054 self.pool.borrow_mut(handle)
1055 }
1056
1057 /// Tries to borrow a reference to an animation in the container.
1058 #[inline]
1059 pub fn try_get(&self, handle: Handle<Animation<T>>) -> Result<&Animation<T>, PoolError> {
1060 self.pool.try_borrow(handle)
1061 }
1062
1063 /// Tries to borrow a mutable reference to an animation in the container.
1064 #[inline]
1065 pub fn try_get_mut(
1066 &mut self,
1067 handle: Handle<Animation<T>>,
1068 ) -> Result<&mut Animation<T>, PoolError> {
1069 self.pool.try_borrow_mut(handle)
1070 }
1071
1072 /// Tries to find an animation by its name in the container.
1073 #[inline]
1074 pub fn find_by_name_ref<S: AsRef<str>>(
1075 &self,
1076 name: S,
1077 ) -> Option<(Handle<Animation<T>>, &Animation<T>)> {
1078 core::find_by_name_ref(self.pool.pair_iter(), name)
1079 }
1080
1081 /// Tries to find an animation by its name in the container.
1082 #[inline]
1083 pub fn find_by_name_mut<S: AsRef<str>>(
1084 &mut self,
1085 name: S,
1086 ) -> Option<(Handle<Animation<T>>, &mut Animation<T>)> {
1087 core::find_by_name_mut(self.pool.pair_iter_mut(), name)
1088 }
1089
1090 /// Removes every animation from the container that does not satisfy a particular condition represented by the given
1091 /// closue.
1092 #[inline]
1093 pub fn retain<P>(&mut self, pred: P)
1094 where
1095 P: FnMut(&Animation<T>) -> bool,
1096 {
1097 self.pool.retain(pred)
1098 }
1099
1100 /// Removes queued animation events from every animation in the container.
1101 ///
1102 /// # Potential use cases
1103 ///
1104 /// Sometimes there is a need to use animation events only from one frame, in this case you should clear events each frame.
1105 /// This situation might come up when you have multiple animations with signals, but at each frame not every event gets
1106 /// processed. This might result in unwanted side effects, like multiple attack events may result in huge damage in a single
1107 /// frame.
1108 pub fn clear_animation_events(&mut self) {
1109 for animation in self.pool.iter_mut() {
1110 animation.events.clear();
1111 }
1112 }
1113}
1114
1115impl<T: EntityId> Visit for AnimationContainer<T> {
1116 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1117 if visitor.is_reading() && self.pool.get_capacity() != 0 {
1118 panic!("Animation pool must be empty on load!");
1119 }
1120
1121 let mut region = visitor.enter_region(name)?;
1122
1123 self.pool.visit("Pool", &mut region)?;
1124
1125 Ok(())
1126 }
1127}
1128
1129impl<T: EntityId> Index<Handle<Animation<T>>> for AnimationContainer<T> {
1130 type Output = Animation<T>;
1131
1132 fn index(&self, index: Handle<Animation<T>>) -> &Self::Output {
1133 &self.pool[index]
1134 }
1135}
1136
1137impl<T: EntityId> IndexMut<Handle<Animation<T>>> for AnimationContainer<T> {
1138 fn index_mut(&mut self, index: Handle<Animation<T>>) -> &mut Self::Output {
1139 &mut self.pool[index]
1140 }
1141}