use super::*;
use crate::error::InvalidValueReason;
impl World {
#[inline]
pub fn step(&mut self, time_step: f32, sub_step_count: i32) -> Result<()> {
self.step_outcome(time_step, sub_step_count)?.into_result()
}
pub fn step_outcome(&mut self, time_step: f32, sub_step_count: i32) -> Result<StepOutcome> {
callback_state::check_not_in_callback()?;
validation::nonnegative("world.step.time_step", time_step)?;
if sub_step_count < 0 {
return Err(validation::invalid(
"world.step.sub_step_count",
InvalidValueReason::OutOfRange,
));
}
let next_contact_epoch = self.state.ledger.prepare_contact_turnover()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
let invocation = callback_state::SharedCallbackState::default();
let _invocation_guard = self
.state
.callbacks
.install_invocation(invocation.clone())?;
unsafe { ffi::b3World_Step(self.raw, time_step, sub_step_count) };
self.finish_step_provenance_locked(next_contact_epoch);
Ok(StepOutcome::from_post_step_result(invocation.drain()))
}
#[inline]
pub fn gravity(&self) -> Result<Vec3> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
if !unsafe { ffi::b3World_IsValid(self.raw) } {
return Err(Error::NativeFailure);
}
Ok(Vec3::from_raw(unsafe { ffi::b3World_GetGravity(self.raw) }))
}
#[inline]
pub fn set_gravity(&mut self, gravity: impl Into<Vec3>) -> Result<()> {
callback_state::check_not_in_callback()?;
let gravity = gravity.into();
validation::vec3("world.gravity", gravity)?;
let _guard = box3d_lock::lock();
if !unsafe { ffi::b3World_IsValid(self.raw) } {
return Err(Error::NativeFailure);
}
unsafe { ffi::b3World_SetGravity(self.raw, gravity.into_raw()) };
Ok(())
}
pub fn explode(&mut self, explosion: &ExplosionDef) -> Result<()> {
callback_state::check_not_in_callback()?;
let raw_explosion = explosion.lower()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_Explode(self.raw, &raw_explosion) };
Ok(())
}
#[inline]
pub fn bounds(&self) -> Result<Aabb> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
if !unsafe { ffi::b3World_IsValid(self.raw) } {
return Err(Error::NativeFailure);
}
Ok(Aabb::from_raw(unsafe { ffi::b3World_GetBounds(self.raw) }))
}
#[inline]
pub fn profile(&self) -> Result<Profile> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
if !unsafe { ffi::b3World_IsValid(self.raw) } {
return Err(Error::NativeFailure);
}
Ok(Profile::from_raw(unsafe {
ffi::b3World_GetProfile(self.raw)
}))
}
#[inline]
pub fn counters(&self) -> Result<Counters> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
if !unsafe { ffi::b3World_IsValid(self.raw) } {
return Err(Error::NativeFailure);
}
Ok(Counters::from_raw(unsafe {
ffi::b3World_GetCounters(self.raw)
}))
}
pub fn enable_sleeping(&mut self, enabled: bool) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_EnableSleeping(self.raw, enabled) };
Ok(())
}
pub fn sleeping_enabled(&self) -> Result<bool> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_IsSleepingEnabled(self.raw) })
}
pub fn enable_continuous(&mut self, enabled: bool) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_EnableContinuous(self.raw, enabled) };
Ok(())
}
pub fn continuous_enabled(&self) -> Result<bool> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_IsContinuousEnabled(self.raw) })
}
pub fn set_restitution_threshold(&mut self, value: f32) -> Result<()> {
validation::nonnegative("world.restitution_threshold", value)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetRestitutionThreshold(self.raw, value) };
Ok(())
}
pub fn restitution_threshold(&self) -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetRestitutionThreshold(self.raw) })
}
pub fn set_hit_event_threshold(&mut self, value: f32) -> Result<()> {
validation::nonnegative("world.hit_event_threshold", value)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetHitEventThreshold(self.raw, value) };
Ok(())
}
pub fn hit_event_threshold(&self) -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetHitEventThreshold(self.raw) })
}
pub fn set_contact_tuning(
&mut self,
hertz: f32,
damping_ratio: f32,
contact_speed: f32,
) -> Result<()> {
validation::nonnegative("world.contact_hertz", hertz)?;
validation::nonnegative("world.contact_damping_ratio", damping_ratio)?;
validation::nonnegative("world.contact_speed", contact_speed)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetContactTuning(self.raw, hertz, damping_ratio, contact_speed) };
Ok(())
}
pub fn set_contact_recycle_distance(&mut self, distance: f32) -> Result<()> {
validation::nonnegative("world.contact_recycle_distance", distance)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetContactRecycleDistance(self.raw, distance) };
Ok(())
}
pub fn contact_recycle_distance(&self) -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetContactRecycleDistance(self.raw) })
}
pub fn set_maximum_linear_speed(&mut self, speed: f32) -> Result<()> {
validation::positive("world.maximum_linear_speed", speed)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetMaximumLinearSpeed(self.raw, speed) };
Ok(())
}
pub fn maximum_linear_speed(&self) -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetMaximumLinearSpeed(self.raw) })
}
pub fn enable_warm_starting(&mut self, enabled: bool) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_EnableWarmStarting(self.raw, enabled) };
Ok(())
}
pub fn warm_starting_enabled(&self) -> Result<bool> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_IsWarmStartingEnabled(self.raw) })
}
pub fn enable_speculative(&mut self, enabled: bool) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_EnableSpeculative(self.raw, enabled) };
Ok(())
}
pub fn awake_body_count(&self) -> Result<i32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetAwakeBodyCount(self.raw) })
}
pub fn max_capacity(&self) -> Result<Capacity> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(Capacity::from_raw(unsafe {
ffi::b3World_GetMaxCapacity(self.raw)
}))
}
pub fn set_worker_count(&mut self, count: i32) -> Result<()> {
if count < 0 || count > ffi::B3_MAX_WORKERS as i32 {
return Err(validation::invalid(
"world.worker_count",
InvalidValueReason::OutOfRange,
));
}
#[cfg(target_arch = "wasm32")]
if count > 1 {
return Err(Error::UnsupportedOnWasm);
}
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_SetWorkerCount(self.raw, count) };
Ok(())
}
pub fn worker_count(&self) -> Result<i32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetWorkerCount(self.raw) })
}
pub fn rebuild_static_tree(&mut self) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
unsafe { ffi::b3World_RebuildStaticTree(self.raw) };
Ok(())
}
}