use super::{
BroadPhasePairEvent, ColliderPair, SAPLayer, SAPProxies, SAPProxy, SAPProxyData, SAPRegionPool,
};
use crate::geometry::broad_phase_multi_sap::SAPProxyIndex;
use crate::geometry::{
ColliderBroadPhaseData, ColliderChanges, ColliderHandle, ColliderPosition, ColliderSet,
ColliderShape,
};
use crate::math::Real;
use crate::utils::IndexMut2;
use parry::bounding_volume::BoundingVolume;
use parry::utils::hashmap::HashMap;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct BroadPhase {
proxies: SAPProxies,
layers: Vec<SAPLayer>,
smallest_layer: u8,
largest_layer: u8,
colliders_proxy_ids: HashMap<ColliderHandle, SAPProxyIndex>,
#[cfg_attr(feature = "serde-serialize", serde(skip))]
region_pool: SAPRegionPool, #[cfg_attr(
feature = "serde-serialize",
serde(
serialize_with = "parry::utils::hashmap::serialize_hashmap_capacity",
deserialize_with = "parry::utils::hashmap::deserialize_hashmap_capacity"
)
)]
reporting: HashMap<(u32, u32), bool>, }
impl Default for BroadPhase {
fn default() -> Self {
Self::new()
}
}
impl BroadPhase {
pub fn new() -> Self {
BroadPhase {
proxies: SAPProxies::new(),
layers: Vec::new(),
smallest_layer: 0,
largest_layer: 0,
region_pool: Vec::new(),
reporting: HashMap::default(),
colliders_proxy_ids: HashMap::default(),
}
}
fn handle_removed_colliders(&mut self, removed_colliders: &[ColliderHandle]) {
for removed in removed_colliders {
if let Some(proxy_id) = self.colliders_proxy_ids.get(removed).copied() {
self.predelete_proxy(proxy_id);
}
}
}
fn predelete_proxy(&mut self, proxy_index: SAPProxyIndex) {
if proxy_index == crate::INVALID_U32 {
return;
}
let proxy = &mut self.proxies[proxy_index];
let layer = &mut self.layers[proxy.layer_id as usize];
layer.predelete_proxy(&mut self.proxies, proxy_index);
}
fn complete_removals(
&mut self,
colliders: &mut ColliderSet,
removed_colliders: &[ColliderHandle],
) {
if self.layers.is_empty() {
return;
}
let mut curr_layer_id = self.smallest_layer;
loop {
let curr_layer = &mut self.layers[curr_layer_id as usize];
if let Some(larger_layer_id) = curr_layer.larger_layer {
let (curr_layer, larger_layer) = self
.layers
.index_mut2(curr_layer_id as usize, larger_layer_id as usize);
curr_layer.complete_removals(
Some(larger_layer),
&mut self.proxies,
&mut self.region_pool,
);
self.reporting.clear();
curr_layer_id = larger_layer_id;
} else {
curr_layer.complete_removals(None, &mut self.proxies, &mut self.region_pool);
self.reporting.clear();
break;
}
}
for removed in removed_colliders {
if let Some(proxy_id) = self.colliders_proxy_ids.remove(removed) {
if proxy_id != crate::INVALID_U32 {
self.proxies.remove(proxy_id);
}
}
if let Some(co) = colliders.get_mut_internal(*removed) {
co.bf_data.proxy_index = crate::INVALID_U32;
}
}
}
fn finalize_layer_insertion(&mut self, layer_id: u8) {
if let Some(larger_layer) = self.layers[layer_id as usize].larger_layer {
self.layers[larger_layer as usize].unregister_all_subregions(&mut self.proxies);
}
if let Some(smaller_layer) = self.layers[layer_id as usize].smaller_layer {
let (smaller_layer, new_layer) = self
.layers
.index_mut2(smaller_layer as usize, layer_id as usize);
smaller_layer.propagate_existing_regions(
new_layer,
&mut self.proxies,
&mut self.region_pool,
);
}
}
fn ensure_layer_exists(&mut self, new_depth: i8) -> u8 {
if self.layers.is_empty() {
let layer_id = self.layers.len() as u8; self.layers
.push(SAPLayer::new(new_depth, layer_id, None, None));
return 0;
}
let mut larger_layer_id = Some(self.smallest_layer);
while let Some(curr_layer_id) = larger_layer_id {
if self.layers[curr_layer_id as usize].depth >= new_depth {
break;
}
larger_layer_id = self.layers[curr_layer_id as usize].larger_layer;
}
match larger_layer_id {
None => {
assert_ne!(self.layers.len() as u8, u8::MAX, "Not yet implemented.");
let new_layer_id = self.layers.len() as u8;
self.layers[self.largest_layer as usize].larger_layer = Some(new_layer_id);
self.layers.push(SAPLayer::new(
new_depth,
new_layer_id,
Some(self.largest_layer),
None,
));
self.largest_layer = new_layer_id;
self.finalize_layer_insertion(new_layer_id);
new_layer_id
}
Some(larger_layer_id) => {
if self.layers[larger_layer_id as usize].depth == new_depth {
larger_layer_id
} else {
let new_layer_id = self.layers.len() as u8;
let smaller_layer_id = self.layers[larger_layer_id as usize].smaller_layer;
self.layers[larger_layer_id as usize].smaller_layer = Some(new_layer_id);
if let Some(smaller_layer_id) = smaller_layer_id {
self.layers[smaller_layer_id as usize].larger_layer = Some(new_layer_id);
} else {
self.smallest_layer = new_layer_id;
}
self.layers.push(SAPLayer::new(
new_depth,
new_layer_id,
smaller_layer_id,
Some(larger_layer_id),
));
self.finalize_layer_insertion(new_layer_id);
new_layer_id
}
}
}
}
fn handle_modified_collider(
&mut self,
prediction_distance: Real,
handle: ColliderHandle,
proxy_index: &mut u32,
collider: (&ColliderPosition, &ColliderShape, &ColliderChanges),
) -> bool {
let (co_pos, co_shape, co_changes) = collider;
let mut aabb = co_shape
.compute_aabb(co_pos)
.loosened(prediction_distance / 2.0);
if aabb.mins.coords.iter().any(|e| !e.is_finite())
|| aabb.maxs.coords.iter().any(|e| !e.is_finite())
{
return false;
}
aabb.mins = super::clamp_point(aabb.mins);
aabb.maxs = super::clamp_point(aabb.maxs);
let prev_aabb;
let layer_id = if let Some(proxy) = self.proxies.get_mut(*proxy_index) {
let mut layer_id = proxy.layer_id;
prev_aabb = proxy.aabb;
proxy.aabb = aabb;
if co_changes.contains(ColliderChanges::SHAPE) {
let new_layer_depth = super::layer_containing_aabb(&aabb);
if new_layer_depth > proxy.layer_depth {
self.layers[proxy.layer_id as usize]
.proper_proxy_moved_to_bigger_layer(&mut self.proxies, *proxy_index);
layer_id = self.ensure_layer_exists(new_layer_depth);
self.proxies[*proxy_index].layer_id = layer_id;
self.proxies[*proxy_index].layer_depth = new_layer_depth;
}
}
layer_id
} else {
let layer_depth = super::layer_containing_aabb(&aabb);
let layer_id = self.ensure_layer_exists(layer_depth);
let proxy = SAPProxy::collider(handle, aabb, layer_id, layer_depth);
prev_aabb = aabb;
*proxy_index = self.proxies.insert(proxy);
layer_id
};
let layer = &mut self.layers[layer_id as usize];
let merged_aabbs = prev_aabb.merged(&aabb);
if merged_aabbs.volume() > aabb.volume() * 1.25 {
layer.preupdate_collider(
*proxy_index,
&aabb,
None,
&mut self.proxies,
&mut self.region_pool,
);
layer.preupdate_collider(
*proxy_index,
&prev_aabb,
Some(&aabb),
&mut self.proxies,
&mut self.region_pool,
);
} else {
layer.preupdate_collider(
*proxy_index,
&merged_aabbs,
Some(&aabb),
&mut self.proxies,
&mut self.region_pool,
);
}
let need_region_propagation = !layer.created_regions.is_empty();
need_region_propagation
}
pub fn update(
&mut self,
prediction_distance: Real,
colliders: &mut ColliderSet,
modified_colliders: &[ColliderHandle],
removed_colliders: &[ColliderHandle],
events: &mut Vec<BroadPhasePairEvent>,
) {
self.handle_removed_colliders(removed_colliders);
let mut need_region_propagation = false;
for handle in modified_colliders {
if let Some(co) = colliders.get_mut_internal(*handle) {
if !co.is_enabled() || !co.changes.needs_broad_phase_update() {
continue;
}
let mut new_proxy_id = co.bf_data.proxy_index;
if self.handle_modified_collider(
prediction_distance,
*handle,
&mut new_proxy_id,
(&co.pos, &co.shape, &co.changes),
) {
need_region_propagation = true;
}
if co.bf_data.proxy_index != new_proxy_id {
self.colliders_proxy_ids.insert(*handle, new_proxy_id);
co.bf_data = ColliderBroadPhaseData {
proxy_index: new_proxy_id,
};
}
}
}
if need_region_propagation {
self.propagate_created_regions();
}
self.update_layers_and_find_pairs(events);
self.complete_removals(colliders, removed_colliders);
}
fn propagate_created_regions(&mut self) {
let mut curr_layer = Some(self.smallest_layer);
while let Some(curr_layer_id) = curr_layer {
let layer = &mut self.layers[curr_layer_id as usize];
let larger_layer = layer.larger_layer;
if !layer.created_regions.is_empty() {
if let Some(larger_layer) = larger_layer {
let (layer, larger_layer) = self
.layers
.index_mut2(curr_layer_id as usize, larger_layer as usize);
layer.propagate_created_regions(
larger_layer,
&mut self.proxies,
&mut self.region_pool,
);
layer.created_regions.clear();
} else {
layer.created_regions.clear();
}
}
curr_layer = larger_layer;
}
}
fn update_layers_and_find_pairs(&mut self, out_events: &mut Vec<BroadPhasePairEvent>) {
if self.layers.is_empty() {
return;
}
let mut layer_id = Some(self.largest_layer);
while let Some(curr_layer_id) = layer_id {
self.layers[curr_layer_id as usize]
.update_regions(&mut self.proxies, &mut self.reporting);
layer_id = self.layers[curr_layer_id as usize].smaller_layer;
for ((proxy_id1, proxy_id2), colliding) in &self.reporting {
let (proxy1, proxy2) = self
.proxies
.elements
.index_mut2(*proxy_id1 as usize, *proxy_id2 as usize);
match (&mut proxy1.data, &mut proxy2.data) {
(SAPProxyData::Collider(handle1), SAPProxyData::Collider(handle2)) => {
if *colliding {
out_events.push(BroadPhasePairEvent::AddPair(ColliderPair::new(
*handle1, *handle2,
)));
} else {
out_events.push(BroadPhasePairEvent::DeletePair(ColliderPair::new(
*handle1, *handle2,
)));
}
}
(SAPProxyData::Collider(_), SAPProxyData::Region(_)) => {
if *colliding {
proxy2
.data
.as_region_mut()
.preupdate_proxy(*proxy_id1, false);
}
}
(SAPProxyData::Region(_), SAPProxyData::Collider(_)) => {
if *colliding {
proxy1
.data
.as_region_mut()
.preupdate_proxy(*proxy_id2, false);
}
}
(SAPProxyData::Region(_), SAPProxyData::Region(_)) => {
}
}
}
self.reporting.clear();
}
}
}
#[cfg(test)]
mod test {
use crate::dynamics::{
ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBodyBuilder, RigidBodySet,
};
use crate::geometry::{BroadPhase, ColliderBuilder, ColliderSet};
#[test]
fn test_add_update_remove() {
let mut broad_phase = BroadPhase::new();
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let mut multibody_joints = MultibodyJointSet::new();
let mut islands = IslandManager::new();
let rb = RigidBodyBuilder::dynamic().build();
let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb);
let coh = colliders.insert_with_parent(co, hrb, &mut bodies);
let mut events = Vec::new();
broad_phase.update(0.0, &mut colliders, &[coh], &[], &mut events);
bodies.remove(
hrb,
&mut islands,
&mut colliders,
&mut impulse_joints,
&mut multibody_joints,
true,
);
broad_phase.update(0.0, &mut colliders, &[], &[coh], &mut events);
let rb = RigidBodyBuilder::dynamic().build();
let co = ColliderBuilder::ball(0.5).build();
let hrb = bodies.insert(rb);
let coh = colliders.insert_with_parent(co, hrb, &mut bodies);
broad_phase.update(0.0, &mut colliders, &[coh], &[], &mut events);
}
}