ncollide3d/pipeline/object/
collision_groups.rs1use crate::pipeline::broad_phase::BroadPhasePairFilter;
2use crate::pipeline::object::{CollisionObjectRef, CollisionObjectSet};
3use na::RealField;
4
5const SELF_COLLISION: u32 = 1 << 31;
6const ALL_GROUPS: u32 = (1 << 30) - 1;
7const NO_GROUP: u32 = 0;
8
9#[derive(Clone, Debug, Copy)]
44pub struct CollisionGroups {
45 membership: u32,
46 whitelist: u32,
47 blacklist: u32,
48}
49
50impl CollisionGroups {
51 #[inline]
54 pub fn new() -> CollisionGroups {
55 CollisionGroups {
56 membership: ALL_GROUPS,
57 whitelist: ALL_GROUPS,
58 blacklist: NO_GROUP,
59 }
60 }
61
62 #[inline]
64 pub fn empty() -> CollisionGroups {
65 CollisionGroups {
66 membership: NO_GROUP,
67 whitelist: NO_GROUP,
68 blacklist: NO_GROUP,
69 }
70 }
71
72 #[inline]
84 pub fn with_membership(mut self, groups: &[usize]) -> CollisionGroups {
85 CollisionGroups::set_mask(&mut self.membership, groups);
86 self
87 }
88
89 #[inline]
101 pub fn with_whitelist(mut self, groups: &[usize]) -> CollisionGroups {
102 CollisionGroups::set_mask(&mut self.whitelist, groups);
103 self
104 }
105
106 #[inline]
118 pub fn with_blacklist(mut self, groups: &[usize]) -> CollisionGroups {
119 CollisionGroups::set_mask(&mut self.blacklist, groups);
120 self
121 }
122
123 #[inline]
125 pub fn max_group_id() -> usize {
126 29
127 }
128
129 #[inline]
130 fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
131 assert!(
132 group_id < 30,
133 "There are at most 30 groups indexed from 0 to 29 (included)."
134 );
135
136 if add {
137 *mask = *mask | (1 << group_id)
138 } else {
139 *mask = *mask & !(1 << group_id)
140 }
141 }
142
143 #[inline]
144 fn set_mask(mask: &mut u32, groups: &[usize]) {
145 *mask = 0;
146 for g in groups.iter() {
147 CollisionGroups::modify_mask(mask, *g, true);
148 }
149 }
150
151 #[inline]
152 fn add_mask(cur_mask: u32, new_mask: u32) -> u32 {
153 assert!(
154 new_mask <= ALL_GROUPS,
155 "There are at most 30 groups indexed from 0 to 29 (included)."
156 );
157
158 cur_mask | new_mask
159 }
160
161 #[inline]
162 fn remove_mask(cur_mask: u32, new_mask: u32) -> u32 {
163 assert!(
164 new_mask <= ALL_GROUPS,
165 "There are at most 30 groups indexed from 0 to 29 (included)."
166 );
167
168 cur_mask & !new_mask
169 }
170
171 #[inline]
172 pub fn add_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
174 self.membership = Self::add_mask(self.membership, group_mask);
175 self
176 }
177
178 #[inline]
179 pub fn remove_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
181 self.membership = Self::remove_mask(self.membership, group_mask);
182 self
183 }
184
185 #[inline]
186 pub fn with_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
188 assert!(
189 group_mask <= ALL_GROUPS,
190 "There are at most 30 groups indexed from 0 to 29 (included)."
191 );
192
193 self.membership = group_mask;
194 self
195 }
196
197 #[inline]
198 pub fn add_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
200 self.whitelist = Self::add_mask(self.whitelist, group_mask);
201 self
202 }
203
204 #[inline]
205 pub fn remove_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
207 self.whitelist = Self::remove_mask(self.whitelist, group_mask);
208 self
209 }
210
211 #[inline]
212 pub fn with_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
214 assert!(
215 group_mask <= ALL_GROUPS,
216 "There are at most 30 groups indexed from 0 to 29 (included)."
217 );
218
219 self.whitelist = group_mask;
220 self
221 }
222
223 #[inline]
224 pub fn add_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
226 self.blacklist = Self::add_mask(self.blacklist, group_mask);
227 self
228 }
229
230 #[inline]
231 pub fn remove_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
233 self.blacklist = Self::remove_mask(self.blacklist, group_mask);
234 self
235 }
236
237 #[inline]
238 pub fn with_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
240 assert!(
241 group_mask <= ALL_GROUPS,
242 "There are at most 30 groups indexed from 0 to 29 (included)."
243 );
244
245 self.blacklist = group_mask;
246 self
247 }
248
249 #[inline]
251 pub fn modify_membership(&mut self, group_id: usize, add: bool) {
252 CollisionGroups::modify_mask(&mut self.membership, group_id, add);
253 }
254
255 #[inline]
257 pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
258 CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
259 }
260
261 #[inline]
263 pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
264 CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
265 }
266
267 #[inline]
269 pub fn set_membership(&mut self, groups: &[usize]) {
270 CollisionGroups::set_mask(&mut self.membership, groups);
271 }
272
273 #[inline]
275 pub fn set_whitelist(&mut self, groups: &[usize]) {
276 CollisionGroups::set_mask(&mut self.whitelist, groups);
277 }
278
279 #[inline]
281 pub fn set_blacklist(&mut self, groups: &[usize]) {
282 CollisionGroups::set_mask(&mut self.blacklist, groups);
283 }
284
285 #[inline]
287 pub fn copy_membership(&mut self, other: &CollisionGroups) {
288 self.membership = other.membership
289 }
290
291 #[inline]
293 pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
294 self.whitelist = other.whitelist
295 }
296
297 #[inline]
299 pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
300 self.blacklist = other.blacklist
301 }
302
303 #[inline]
305 pub fn enable_self_interaction(&mut self) {
306 self.whitelist = self.whitelist | SELF_COLLISION;
307 }
308
309 #[inline]
311 pub fn disable_self_interaction(&mut self) {
312 self.whitelist = self.whitelist & !SELF_COLLISION;
313 }
314
315 #[inline]
316 fn is_inside_mask(mask: u32, group_id: usize) -> bool {
317 assert!(
318 group_id < 30,
319 "There are at most 30 groups indexed from 0 to 29 (included)."
320 );
321 mask & (1 << group_id) != 0
322 }
323
324 #[inline]
326 pub fn is_member_of(&self, group_id: usize) -> bool {
327 CollisionGroups::is_inside_mask(self.membership, group_id)
328 }
329
330 #[inline]
332 pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
333 CollisionGroups::is_inside_mask(self.whitelist, group_id)
334 }
335
336 #[inline]
338 pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
339 CollisionGroups::is_inside_mask(self.blacklist, group_id)
340 }
341
342 #[inline]
346 pub fn can_interact_with(&self, group_id: usize) -> bool {
347 !CollisionGroups::is_inside_mask(self.blacklist, group_id)
348 && CollisionGroups::is_inside_mask(self.whitelist, group_id)
349 }
350
351 #[inline]
353 pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
354 self.membership & other.blacklist == 0
356 && other.membership & self.blacklist == 0
357 && self.membership & other.whitelist != 0
358 && other.membership & self.whitelist != 0
359 }
360
361 #[inline]
363 pub fn can_interact_with_self(&self) -> bool {
364 self.whitelist & SELF_COLLISION != 0
365 }
366}
367
368impl Default for CollisionGroups {
369 #[inline]
370 fn default() -> Self {
371 CollisionGroups::new()
372 }
373}
374
375pub struct CollisionGroupsPairFilter;
377
378impl CollisionGroupsPairFilter {
379 #[inline]
381 pub fn new() -> CollisionGroupsPairFilter {
382 CollisionGroupsPairFilter
383 }
384}
385
386impl<N: RealField + Copy, Set: CollisionObjectSet<N>> BroadPhasePairFilter<N, Set>
387 for CollisionGroupsPairFilter
388{
389 fn is_pair_valid(
390 &self,
391 h1: Set::CollisionObjectHandle,
392 h2: Set::CollisionObjectHandle,
393 s: &Set,
394 ) -> bool {
395 let co1 = try_ret!(s.collision_object(h1), false);
396 let co2 = try_ret!(s.collision_object(h2), false);
397
398 if h1 == h2 {
399 co1.collision_groups().can_interact_with_self()
400 } else {
401 co1.collision_groups()
402 .can_interact_with_groups(co2.collision_groups())
403 }
404 }
405}