use crate::bitset::BitSet;
use crate::constants::GRAPH_COLOR_COUNT;
use crate::contact::ContactSim;
use crate::joint::JointSim;
pub const OVERFLOW_INDEX: i32 = GRAPH_COLOR_COUNT - 1;
pub const DYNAMIC_COLOR_COUNT: i32 = GRAPH_COLOR_COUNT - 4;
#[derive(Debug, Clone, Default)]
pub struct GraphColor {
pub body_set: BitSet,
pub contact_sims: Vec<ContactSim>,
pub joint_sims: Vec<JointSim>,
}
#[derive(Debug, Clone, Default)]
pub struct ConstraintGraph {
pub colors: Vec<GraphColor>,
}
use crate::math_functions::max_int;
use crate::solver_set::AWAKE_SET;
use crate::types::{BodyType, Capacity};
use crate::world::World;
impl ConstraintGraph {
pub fn new(capacity: &Capacity) -> ConstraintGraph {
const _: () = assert!(GRAPH_COLOR_COUNT >= 2, "must have at least two colors");
const _: () = assert!(DYNAMIC_COLOR_COUNT >= 2, "need more dynamic colors");
let body_capacity = max_int(capacity.static_body_count + capacity.dynamic_body_count, 16);
let mut colors = Vec::with_capacity(GRAPH_COLOR_COUNT as usize);
for i in 0..GRAPH_COLOR_COUNT {
let mut color = GraphColor::default();
if i < OVERFLOW_INDEX {
color.body_set = BitSet::new(body_capacity as u32);
color.body_set.set_bit_count_and_clear(body_capacity as u32);
color.contact_sims.reserve(16);
}
colors.push(color);
}
ConstraintGraph { colors }
}
}
pub fn add_contact_to_graph(world: &mut World, contact_sim: ContactSim, contact_id: i32) {
use crate::contact::contact_flags::{SIM_TOUCHING, TOUCHING};
debug_assert!(contact_sim.manifold.point_count > 0);
debug_assert!(contact_sim.sim_flags & SIM_TOUCHING != 0);
debug_assert!(world.contacts[contact_id as usize].flags & TOUCHING != 0);
let mut color_index = OVERFLOW_INDEX;
let (body_id_a, body_id_b) = {
let contact = &world.contacts[contact_id as usize];
(contact.edges[0].body_id, contact.edges[1].body_id)
};
let type_a = world.bodies[body_id_a as usize].type_;
let type_b = world.bodies[body_id_b as usize].type_;
debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
for i in 0..DYNAMIC_COLOR_COUNT {
let color = &mut world.constraint_graph.colors[i as usize];
if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
{
continue;
}
color.body_set.set_bit_grow(body_id_a as u32);
color.body_set.set_bit_grow(body_id_b as u32);
color_index = i;
break;
}
} else if type_a == BodyType::Dynamic {
let mut i = OVERFLOW_INDEX - 1;
while i >= 1 {
let color = &mut world.constraint_graph.colors[i as usize];
if !color.body_set.get_bit(body_id_a as u32) {
color.body_set.set_bit_grow(body_id_a as u32);
color_index = i;
break;
}
i -= 1;
}
} else if type_b == BodyType::Dynamic {
let mut i = OVERFLOW_INDEX - 1;
while i >= 1 {
let color = &mut world.constraint_graph.colors[i as usize];
if !color.body_set.get_bit(body_id_b as u32) {
color.body_set.set_bit_grow(body_id_b as u32);
color_index = i;
break;
}
i -= 1;
}
}
let local_index = world.constraint_graph.colors[color_index as usize]
.contact_sims
.len() as i32;
{
let contact = &mut world.contacts[contact_id as usize];
contact.color_index = color_index;
contact.local_index = local_index;
}
let mut new_contact = contact_sim;
if type_a == BodyType::Static {
new_contact.body_sim_index_a = crate::core::NULL_INDEX;
new_contact.inv_mass_a = 0.0;
new_contact.inv_i_a = 0.0;
} else {
debug_assert!(world.bodies[body_id_a as usize].set_index == AWAKE_SET);
let local = world.bodies[body_id_a as usize].local_index;
new_contact.body_sim_index_a = local;
let body_sim_a = &world.solver_sets[AWAKE_SET as usize].body_sims[local as usize];
new_contact.inv_mass_a = body_sim_a.inv_mass;
new_contact.inv_i_a = body_sim_a.inv_inertia;
}
if type_b == BodyType::Static {
new_contact.body_sim_index_b = crate::core::NULL_INDEX;
new_contact.inv_mass_b = 0.0;
new_contact.inv_i_b = 0.0;
} else {
debug_assert!(world.bodies[body_id_b as usize].set_index == AWAKE_SET);
let local = world.bodies[body_id_b as usize].local_index;
new_contact.body_sim_index_b = local;
let body_sim_b = &world.solver_sets[AWAKE_SET as usize].body_sims[local as usize];
new_contact.inv_mass_b = body_sim_b.inv_mass;
new_contact.inv_i_b = body_sim_b.inv_inertia;
}
world.constraint_graph.colors[color_index as usize]
.contact_sims
.push(new_contact);
}
pub fn remove_contact_from_graph(
world: &mut World,
body_id_a: i32,
body_id_b: i32,
color_index: i32,
local_index: i32,
) {
debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
let color = &mut world.constraint_graph.colors[color_index as usize];
if color_index != OVERFLOW_INDEX {
color.body_set.clear_bit(body_id_a as u32);
color.body_set.clear_bit(body_id_b as u32);
}
let moved_index = color.contact_sims.len() as i32 - 1;
color.contact_sims.swap_remove(local_index as usize);
if moved_index != local_index {
let moved_id = color.contact_sims[local_index as usize].contact_id;
let moved_contact = &mut world.contacts[moved_id as usize];
debug_assert!(moved_contact.set_index == AWAKE_SET);
debug_assert!(moved_contact.color_index == color_index);
debug_assert!(moved_contact.local_index == moved_index);
moved_contact.local_index = local_index;
}
}
fn assign_joint_color(
graph: &mut ConstraintGraph,
body_id_a: i32,
body_id_b: i32,
type_a: BodyType,
type_b: BodyType,
) -> i32 {
debug_assert!(type_a == BodyType::Dynamic || type_b == BodyType::Dynamic);
if type_a == BodyType::Dynamic && type_b == BodyType::Dynamic {
for i in 0..DYNAMIC_COLOR_COUNT {
let color = &mut graph.colors[i as usize];
if color.body_set.get_bit(body_id_a as u32) || color.body_set.get_bit(body_id_b as u32)
{
continue;
}
color.body_set.set_bit_grow(body_id_a as u32);
color.body_set.set_bit_grow(body_id_b as u32);
return i;
}
} else if type_a == BodyType::Dynamic {
let mut i = OVERFLOW_INDEX - 1;
while i >= 1 {
let color = &mut graph.colors[i as usize];
if !color.body_set.get_bit(body_id_a as u32) {
color.body_set.set_bit_grow(body_id_a as u32);
return i;
}
i -= 1;
}
} else if type_b == BodyType::Dynamic {
let mut i = OVERFLOW_INDEX - 1;
while i >= 1 {
let color = &mut graph.colors[i as usize];
if !color.body_set.get_bit(body_id_b as u32) {
color.body_set.set_bit_grow(body_id_b as u32);
return i;
}
i -= 1;
}
}
OVERFLOW_INDEX
}
pub fn create_joint_in_graph(world: &mut World, joint_id: i32) -> (i32, i32) {
let (body_id_a, body_id_b) = {
let joint = &world.joints[joint_id as usize];
(joint.edges[0].body_id, joint.edges[1].body_id)
};
let type_a = world.bodies[body_id_a as usize].type_;
let type_b = world.bodies[body_id_b as usize].type_;
let color_index = assign_joint_color(
&mut world.constraint_graph,
body_id_a,
body_id_b,
type_a,
type_b,
);
world.constraint_graph.colors[color_index as usize]
.joint_sims
.push(JointSim::default());
let local_index = world.constraint_graph.colors[color_index as usize]
.joint_sims
.len() as i32
- 1;
let joint = &mut world.joints[joint_id as usize];
joint.color_index = color_index;
joint.local_index = local_index;
(color_index, local_index)
}
pub fn add_joint_to_graph(world: &mut World, joint_sim: JointSim, joint_id: i32) {
let (color_index, local_index) = create_joint_in_graph(world, joint_id);
world.constraint_graph.colors[color_index as usize].joint_sims[local_index as usize] =
joint_sim;
}
pub fn remove_joint_from_graph(
world: &mut World,
body_id_a: i32,
body_id_b: i32,
color_index: i32,
local_index: i32,
) {
debug_assert!((0..GRAPH_COLOR_COUNT).contains(&color_index));
let color = &mut world.constraint_graph.colors[color_index as usize];
if color_index != OVERFLOW_INDEX {
color.body_set.clear_bit(body_id_a as u32);
color.body_set.clear_bit(body_id_b as u32);
}
let moved_index = color.joint_sims.len() as i32 - 1;
color.joint_sims.swap_remove(local_index as usize);
if moved_index != local_index {
let moved_id = color.joint_sims[local_index as usize].joint_id;
let moved_joint = &mut world.joints[moved_id as usize];
debug_assert!(moved_joint.set_index == AWAKE_SET);
debug_assert!(moved_joint.color_index == color_index);
debug_assert!(moved_joint.local_index == moved_index);
moved_joint.local_index = local_index;
}
}
const GRAPH_COLORS: [crate::debug_draw::HexColor; GRAPH_COLOR_COUNT as usize] = {
use crate::debug_draw::HexColor;
[
HexColor::RED,
HexColor::ORANGE,
HexColor::YELLOW,
HexColor::LIME_GREEN,
HexColor::SPRING_GREEN,
HexColor::AQUA,
HexColor::DODGER_BLUE,
HexColor::BLUE_VIOLET,
HexColor::MAGENTA,
HexColor::DEEP_PINK,
HexColor::CRIMSON,
HexColor::CORAL,
HexColor::GOLD,
HexColor::GREEN_YELLOW,
HexColor::MEDIUM_SEA_GREEN,
HexColor::TURQUOISE,
HexColor::DEEP_SKY_BLUE,
HexColor::CORNFLOWER_BLUE,
HexColor::MEDIUM_SLATE_BLUE,
HexColor::MEDIUM_ORCHID,
HexColor::HOT_PINK,
HexColor::TOMATO,
HexColor::KHAKI,
HexColor::SILVER,
]
};
pub fn get_graph_color(index: i32) -> crate::debug_draw::HexColor {
debug_assert!((0..GRAPH_COLOR_COUNT).contains(&index));
GRAPH_COLORS[index as usize]
}