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}