1use super::Shape;
7use crate::aabb::farthest_point_on_aabb;
8use crate::broad_phase::{proxy_type, BroadPhase};
9use crate::compound::compute_compound_aabb;
10use crate::constants::speculative_distance;
11use crate::core::NULL_INDEX;
12use crate::geometry::{
13 compute_capsule_aabb, compute_capsule_mass, compute_sphere_aabb, compute_sphere_mass, MassData,
14 ShapeExtent,
15};
16use crate::height_field::compute_height_field_aabb;
17use crate::hull::{compute_hull_aabb, compute_hull_extent, compute_hull_mass};
18use crate::math_functions::{
19 aabb_center, abs, add, lerp, max, min_float, sub, Aabb, Transform, Vec3, WorldTransform,
20 TRANSFORM_IDENTITY, VEC3_ZERO,
21};
22use crate::mesh::compute_mesh_aabb;
23use crate::types::BodyType;
24
25use super::ShapeGeometry;
26
27pub(crate) fn update_shape_aabbs(
30 shape: &mut Shape,
31 transform: WorldTransform,
32 proxy_type_: BodyType,
33) {
34 let speculative = speculative_distance();
35 let aabb_margin = shape.aabb_margin;
36
37 let aabb = compute_fat_shape_aabb(shape, transform, speculative);
38 shape.aabb = aabb;
39
40 let margin = if proxy_type_ == BodyType::Static {
42 speculative
43 } else {
44 aabb_margin
45 };
46 shape.fat_aabb = Aabb {
47 lower_bound: Vec3 {
48 x: aabb.lower_bound.x - margin,
49 y: aabb.lower_bound.y - margin,
50 z: aabb.lower_bound.z - margin,
51 },
52 upper_bound: Vec3 {
53 x: aabb.upper_bound.x + margin,
54 y: aabb.upper_bound.y + margin,
55 z: aabb.upper_bound.z + margin,
56 },
57 };
58}
59
60pub fn create_shape_proxy(
62 shape: &mut Shape,
63 bp: &mut BroadPhase,
64 type_: BodyType,
65 transform: WorldTransform,
66 force_pair_creation: bool,
67) {
68 debug_assert!(shape.proxy_key == NULL_INDEX);
69
70 update_shape_aabbs(shape, transform, type_);
71
72 shape.proxy_key = bp.create_proxy(
73 type_,
74 shape.fat_aabb,
75 shape.filter.category_bits,
76 shape.id,
77 force_pair_creation,
78 );
79 debug_assert!((proxy_type(shape.proxy_key) as usize) < crate::types::BODY_TYPE_COUNT);
80}
81
82pub fn destroy_shape_proxy(shape: &mut Shape, bp: &mut BroadPhase) {
84 if shape.proxy_key != NULL_INDEX {
85 bp.destroy_proxy(shape.proxy_key);
86 shape.proxy_key = NULL_INDEX;
87 }
88}
89
90pub fn compute_shape_aabb(shape: &Shape, transform: Transform) -> Aabb {
92 match &shape.geometry {
93 ShapeGeometry::Capsule(capsule) => compute_capsule_aabb(capsule, transform),
94 ShapeGeometry::Compound(compound) => compute_compound_aabb(compound, transform),
95 ShapeGeometry::HeightField(hf) => compute_height_field_aabb(hf, transform),
96 ShapeGeometry::Hull(hull) => compute_hull_aabb(hull, transform),
97 ShapeGeometry::Mesh { data, scale } => compute_mesh_aabb(data, transform, *scale),
98 ShapeGeometry::Sphere(sphere) => compute_sphere_aabb(sphere, transform),
99 }
100}
101
102pub fn compute_fat_shape_aabb(shape: &Shape, transform: WorldTransform, extra: f32) -> Aabb {
104 let r = Vec3 {
105 x: extra,
106 y: extra,
107 z: extra,
108 };
109 #[cfg(feature = "double-precision")]
110 {
111 use crate::math_functions::{offset_aabb, VEC3_ZERO};
112 let rotation = Transform {
115 p: VEC3_ZERO,
116 q: transform.q,
117 };
118 let mut local_box = compute_shape_aabb(shape, rotation);
119 local_box.lower_bound = sub(local_box.lower_bound, r);
120 local_box.upper_bound = add(local_box.upper_bound, r);
121 offset_aabb(local_box, transform.p)
122 }
123 #[cfg(not(feature = "double-precision"))]
124 {
125 let mut aabb = compute_shape_aabb(shape, transform);
126 aabb.lower_bound = sub(aabb.lower_bound, r);
127 aabb.upper_bound = add(aabb.upper_bound, r);
128 aabb
129 }
130}
131
132pub fn get_shape_centroid(shape: &Shape) -> Vec3 {
134 match &shape.geometry {
135 ShapeGeometry::Capsule(capsule) => lerp(capsule.center1, capsule.center2, 0.5),
136 ShapeGeometry::Compound(compound) => {
137 let aabb = compute_compound_aabb(compound, TRANSFORM_IDENTITY);
138 aabb_center(aabb)
139 }
140 ShapeGeometry::Sphere(sphere) => sphere.center,
141 ShapeGeometry::Hull(hull) => hull.center,
142 ShapeGeometry::Mesh { data, scale } => {
143 let aabb = compute_mesh_aabb(data, TRANSFORM_IDENTITY, *scale);
144 aabb_center(aabb)
145 }
146 ShapeGeometry::HeightField(hf) => {
147 let aabb = compute_height_field_aabb(hf, TRANSFORM_IDENTITY);
148 aabb_center(aabb)
149 }
150 }
151}
152
153pub fn compute_shape_mass(shape: &Shape) -> MassData {
155 match &shape.geometry {
156 ShapeGeometry::Capsule(capsule) => compute_capsule_mass(capsule, shape.density),
157 ShapeGeometry::Hull(hull) => compute_hull_mass(hull, shape.density),
158 ShapeGeometry::Sphere(sphere) => compute_sphere_mass(sphere, shape.density),
159 _ => MassData::default(),
160 }
161}
162
163pub fn make_shape_proxy(shape: &Shape) -> crate::distance::ShapeProxy {
166 use crate::distance::make_proxy;
167 use crate::hull::get_hull_points;
168
169 match &shape.geometry {
170 ShapeGeometry::Capsule(capsule) => {
171 make_proxy(&[capsule.center1, capsule.center2], capsule.radius)
172 }
173 ShapeGeometry::Sphere(sphere) => make_proxy(&[sphere.center], sphere.radius),
174 ShapeGeometry::Hull(hull) => make_proxy(get_hull_points(hull), 0.0),
175 _ => {
176 debug_assert!(false, "make_shape_proxy is for convex shapes only");
177 make_proxy(&[VEC3_ZERO], 0.0)
178 }
179 }
180}
181
182pub fn compute_shape_extent(shape: &Shape, local_center: Vec3) -> ShapeExtent {
184 let mut extent = ShapeExtent::default();
185
186 match &shape.geometry {
187 ShapeGeometry::Capsule(capsule) => {
188 let radius = capsule.radius;
189 extent.min_extent = radius;
190 let c1 = sub(capsule.center1, local_center);
191 let c2 = sub(capsule.center2, local_center);
192 let r = Vec3 {
193 x: radius,
194 y: radius,
195 z: radius,
196 };
197 extent.max_extent = add(max(c1, c2), r);
198 }
199
200 ShapeGeometry::Compound(compound) => {
201 let aabb = compute_compound_aabb(compound, TRANSFORM_IDENTITY);
202 let r1 = crate::math_functions::length(sub(aabb.lower_bound, local_center));
203 let r2 = crate::math_functions::length(sub(aabb.upper_bound, local_center));
204 extent.min_extent = min_float(r1, r2);
205 let p = farthest_point_on_aabb(aabb, local_center);
206 extent.max_extent = abs(sub(p, local_center));
207 }
208
209 ShapeGeometry::Sphere(sphere) => {
210 let radius = sphere.radius;
211 extent.min_extent = radius;
212 let r = Vec3 {
213 x: radius,
214 y: radius,
215 z: radius,
216 };
217 let p = add(sub(sphere.center, local_center), r);
218 extent.max_extent = abs(sub(p, local_center));
219 }
220
221 ShapeGeometry::Hull(hull) => {
222 extent = compute_hull_extent(hull, local_center);
223 }
224
225 ShapeGeometry::Mesh { data, scale } => {
226 let aabb = compute_mesh_aabb(data, TRANSFORM_IDENTITY, *scale);
227 let r1 = crate::math_functions::length(sub(aabb.lower_bound, local_center));
228 let r2 = crate::math_functions::length(sub(aabb.upper_bound, local_center));
229 extent.min_extent = min_float(r1, r2);
230 let p = farthest_point_on_aabb(aabb, local_center);
231 extent.max_extent = abs(p);
232 }
233
234 ShapeGeometry::HeightField(_) => {}
235 }
236
237 extent
238}