rapier3d/geometry/interaction_groups.rs
1#![allow(clippy::bad_bit_mask)] // Clippy will complain about the bitmasks due to Group::NONE being 0.
2
3/// Pairwise filtering using bit masks.
4///
5/// This filtering method is based on two 32-bit values:
6/// - The interaction groups memberships.
7/// - The interaction groups filter.
8///
9/// An interaction is allowed between two filters `a` and `b` when two conditions
10/// are met simultaneously:
11/// - The groups membership of `a` has at least one bit set to `1` in common with the groups filter of `b`.
12/// - The groups membership of `b` has at least one bit set to `1` in common with the groups filter of `a`.
13///
14/// In other words, interactions are allowed between two filter iff. the following condition is met:
15/// ```ignore
16/// (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0
17/// ```
18#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
19#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
20#[repr(C)]
21pub struct InteractionGroups {
22 /// Groups memberships.
23 pub memberships: Group,
24 /// Groups filter.
25 pub filter: Group,
26}
27
28impl InteractionGroups {
29 /// Initializes with the given interaction groups and interaction mask.
30 pub const fn new(memberships: Group, filter: Group) -> Self {
31 Self {
32 memberships,
33 filter,
34 }
35 }
36
37 /// Allow interaction with everything.
38 pub const fn all() -> Self {
39 Self::new(Group::ALL, Group::ALL)
40 }
41
42 /// Prevent all interactions.
43 pub const fn none() -> Self {
44 Self::new(Group::NONE, Group::NONE)
45 }
46
47 /// Sets the group this filter is part of.
48 pub const fn with_memberships(mut self, memberships: Group) -> Self {
49 self.memberships = memberships;
50 self
51 }
52
53 /// Sets the interaction mask of this filter.
54 pub const fn with_filter(mut self, filter: Group) -> Self {
55 self.filter = filter;
56 self
57 }
58
59 /// Check if interactions should be allowed based on the interaction memberships and filter.
60 ///
61 /// An interaction is allowed iff. the memberships of `self` contain at least one bit set to 1 in common
62 /// with the filter of `rhs`, and vice-versa.
63 #[inline]
64 pub const fn test(self, rhs: Self) -> bool {
65 // NOTE: since const ops is not stable, we have to convert `Group` into u32
66 // to use & operator in const context.
67 (self.memberships.bits() & rhs.filter.bits()) != 0
68 && (rhs.memberships.bits() & self.filter.bits()) != 0
69 }
70}
71
72impl Default for InteractionGroups {
73 fn default() -> Self {
74 Self {
75 memberships: Group::GROUP_1,
76 filter: Group::ALL,
77 }
78 }
79}
80
81bitflags::bitflags! {
82 /// A bit mask identifying groups for interaction.
83 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
84 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
85 pub struct Group: u32 {
86 /// The group n°1.
87 const GROUP_1 = 1 << 0;
88 /// The group n°2.
89 const GROUP_2 = 1 << 1;
90 /// The group n°3.
91 const GROUP_3 = 1 << 2;
92 /// The group n°4.
93 const GROUP_4 = 1 << 3;
94 /// The group n°5.
95 const GROUP_5 = 1 << 4;
96 /// The group n°6.
97 const GROUP_6 = 1 << 5;
98 /// The group n°7.
99 const GROUP_7 = 1 << 6;
100 /// The group n°8.
101 const GROUP_8 = 1 << 7;
102 /// The group n°9.
103 const GROUP_9 = 1 << 8;
104 /// The group n°10.
105 const GROUP_10 = 1 << 9;
106 /// The group n°11.
107 const GROUP_11 = 1 << 10;
108 /// The group n°12.
109 const GROUP_12 = 1 << 11;
110 /// The group n°13.
111 const GROUP_13 = 1 << 12;
112 /// The group n°14.
113 const GROUP_14 = 1 << 13;
114 /// The group n°15.
115 const GROUP_15 = 1 << 14;
116 /// The group n°16.
117 const GROUP_16 = 1 << 15;
118 /// The group n°17.
119 const GROUP_17 = 1 << 16;
120 /// The group n°18.
121 const GROUP_18 = 1 << 17;
122 /// The group n°19.
123 const GROUP_19 = 1 << 18;
124 /// The group n°20.
125 const GROUP_20 = 1 << 19;
126 /// The group n°21.
127 const GROUP_21 = 1 << 20;
128 /// The group n°22.
129 const GROUP_22 = 1 << 21;
130 /// The group n°23.
131 const GROUP_23 = 1 << 22;
132 /// The group n°24.
133 const GROUP_24 = 1 << 23;
134 /// The group n°25.
135 const GROUP_25 = 1 << 24;
136 /// The group n°26.
137 const GROUP_26 = 1 << 25;
138 /// The group n°27.
139 const GROUP_27 = 1 << 26;
140 /// The group n°28.
141 const GROUP_28 = 1 << 27;
142 /// The group n°29.
143 const GROUP_29 = 1 << 28;
144 /// The group n°30.
145 const GROUP_30 = 1 << 29;
146 /// The group n°31.
147 const GROUP_31 = 1 << 30;
148 /// The group n°32.
149 const GROUP_32 = 1 << 31;
150
151 /// All of the groups.
152 const ALL = u32::MAX;
153 /// None of the groups.
154 const NONE = 0;
155 }
156}
157
158impl From<u32> for Group {
159 #[inline]
160 fn from(val: u32) -> Self {
161 Self::from_bits_retain(val)
162 }
163}
164
165impl From<Group> for u32 {
166 #[inline]
167 fn from(val: Group) -> Self {
168 val.bits()
169 }
170}