use super::body_flags;
use super::lifecycle::{
create_island_for_body, destroy_body_contacts, get_body_full_id, get_body_transform_quick,
remove_body_from_island, sync_body_flags, wake_body,
};
use super::mass::update_body_mass_data;
use crate::core::NULL_INDEX;
use crate::geometry::ShapeType;
use crate::id::BodyId;
use crate::island::{link_joint, unlink_joint, validate_island};
use crate::shape::{create_shape_proxy, destroy_shape_proxy};
use crate::solver_set::{transfer_body, transfer_joint, AWAKE_SET, DISABLED_SET, STATIC_SET};
use crate::types::BodyType;
use crate::world::World;
pub fn body_set_type(world: &mut World, body_id: BodyId, type_: BodyType) {
crate::recording::with_recording(world, |rec| {
rec.write_body_set_type(body_id, type_ as i32);
});
debug_assert!(!world.locked);
if world.locked {
return;
}
world.locked = true;
let body_index = get_body_full_id(world, body_id);
let original_type = world.bodies[body_index as usize].type_;
if original_type == type_ {
world.locked = false;
return;
}
if type_ != BodyType::Static {
let mut shape_id = world.bodies[body_index as usize].head_shape_id;
while shape_id != NULL_INDEX {
let shape = &world.shapes[shape_id as usize];
if shape.shape_type() == ShapeType::Compound || shape.shape_type() == ShapeType::Height
{
world.locked = false;
return;
}
shape_id = shape.next_shape_id;
}
}
if world.bodies[body_index as usize].set_index == DISABLED_SET {
world.bodies[body_index as usize].type_ = type_;
if type_ == BodyType::Dynamic {
world.bodies[body_index as usize].flags |= body_flags::DYNAMIC_FLAG;
} else {
world.bodies[body_index as usize].flags &= !body_flags::DYNAMIC_FLAG;
}
sync_body_flags(world, body_index);
update_body_mass_data(world, body_index);
world.locked = false;
return;
}
destroy_body_contacts(world, body_index, false);
wake_body(world, body_index);
let mut joint_key = world.bodies[body_index as usize].head_joint_key;
while joint_key != NULL_INDEX {
let joint_id = joint_key >> 1;
let edge_index = joint_key & 1;
joint_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
if world.joints[joint_id as usize].set_index == DISABLED_SET {
continue;
}
let body_a = world.joints[joint_id as usize].edges[0].body_id;
let body_b = world.joints[joint_id as usize].edges[1].body_id;
wake_body(world, body_a);
wake_body(world, body_b);
unlink_joint(world, joint_id);
let joint_source_set = world.joints[joint_id as usize].set_index;
transfer_joint(world, STATIC_SET, joint_source_set, joint_id);
}
world.bodies[body_index as usize].type_ = type_;
if type_ == BodyType::Dynamic {
world.bodies[body_index as usize].flags |= body_flags::DYNAMIC_FLAG;
} else {
world.bodies[body_index as usize].flags &= !body_flags::DYNAMIC_FLAG;
}
let source_set = world.bodies[body_index as usize].set_index;
let target_set = if type_ == BodyType::Static {
STATIC_SET
} else {
AWAKE_SET
};
transfer_body(world, target_set, source_set, body_index);
if original_type == BodyType::Static {
create_island_for_body(world, AWAKE_SET, body_index);
} else if type_ == BodyType::Static {
remove_body_from_island(world, body_index);
}
joint_key = world.bodies[body_index as usize].head_joint_key;
while joint_key != NULL_INDEX {
let joint_id = joint_key >> 1;
let edge_index = joint_key & 1;
joint_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
if world.joints[joint_id as usize].set_index == DISABLED_SET {
continue;
}
debug_assert!(world.joints[joint_id as usize].set_index == STATIC_SET);
let body_a = world.joints[joint_id as usize].edges[0].body_id;
let body_b = world.joints[joint_id as usize].edges[1].body_id;
debug_assert!(
world.bodies[body_a as usize].set_index == STATIC_SET
|| world.bodies[body_a as usize].set_index == AWAKE_SET
);
debug_assert!(
world.bodies[body_b as usize].set_index == STATIC_SET
|| world.bodies[body_b as usize].set_index == AWAKE_SET
);
if world.bodies[body_a as usize].type_ == BodyType::Dynamic
|| world.bodies[body_b as usize].type_ == BodyType::Dynamic
{
transfer_joint(world, AWAKE_SET, STATIC_SET, joint_id);
}
}
let transform = get_body_transform_quick(world, &world.bodies[body_index as usize]);
let mut shape_id = world.bodies[body_index as usize].head_shape_id;
while shape_id != NULL_INDEX {
let next_shape_id = world.shapes[shape_id as usize].next_shape_id;
debug_assert!(world.shapes[shape_id as usize].shape_type() != ShapeType::Compound);
{
let (shapes, broad_phase) = (&mut world.shapes, &mut world.broad_phase);
destroy_shape_proxy(&mut shapes[shape_id as usize], broad_phase);
create_shape_proxy(
&mut shapes[shape_id as usize],
broad_phase,
type_,
transform,
true,
);
}
shape_id = next_shape_id;
}
joint_key = world.bodies[body_index as usize].head_joint_key;
while joint_key != NULL_INDEX {
let joint_id = joint_key >> 1;
let edge_index = joint_key & 1;
joint_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
let other_edge_index = edge_index ^ 1;
let other_body_id =
world.joints[joint_id as usize].edges[other_edge_index as usize].body_id;
if world.bodies[other_body_id as usize].set_index == DISABLED_SET {
continue;
}
if world.bodies[body_index as usize].type_ != BodyType::Dynamic
&& world.bodies[other_body_id as usize].type_ != BodyType::Dynamic
{
continue;
}
link_joint(world, joint_id);
}
sync_body_flags(world, body_index);
update_body_mass_data(world, body_index);
world.validate_solver_sets();
let island_id = world.bodies[body_index as usize].island_id;
validate_island(world, island_id);
world.locked = false;
}
pub fn body_disable(world: &mut World, body_id: BodyId) {
crate::recording::with_recording(world, |rec| {
rec.write_body_disable(body_id);
});
debug_assert!(!world.locked);
if world.locked {
return;
}
world.locked = true;
let body_index = get_body_full_id(world, body_id);
if world.bodies[body_index as usize].set_index == DISABLED_SET {
world.locked = false;
return;
}
destroy_body_contacts(world, body_index, true);
let set_index = world.bodies[body_index as usize].set_index;
let mut joint_key = world.bodies[body_index as usize].head_joint_key;
while joint_key != NULL_INDEX {
let joint_id = joint_key >> 1;
let edge_index = joint_key & 1;
joint_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
if world.joints[joint_id as usize].set_index == DISABLED_SET {
continue;
}
debug_assert!(
world.joints[joint_id as usize].set_index == set_index || set_index == STATIC_SET
);
unlink_joint(world, joint_id);
let joint_set = world.joints[joint_id as usize].set_index;
transfer_joint(world, DISABLED_SET, joint_set, joint_id);
}
let mut shape_id = world.bodies[body_index as usize].head_shape_id;
while shape_id != NULL_INDEX {
let next_shape_id = world.shapes[shape_id as usize].next_shape_id;
{
let (shapes, broad_phase) = (&mut world.shapes, &mut world.broad_phase);
destroy_shape_proxy(&mut shapes[shape_id as usize], broad_phase);
}
shape_id = next_shape_id;
}
remove_body_from_island(world, body_index);
transfer_body(world, DISABLED_SET, set_index, body_index);
world.validate_solver_sets();
world.locked = false;
}
pub fn body_enable(world: &mut World, body_id: BodyId) {
crate::recording::with_recording(world, |rec| {
rec.write_body_enable(body_id);
});
debug_assert!(!world.locked);
if world.locked {
return;
}
let body_index = get_body_full_id(world, body_id);
if world.bodies[body_index as usize].set_index != DISABLED_SET {
return;
}
let set_id = if world.bodies[body_index as usize].type_ == BodyType::Static {
STATIC_SET
} else {
AWAKE_SET
};
transfer_body(world, set_id, DISABLED_SET, body_index);
let transform = get_body_transform_quick(world, &world.bodies[body_index as usize]);
let proxy_type = world.bodies[body_index as usize].type_;
let mut shape_id = world.bodies[body_index as usize].head_shape_id;
while shape_id != NULL_INDEX {
let next_shape_id = world.shapes[shape_id as usize].next_shape_id;
{
let (shapes, broad_phase) = (&mut world.shapes, &mut world.broad_phase);
create_shape_proxy(
&mut shapes[shape_id as usize],
broad_phase,
proxy_type,
transform,
true,
);
}
shape_id = next_shape_id;
}
if set_id != STATIC_SET {
create_island_for_body(world, set_id, body_index);
}
let mut joint_key = world.bodies[body_index as usize].head_joint_key;
while joint_key != NULL_INDEX {
let joint_id = joint_key >> 1;
let edge_index = joint_key & 1;
debug_assert!(world.joints[joint_id as usize].set_index == DISABLED_SET);
debug_assert!(world.joints[joint_id as usize].island_id == NULL_INDEX);
joint_key = world.joints[joint_id as usize].edges[edge_index as usize].next_key;
let body_a = world.joints[joint_id as usize].edges[0].body_id;
let body_b = world.joints[joint_id as usize].edges[1].body_id;
if world.bodies[body_a as usize].set_index == DISABLED_SET
|| world.bodies[body_b as usize].set_index == DISABLED_SET
{
continue;
}
let joint_set_id = if world.bodies[body_a as usize].set_index == STATIC_SET
&& world.bodies[body_b as usize].set_index == STATIC_SET
{
STATIC_SET
} else if world.bodies[body_a as usize].set_index == STATIC_SET {
world.bodies[body_b as usize].set_index
} else {
world.bodies[body_a as usize].set_index
};
transfer_joint(world, joint_set_id, DISABLED_SET, joint_id);
if joint_set_id != STATIC_SET {
link_joint(world, joint_id);
}
}
world.validate_solver_sets();
}