use crate::compound::CompoundData;
use crate::core::NULL_INDEX;
use crate::geometry::{Capsule, ShapeType, Sphere, SurfaceMaterial};
use crate::height_field::HeightFieldData;
use crate::hull::HullData;
use crate::math_functions::{Aabb, Vec3, BOUNDS3_EMPTY, VEC3_ONE, VEC3_ZERO};
use crate::mesh::MeshData;
use crate::types::{Filter, QueryFilter};
use std::rc::Rc;
pub mod shape_flags {
pub const ENABLE_SENSOR_EVENTS: u8 = 0x01;
pub const ENABLE_CONTACT_EVENTS: u8 = 0x02;
pub const ENABLE_CUSTOM_FILTERING: u8 = 0x04;
pub const ENABLE_HIT_EVENTS: u8 = 0x08;
pub const ENABLE_PRE_SOLVE_EVENTS: u8 = 0x10;
pub const ENLARGED_AABB: u8 = 0x20;
}
#[derive(Debug, Clone)]
pub enum ShapeGeometry {
Capsule(Capsule),
Sphere(Sphere),
Hull(Rc<HullData>),
Mesh {
data: MeshData,
scale: Vec3,
},
HeightField(HeightFieldData),
Compound(CompoundData),
}
impl ShapeGeometry {
pub fn shape_type(&self) -> ShapeType {
match self {
ShapeGeometry::Capsule(_) => ShapeType::Capsule,
ShapeGeometry::Sphere(_) => ShapeType::Sphere,
ShapeGeometry::Hull(_) => ShapeType::Hull,
ShapeGeometry::Mesh { .. } => ShapeType::Mesh,
ShapeGeometry::HeightField(_) => ShapeType::Height,
ShapeGeometry::Compound(_) => ShapeType::Compound,
}
}
}
impl Default for ShapeGeometry {
fn default() -> Self {
ShapeGeometry::Capsule(Capsule::default())
}
}
#[derive(Debug, Clone)]
pub struct Shape {
pub id: i32,
pub body_id: i32,
pub prev_shape_id: i32,
pub next_shape_id: i32,
pub sensor_index: i32,
pub proxy_key: i32,
pub density: f32,
pub explosion_scale: f32,
pub aabb_margin: f32,
pub aabb: Aabb,
pub fat_aabb: Aabb,
pub local_centroid: Vec3,
pub material: SurfaceMaterial,
pub materials: Vec<SurfaceMaterial>,
pub filter: Filter,
pub user_data: u64,
pub user_shape: u64,
pub name_id: u32,
pub generation: u16,
pub flags: u8,
pub geometry: ShapeGeometry,
}
impl Shape {
pub fn shape_type(&self) -> ShapeType {
self.geometry.shape_type()
}
pub fn material_count(&self) -> i32 {
if self.materials.is_empty() {
1
} else {
self.materials.len() as i32
}
}
pub fn shape_materials(&self) -> &[SurfaceMaterial] {
if self.materials.is_empty() {
core::slice::from_ref(&self.material)
} else {
&self.materials
}
}
pub fn get_material(&self, index: i32) -> &SurfaceMaterial {
let mats = self.shape_materials();
&mats[index as usize]
}
pub fn shape_materials_mut(&mut self) -> &mut [SurfaceMaterial] {
if self.materials.is_empty() {
core::slice::from_mut(&mut self.material)
} else {
&mut self.materials
}
}
pub fn get_material_mut(&mut self, index: i32) -> &mut SurfaceMaterial {
&mut self.shape_materials_mut()[index as usize]
}
pub fn get_shape_user_material_id(&self, child_index: i32, triangle_index: i32) -> u64 {
use crate::compound::{get_compound_child, ChildGeometry, MAX_COMPOUND_MESH_MATERIALS};
use crate::height_field::get_height_field_material;
use crate::math_functions::clamp_int;
use crate::mesh::get_mesh_material_indices;
let mut material_index = 0i32;
match &self.geometry {
ShapeGeometry::Mesh { data, .. } => {
let indices = get_mesh_material_indices(data);
if !indices.is_empty() {
material_index = indices[triangle_index as usize] as i32;
}
}
ShapeGeometry::HeightField(height_field) => {
material_index = get_height_field_material(height_field, triangle_index);
}
ShapeGeometry::Compound(compound) => {
let child = get_compound_child(compound, child_index);
if let ChildGeometry::Mesh(mesh) = child.geometry {
let indices = get_mesh_material_indices(mesh.data);
let mesh_material_index = if !indices.is_empty() {
indices[triangle_index as usize] as i32
} else {
0
};
let mesh_material_index = clamp_int(
mesh_material_index,
0,
MAX_COMPOUND_MESH_MATERIALS as i32 - 1,
);
material_index = child.material_indices[mesh_material_index as usize];
} else {
material_index = child.material_indices[0];
}
}
_ => {}
}
let material_index = clamp_int(material_index, 0, self.material_count() - 1);
self.shape_materials()[material_index as usize].user_material_id
}
}
impl Default for Shape {
fn default() -> Self {
Shape {
id: NULL_INDEX,
body_id: NULL_INDEX,
prev_shape_id: NULL_INDEX,
next_shape_id: NULL_INDEX,
sensor_index: NULL_INDEX,
proxy_key: NULL_INDEX,
density: 0.0,
explosion_scale: 1.0,
aabb_margin: 0.0,
aabb: BOUNDS3_EMPTY,
fat_aabb: BOUNDS3_EMPTY,
local_centroid: VEC3_ZERO,
material: SurfaceMaterial::default(),
materials: Vec::new(),
filter: Filter::default(),
user_data: 0,
user_shape: 0,
name_id: 0,
generation: 0,
flags: 0,
geometry: ShapeGeometry::default(),
}
}
}
pub fn should_shapes_collide(filter_a: Filter, filter_b: Filter) -> bool {
if filter_a.group_index == filter_b.group_index && filter_a.group_index != 0 {
return filter_a.group_index > 0;
}
(filter_a.mask_bits & filter_b.category_bits) != 0
&& (filter_a.category_bits & filter_b.mask_bits) != 0
}
pub fn should_query_collide(shape_filter: &Filter, query_filter: &QueryFilter) -> bool {
(shape_filter.category_bits & query_filter.mask_bits) != 0
&& (shape_filter.mask_bits & query_filter.category_bits) != 0
}
pub fn mesh_geometry(data: MeshData) -> ShapeGeometry {
ShapeGeometry::Mesh {
data,
scale: VEC3_ONE,
}
}
mod accessors;
mod api;
mod dispatch;
mod geometry_set;
pub(crate) mod lifecycle;
mod mutators;
mod query;
mod toi;
mod wind;
pub use accessors::*;
pub use api::*;
pub use dispatch::*;
pub use geometry_set::*;
pub use mutators::*;
pub use query::*;
pub use toi::*;
pub use wind::*;