bevy_animation/
graph.rs

1//! The animation graph, which allows animations to be blended together.
2
3use core::{
4    fmt::Write,
5    iter,
6    ops::{Index, IndexMut, Range},
7};
8use std::io;
9
10use bevy_asset::{
11    io::Reader, Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, Handle, LoadContext,
12};
13use bevy_derive::{Deref, DerefMut};
14use bevy_ecs::{
15    component::Component,
16    message::MessageReader,
17    reflect::ReflectComponent,
18    resource::Resource,
19    system::{Res, ResMut},
20};
21use bevy_platform::collections::HashMap;
22use bevy_reflect::{prelude::ReflectDefault, Reflect};
23use derive_more::derive::From;
24use petgraph::{
25    graph::{DiGraph, NodeIndex},
26    Direction,
27};
28use ron::de::SpannedError;
29use serde::{Deserialize, Serialize};
30use smallvec::SmallVec;
31use thiserror::Error;
32use tracing::warn;
33
34use crate::{AnimationClip, AnimationTargetId};
35
36/// A graph structure that describes how animation clips are to be blended
37/// together.
38///
39/// Applications frequently want to be able to play multiple animations at once
40/// and to fine-tune the influence that animations have on a skinned mesh. Bevy
41/// uses an *animation graph* to store this information. Animation graphs are a
42/// directed acyclic graph (DAG) that describes how animations are to be
43/// weighted and combined together. Every frame, Bevy evaluates the graph from
44/// the root and blends the animations together in a bottom-up fashion to
45/// produce the final pose.
46///
47/// There are three types of nodes: *blend nodes*, *add nodes*, and *clip
48/// nodes*, all of which can have an associated weight. Blend nodes and add
49/// nodes have no associated animation clip and combine the animations of their
50/// children according to those children's weights. Clip nodes specify an
51/// animation clip to play. When a graph is created, it starts with only a
52/// single blend node, the root node.
53///
54/// For example, consider the following graph:
55///
56/// ```text
57/// ┌────────────┐                                      
58/// │            │                                      
59/// │    Idle    ├─────────────────────┐                
60/// │            │                     │                
61/// └────────────┘                     │                
62///                                    │                
63/// ┌────────────┐                     │  ┌────────────┐
64/// │            │                     │  │            │
65/// │    Run     ├──┐                  ├──┤    Root    │
66/// │            │  │  ┌────────────┐  │  │            │
67/// └────────────┘  │  │   Blend    │  │  └────────────┘
68///                 ├──┤            ├──┘                
69/// ┌────────────┐  │  │    0.5     │                   
70/// │            │  │  └────────────┘                   
71/// │    Walk    ├──┘                                   
72/// │            │                                      
73/// └────────────┘                                      
74/// ```
75///
76/// In this case, assuming that Idle, Run, and Walk are all playing with weight
77/// 1.0, the Run and Walk animations will be equally blended together, then
78/// their weights will be halved and finally blended with the Idle animation.
79/// Thus the weight of Run and Walk are effectively half of the weight of Idle.
80///
81/// Nodes can optionally have a *mask*, a bitfield that restricts the set of
82/// animation targets that the node and its descendants affect. Each bit in the
83/// mask corresponds to a *mask group*, which is a set of animation targets
84/// (bones). An animation target can belong to any number of mask groups within
85/// the context of an animation graph.
86///
87/// When the appropriate bit is set in a node's mask, neither the node nor its
88/// descendants will animate any animation targets belonging to that mask group.
89/// That is, setting a mask bit to 1 *disables* the animation targets in that
90/// group. If an animation target belongs to multiple mask groups, masking any
91/// one of the mask groups that it belongs to will mask that animation target.
92/// (Thus an animation target will only be animated if *all* of its mask groups
93/// are unmasked.)
94///
95/// A common use of masks is to allow characters to hold objects. For this, the
96/// typical workflow is to assign each character's hand to a mask group. Then,
97/// when the character picks up an object, the application masks out the hand
98/// that the object is held in for the character's animation set, then positions
99/// the hand's digits as necessary to grasp the object. The character's
100/// animations will continue to play but will not affect the hand, which will
101/// continue to be depicted as holding the object.
102///
103/// Animation graphs are assets and can be serialized to and loaded from [RON]
104/// files. Canonically, such files have an `.animgraph.ron` extension.
105///
106/// The animation graph implements [RFC 51]. See that document for more
107/// information.
108///
109/// [RON]: https://github.com/ron-rs/ron
110///
111/// [RFC 51]: https://github.com/bevyengine/rfcs/blob/main/rfcs/51-animation-composition.md
112#[derive(Asset, Reflect, Clone, Debug)]
113#[reflect(Debug, Clone)]
114pub struct AnimationGraph {
115    /// The `petgraph` data structure that defines the animation graph.
116    pub graph: AnimationDiGraph,
117
118    /// The index of the root node in the animation graph.
119    pub root: NodeIndex,
120
121    /// The mask groups that each animation target (bone) belongs to.
122    ///
123    /// Each value in this map is a bitfield, in which 0 in bit position N
124    /// indicates that the animation target doesn't belong to mask group N, and
125    /// a 1 in position N indicates that the animation target does belong to
126    /// mask group N.
127    ///
128    /// Animation targets not in this collection are treated as though they
129    /// don't belong to any mask groups.
130    pub mask_groups: HashMap<AnimationTargetId, AnimationMask>,
131}
132
133/// A [`Handle`] to the [`AnimationGraph`] to be used by the [`AnimationPlayer`](crate::AnimationPlayer) on the same entity.
134#[derive(Component, Clone, Debug, Default, Deref, DerefMut, Reflect, PartialEq, Eq, From)]
135#[reflect(Component, Default, Clone)]
136pub struct AnimationGraphHandle(pub Handle<AnimationGraph>);
137
138impl From<AnimationGraphHandle> for AssetId<AnimationGraph> {
139    fn from(handle: AnimationGraphHandle) -> Self {
140        handle.id()
141    }
142}
143
144impl From<&AnimationGraphHandle> for AssetId<AnimationGraph> {
145    fn from(handle: &AnimationGraphHandle) -> Self {
146        handle.id()
147    }
148}
149
150/// A type alias for the `petgraph` data structure that defines the animation
151/// graph.
152pub type AnimationDiGraph = DiGraph<AnimationGraphNode, (), u32>;
153
154/// The index of either an animation or blend node in the animation graph.
155///
156/// These indices are the way that [animation players] identify each animation.
157///
158/// [animation players]: crate::AnimationPlayer
159pub type AnimationNodeIndex = NodeIndex<u32>;
160
161/// An individual node within an animation graph.
162///
163/// The [`AnimationGraphNode::node_type`] field specifies the type of node: one
164/// of a *clip node*, a *blend node*, or an *add node*. Clip nodes, the leaves
165/// of the graph, contain animation clips to play. Blend and add nodes describe
166/// how to combine their children to produce a final animation.
167#[derive(Clone, Reflect, Debug)]
168#[reflect(Clone)]
169pub struct AnimationGraphNode {
170    /// Animation node data specific to the type of node (clip, blend, or add).
171    ///
172    /// In the case of clip nodes, this contains the actual animation clip
173    /// associated with the node.
174    pub node_type: AnimationNodeType,
175
176    /// A bitfield specifying the mask groups that this node and its descendants
177    /// will not affect.
178    ///
179    /// A 0 in bit N indicates that this node and its descendants *can* animate
180    /// animation targets in mask group N, while a 1 in bit N indicates that
181    /// this node and its descendants *cannot* animate mask group N.
182    pub mask: AnimationMask,
183
184    /// The weight of this node, which signifies its contribution in blending.
185    ///
186    /// Note that this does not propagate down the graph hierarchy; rather,
187    /// each [Blend] and [Add] node uses the weights of its children to determine
188    /// the total animation that is accumulated at that node. The parent node's
189    /// weight is used only to determine the contribution of that total animation
190    /// in *further* blending.
191    ///
192    /// In other words, it is as if the blend node is replaced by a single clip
193    /// node consisting of the blended animation with the weight specified at the
194    /// blend node.
195    ///
196    /// For animation clips, this weight is also multiplied by the [active animation weight]
197    /// before being applied.
198    ///
199    /// [Blend]: AnimationNodeType::Blend
200    /// [Add]: AnimationNodeType::Add
201    /// [active animation weight]: crate::ActiveAnimation::weight
202    pub weight: f32,
203}
204
205/// Animation node data specific to the type of node (clip, blend, or add).
206///
207/// In the case of clip nodes, this contains the actual animation clip
208/// associated with the node.
209#[derive(Clone, Default, Reflect, Debug)]
210#[reflect(Clone)]
211pub enum AnimationNodeType {
212    /// A *clip node*, which plays an animation clip.
213    ///
214    /// These are always the leaves of the graph.
215    Clip(Handle<AnimationClip>),
216
217    /// A *blend node*, which blends its children according to their weights.
218    ///
219    /// The weights of all the children of this node are normalized to 1.0.
220    #[default]
221    Blend,
222
223    /// An *additive blend node*, which combines the animations of its children
224    /// additively.
225    ///
226    /// The weights of all the children of this node are *not* normalized to
227    /// 1.0. Rather, each child is multiplied by its respective weight and
228    /// added in sequence.
229    ///
230    /// Add nodes are primarily useful for superimposing an animation for a
231    /// portion of a rig on top of the main animation. For example, an add node
232    /// could superimpose a weapon attack animation for a character's limb on
233    /// top of a running animation to produce an animation of a character
234    /// attacking while running.
235    Add,
236}
237
238/// An [`AssetLoader`] that can load [`AnimationGraph`]s as assets.
239///
240/// The canonical extension for [`AnimationGraph`]s is `.animgraph.ron`. Plain
241/// `.animgraph` is supported as well.
242#[derive(Default)]
243pub struct AnimationGraphAssetLoader;
244
245/// Errors that can occur when serializing animation graphs to RON.
246#[derive(Error, Debug)]
247pub enum AnimationGraphSaveError {
248    /// An I/O error occurred.
249    #[error(transparent)]
250    Io(#[from] io::Error),
251    /// An error occurred in RON serialization.
252    #[error(transparent)]
253    Ron(#[from] ron::Error),
254    /// An error occurred converting the graph to its serialization form.
255    #[error(transparent)]
256    ConvertToSerialized(#[from] NonPathHandleError),
257}
258
259/// Errors that can occur when deserializing animation graphs from RON.
260#[derive(Error, Debug)]
261pub enum AnimationGraphLoadError {
262    /// An I/O error occurred.
263    #[error(transparent)]
264    Io(#[from] io::Error),
265    /// An error occurred in RON deserialization.
266    #[error(transparent)]
267    Ron(#[from] ron::Error),
268    /// An error occurred in RON deserialization, and the location of the error
269    /// is supplied.
270    #[error(transparent)]
271    SpannedRon(#[from] SpannedError),
272    /// The deserialized graph contained legacy data that we no longer support.
273    #[error(
274        "The deserialized AnimationGraph contained an AnimationClip referenced by an AssetId, \
275    which is no longer supported. Consider manually deserializing the SerializedAnimationGraph \
276    type and determine how to migrate any SerializedAnimationClip::AssetId animation clips"
277    )]
278    GraphContainsLegacyAssetId,
279}
280
281/// Acceleration structures for animation graphs that allows Bevy to evaluate
282/// them quickly.
283///
284/// These are kept up to date as [`AnimationGraph`] instances are added,
285/// modified, and removed.
286#[derive(Default, Reflect, Resource)]
287pub struct ThreadedAnimationGraphs(
288    pub(crate) HashMap<AssetId<AnimationGraph>, ThreadedAnimationGraph>,
289);
290
291/// An acceleration structure for an animation graph that allows Bevy to
292/// evaluate it quickly.
293///
294/// This is kept up to date as the associated [`AnimationGraph`] instance is
295/// added, modified, or removed.
296#[derive(Default, Reflect)]
297pub struct ThreadedAnimationGraph {
298    /// A cached postorder traversal of the graph.
299    ///
300    /// The node indices here are stored in postorder. Siblings are stored in
301    /// descending order. This is because the
302    /// [`AnimationCurveEvaluator`](`crate::animation_curves::AnimationCurveEvaluator`) uses a stack for
303    /// evaluation. Consider this graph:
304    ///
305    /// ```text
306    ///             ┌─────┐
307    ///             │     │
308    ///             │  1  │
309    ///             │     │
310    ///             └──┬──┘
311    ///                │
312    ///        ┌───────┼───────┐
313    ///        │       │       │
314    ///        ▼       ▼       ▼
315    ///     ┌─────┐ ┌─────┐ ┌─────┐
316    ///     │     │ │     │ │     │
317    ///     │  2  │ │  3  │ │  4  │
318    ///     │     │ │     │ │     │
319    ///     └──┬──┘ └─────┘ └─────┘
320    ///        │
321    ///    ┌───┴───┐
322    ///    │       │
323    ///    ▼       ▼
324    /// ┌─────┐ ┌─────┐
325    /// │     │ │     │
326    /// │  5  │ │  6  │
327    /// │     │ │     │
328    /// └─────┘ └─────┘
329    /// ```
330    ///
331    /// The postorder traversal in this case will be (4, 3, 6, 5, 2, 1).
332    ///
333    /// The fact that the children of each node are sorted in reverse ensures
334    /// that, at each level, the order of blending proceeds in ascending order
335    /// by node index, as we guarantee. To illustrate this, consider the way
336    /// the graph above is evaluated. (Interpolation is represented with the ⊕
337    /// symbol.)
338    ///
339    /// | Step | Node | Operation  | Stack (after operation) | Blend Register |
340    /// | ---- | ---- | ---------- | ----------------------- | -------------- |
341    /// | 1    | 4    | Push       | 4                       |                |
342    /// | 2    | 3    | Push       | 4 3                     |                |
343    /// | 3    | 6    | Push       | 4 3 6                   |                |
344    /// | 4    | 5    | Push       | 4 3 6 5                 |                |
345    /// | 5    | 2    | Blend 5    | 4 3 6                   | 5              |
346    /// | 6    | 2    | Blend 6    | 4 3                     | 5 ⊕ 6          |
347    /// | 7    | 2    | Push Blend | 4 3 2                   |                |
348    /// | 8    | 1    | Blend 2    | 4 3                     | 2              |
349    /// | 9    | 1    | Blend 3    | 4                       | 2 ⊕ 3          |
350    /// | 10   | 1    | Blend 4    |                         | 2 ⊕ 3 ⊕ 4      |
351    /// | 11   | 1    | Push Blend | 1                       |                |
352    /// | 12   |      | Commit     |                         |                |
353    pub threaded_graph: Vec<AnimationNodeIndex>,
354
355    /// A mapping from each parent node index to the range within
356    /// [`Self::sorted_edges`].
357    ///
358    /// This allows for quick lookup of the children of each node, sorted in
359    /// ascending order of node index, without having to sort the result of the
360    /// `petgraph` traversal functions every frame.
361    pub sorted_edge_ranges: Vec<Range<u32>>,
362
363    /// A list of the children of each node, sorted in ascending order.
364    pub sorted_edges: Vec<AnimationNodeIndex>,
365
366    /// A mapping from node index to a bitfield specifying the mask groups that
367    /// this node masks *out* (i.e. doesn't animate).
368    ///
369    /// A 1 in bit position N indicates that this node doesn't animate any
370    /// targets of mask group N.
371    pub computed_masks: Vec<u64>,
372}
373
374/// A version of [`AnimationGraph`] suitable for serializing as an asset.
375///
376/// Animation nodes can refer to external animation clips, and the [`AssetId`]
377/// is typically not sufficient to identify the clips, since the
378/// [`bevy_asset::AssetServer`] assigns IDs in unpredictable ways. That fact
379/// motivates this type, which replaces the `Handle<AnimationClip>` with an
380/// asset path.  Loading an animation graph via the [`bevy_asset::AssetServer`]
381/// actually loads a serialized instance of this type, as does serializing an
382/// [`AnimationGraph`] through `serde`.
383#[derive(Serialize, Deserialize)]
384pub struct SerializedAnimationGraph {
385    /// Corresponds to the `graph` field on [`AnimationGraph`].
386    pub graph: DiGraph<SerializedAnimationGraphNode, (), u32>,
387    /// Corresponds to the `root` field on [`AnimationGraph`].
388    pub root: NodeIndex,
389    /// Corresponds to the `mask_groups` field on [`AnimationGraph`].
390    pub mask_groups: HashMap<AnimationTargetId, AnimationMask>,
391}
392
393/// A version of [`AnimationGraphNode`] suitable for serializing as an asset.
394///
395/// See the comments in [`SerializedAnimationGraph`] for more information.
396#[derive(Serialize, Deserialize)]
397pub struct SerializedAnimationGraphNode {
398    /// Corresponds to the `node_type` field on [`AnimationGraphNode`].
399    pub node_type: SerializedAnimationNodeType,
400    /// Corresponds to the `mask` field on [`AnimationGraphNode`].
401    pub mask: AnimationMask,
402    /// Corresponds to the `weight` field on [`AnimationGraphNode`].
403    pub weight: f32,
404}
405
406/// A version of [`AnimationNodeType`] suitable for serializing as part of a
407/// [`SerializedAnimationGraphNode`] asset.
408#[derive(Serialize, Deserialize)]
409pub enum SerializedAnimationNodeType {
410    /// Corresponds to [`AnimationNodeType::Clip`].
411    Clip(MigrationSerializedAnimationClip),
412    /// Corresponds to [`AnimationNodeType::Blend`].
413    Blend,
414    /// Corresponds to [`AnimationNodeType::Add`].
415    Add,
416}
417
418/// A type to facilitate migration from the legacy format of [`SerializedAnimationGraph`] to the
419/// new format.
420///
421/// By using untagged serde deserialization, we can try to deserialize the modern form, then
422/// fallback to the legacy form. Users must migrate to the modern form by Bevy 0.18.
423// TODO: Delete this after Bevy 0.17.
424#[derive(Serialize, Deserialize)]
425#[serde(untagged)]
426pub enum MigrationSerializedAnimationClip {
427    /// This is the new type of this field.
428    Modern(AssetPath<'static>),
429    /// This is the legacy type of this field. Users must migrate away from this.
430    #[serde(skip_serializing)]
431    Legacy(SerializedAnimationClip),
432}
433
434/// The legacy form of serialized animation clips. This allows raw asset IDs to be deserialized.
435// TODO: Delete this after Bevy 0.17.
436#[derive(Deserialize)]
437pub enum SerializedAnimationClip {
438    /// Records an asset path.
439    AssetPath(AssetPath<'static>),
440    /// The fallback that records an asset ID.
441    ///
442    /// Because asset IDs can change, this should not be relied upon. Prefer to
443    /// use asset paths where possible.
444    AssetId(AssetId<AnimationClip>),
445}
446
447/// The type of an animation mask bitfield.
448///
449/// Bit N corresponds to mask group N.
450///
451/// Because this is a 64-bit value, there is currently a limitation of 64 mask
452/// groups per animation graph.
453pub type AnimationMask = u64;
454
455impl AnimationGraph {
456    /// Creates a new animation graph with a root node and no other nodes.
457    pub fn new() -> Self {
458        let mut graph = DiGraph::default();
459        let root = graph.add_node(AnimationGraphNode::default());
460        Self {
461            graph,
462            root,
463            mask_groups: HashMap::default(),
464        }
465    }
466
467    /// A convenience function for creating an [`AnimationGraph`] from a single
468    /// [`AnimationClip`].
469    ///
470    /// The clip will be a direct child of the root with weight 1.0. Both the
471    /// graph and the index of the added node are returned as a tuple.
472    pub fn from_clip(clip: Handle<AnimationClip>) -> (Self, AnimationNodeIndex) {
473        let mut graph = Self::new();
474        let node_index = graph.add_clip(clip, 1.0, graph.root);
475        (graph, node_index)
476    }
477
478    /// A convenience method to create an [`AnimationGraph`]s with an iterator
479    /// of clips.
480    ///
481    /// All of the animation clips will be direct children of the root with
482    /// weight 1.0.
483    ///
484    /// Returns the graph and indices of the new nodes.
485    pub fn from_clips<'a, I>(clips: I) -> (Self, Vec<AnimationNodeIndex>)
486    where
487        I: IntoIterator<Item = Handle<AnimationClip>>,
488        <I as IntoIterator>::IntoIter: 'a,
489    {
490        let mut graph = Self::new();
491        let indices = graph.add_clips(clips, 1.0, graph.root).collect();
492        (graph, indices)
493    }
494
495    /// Adds an [`AnimationClip`] to the animation graph with the given weight
496    /// and returns its index.
497    ///
498    /// The animation clip will be the child of the given parent. The resulting
499    /// node will have no mask.
500    pub fn add_clip(
501        &mut self,
502        clip: Handle<AnimationClip>,
503        weight: f32,
504        parent: AnimationNodeIndex,
505    ) -> AnimationNodeIndex {
506        let node_index = self.graph.add_node(AnimationGraphNode {
507            node_type: AnimationNodeType::Clip(clip),
508            mask: 0,
509            weight,
510        });
511        self.graph.add_edge(parent, node_index, ());
512        node_index
513    }
514
515    /// Adds an [`AnimationClip`] to the animation graph with the given weight
516    /// and mask, and returns its index.
517    ///
518    /// The animation clip will be the child of the given parent.
519    pub fn add_clip_with_mask(
520        &mut self,
521        clip: Handle<AnimationClip>,
522        mask: AnimationMask,
523        weight: f32,
524        parent: AnimationNodeIndex,
525    ) -> AnimationNodeIndex {
526        let node_index = self.graph.add_node(AnimationGraphNode {
527            node_type: AnimationNodeType::Clip(clip),
528            mask,
529            weight,
530        });
531        self.graph.add_edge(parent, node_index, ());
532        node_index
533    }
534
535    /// A convenience method to add multiple [`AnimationClip`]s to the animation
536    /// graph.
537    ///
538    /// All of the animation clips will have the same weight and will be
539    /// parented to the same node.
540    ///
541    /// Returns the indices of the new nodes.
542    pub fn add_clips<'a, I>(
543        &'a mut self,
544        clips: I,
545        weight: f32,
546        parent: AnimationNodeIndex,
547    ) -> impl Iterator<Item = AnimationNodeIndex> + 'a
548    where
549        I: IntoIterator<Item = Handle<AnimationClip>>,
550        <I as IntoIterator>::IntoIter: 'a,
551    {
552        clips
553            .into_iter()
554            .map(move |clip| self.add_clip(clip, weight, parent))
555    }
556
557    /// Adds a blend node to the animation graph with the given weight and
558    /// returns its index.
559    ///
560    /// The blend node will be placed under the supplied `parent` node. During
561    /// animation evaluation, the descendants of this blend node will have their
562    /// weights multiplied by the weight of the blend. The blend node will have
563    /// no mask.
564    pub fn add_blend(&mut self, weight: f32, parent: AnimationNodeIndex) -> AnimationNodeIndex {
565        let node_index = self.graph.add_node(AnimationGraphNode {
566            node_type: AnimationNodeType::Blend,
567            mask: 0,
568            weight,
569        });
570        self.graph.add_edge(parent, node_index, ());
571        node_index
572    }
573
574    /// Adds a blend node to the animation graph with the given weight and
575    /// returns its index.
576    ///
577    /// The blend node will be placed under the supplied `parent` node. During
578    /// animation evaluation, the descendants of this blend node will have their
579    /// weights multiplied by the weight of the blend. Neither this node nor its
580    /// descendants will affect animation targets that belong to mask groups not
581    /// in the given `mask`.
582    pub fn add_blend_with_mask(
583        &mut self,
584        mask: AnimationMask,
585        weight: f32,
586        parent: AnimationNodeIndex,
587    ) -> AnimationNodeIndex {
588        let node_index = self.graph.add_node(AnimationGraphNode {
589            node_type: AnimationNodeType::Blend,
590            mask,
591            weight,
592        });
593        self.graph.add_edge(parent, node_index, ());
594        node_index
595    }
596
597    /// Adds a blend node to the animation graph with the given weight and
598    /// returns its index.
599    ///
600    /// The blend node will be placed under the supplied `parent` node. During
601    /// animation evaluation, the descendants of this blend node will have their
602    /// weights multiplied by the weight of the blend. The blend node will have
603    /// no mask.
604    pub fn add_additive_blend(
605        &mut self,
606        weight: f32,
607        parent: AnimationNodeIndex,
608    ) -> AnimationNodeIndex {
609        let node_index = self.graph.add_node(AnimationGraphNode {
610            node_type: AnimationNodeType::Add,
611            mask: 0,
612            weight,
613        });
614        self.graph.add_edge(parent, node_index, ());
615        node_index
616    }
617
618    /// Adds a blend node to the animation graph with the given weight and
619    /// returns its index.
620    ///
621    /// The blend node will be placed under the supplied `parent` node. During
622    /// animation evaluation, the descendants of this blend node will have their
623    /// weights multiplied by the weight of the blend. Neither this node nor its
624    /// descendants will affect animation targets that belong to mask groups not
625    /// in the given `mask`.
626    pub fn add_additive_blend_with_mask(
627        &mut self,
628        mask: AnimationMask,
629        weight: f32,
630        parent: AnimationNodeIndex,
631    ) -> AnimationNodeIndex {
632        let node_index = self.graph.add_node(AnimationGraphNode {
633            node_type: AnimationNodeType::Add,
634            mask,
635            weight,
636        });
637        self.graph.add_edge(parent, node_index, ());
638        node_index
639    }
640
641    /// Adds an edge from the edge `from` to `to`, making `to` a child of
642    /// `from`.
643    ///
644    /// The behavior is unspecified if adding this produces a cycle in the
645    /// graph.
646    pub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex) {
647        self.graph.add_edge(from, to, ());
648    }
649
650    /// Removes an edge between `from` and `to` if it exists.
651    ///
652    /// Returns true if the edge was successfully removed or false if no such
653    /// edge existed.
654    pub fn remove_edge(&mut self, from: NodeIndex, to: NodeIndex) -> bool {
655        self.graph
656            .find_edge(from, to)
657            .map(|edge| self.graph.remove_edge(edge))
658            .is_some()
659    }
660
661    /// Returns the [`AnimationGraphNode`] associated with the given index.
662    ///
663    /// If no node with the given index exists, returns `None`.
664    pub fn get(&self, animation: AnimationNodeIndex) -> Option<&AnimationGraphNode> {
665        self.graph.node_weight(animation)
666    }
667
668    /// Returns a mutable reference to the [`AnimationGraphNode`] associated
669    /// with the given index.
670    ///
671    /// If no node with the given index exists, returns `None`.
672    pub fn get_mut(&mut self, animation: AnimationNodeIndex) -> Option<&mut AnimationGraphNode> {
673        self.graph.node_weight_mut(animation)
674    }
675
676    /// Returns an iterator over the [`AnimationGraphNode`]s in this graph.
677    pub fn nodes(&self) -> impl Iterator<Item = AnimationNodeIndex> {
678        self.graph.node_indices()
679    }
680
681    /// Serializes the animation graph to the given [`Write`]r in RON format.
682    ///
683    /// If writing to a file, it can later be loaded with the
684    /// [`AnimationGraphAssetLoader`] to reconstruct the graph.
685    pub fn save<W>(&self, writer: &mut W) -> Result<(), AnimationGraphSaveError>
686    where
687        W: Write,
688    {
689        let mut ron_serializer = ron::ser::Serializer::new(writer, None)?;
690        let serialized_graph: SerializedAnimationGraph = self.clone().try_into()?;
691        Ok(serialized_graph.serialize(&mut ron_serializer)?)
692    }
693
694    /// Adds an animation target (bone) to the mask group with the given ID.
695    ///
696    /// Calling this method multiple times with the same animation target but
697    /// different mask groups will result in that target being added to all of
698    /// the specified groups.
699    pub fn add_target_to_mask_group(&mut self, target: AnimationTargetId, mask_group: u32) {
700        *self.mask_groups.entry(target).or_default() |= 1 << mask_group;
701    }
702}
703
704impl AnimationGraphNode {
705    /// Masks out the mask groups specified by the given `mask` bitfield.
706    ///
707    /// A 1 in bit position N causes this function to mask out mask group N, and
708    /// thus neither this node nor its descendants will animate any animation
709    /// targets that belong to group N.
710    pub fn add_mask(&mut self, mask: AnimationMask) -> &mut Self {
711        self.mask |= mask;
712        self
713    }
714
715    /// Unmasks the mask groups specified by the given `mask` bitfield.
716    ///
717    /// A 1 in bit position N causes this function to unmask mask group N, and
718    /// thus this node and its descendants will be allowed to animate animation
719    /// targets that belong to group N, unless another mask masks those targets
720    /// out.
721    pub fn remove_mask(&mut self, mask: AnimationMask) -> &mut Self {
722        self.mask &= !mask;
723        self
724    }
725
726    /// Masks out the single mask group specified by `group`.
727    ///
728    /// After calling this function, neither this node nor its descendants will
729    /// animate any animation targets that belong to the given `group`.
730    pub fn add_mask_group(&mut self, group: u32) -> &mut Self {
731        self.add_mask(1 << group)
732    }
733
734    /// Unmasks the single mask group specified by `group`.
735    ///
736    /// After calling this function, this node and its descendants will be
737    /// allowed to animate animation targets that belong to the given `group`,
738    /// unless another mask masks those targets out.
739    pub fn remove_mask_group(&mut self, group: u32) -> &mut Self {
740        self.remove_mask(1 << group)
741    }
742}
743
744impl Index<AnimationNodeIndex> for AnimationGraph {
745    type Output = AnimationGraphNode;
746
747    fn index(&self, index: AnimationNodeIndex) -> &Self::Output {
748        &self.graph[index]
749    }
750}
751
752impl IndexMut<AnimationNodeIndex> for AnimationGraph {
753    fn index_mut(&mut self, index: AnimationNodeIndex) -> &mut Self::Output {
754        &mut self.graph[index]
755    }
756}
757
758impl Default for AnimationGraphNode {
759    fn default() -> Self {
760        Self {
761            node_type: Default::default(),
762            mask: 0,
763            weight: 1.0,
764        }
765    }
766}
767
768impl Default for AnimationGraph {
769    fn default() -> Self {
770        Self::new()
771    }
772}
773
774impl AssetLoader for AnimationGraphAssetLoader {
775    type Asset = AnimationGraph;
776
777    type Settings = ();
778
779    type Error = AnimationGraphLoadError;
780
781    async fn load(
782        &self,
783        reader: &mut dyn Reader,
784        _: &Self::Settings,
785        load_context: &mut LoadContext<'_>,
786    ) -> Result<Self::Asset, Self::Error> {
787        let mut bytes = Vec::new();
788        reader.read_to_end(&mut bytes).await?;
789
790        // Deserialize a `SerializedAnimationGraph` directly, so that we can
791        // get the list of the animation clips it refers to and load them.
792        let mut deserializer = ron::de::Deserializer::from_bytes(&bytes)?;
793        let serialized_animation_graph = SerializedAnimationGraph::deserialize(&mut deserializer)
794            .map_err(|err| deserializer.span_error(err))?;
795
796        // Load all `AssetPath`s to convert from a `SerializedAnimationGraph` to a real
797        // `AnimationGraph`. This is effectively a `DiGraph::map`, but this allows us to return
798        // errors.
799        let mut animation_graph = DiGraph::with_capacity(
800            serialized_animation_graph.graph.node_count(),
801            serialized_animation_graph.graph.edge_count(),
802        );
803
804        let mut already_warned = false;
805        for serialized_node in serialized_animation_graph.graph.node_weights() {
806            animation_graph.add_node(AnimationGraphNode {
807                node_type: match serialized_node.node_type {
808                    SerializedAnimationNodeType::Clip(ref clip) => match clip {
809                        MigrationSerializedAnimationClip::Modern(path) => {
810                            AnimationNodeType::Clip(load_context.load(path.clone()))
811                        }
812                        MigrationSerializedAnimationClip::Legacy(
813                            SerializedAnimationClip::AssetPath(path),
814                        ) => {
815                            if !already_warned {
816                                let path = load_context.asset_path();
817                                warn!(
818                                    "Loaded an AnimationGraph asset at \"{path}\" which contains a \
819                                    legacy-style SerializedAnimationClip. Please re-save the asset \
820                                    using AnimationGraph::save to automatically migrate to the new \
821                                    format"
822                                );
823                                already_warned = true;
824                            }
825                            AnimationNodeType::Clip(load_context.load(path.clone()))
826                        }
827                        MigrationSerializedAnimationClip::Legacy(
828                            SerializedAnimationClip::AssetId(_),
829                        ) => {
830                            return Err(AnimationGraphLoadError::GraphContainsLegacyAssetId);
831                        }
832                    },
833                    SerializedAnimationNodeType::Blend => AnimationNodeType::Blend,
834                    SerializedAnimationNodeType::Add => AnimationNodeType::Add,
835                },
836                mask: serialized_node.mask,
837                weight: serialized_node.weight,
838            });
839        }
840        for edge in serialized_animation_graph.graph.raw_edges() {
841            animation_graph.add_edge(edge.source(), edge.target(), ());
842        }
843        Ok(AnimationGraph {
844            graph: animation_graph,
845            root: serialized_animation_graph.root,
846            mask_groups: serialized_animation_graph.mask_groups,
847        })
848    }
849
850    fn extensions(&self) -> &[&str] {
851        &["animgraph", "animgraph.ron"]
852    }
853}
854
855impl TryFrom<AnimationGraph> for SerializedAnimationGraph {
856    type Error = NonPathHandleError;
857
858    fn try_from(animation_graph: AnimationGraph) -> Result<Self, NonPathHandleError> {
859        // Convert all the `Handle<AnimationClip>` to AssetPath, so that
860        // `AnimationGraphAssetLoader` can load them. This is effectively just doing a
861        // `DiGraph::map`, except we need to return an error if any handles aren't associated to a
862        // path.
863        let mut serialized_graph = DiGraph::with_capacity(
864            animation_graph.graph.node_count(),
865            animation_graph.graph.edge_count(),
866        );
867        for node in animation_graph.graph.node_weights() {
868            serialized_graph.add_node(SerializedAnimationGraphNode {
869                weight: node.weight,
870                mask: node.mask,
871                node_type: match node.node_type {
872                    AnimationNodeType::Clip(ref clip) => match clip.path() {
873                        Some(path) => SerializedAnimationNodeType::Clip(
874                            MigrationSerializedAnimationClip::Modern(path.clone()),
875                        ),
876                        None => return Err(NonPathHandleError),
877                    },
878                    AnimationNodeType::Blend => SerializedAnimationNodeType::Blend,
879                    AnimationNodeType::Add => SerializedAnimationNodeType::Add,
880                },
881            });
882        }
883        for edge in animation_graph.graph.raw_edges() {
884            serialized_graph.add_edge(edge.source(), edge.target(), ());
885        }
886        Ok(Self {
887            graph: serialized_graph,
888            root: animation_graph.root,
889            mask_groups: animation_graph.mask_groups,
890        })
891    }
892}
893
894/// Error for when only path [`Handle`]s are supported.
895#[derive(Error, Debug)]
896#[error("AnimationGraph contains a handle to an AnimationClip that does not correspond to an asset path")]
897pub struct NonPathHandleError;
898
899/// A system that creates, updates, and removes [`ThreadedAnimationGraph`]
900/// structures for every changed [`AnimationGraph`].
901///
902/// The [`ThreadedAnimationGraph`] contains acceleration structures that allow
903/// for quick evaluation of that graph's animations.
904pub(crate) fn thread_animation_graphs(
905    mut threaded_animation_graphs: ResMut<ThreadedAnimationGraphs>,
906    animation_graphs: Res<Assets<AnimationGraph>>,
907    mut animation_graph_asset_events: MessageReader<AssetEvent<AnimationGraph>>,
908) {
909    for animation_graph_asset_event in animation_graph_asset_events.read() {
910        match *animation_graph_asset_event {
911            AssetEvent::Added { id }
912            | AssetEvent::Modified { id }
913            | AssetEvent::LoadedWithDependencies { id } => {
914                // Fetch the animation graph.
915                let Some(animation_graph) = animation_graphs.get(id) else {
916                    continue;
917                };
918
919                // Reuse the allocation if possible.
920                let mut threaded_animation_graph =
921                    threaded_animation_graphs.0.remove(&id).unwrap_or_default();
922                threaded_animation_graph.clear();
923
924                // Recursively thread the graph in postorder.
925                threaded_animation_graph.init(animation_graph);
926                threaded_animation_graph.build_from(
927                    &animation_graph.graph,
928                    animation_graph.root,
929                    0,
930                );
931
932                // Write in the threaded graph.
933                threaded_animation_graphs
934                    .0
935                    .insert(id, threaded_animation_graph);
936            }
937
938            AssetEvent::Removed { id } => {
939                threaded_animation_graphs.0.remove(&id);
940            }
941            AssetEvent::Unused { .. } => {}
942        }
943    }
944}
945
946impl ThreadedAnimationGraph {
947    /// Removes all the data in this [`ThreadedAnimationGraph`], keeping the
948    /// memory around for later reuse.
949    fn clear(&mut self) {
950        self.threaded_graph.clear();
951        self.sorted_edge_ranges.clear();
952        self.sorted_edges.clear();
953    }
954
955    /// Prepares the [`ThreadedAnimationGraph`] for recursion.
956    fn init(&mut self, animation_graph: &AnimationGraph) {
957        let node_count = animation_graph.graph.node_count();
958        let edge_count = animation_graph.graph.edge_count();
959
960        self.threaded_graph.reserve(node_count);
961        self.sorted_edges.reserve(edge_count);
962
963        self.sorted_edge_ranges.clear();
964        self.sorted_edge_ranges
965            .extend(iter::repeat_n(0..0, node_count));
966
967        self.computed_masks.clear();
968        self.computed_masks.extend(iter::repeat_n(0, node_count));
969    }
970
971    /// Recursively constructs the [`ThreadedAnimationGraph`] for the subtree
972    /// rooted at the given node.
973    ///
974    /// `mask` specifies the computed mask of the parent node. (It could be
975    /// fetched from the [`Self::computed_masks`] field, but we pass it
976    /// explicitly as a micro-optimization.)
977    fn build_from(
978        &mut self,
979        graph: &AnimationDiGraph,
980        node_index: AnimationNodeIndex,
981        mut mask: u64,
982    ) {
983        // Accumulate the mask.
984        mask |= graph.node_weight(node_index).unwrap().mask;
985        self.computed_masks[node_index.index()] = mask;
986
987        // Gather up the indices of our children, and sort them.
988        let mut kids: SmallVec<[AnimationNodeIndex; 8]> = graph
989            .neighbors_directed(node_index, Direction::Outgoing)
990            .collect();
991        kids.sort_unstable();
992
993        // Write in the list of kids.
994        self.sorted_edge_ranges[node_index.index()] =
995            (self.sorted_edges.len() as u32)..((self.sorted_edges.len() + kids.len()) as u32);
996        self.sorted_edges.extend_from_slice(&kids);
997
998        // Recurse. (This is a postorder traversal.)
999        for kid in kids.into_iter().rev() {
1000            self.build_from(graph, kid, mask);
1001        }
1002
1003        // Finally, push our index.
1004        self.threaded_graph.push(node_index);
1005    }
1006}