use glam::Vec2;
use crate::{BodyId, ShapeId};
#[derive(Debug)]
pub struct World {
pub id: sys::b2WorldId,
pub dt: f32,
}
impl World {
const SUBSTEPS: i32 = 4;
pub fn new(delta_time: f32) -> Self {
let id = unsafe { sys::b2CreateWorld(&sys::b2DefaultWorldDef()) };
Self { id, dt: delta_time }
}
pub fn dt(&self) -> f32 {
self.dt
}
pub fn step(&self) {
unsafe {
sys::b2World_Step(self.id, self.dt, Self::SUBSTEPS);
}
}
pub fn destroy(self) {
unsafe { sys::b2DestroyWorld(self.id) }
}
pub fn set_gravity(&self, gravity: Vec2) {
unsafe { sys::b2World_SetGravity(self.id, gravity.into()) }
}
pub fn set_length_units_per_meter(&self, ppm: f32) {
unsafe { sys::b2SetLengthUnitsPerMeter(ppm) }
}
pub fn length_units_per_meter(&self) -> f32 {
unsafe { sys::b2GetLengthUnitsPerMeter() }
}
pub fn create_body(&self, body_definition: &crate::BodyDefinition) -> BodyId {
BodyId::create(self, body_definition)
}
pub fn overlap_circle<OverlapFn>(&self, circle_position: Vec2, radius: f32, mut overlap: OverlapFn) -> OverlapStats
where
OverlapFn: FnMut(ShapeId) -> bool,
{
let hit_circle = unsafe { sys::b2MakeProxy(&circle_position as *const Vec2 as *const sys::b2Vec2, 1, radius) };
extern "C" fn overlap_trampoline<OverlapFn>(shape: sys::b2ShapeId, cback: *mut std::ffi::c_void) -> bool
where
OverlapFn: FnMut(ShapeId) -> bool,
{
let cback: &mut OverlapFn = unsafe { &mut *(cback as *mut OverlapFn) };
cback(ShapeId::from_b2(shape))
}
let performance_stats = unsafe {
sys::b2World_OverlapShape(
self.id,
&hit_circle,
sys::b2DefaultQueryFilter(),
Some(overlap_trampoline::<OverlapFn>),
&mut overlap as *mut _ as *mut _,
)
};
unsafe { std::mem::transmute::<sys::b2TreeStats, OverlapStats>(performance_stats) }
}
pub fn contact_events(&self) -> impl Iterator<Item = (BodyId, BodyId)> {
unsafe {
let contact_events = sys::b2World_GetContactEvents(self.id);
let begin_events: &mut [sys::b2ContactBeginTouchEvent] =
std::slice::from_raw_parts_mut(contact_events.beginEvents, contact_events.beginCount as usize);
begin_events.iter_mut().filter_map(|e| {
if !sys::b2Shape_IsValid(e.shapeIdA) || !sys::b2Shape_IsValid(e.shapeIdB) {
None
} else {
Some((
sys::b2Shape_GetBody(e.shapeIdA).into(),
sys::b2Shape_GetBody(e.shapeIdB).into(),
))
}
})
}
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct OverlapStats {
pub node_visits: i32,
pub leaf_visits: i32,
}
static_assertions::assert_eq_size!(sys::b2TreeStats, OverlapStats);
static_assertions::assert_eq_align!(sys::b2TreeStats, OverlapStats);
static_assertions::const_assert_eq!(
std::mem::offset_of!(sys::b2TreeStats, nodeVisits),
std::mem::offset_of!(OverlapStats, node_visits)
);
static_assertions::const_assert_eq!(
std::mem::offset_of!(sys::b2TreeStats, leafVisits),
std::mem::offset_of!(OverlapStats, leaf_visits)
);