fyrox_animation/machine/
mask.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Layer mask is a sort of blacklist that prevents layer from animating certain nodes. See [`LayerMask`] docs
22//! for more info.
23
24use crate::core::{reflect::prelude::*, visitor::prelude::*};
25use crate::EntityId;
26
27/// Layer mask is a sort of blacklist that prevents layer from animating certain nodes. Its main use case is to
28/// disable animation on animation layers for specific body parts of humanoid (but not only) characters. The
29/// mask holds handles of nodes that **will not** be animated.
30#[derive(Default, Debug, Visit, Reflect, Clone, PartialEq, Eq)]
31pub struct LayerMask<T: EntityId> {
32    excluded_bones: Vec<T>,
33}
34
35impl<T: EntityId> From<Vec<T>> for LayerMask<T> {
36    fn from(mut excluded_bones: Vec<T>) -> Self {
37        excluded_bones.sort();
38        Self { excluded_bones }
39    }
40}
41
42impl<T: EntityId> LayerMask<T> {
43    /// Merges a given layer mask in the current mask, handles will be automatically de-duplicated.
44    pub fn merge(&mut self, other: LayerMask<T>) {
45        for handle in other.into_inner() {
46            if !self.contains(handle) {
47                self.add(handle);
48            }
49        }
50    }
51
52    /// Adds a node handle to the mask. You can add as many nodes here as you want and pretty much any handle,
53    /// but you should keep handles only to nodes are affected by your animations. Otherwise you'll just make
54    /// the inner container bigger and it will degrade in performance.
55    ///
56    /// # Performance
57    ///
58    /// The method has O(log(n)) complexity, which means it is very fast for most use cases.
59    #[inline]
60    pub fn add(&mut self, node: T) {
61        let index = self.excluded_bones.partition_point(|h| h < &node);
62
63        self.excluded_bones.insert(index, node);
64    }
65
66    /// Removes a given node handle from the mask (if any).
67    ///
68    /// # Performance
69    ///
70    /// The method has O(log(n)) complexity, which means it is very fast for most use cases.
71    pub fn remove(&mut self, node: T) {
72        if let Some(index) = self.index_of(node) {
73            self.excluded_bones.remove(index);
74        }
75    }
76
77    fn index_of(&self, id: T) -> Option<usize> {
78        self.excluded_bones.binary_search(&id).ok()
79    }
80
81    /// Checks if the mask contains a given node handle or not.
82    ///
83    /// # Performance
84    ///
85    /// The method has O(log(n)) complexity, which means it is very fast for most use cases.
86    #[inline]
87    pub fn contains(&self, node: T) -> bool {
88        self.index_of(node).is_some()
89    }
90
91    /// Check if a node should be animated or not.
92    ///
93    /// # Performance
94    ///
95    /// The method has O(log(n)) complexity, which means it is very fast for most use cases.
96    #[inline]
97    pub fn should_animate(&self, node: T) -> bool {
98        !self.contains(node)
99    }
100
101    /// Return a reference to inner container. There's only non-mutable version because inner container must always
102    /// be sorted.
103    #[inline]
104    pub fn inner(&self) -> &Vec<T> {
105        &self.excluded_bones
106    }
107
108    /// Converts the mask into inner container.
109    #[inline]
110    pub fn into_inner(self) -> Vec<T> {
111        self.excluded_bones
112    }
113}