use std::marker::PhantomData;
pub mod chain;
pub mod helpers;
use crate::body::Body;
use crate::error::ApiResult;
use crate::filter::Filter;
use crate::types::{BodyId, ChainId, ShapeId, Vec2};
use crate::world::World;
use boxdd_sys::ffi;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::Arc;
pub struct Shape<'w> {
pub(crate) id: ShapeId,
#[allow(dead_code)]
pub(crate) core: Arc<crate::core::world_core::WorldCore>,
_world: PhantomData<&'w World>,
}
pub struct OwnedShape {
id: ShapeId,
core: Arc<crate::core::world_core::WorldCore>,
destroy_on_drop: bool,
update_body_mass_on_drop: bool,
_not_send: PhantomData<Rc<()>>,
}
impl OwnedShape {
pub(crate) fn new(core: Arc<crate::core::world_core::WorldCore>, id: ShapeId) -> Self {
core.owned_shapes
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self {
id,
core,
destroy_on_drop: true,
update_body_mass_on_drop: true,
_not_send: PhantomData,
}
}
pub fn id(&self) -> ShapeId {
self.id
}
pub fn world_id(&self) -> ffi::b2WorldId {
self.assert_valid();
unsafe { ffi::b2Shape_GetWorld(self.id) }
}
pub fn try_world_id(&self) -> ApiResult<ffi::b2WorldId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetWorld(self.id) })
}
pub fn parent_chain_id(&self) -> Option<ChainId> {
self.assert_valid();
let cid = unsafe { ffi::b2Shape_GetParentChain(self.id) };
if unsafe { ffi::b2Chain_IsValid(cid) } {
Some(cid)
} else {
None
}
}
pub fn try_parent_chain_id(&self) -> ApiResult<Option<ChainId>> {
self.check_valid()?;
let cid = unsafe { ffi::b2Shape_GetParentChain(self.id) };
if unsafe { ffi::b2Chain_IsValid(cid) } {
Ok(Some(cid))
} else {
Ok(None)
}
}
pub fn is_valid(&self) -> bool {
crate::core::callback_state::assert_not_in_callback();
unsafe { ffi::b2Shape_IsValid(self.id) }
}
pub fn try_is_valid(&self) -> ApiResult<bool> {
crate::core::callback_state::check_not_in_callback()?;
Ok(unsafe { ffi::b2Shape_IsValid(self.id) })
}
#[inline]
fn assert_valid(&self) {
crate::core::debug_checks::assert_shape_valid(self.id);
}
#[inline]
fn check_valid(&self) -> ApiResult<()> {
crate::core::debug_checks::check_shape_valid(self.id)
}
pub fn as_id(&self) -> ShapeId {
self.id
}
pub fn is_sensor(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Shape_IsSensor(self.id) }
}
pub fn try_is_sensor(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_IsSensor(self.id) })
}
pub fn shape_type(&self) -> ffi::b2ShapeType {
self.assert_valid();
unsafe { ffi::b2Shape_GetType(self.id) }
}
pub fn try_shape_type(&self) -> ApiResult<ffi::b2ShapeType> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetType(self.id) })
}
pub fn body_id(&self) -> BodyId {
self.assert_valid();
unsafe { ffi::b2Shape_GetBody(self.id) }
}
pub fn try_body_id(&self) -> ApiResult<BodyId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetBody(self.id) })
}
pub fn circle(&self) -> ffi::b2Circle {
self.assert_valid();
unsafe { ffi::b2Shape_GetCircle(self.id) }
}
pub fn segment(&self) -> ffi::b2Segment {
self.assert_valid();
unsafe { ffi::b2Shape_GetSegment(self.id) }
}
pub fn capsule(&self) -> ffi::b2Capsule {
self.assert_valid();
unsafe { ffi::b2Shape_GetCapsule(self.id) }
}
pub fn polygon(&self) -> ffi::b2Polygon {
self.assert_valid();
unsafe { ffi::b2Shape_GetPolygon(self.id) }
}
pub fn closest_point<V: Into<Vec2>>(&self, target: V) -> Vec2 {
self.assert_valid();
let t: ffi::b2Vec2 = target.into().into();
Vec2::from(unsafe { ffi::b2Shape_GetClosestPoint(self.id, t) })
}
pub fn try_closest_point<V: Into<Vec2>>(&self, target: V) -> ApiResult<Vec2> {
self.check_valid()?;
let t: ffi::b2Vec2 = target.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Shape_GetClosestPoint(self.id, t)
}))
}
pub fn apply_wind<V: Into<Vec2>>(&mut self, wind: V, drag: f32, lift: f32, wake: bool) {
self.assert_valid();
let w: ffi::b2Vec2 = wind.into().into();
unsafe { ffi::b2Shape_ApplyWind(self.id, w, drag, lift, wake) }
}
pub fn try_apply_wind<V: Into<Vec2>>(
&mut self,
wind: V,
drag: f32,
lift: f32,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let w: ffi::b2Vec2 = wind.into().into();
unsafe { ffi::b2Shape_ApplyWind(self.id, w, drag, lift, wake) }
Ok(())
}
pub fn set_circle(&mut self, c: &ffi::b2Circle) {
self.assert_valid();
unsafe { ffi::b2Shape_SetCircle(self.id, c) }
}
pub fn try_set_circle(&mut self, c: &ffi::b2Circle) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetCircle(self.id, c) }
Ok(())
}
pub fn set_segment(&mut self, s: &ffi::b2Segment) {
self.assert_valid();
unsafe { ffi::b2Shape_SetSegment(self.id, s) }
}
pub fn try_set_segment(&mut self, s: &ffi::b2Segment) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetSegment(self.id, s) }
Ok(())
}
pub fn set_capsule(&mut self, c: &ffi::b2Capsule) {
self.assert_valid();
unsafe { ffi::b2Shape_SetCapsule(self.id, c) }
}
pub fn try_set_capsule(&mut self, c: &ffi::b2Capsule) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetCapsule(self.id, c) }
Ok(())
}
pub fn set_polygon(&mut self, p: &ffi::b2Polygon) {
self.assert_valid();
unsafe { ffi::b2Shape_SetPolygon(self.id, p) }
}
pub fn try_set_polygon(&mut self, p: &ffi::b2Polygon) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetPolygon(self.id, p) }
Ok(())
}
pub fn filter(&self) -> Filter {
self.assert_valid();
Filter::from(unsafe { ffi::b2Shape_GetFilter(self.id) })
}
pub fn try_filter(&self) -> ApiResult<Filter> {
self.check_valid()?;
Ok(Filter::from(unsafe { ffi::b2Shape_GetFilter(self.id) }))
}
pub fn set_filter(&mut self, f: Filter) {
self.assert_valid();
unsafe { ffi::b2Shape_SetFilter(self.id, f.into()) }
}
pub fn try_set_filter(&mut self, f: Filter) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetFilter(self.id, f.into()) }
Ok(())
}
pub fn set_density(&mut self, density: f32, update_body_mass: bool) {
self.assert_valid();
unsafe { ffi::b2Shape_SetDensity(self.id, density, update_body_mass) }
}
pub fn try_set_density(&mut self, density: f32, update_body_mass: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetDensity(self.id, density, update_body_mass) }
Ok(())
}
pub fn density(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetDensity(self.id) }
}
pub fn try_density(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetDensity(self.id) })
}
pub fn set_friction(&mut self, friction: f32) {
self.assert_valid();
unsafe { ffi::b2Shape_SetFriction(self.id, friction) }
}
pub fn try_set_friction(&mut self, friction: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetFriction(self.id, friction) }
Ok(())
}
pub fn friction(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetFriction(self.id) }
}
pub fn try_friction(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetFriction(self.id) })
}
pub fn set_restitution(&mut self, restitution: f32) {
self.assert_valid();
unsafe { ffi::b2Shape_SetRestitution(self.id, restitution) }
}
pub fn try_set_restitution(&mut self, restitution: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetRestitution(self.id, restitution) }
Ok(())
}
pub fn restitution(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetRestitution(self.id) }
}
pub fn try_restitution(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetRestitution(self.id) })
}
pub fn set_user_material(&mut self, material: u64) {
self.assert_valid();
unsafe { ffi::b2Shape_SetUserMaterial(self.id, material) }
}
pub fn try_set_user_material(&mut self, material: u64) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetUserMaterial(self.id, material) }
Ok(())
}
pub fn user_material(&self) -> u64 {
self.assert_valid();
unsafe { ffi::b2Shape_GetUserMaterial(self.id) }
}
pub fn try_user_material(&self) -> ApiResult<u64> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetUserMaterial(self.id) })
}
pub fn set_surface_material(&mut self, material: &SurfaceMaterial) {
self.assert_valid();
unsafe { ffi::b2Shape_SetSurfaceMaterial(self.id, &material.0) }
}
pub fn try_set_surface_material(&mut self, material: &SurfaceMaterial) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetSurfaceMaterial(self.id, &material.0) }
Ok(())
}
pub fn surface_material(&self) -> SurfaceMaterial {
self.assert_valid();
SurfaceMaterial(unsafe { ffi::b2Shape_GetSurfaceMaterial(self.id) })
}
pub fn try_surface_material(&self) -> ApiResult<SurfaceMaterial> {
self.check_valid()?;
Ok(SurfaceMaterial(unsafe {
ffi::b2Shape_GetSurfaceMaterial(self.id)
}))
}
pub fn contact_data(&self) -> Vec<ffi::b2ContactData> {
self.assert_valid();
let cap = unsafe { ffi::b2Shape_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Vec::new();
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Shape_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
vec
}
pub fn try_contact_data(&self) -> ApiResult<Vec<ffi::b2ContactData>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Shape_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Ok(Vec::new());
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Shape_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
Ok(vec)
}
pub fn sensor_capacity(&self) -> i32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetSensorCapacity(self.id) }
}
pub fn try_sensor_capacity(&self) -> ApiResult<i32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetSensorCapacity(self.id) })
}
pub fn sensor_overlaps(&self) -> Vec<ShapeId> {
self.assert_valid();
let cap = self.sensor_capacity();
if cap <= 0 {
return Vec::new();
}
let mut ids: Vec<ShapeId> = Vec::with_capacity(cap as usize);
let wrote =
unsafe { ffi::b2Shape_GetSensorData(self.id, ids.as_mut_ptr(), cap) }.max(0) as usize;
unsafe { ids.set_len(wrote.min(cap as usize)) };
ids
}
pub fn try_sensor_overlaps(&self) -> ApiResult<Vec<ShapeId>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Shape_GetSensorCapacity(self.id) };
if cap <= 0 {
return Ok(Vec::new());
}
let mut ids: Vec<ShapeId> = Vec::with_capacity(cap as usize);
let wrote =
unsafe { ffi::b2Shape_GetSensorData(self.id, ids.as_mut_ptr(), cap) }.max(0) as usize;
unsafe { ids.set_len(wrote.min(cap as usize)) };
Ok(ids)
}
pub fn sensor_overlaps_valid(&self) -> Vec<ShapeId> {
self.sensor_overlaps()
.into_iter()
.filter(|&sid| unsafe { ffi::b2Shape_IsValid(sid) })
.collect()
}
pub unsafe fn set_user_data_ptr(&mut self, p: *mut c_void) {
self.assert_valid();
let _ = self.core.clear_shape_user_data(self.id);
unsafe { ffi::b2Shape_SetUserData(self.id, p) }
}
pub unsafe fn try_set_user_data_ptr(&mut self, p: *mut c_void) -> ApiResult<()> {
self.check_valid()?;
let _ = self.core.clear_shape_user_data(self.id);
unsafe { ffi::b2Shape_SetUserData(self.id, p) }
Ok(())
}
pub fn user_data_ptr(&self) -> *mut c_void {
self.assert_valid();
unsafe { ffi::b2Shape_GetUserData(self.id) }
}
pub fn try_user_data_ptr(&self) -> ApiResult<*mut c_void> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetUserData(self.id) })
}
pub fn set_user_data<T: 'static>(&mut self, value: T) {
self.assert_valid();
let p = self.core.set_shape_user_data(self.id, value);
unsafe { ffi::b2Shape_SetUserData(self.id, p) };
}
pub fn try_set_user_data<T: 'static>(&mut self, value: T) -> ApiResult<()> {
self.check_valid()?;
let p = self.core.set_shape_user_data(self.id, value);
unsafe { ffi::b2Shape_SetUserData(self.id, p) };
Ok(())
}
pub fn clear_user_data(&mut self) -> bool {
self.assert_valid();
let had = self.core.clear_shape_user_data(self.id);
if had {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
had
}
pub fn try_clear_user_data(&mut self) -> ApiResult<bool> {
self.check_valid()?;
let had = self.core.clear_shape_user_data(self.id);
if had {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(had)
}
pub fn with_user_data<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_shape_user_data(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data<T: 'static, R>(
&self,
f: impl FnOnce(&T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_shape_user_data(self.id, f)
}
pub fn with_user_data_mut<T: 'static, R>(&mut self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_shape_user_data_mut(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data_mut<T: 'static, R>(
&mut self,
f: impl FnOnce(&mut T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_shape_user_data_mut(self.id, f)
}
pub fn take_user_data<T: 'static>(&mut self) -> Option<T> {
self.assert_valid();
let v = self
.core
.take_shape_user_data::<T>(self.id)
.expect("user data type mismatch");
if v.is_some() {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
v
}
pub fn try_take_user_data<T: 'static>(&mut self) -> ApiResult<Option<T>> {
self.check_valid()?;
let v = self.core.take_shape_user_data::<T>(self.id)?;
if v.is_some() {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(v)
}
pub fn update_body_mass_on_drop(mut self, flag: bool) -> Self {
self.update_body_mass_on_drop = flag;
self
}
pub fn into_id(mut self) -> ShapeId {
self.destroy_on_drop = false;
self.id
}
pub fn destroy(mut self, update_body_mass: bool) {
if self.destroy_on_drop && unsafe { ffi::b2Shape_IsValid(self.id) } {
if crate::core::callback_state::in_callback() || self.core.events_buffers_are_borrowed()
{
self.core
.defer_destroy(crate::core::world_core::DeferredDestroy::Shape {
id: self.id,
update_body_mass,
});
} else {
unsafe { ffi::b2DestroyShape(self.id, update_body_mass) };
let _ = self.core.clear_shape_user_data(self.id);
#[cfg(feature = "serialize")]
self.core.remove_shape_flags(self.id);
}
}
self.destroy_on_drop = false;
}
}
impl Drop for OwnedShape {
fn drop(&mut self) {
let _ = self.core.id;
let prev = self
.core
.owned_shapes
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
debug_assert!(prev > 0, "owned shape counter underflow");
if self.destroy_on_drop && unsafe { ffi::b2Shape_IsValid(self.id) } {
if crate::core::callback_state::in_callback() || self.core.events_buffers_are_borrowed()
{
self.core
.defer_destroy(crate::core::world_core::DeferredDestroy::Shape {
id: self.id,
update_body_mass: self.update_body_mass_on_drop,
});
} else {
unsafe { ffi::b2DestroyShape(self.id, self.update_body_mass_on_drop) };
let _ = self.core.clear_shape_user_data(self.id);
#[cfg(feature = "serialize")]
self.core.remove_shape_flags(self.id);
}
}
}
}
impl<'w> Shape<'w> {
pub(crate) fn new(core: Arc<crate::core::world_core::WorldCore>, id: ShapeId) -> Self {
Self {
id,
core,
_world: PhantomData,
}
}
#[inline]
fn assert_valid(&self) {
crate::core::debug_checks::assert_shape_valid(self.id);
}
#[inline]
fn check_valid(&self) -> ApiResult<()> {
crate::core::debug_checks::check_shape_valid(self.id)
}
pub fn id(&self) -> ShapeId {
self.id
}
pub fn world_id(&self) -> ffi::b2WorldId {
self.assert_valid();
unsafe { ffi::b2Shape_GetWorld(self.id) }
}
pub fn try_world_id(&self) -> ApiResult<ffi::b2WorldId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetWorld(self.id) })
}
pub fn parent_chain_id(&self) -> Option<ChainId> {
self.assert_valid();
let cid = unsafe { ffi::b2Shape_GetParentChain(self.id) };
if unsafe { ffi::b2Chain_IsValid(cid) } {
Some(cid)
} else {
None
}
}
pub fn try_parent_chain_id(&self) -> ApiResult<Option<ChainId>> {
self.check_valid()?;
let cid = unsafe { ffi::b2Shape_GetParentChain(self.id) };
if unsafe { ffi::b2Chain_IsValid(cid) } {
Ok(Some(cid))
} else {
Ok(None)
}
}
pub fn is_valid(&self) -> bool {
crate::core::callback_state::assert_not_in_callback();
unsafe { ffi::b2Shape_IsValid(self.id) }
}
pub fn try_is_valid(&self) -> ApiResult<bool> {
crate::core::callback_state::check_not_in_callback()?;
Ok(unsafe { ffi::b2Shape_IsValid(self.id) })
}
pub fn shape_type(&self) -> ffi::b2ShapeType {
self.assert_valid();
unsafe { ffi::b2Shape_GetType(self.id) }
}
pub fn try_shape_type(&self) -> ApiResult<ffi::b2ShapeType> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetType(self.id) })
}
pub fn body_id(&self) -> BodyId {
self.assert_valid();
unsafe { ffi::b2Shape_GetBody(self.id) }
}
pub fn try_body_id(&self) -> ApiResult<BodyId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetBody(self.id) })
}
pub fn circle(&self) -> ffi::b2Circle {
self.assert_valid();
unsafe { ffi::b2Shape_GetCircle(self.id) }
}
pub fn segment(&self) -> ffi::b2Segment {
self.assert_valid();
unsafe { ffi::b2Shape_GetSegment(self.id) }
}
pub fn capsule(&self) -> ffi::b2Capsule {
self.assert_valid();
unsafe { ffi::b2Shape_GetCapsule(self.id) }
}
pub fn polygon(&self) -> ffi::b2Polygon {
self.assert_valid();
unsafe { ffi::b2Shape_GetPolygon(self.id) }
}
pub fn closest_point<V: Into<Vec2>>(&self, target: V) -> Vec2 {
self.assert_valid();
let t: ffi::b2Vec2 = target.into().into();
Vec2::from(unsafe { ffi::b2Shape_GetClosestPoint(self.id, t) })
}
pub fn try_closest_point<V: Into<Vec2>>(&self, target: V) -> ApiResult<Vec2> {
self.check_valid()?;
let t: ffi::b2Vec2 = target.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Shape_GetClosestPoint(self.id, t)
}))
}
pub fn apply_wind<V: Into<Vec2>>(&mut self, wind: V, drag: f32, lift: f32, wake: bool) {
self.assert_valid();
let w: ffi::b2Vec2 = wind.into().into();
unsafe { ffi::b2Shape_ApplyWind(self.id, w, drag, lift, wake) }
}
pub fn try_apply_wind<V: Into<Vec2>>(
&mut self,
wind: V,
drag: f32,
lift: f32,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let w: ffi::b2Vec2 = wind.into().into();
unsafe { ffi::b2Shape_ApplyWind(self.id, w, drag, lift, wake) }
Ok(())
}
pub fn set_circle(&mut self, c: &ffi::b2Circle) {
self.assert_valid();
unsafe { ffi::b2Shape_SetCircle(self.id, c) }
}
pub fn try_set_circle(&mut self, c: &ffi::b2Circle) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetCircle(self.id, c) }
Ok(())
}
pub fn set_segment(&mut self, s: &ffi::b2Segment) {
self.assert_valid();
unsafe { ffi::b2Shape_SetSegment(self.id, s) }
}
pub fn try_set_segment(&mut self, s: &ffi::b2Segment) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetSegment(self.id, s) }
Ok(())
}
pub fn set_capsule(&mut self, c: &ffi::b2Capsule) {
self.assert_valid();
unsafe { ffi::b2Shape_SetCapsule(self.id, c) }
}
pub fn try_set_capsule(&mut self, c: &ffi::b2Capsule) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetCapsule(self.id, c) }
Ok(())
}
pub fn set_polygon(&mut self, p: &ffi::b2Polygon) {
self.assert_valid();
unsafe { ffi::b2Shape_SetPolygon(self.id, p) }
}
pub fn try_set_polygon(&mut self, p: &ffi::b2Polygon) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetPolygon(self.id, p) }
Ok(())
}
pub fn filter(&self) -> Filter {
self.assert_valid();
Filter::from(unsafe { ffi::b2Shape_GetFilter(self.id) })
}
pub fn try_filter(&self) -> ApiResult<Filter> {
self.check_valid()?;
Ok(Filter::from(unsafe { ffi::b2Shape_GetFilter(self.id) }))
}
pub fn set_filter(&mut self, f: Filter) {
self.assert_valid();
unsafe { ffi::b2Shape_SetFilter(self.id, f.into()) }
}
pub fn try_set_filter(&mut self, f: Filter) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetFilter(self.id, f.into()) }
Ok(())
}
pub fn is_sensor(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Shape_IsSensor(self.id) }
}
pub fn try_is_sensor(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_IsSensor(self.id) })
}
pub fn set_density(&mut self, density: f32, update_body_mass: bool) {
self.assert_valid();
unsafe { ffi::b2Shape_SetDensity(self.id, density, update_body_mass) }
}
pub fn try_set_density(&mut self, density: f32, update_body_mass: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetDensity(self.id, density, update_body_mass) }
Ok(())
}
pub fn density(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetDensity(self.id) }
}
pub fn try_density(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetDensity(self.id) })
}
pub fn set_friction(&mut self, friction: f32) {
self.assert_valid();
unsafe { ffi::b2Shape_SetFriction(self.id, friction) }
}
pub fn try_set_friction(&mut self, friction: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetFriction(self.id, friction) }
Ok(())
}
pub fn friction(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetFriction(self.id) }
}
pub fn try_friction(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetFriction(self.id) })
}
pub fn set_restitution(&mut self, restitution: f32) {
self.assert_valid();
unsafe { ffi::b2Shape_SetRestitution(self.id, restitution) }
}
pub fn try_set_restitution(&mut self, restitution: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetRestitution(self.id, restitution) }
Ok(())
}
pub fn restitution(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetRestitution(self.id) }
}
pub fn try_restitution(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetRestitution(self.id) })
}
pub fn set_user_material(&mut self, material: u64) {
self.assert_valid();
unsafe { ffi::b2Shape_SetUserMaterial(self.id, material) }
}
pub fn try_set_user_material(&mut self, material: u64) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetUserMaterial(self.id, material) }
Ok(())
}
pub fn user_material(&self) -> u64 {
self.assert_valid();
unsafe { ffi::b2Shape_GetUserMaterial(self.id) }
}
pub fn try_user_material(&self) -> ApiResult<u64> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetUserMaterial(self.id) })
}
pub fn set_surface_material(&mut self, material: &SurfaceMaterial) {
self.assert_valid();
unsafe { ffi::b2Shape_SetSurfaceMaterial(self.id, &material.0) }
}
pub fn try_set_surface_material(&mut self, material: &SurfaceMaterial) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Shape_SetSurfaceMaterial(self.id, &material.0) }
Ok(())
}
pub fn surface_material(&self) -> SurfaceMaterial {
self.assert_valid();
SurfaceMaterial(unsafe { ffi::b2Shape_GetSurfaceMaterial(self.id) })
}
pub fn try_surface_material(&self) -> ApiResult<SurfaceMaterial> {
self.check_valid()?;
Ok(SurfaceMaterial(unsafe {
ffi::b2Shape_GetSurfaceMaterial(self.id)
}))
}
pub unsafe fn set_user_data_ptr(&mut self, p: *mut core::ffi::c_void) {
self.assert_valid();
let _ = self.core.clear_shape_user_data(self.id);
unsafe { ffi::b2Shape_SetUserData(self.id, p) }
}
pub unsafe fn try_set_user_data_ptr(&mut self, p: *mut core::ffi::c_void) -> ApiResult<()> {
self.check_valid()?;
let _ = self.core.clear_shape_user_data(self.id);
unsafe { ffi::b2Shape_SetUserData(self.id, p) }
Ok(())
}
pub fn user_data_ptr(&self) -> *mut core::ffi::c_void {
self.assert_valid();
unsafe { ffi::b2Shape_GetUserData(self.id) }
}
pub fn try_user_data_ptr(&self) -> ApiResult<*mut core::ffi::c_void> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetUserData(self.id) })
}
pub fn set_user_data<T: 'static>(&mut self, value: T) {
self.assert_valid();
let p = self.core.set_shape_user_data(self.id, value);
unsafe { ffi::b2Shape_SetUserData(self.id, p) };
}
pub fn try_set_user_data<T: 'static>(&mut self, value: T) -> ApiResult<()> {
self.check_valid()?;
let p = self.core.set_shape_user_data(self.id, value);
unsafe { ffi::b2Shape_SetUserData(self.id, p) };
Ok(())
}
pub fn clear_user_data(&mut self) -> bool {
self.assert_valid();
let had = self.core.clear_shape_user_data(self.id);
if had {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
had
}
pub fn try_clear_user_data(&mut self) -> ApiResult<bool> {
self.check_valid()?;
let had = self.core.clear_shape_user_data(self.id);
if had {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(had)
}
pub fn with_user_data<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_shape_user_data(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data<T: 'static, R>(
&self,
f: impl FnOnce(&T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_shape_user_data(self.id, f)
}
pub fn with_user_data_mut<T: 'static, R>(&mut self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_shape_user_data_mut(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data_mut<T: 'static, R>(
&mut self,
f: impl FnOnce(&mut T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_shape_user_data_mut(self.id, f)
}
pub fn take_user_data<T: 'static>(&mut self) -> Option<T> {
self.assert_valid();
let v = self
.core
.take_shape_user_data::<T>(self.id)
.expect("user data type mismatch");
if v.is_some() {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
v
}
pub fn try_take_user_data<T: 'static>(&mut self) -> ApiResult<Option<T>> {
self.check_valid()?;
let v = self.core.take_shape_user_data::<T>(self.id)?;
if v.is_some() {
unsafe { ffi::b2Shape_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(v)
}
pub fn contact_data(&self) -> Vec<ffi::b2ContactData> {
self.assert_valid();
let cap = unsafe { ffi::b2Shape_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Vec::new();
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Shape_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
vec
}
pub fn try_contact_data(&self) -> ApiResult<Vec<ffi::b2ContactData>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Shape_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Ok(Vec::new());
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Shape_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
Ok(vec)
}
pub fn sensor_capacity(&self) -> i32 {
self.assert_valid();
unsafe { ffi::b2Shape_GetSensorCapacity(self.id) }
}
pub fn try_sensor_capacity(&self) -> ApiResult<i32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Shape_GetSensorCapacity(self.id) })
}
pub fn sensor_overlaps(&self) -> Vec<ShapeId> {
self.assert_valid();
let cap = self.sensor_capacity();
if cap <= 0 {
return Vec::new();
}
let mut ids: Vec<ShapeId> = Vec::with_capacity(cap as usize);
let wrote =
unsafe { ffi::b2Shape_GetSensorData(self.id, ids.as_mut_ptr(), cap) }.max(0) as usize;
unsafe { ids.set_len(wrote.min(cap as usize)) };
ids
}
pub fn try_sensor_overlaps(&self) -> ApiResult<Vec<ShapeId>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Shape_GetSensorCapacity(self.id) };
if cap <= 0 {
return Ok(Vec::new());
}
let mut ids: Vec<ShapeId> = Vec::with_capacity(cap as usize);
let wrote =
unsafe { ffi::b2Shape_GetSensorData(self.id, ids.as_mut_ptr(), cap) }.max(0) as usize;
unsafe { ids.set_len(wrote.min(cap as usize)) };
Ok(ids)
}
pub fn sensor_overlaps_valid(&self) -> Vec<ShapeId> {
self.sensor_overlaps()
.into_iter()
.filter(|&sid| unsafe { ffi::b2Shape_IsValid(sid) })
.collect()
}
pub fn destroy(self, update_body_mass: bool) {
crate::core::callback_state::assert_not_in_callback();
if unsafe { ffi::b2Shape_IsValid(self.id) } {
unsafe { ffi::b2DestroyShape(self.id, update_body_mass) };
let _ = self.core.clear_shape_user_data(self.id);
#[cfg(feature = "serialize")]
self.core.remove_shape_flags(self.id);
}
}
pub fn try_destroy(self, update_body_mass: bool) -> ApiResult<()> {
self.check_valid()?;
if unsafe { ffi::b2Shape_IsValid(self.id) } {
unsafe { ffi::b2DestroyShape(self.id, update_body_mass) };
let _ = self.core.clear_shape_user_data(self.id);
#[cfg(feature = "serialize")]
self.core.remove_shape_flags(self.id);
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct SurfaceMaterial(pub(crate) ffi::b2SurfaceMaterial);
impl Default for SurfaceMaterial {
fn default() -> Self {
Self(unsafe { ffi::b2DefaultSurfaceMaterial() })
}
}
impl SurfaceMaterial {
pub fn friction(mut self, v: f32) -> Self {
self.0.friction = v;
self
}
pub fn restitution(mut self, v: f32) -> Self {
self.0.restitution = v;
self
}
pub fn rolling_resistance(mut self, v: f32) -> Self {
self.0.rollingResistance = v;
self
}
pub fn tangent_speed(mut self, v: f32) -> Self {
self.0.tangentSpeed = v;
self
}
pub fn user_material_id(mut self, v: u64) -> Self {
self.0.userMaterialId = v;
self
}
pub fn custom_color(mut self, rgba: u32) -> Self {
self.0.customColor = rgba;
self
}
}
#[doc(alias = "shape_def")]
#[doc(alias = "shapedef")]
#[derive(Clone, Debug)]
pub struct ShapeDef(pub(crate) ffi::b2ShapeDef);
impl Default for ShapeDef {
fn default() -> Self {
Self(unsafe { ffi::b2DefaultShapeDef() })
}
}
impl ShapeDef {
pub fn builder() -> ShapeDefBuilder {
ShapeDefBuilder {
def: Self::default(),
}
}
}
#[doc(alias = "shape_builder")]
#[doc(alias = "shapebuilder")]
#[derive(Clone, Debug)]
pub struct ShapeDefBuilder {
def: ShapeDef,
}
impl ShapeDefBuilder {
pub fn material(mut self, mat: SurfaceMaterial) -> Self {
self.def.0.material = mat.0;
self
}
pub fn density(mut self, v: f32) -> Self {
self.def.0.density = v;
self
}
pub fn filter(mut self, f: ffi::b2Filter) -> Self {
self.def.0.filter = f;
self
}
pub fn filter_ex(mut self, f: Filter) -> Self {
self.def.0.filter = f.into();
self
}
pub fn enable_custom_filtering(mut self, flag: bool) -> Self {
self.def.0.enableCustomFiltering = flag;
self
}
pub fn sensor(mut self, flag: bool) -> Self {
self.def.0.isSensor = flag;
self
}
pub fn enable_sensor_events(mut self, flag: bool) -> Self {
self.def.0.enableSensorEvents = flag;
self
}
pub fn enable_contact_events(mut self, flag: bool) -> Self {
self.def.0.enableContactEvents = flag;
self
}
pub fn enable_hit_events(mut self, flag: bool) -> Self {
self.def.0.enableHitEvents = flag;
self
}
pub fn enable_pre_solve_events(mut self, flag: bool) -> Self {
self.def.0.enablePreSolveEvents = flag;
self
}
pub fn invoke_contact_creation(mut self, flag: bool) -> Self {
self.def.0.invokeContactCreation = flag;
self
}
pub fn update_body_mass(mut self, flag: bool) -> Self {
self.def.0.updateBodyMass = flag;
self
}
#[must_use]
pub fn build(self) -> ShapeDef {
self.def
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for SurfaceMaterial {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(serde::Serialize)]
struct Repr {
friction: f32,
restitution: f32,
rolling_resistance: f32,
tangent_speed: f32,
user_material_id: u64,
custom_color: u32,
}
let r = Repr {
friction: self.0.friction,
restitution: self.0.restitution,
rolling_resistance: self.0.rollingResistance,
tangent_speed: self.0.tangentSpeed,
user_material_id: self.0.userMaterialId,
custom_color: self.0.customColor,
};
r.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for SurfaceMaterial {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct Repr {
#[serde(default)]
friction: f32,
#[serde(default)]
restitution: f32,
#[serde(default)]
rolling_resistance: f32,
#[serde(default)]
tangent_speed: f32,
#[serde(default)]
user_material_id: u64,
#[serde(default)]
custom_color: u32,
}
let r = Repr::deserialize(deserializer)?;
let mut sm = SurfaceMaterial::default();
sm = sm
.friction(r.friction)
.restitution(r.restitution)
.rolling_resistance(r.rolling_resistance)
.tangent_speed(r.tangent_speed)
.user_material_id(r.user_material_id)
.custom_color(r.custom_color);
Ok(sm)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for ShapeDef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(serde::Serialize)]
struct Repr {
material: SurfaceMaterial,
density: f32,
filter: Filter,
enable_custom_filtering: bool,
is_sensor: bool,
enable_sensor_events: bool,
enable_contact_events: bool,
enable_hit_events: bool,
enable_pre_solve_events: bool,
invoke_contact_creation: bool,
update_body_mass: bool,
}
let r = Repr {
material: SurfaceMaterial(self.0.material),
density: self.0.density,
filter: Filter::from(self.0.filter),
enable_custom_filtering: self.0.enableCustomFiltering,
is_sensor: self.0.isSensor,
enable_sensor_events: self.0.enableSensorEvents,
enable_contact_events: self.0.enableContactEvents,
enable_hit_events: self.0.enableHitEvents,
enable_pre_solve_events: self.0.enablePreSolveEvents,
invoke_contact_creation: self.0.invokeContactCreation,
update_body_mass: self.0.updateBodyMass,
};
r.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for ShapeDef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct Repr {
#[serde(default)]
material: Option<SurfaceMaterial>,
#[serde(default)]
density: f32,
#[serde(default)]
filter: Option<Filter>,
#[serde(default)]
enable_custom_filtering: bool,
#[serde(default)]
is_sensor: bool,
#[serde(default)]
enable_sensor_events: bool,
#[serde(default)]
enable_contact_events: bool,
#[serde(default)]
enable_hit_events: bool,
#[serde(default)]
enable_pre_solve_events: bool,
#[serde(default)]
invoke_contact_creation: bool,
#[serde(default)]
update_body_mass: bool,
}
let r = Repr::deserialize(deserializer)?;
let mut b = ShapeDef::builder();
if let Some(mat) = r.material {
b = b.material(mat);
}
if let Some(f) = r.filter {
b = b.filter_ex(f);
}
b = b
.density(r.density)
.enable_custom_filtering(r.enable_custom_filtering)
.sensor(r.is_sensor)
.enable_sensor_events(r.enable_sensor_events)
.enable_contact_events(r.enable_contact_events)
.enable_hit_events(r.enable_hit_events)
.enable_pre_solve_events(r.enable_pre_solve_events)
.invoke_contact_creation(r.invoke_contact_creation)
.update_body_mass(r.update_body_mass);
Ok(b.build())
}
}
#[inline]
pub fn circle<V: Into<crate::types::Vec2>>(center: V, radius: f32) -> ffi::b2Circle {
ffi::b2Circle {
center: ffi::b2Vec2::from(center.into()),
radius,
}
}
#[inline]
pub fn segment<V: Into<crate::types::Vec2>>(p1: V, p2: V) -> ffi::b2Segment {
ffi::b2Segment {
point1: ffi::b2Vec2::from(p1.into()),
point2: ffi::b2Vec2::from(p2.into()),
}
}
pub use helpers::{box_polygon, capsule, polygon_from_points};
impl<'w> Body<'w> {
pub fn create_circle_shape(&mut self, def: &ShapeDef, c: &ffi::b2Circle) -> Shape<'w> {
crate::core::debug_checks::assert_body_valid(self.id);
let id = unsafe { ffi::b2CreateCircleShape(self.id, &def.0, c) };
#[cfg(feature = "serialize")]
self.core.record_shape_flags(id, &def.0);
Shape::new(Arc::clone(&self.core), id)
}
pub fn create_segment_shape(&mut self, def: &ShapeDef, s: &ffi::b2Segment) -> Shape<'w> {
crate::core::debug_checks::assert_body_valid(self.id);
let id = unsafe { ffi::b2CreateSegmentShape(self.id, &def.0, s) };
#[cfg(feature = "serialize")]
self.core.record_shape_flags(id, &def.0);
Shape::new(Arc::clone(&self.core), id)
}
pub fn create_capsule_shape(&mut self, def: &ShapeDef, c: &ffi::b2Capsule) -> Shape<'w> {
crate::core::debug_checks::assert_body_valid(self.id);
let id = unsafe { ffi::b2CreateCapsuleShape(self.id, &def.0, c) };
#[cfg(feature = "serialize")]
self.core.record_shape_flags(id, &def.0);
Shape::new(Arc::clone(&self.core), id)
}
pub fn create_polygon_shape(&mut self, def: &ShapeDef, p: &ffi::b2Polygon) -> Shape<'w> {
crate::core::debug_checks::assert_body_valid(self.id);
let id = unsafe { ffi::b2CreatePolygonShape(self.id, &def.0, p) };
#[cfg(feature = "serialize")]
self.core.record_shape_flags(id, &def.0);
Shape::new(Arc::clone(&self.core), id)
}
pub fn create_box(&mut self, def: &ShapeDef, half_w: f32, half_h: f32) -> Shape<'w> {
let poly = unsafe { ffi::b2MakeBox(half_w, half_h) };
self.create_polygon_shape(def, &poly)
}
pub fn create_circle_simple(&mut self, def: &ShapeDef, radius: f32) -> Shape<'w> {
let c = ffi::b2Circle {
center: ffi::b2Vec2 { x: 0.0, y: 0.0 },
radius,
};
self.create_circle_shape(def, &c)
}
pub fn create_segment_simple<V: Into<crate::types::Vec2>>(
&mut self,
def: &ShapeDef,
p1: V,
p2: V,
) -> Shape<'w> {
let seg = ffi::b2Segment {
point1: ffi::b2Vec2::from(p1.into()),
point2: ffi::b2Vec2::from(p2.into()),
};
self.create_segment_shape(def, &seg)
}
pub fn create_capsule_simple<V: Into<crate::types::Vec2>>(
&mut self,
def: &ShapeDef,
c1: V,
c2: V,
radius: f32,
) -> Shape<'w> {
let cap = ffi::b2Capsule {
center1: ffi::b2Vec2::from(c1.into()),
center2: ffi::b2Vec2::from(c2.into()),
radius,
};
self.create_capsule_shape(def, &cap)
}
pub fn create_polygon_from_points<I, P>(
&mut self,
def: &ShapeDef,
points: I,
radius: f32,
) -> Option<Shape<'w>>
where
I: IntoIterator<Item = P>,
P: Into<crate::types::Vec2>,
{
let poly = crate::shapes::polygon_from_points(points, radius)?;
Some(self.create_polygon_shape(def, &poly))
}
}