#[cfg(feature = "serialize")]
use bevy::reflect::{ReflectDeserialize, ReflectSerialize};
use bevy::{
ecs::{entity::Entity, resource::Resource},
reflect::Reflect,
};
use crate::{
collision::contact_types::{ContactEdge, ContactGraphInternal, ContactId},
data_structures::bit_vec::BitVec,
prelude::{ContactPair, ContactPairFlags},
};
use super::contact::ContactConstraint;
pub const GRAPH_COLOR_COUNT: usize = 24;
pub const COLOR_OVERFLOW_INDEX: usize = GRAPH_COLOR_COUNT - 1;
pub const DYNAMIC_COLOR_COUNT: usize = GRAPH_COLOR_COUNT - 4;
#[derive(Clone, Debug, Default, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug)]
pub struct GraphColor {
pub body_set: BitVec,
pub manifold_handles: Vec<ContactManifoldHandle>,
pub contact_constraints: Vec<ContactConstraint>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, PartialEq)]
pub struct ContactManifoldHandle {
pub contact_id: ContactId,
pub manifold_index: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, PartialEq)]
pub struct ContactConstraintHandle {
pub color_index: u8,
pub local_index: usize,
}
#[derive(Resource, Clone, Debug, Reflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug)]
pub struct ConstraintGraph {
pub colors: Vec<GraphColor>,
}
impl Default for ConstraintGraph {
fn default() -> Self {
Self::new(16)
}
}
impl ConstraintGraph {
pub fn new(body_capacity: usize) -> Self {
let mut colors = Vec::with_capacity(GRAPH_COLOR_COUNT);
let bit_capacity = body_capacity.max(8);
for _ in 0..GRAPH_COLOR_COUNT {
let mut body_set = BitVec::new(bit_capacity);
body_set.set_bit_count_and_clear(bit_capacity);
colors.push(GraphColor {
body_set,
manifold_handles: Vec::with_capacity(bit_capacity),
contact_constraints: Vec::with_capacity(bit_capacity),
});
}
Self { colors }
}
pub fn push_manifold(&mut self, contact_edge: &mut ContactEdge, contact_pair: &ContactPair) {
let (Some(body1), Some(body2)) = (contact_pair.body1, contact_pair.body2) else {
return;
};
let is_static1 = contact_pair.flags.contains(ContactPairFlags::STATIC1);
let is_static2 = contact_pair.flags.contains(ContactPairFlags::STATIC2);
debug_assert!(!contact_pair.manifolds.is_empty());
debug_assert!(!is_static1 || !is_static2);
let mut color_index = COLOR_OVERFLOW_INDEX;
if !is_static1 && !is_static2 {
for i in 0..DYNAMIC_COLOR_COUNT {
let color = &mut self.colors[i];
if color.body_set.get(body1.index_u32() as usize)
|| color.body_set.get(body2.index_u32() as usize)
{
continue;
}
color.body_set.set_and_grow(body1.index_u32() as usize);
color.body_set.set_and_grow(body2.index_u32() as usize);
color_index = i;
break;
}
} else if !is_static1 {
for i in (1..COLOR_OVERFLOW_INDEX).rev() {
let color = &mut self.colors[i];
if color.body_set.get(body1.index_u32() as usize) {
continue;
}
color.body_set.set_and_grow(body1.index_u32() as usize);
color_index = i;
break;
}
} else if !is_static2 {
for i in (1..COLOR_OVERFLOW_INDEX).rev() {
let color = &mut self.colors[i];
if color.body_set.get(body2.index_u32() as usize) {
continue;
}
color.body_set.set_and_grow(body2.index_u32() as usize);
color_index = i;
break;
}
}
let color = &mut self.colors[color_index];
let manifold_index = contact_edge.constraint_handles.len();
contact_edge
.constraint_handles
.push(ContactConstraintHandle {
color_index: color_index as u8,
local_index: color.manifold_handles.len(),
});
color.manifold_handles.push(ContactManifoldHandle {
contact_id: contact_pair.contact_id,
manifold_index,
});
}
pub fn pop_manifold(
&mut self,
contact_graph: &mut ContactGraphInternal,
contact_id: ContactId,
body1: Entity,
body2: Entity,
) -> Option<ContactConstraintHandle> {
let contact_edge = contact_graph
.edge_weight_mut(contact_id.into())
.unwrap_or_else(|| panic!("Contact edge not found in graph: {contact_id:?}"));
let contact_constraint_handle = contact_edge.constraint_handles.pop()?;
let color_index = contact_constraint_handle.color_index as usize;
let local_index = contact_constraint_handle.local_index;
debug_assert!(color_index < GRAPH_COLOR_COUNT);
let color = &mut self.colors[color_index];
if color_index != COLOR_OVERFLOW_INDEX {
color.body_set.unset(body1.index_u32() as usize);
color.body_set.unset(body2.index_u32() as usize);
}
let moved_index = color.manifold_handles.len() - 1;
color.manifold_handles.swap_remove(local_index);
if moved_index != local_index {
let moved_handle = &mut color.manifold_handles[local_index];
let contact_edge = contact_graph
.edge_weight_mut(moved_handle.contact_id.into())
.unwrap_or_else(|| {
panic!(
"Contact edge not found in graph: {:?}",
moved_handle.contact_id
)
});
let constraint_handle =
&mut contact_edge.constraint_handles[moved_handle.manifold_index];
debug_assert!(constraint_handle.color_index == color_index as u8);
debug_assert!(constraint_handle.local_index == moved_index);
constraint_handle.local_index = local_index;
}
Some(contact_constraint_handle)
}
pub fn clear(&mut self) {
for color in &mut self.colors {
color.body_set.clear();
color.manifold_handles.clear();
color.contact_constraints.clear();
}
}
}