1use crate::compound::CompoundData;
15use crate::core::NULL_INDEX;
16use crate::geometry::{Capsule, ShapeType, Sphere, SurfaceMaterial};
17use crate::height_field::HeightFieldData;
18use crate::hull::HullData;
19use crate::math_functions::{Aabb, Vec3, BOUNDS3_EMPTY, VEC3_ONE, VEC3_ZERO};
20use crate::mesh::MeshData;
21use crate::types::{Filter, QueryFilter};
22use std::rc::Rc;
23
24pub mod shape_flags {
26 pub const ENABLE_SENSOR_EVENTS: u8 = 0x01;
27 pub const ENABLE_CONTACT_EVENTS: u8 = 0x02;
28 pub const ENABLE_CUSTOM_FILTERING: u8 = 0x04;
29 pub const ENABLE_HIT_EVENTS: u8 = 0x08;
30 pub const ENABLE_PRE_SOLVE_EVENTS: u8 = 0x10;
31 pub const ENLARGED_AABB: u8 = 0x20;
32}
33
34#[derive(Debug, Clone)]
36pub enum ShapeGeometry {
37 Capsule(Capsule),
38 Sphere(Sphere),
39 Hull(Rc<HullData>),
41 Mesh {
43 data: MeshData,
44 scale: Vec3,
45 },
46 HeightField(HeightFieldData),
47 Compound(CompoundData),
48}
49
50impl ShapeGeometry {
51 pub fn shape_type(&self) -> ShapeType {
53 match self {
54 ShapeGeometry::Capsule(_) => ShapeType::Capsule,
55 ShapeGeometry::Sphere(_) => ShapeType::Sphere,
56 ShapeGeometry::Hull(_) => ShapeType::Hull,
57 ShapeGeometry::Mesh { .. } => ShapeType::Mesh,
58 ShapeGeometry::HeightField(_) => ShapeType::Height,
59 ShapeGeometry::Compound(_) => ShapeType::Compound,
60 }
61 }
62}
63
64impl Default for ShapeGeometry {
65 fn default() -> Self {
66 ShapeGeometry::Capsule(Capsule::default())
67 }
68}
69
70#[derive(Debug, Clone)]
76pub struct Shape {
77 pub id: i32,
78 pub body_id: i32,
79 pub prev_shape_id: i32,
80 pub next_shape_id: i32,
81 pub sensor_index: i32,
82 pub proxy_key: i32,
83 pub density: f32,
84 pub explosion_scale: f32,
85 pub aabb_margin: f32,
86
87 pub aabb: Aabb,
88 pub fat_aabb: Aabb,
89 pub local_centroid: Vec3,
90
91 pub material: SurfaceMaterial,
93 pub materials: Vec<SurfaceMaterial>,
96
97 pub filter: Filter,
98 pub user_data: u64,
99 pub user_shape: u64,
101
102 pub name_id: u32,
103 pub generation: u16,
104
105 pub flags: u8,
107
108 pub geometry: ShapeGeometry,
110}
111
112impl Shape {
113 pub fn shape_type(&self) -> ShapeType {
115 self.geometry.shape_type()
116 }
117
118 pub fn material_count(&self) -> i32 {
120 if self.materials.is_empty() {
121 1
122 } else {
123 self.materials.len() as i32
124 }
125 }
126
127 pub fn shape_materials(&self) -> &[SurfaceMaterial] {
132 if self.materials.is_empty() {
133 core::slice::from_ref(&self.material)
134 } else {
135 &self.materials
136 }
137 }
138
139 pub fn get_material(&self, index: i32) -> &SurfaceMaterial {
141 let mats = self.shape_materials();
142 &mats[index as usize]
143 }
144
145 pub fn shape_materials_mut(&mut self) -> &mut [SurfaceMaterial] {
147 if self.materials.is_empty() {
148 core::slice::from_mut(&mut self.material)
149 } else {
150 &mut self.materials
151 }
152 }
153
154 pub fn get_material_mut(&mut self, index: i32) -> &mut SurfaceMaterial {
156 &mut self.shape_materials_mut()[index as usize]
157 }
158
159 pub fn get_shape_user_material_id(&self, child_index: i32, triangle_index: i32) -> u64 {
166 use crate::compound::{get_compound_child, ChildGeometry, MAX_COMPOUND_MESH_MATERIALS};
167 use crate::height_field::get_height_field_material;
168 use crate::math_functions::clamp_int;
169 use crate::mesh::get_mesh_material_indices;
170
171 let mut material_index = 0i32;
172 match &self.geometry {
173 ShapeGeometry::Mesh { data, .. } => {
174 let indices = get_mesh_material_indices(data);
175 if !indices.is_empty() {
176 material_index = indices[triangle_index as usize] as i32;
177 }
178 }
179 ShapeGeometry::HeightField(height_field) => {
180 material_index = get_height_field_material(height_field, triangle_index);
181 }
182 ShapeGeometry::Compound(compound) => {
183 let child = get_compound_child(compound, child_index);
184 if let ChildGeometry::Mesh(mesh) = child.geometry {
185 let indices = get_mesh_material_indices(mesh.data);
186 let mesh_material_index = if !indices.is_empty() {
187 indices[triangle_index as usize] as i32
188 } else {
189 0
190 };
191 let mesh_material_index = clamp_int(
192 mesh_material_index,
193 0,
194 MAX_COMPOUND_MESH_MATERIALS as i32 - 1,
195 );
196 material_index = child.material_indices[mesh_material_index as usize];
197 } else {
198 material_index = child.material_indices[0];
199 }
200 }
201 _ => {}
202 }
203
204 let material_index = clamp_int(material_index, 0, self.material_count() - 1);
205 self.shape_materials()[material_index as usize].user_material_id
206 }
207}
208
209impl Default for Shape {
210 fn default() -> Self {
211 Shape {
212 id: NULL_INDEX,
213 body_id: NULL_INDEX,
214 prev_shape_id: NULL_INDEX,
215 next_shape_id: NULL_INDEX,
216 sensor_index: NULL_INDEX,
217 proxy_key: NULL_INDEX,
218 density: 0.0,
219 explosion_scale: 1.0,
220 aabb_margin: 0.0,
221 aabb: BOUNDS3_EMPTY,
222 fat_aabb: BOUNDS3_EMPTY,
223 local_centroid: VEC3_ZERO,
224 material: SurfaceMaterial::default(),
225 materials: Vec::new(),
226 filter: Filter::default(),
227 user_data: 0,
228 user_shape: 0,
229 name_id: 0,
230 generation: 0,
231 flags: 0,
232 geometry: ShapeGeometry::default(),
233 }
234 }
235}
236
237pub fn should_shapes_collide(filter_a: Filter, filter_b: Filter) -> bool {
239 if filter_a.group_index == filter_b.group_index && filter_a.group_index != 0 {
240 return filter_a.group_index > 0;
241 }
242
243 (filter_a.mask_bits & filter_b.category_bits) != 0
244 && (filter_a.category_bits & filter_b.mask_bits) != 0
245}
246
247pub fn should_query_collide(shape_filter: &Filter, query_filter: &QueryFilter) -> bool {
249 (shape_filter.category_bits & query_filter.mask_bits) != 0
250 && (shape_filter.mask_bits & query_filter.category_bits) != 0
251}
252
253pub fn mesh_geometry(data: MeshData) -> ShapeGeometry {
255 ShapeGeometry::Mesh {
256 data,
257 scale: VEC3_ONE,
258 }
259}
260
261mod accessors;
262mod api;
263mod dispatch;
264mod geometry_set;
265pub(crate) mod lifecycle;
266mod mutators;
267mod query;
268mod toi;
269mod wind;
270
271pub use accessors::*;
272pub use api::*;
273pub use dispatch::*;
274pub use geometry_set::*;
275pub use mutators::*;
276pub use query::*;
277pub use toi::*;
278pub use wind::*;