use crate::pipeline::broad_phase::BroadPhasePairFilter;
use crate::pipeline::object::{CollisionObjectRef, CollisionObjectSet};
use na::RealField;
const SELF_COLLISION: u32 = 1 << 31;
const ALL_GROUPS: u32 = (1 << 30) - 1;
const NO_GROUP: u32 = 0;
#[derive(Clone, Debug, Copy)]
pub struct CollisionGroups {
membership: u32,
whitelist: u32,
blacklist: u32,
}
impl CollisionGroups {
#[inline]
pub fn new() -> CollisionGroups {
CollisionGroups {
membership: ALL_GROUPS,
whitelist: ALL_GROUPS,
blacklist: NO_GROUP,
}
}
#[inline]
pub fn empty() -> CollisionGroups {
CollisionGroups {
membership: NO_GROUP,
whitelist: NO_GROUP,
blacklist: NO_GROUP,
}
}
#[inline]
pub fn with_membership(mut self, groups: &[usize]) -> CollisionGroups {
CollisionGroups::set_mask(&mut self.membership, groups);
self
}
#[inline]
pub fn with_whitelist(mut self, groups: &[usize]) -> CollisionGroups {
CollisionGroups::set_mask(&mut self.whitelist, groups);
self
}
#[inline]
pub fn with_blacklist(mut self, groups: &[usize]) -> CollisionGroups {
CollisionGroups::set_mask(&mut self.blacklist, groups);
self
}
#[inline]
pub fn max_group_id() -> usize {
29
}
#[inline]
fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
assert!(
group_id < 30,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
if add {
*mask = *mask | (1 << group_id)
} else {
*mask = *mask & !(1 << group_id)
}
}
#[inline]
fn set_mask(mask: &mut u32, groups: &[usize]) {
*mask = 0;
for g in groups.iter() {
CollisionGroups::modify_mask(mask, *g, true);
}
}
#[inline]
fn add_mask(cur_mask: u32, new_mask: u32) -> u32 {
assert!(
new_mask <= ALL_GROUPS,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
cur_mask | new_mask
}
#[inline]
fn remove_mask(cur_mask: u32, new_mask: u32) -> u32 {
assert!(
new_mask <= ALL_GROUPS,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
cur_mask & !new_mask
}
#[inline]
pub fn add_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.membership = Self::add_mask(self.membership, group_mask);
self
}
#[inline]
pub fn remove_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.membership = Self::remove_mask(self.membership, group_mask);
self
}
#[inline]
pub fn with_membership_by_mask(mut self, group_mask: u32) -> CollisionGroups {
assert!(
group_mask <= ALL_GROUPS,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
self.membership = group_mask;
self
}
#[inline]
pub fn add_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.whitelist = Self::add_mask(self.whitelist, group_mask);
self
}
#[inline]
pub fn remove_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.whitelist = Self::remove_mask(self.whitelist, group_mask);
self
}
#[inline]
pub fn with_whitelist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
assert!(
group_mask <= ALL_GROUPS,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
self.whitelist = group_mask;
self
}
#[inline]
pub fn add_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.blacklist = Self::add_mask(self.blacklist, group_mask);
self
}
#[inline]
pub fn remove_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
self.blacklist = Self::remove_mask(self.blacklist, group_mask);
self
}
#[inline]
pub fn with_blacklist_by_mask(mut self, group_mask: u32) -> CollisionGroups {
assert!(
group_mask <= ALL_GROUPS,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
self.blacklist = group_mask;
self
}
#[inline]
pub fn modify_membership(&mut self, group_id: usize, add: bool) {
CollisionGroups::modify_mask(&mut self.membership, group_id, add);
}
#[inline]
pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
}
#[inline]
pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
}
#[inline]
pub fn set_membership(&mut self, groups: &[usize]) {
CollisionGroups::set_mask(&mut self.membership, groups);
}
#[inline]
pub fn set_whitelist(&mut self, groups: &[usize]) {
CollisionGroups::set_mask(&mut self.whitelist, groups);
}
#[inline]
pub fn set_blacklist(&mut self, groups: &[usize]) {
CollisionGroups::set_mask(&mut self.blacklist, groups);
}
#[inline]
pub fn copy_membership(&mut self, other: &CollisionGroups) {
self.membership = other.membership
}
#[inline]
pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
self.whitelist = other.whitelist
}
#[inline]
pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
self.blacklist = other.blacklist
}
#[inline]
pub fn enable_self_interaction(&mut self) {
self.whitelist = self.whitelist | SELF_COLLISION;
}
#[inline]
pub fn disable_self_interaction(&mut self) {
self.whitelist = self.whitelist & !SELF_COLLISION;
}
#[inline]
fn is_inside_mask(mask: u32, group_id: usize) -> bool {
assert!(
group_id < 30,
"There are at most 30 groups indexed from 0 to 29 (included)."
);
mask & (1 << group_id) != 0
}
#[inline]
pub fn is_member_of(&self, group_id: usize) -> bool {
CollisionGroups::is_inside_mask(self.membership, group_id)
}
#[inline]
pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
CollisionGroups::is_inside_mask(self.whitelist, group_id)
}
#[inline]
pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
CollisionGroups::is_inside_mask(self.blacklist, group_id)
}
#[inline]
pub fn can_interact_with(&self, group_id: usize) -> bool {
!CollisionGroups::is_inside_mask(self.blacklist, group_id)
&& CollisionGroups::is_inside_mask(self.whitelist, group_id)
}
#[inline]
pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
self.membership & other.blacklist == 0
&& other.membership & self.blacklist == 0
&& self.membership & other.whitelist != 0
&& other.membership & self.whitelist != 0
}
#[inline]
pub fn can_interact_with_self(&self) -> bool {
self.whitelist & SELF_COLLISION != 0
}
}
impl Default for CollisionGroups {
#[inline]
fn default() -> Self {
CollisionGroups::new()
}
}
pub struct CollisionGroupsPairFilter;
impl CollisionGroupsPairFilter {
#[inline]
pub fn new() -> CollisionGroupsPairFilter {
CollisionGroupsPairFilter
}
}
impl<N: RealField + Copy, Set: CollisionObjectSet<N>> BroadPhasePairFilter<N, Set>
for CollisionGroupsPairFilter
{
fn is_pair_valid(
&self,
h1: Set::CollisionObjectHandle,
h2: Set::CollisionObjectHandle,
s: &Set,
) -> bool {
let co1 = try_ret!(s.collision_object(h1), false);
let co2 = try_ret!(s.collision_object(h2), false);
if h1 == h2 {
co1.collision_groups().can_interact_with_self()
} else {
co1.collision_groups()
.can_interact_with_groups(co2.collision_groups())
}
}
}