1use super::{Shape, ShapeExtent};
6use crate::broad_phase::{proxy_type, BroadPhase};
7use crate::collision::ShapeGeometry;
8use crate::collision::{CastOutput, MassData, PlaneResult, RayCastInput, ShapeCastInput};
9use crate::constants::speculative_distance;
10use crate::core::NULL_INDEX;
11use crate::distance::{make_proxy, ShapeProxy};
12use crate::geometry::{
13 collide_mover_and_capsule, collide_mover_and_circle, collide_mover_and_polygon,
14 collide_mover_and_segment, compute_capsule_aabb, compute_capsule_mass, compute_circle_aabb,
15 compute_circle_mass, compute_fat_shape_aabb, compute_polygon_aabb, compute_polygon_mass,
16 compute_segment_aabb, ray_cast_capsule, ray_cast_circle, ray_cast_polygon, ray_cast_segment,
17 shape_cast_capsule, shape_cast_circle, shape_cast_polygon, shape_cast_segment,
18};
19use crate::math_functions::{
20 abs_float, add, cross, dot, inv_rotate_vector, inv_transform_point, length, length_squared,
21 lerp, max_float, min_float, mul_sv, rotate_vector, sub, transform_point, Aabb, Transform, Vec2,
22 WorldTransform, PI,
23};
24use crate::types::BodyType;
25
26pub(crate) fn update_shape_aabbs(
29 shape: &mut Shape,
30 transform: WorldTransform,
31 proxy_type_: BodyType,
32) {
33 let speculative = speculative_distance();
35 let aabb_margin = shape.aabb_margin;
36
37 let aabb = compute_fat_shape_aabb(&shape.geometry, 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: Vec2 {
48 x: aabb.lower_bound.x - margin,
49 y: aabb.lower_bound.y - margin,
50 },
51 upper_bound: Vec2 {
52 x: aabb.upper_bound.x + margin,
53 y: aabb.upper_bound.y + margin,
54 },
55 };
56}
57
58pub fn create_shape_proxy(
60 shape: &mut Shape,
61 bp: &mut BroadPhase,
62 type_: BodyType,
63 transform: WorldTransform,
64 force_pair_creation: bool,
65) {
66 debug_assert!(shape.proxy_key == NULL_INDEX);
67
68 update_shape_aabbs(shape, transform, type_);
69
70 shape.proxy_key = bp.create_proxy(
72 type_,
73 shape.fat_aabb,
74 shape.filter.category_bits,
75 shape.id,
76 force_pair_creation,
77 );
78 debug_assert!((proxy_type(shape.proxy_key) as usize) < crate::types::BODY_TYPE_COUNT);
79}
80
81pub fn destroy_shape_proxy(shape: &mut Shape, bp: &mut BroadPhase) {
83 if shape.proxy_key != NULL_INDEX {
84 bp.destroy_proxy(shape.proxy_key);
85 shape.proxy_key = NULL_INDEX;
86 }
87}
88
89pub fn compute_shape_mass(shape: &Shape) -> MassData {
91 match &shape.geometry {
92 ShapeGeometry::Capsule(capsule) => compute_capsule_mass(capsule, shape.density),
93 ShapeGeometry::Circle(circle) => compute_circle_mass(circle, shape.density),
94 ShapeGeometry::Polygon(polygon) => compute_polygon_mass(polygon, shape.density),
95 _ => MassData::default(),
96 }
97}
98
99pub fn compute_shape_extent(shape: &Shape, local_center: Vec2) -> ShapeExtent {
101 let mut extent = ShapeExtent::default();
102
103 match &shape.geometry {
104 ShapeGeometry::Capsule(capsule) => {
105 let radius = capsule.radius;
106 extent.min_extent = radius;
107 let c1 = sub(capsule.center1, local_center);
108 let c2 = sub(capsule.center2, local_center);
109 extent.max_extent = max_float(length_squared(c1), length_squared(c2)).sqrt() + radius;
110 }
111
112 ShapeGeometry::Circle(circle) => {
113 let radius = circle.radius;
114 extent.min_extent = radius;
115 extent.max_extent = length(sub(circle.center, local_center)) + radius;
116 }
117
118 ShapeGeometry::Polygon(poly) => {
119 let mut min_extent = crate::constants::huge();
120 let mut max_extent_sqr = 0.0f32;
121 let count = poly.count as usize;
122 for i in 0..count {
123 let v = poly.vertices[i];
124 let plane_offset = dot(poly.normals[i], sub(v, poly.centroid));
125 min_extent = min_float(min_extent, plane_offset);
126
127 let distance_sqr = length_squared(sub(v, local_center));
128 max_extent_sqr = max_float(max_extent_sqr, distance_sqr);
129 }
130
131 extent.min_extent = min_extent + poly.radius;
132 extent.max_extent = max_extent_sqr.sqrt() + poly.radius;
133 }
134
135 ShapeGeometry::Segment(segment) => {
136 extent.min_extent = 0.0;
137 let c1 = sub(segment.point1, local_center);
138 let c2 = sub(segment.point2, local_center);
139 extent.max_extent = max_float(length_squared(c1), length_squared(c2)).sqrt();
140 }
141
142 ShapeGeometry::ChainSegment(chain_segment) => {
143 extent.min_extent = 0.0;
144 let c1 = sub(chain_segment.segment.point1, local_center);
145 let c2 = sub(chain_segment.segment.point2, local_center);
146 extent.max_extent = max_float(length_squared(c1), length_squared(c2)).sqrt();
147 }
148 }
149
150 extent
151}
152
153pub fn compute_shape_aabb(shape: &Shape, xf: WorldTransform) -> Aabb {
155 match &shape.geometry {
156 ShapeGeometry::Capsule(capsule) => compute_capsule_aabb(capsule, xf),
157 ShapeGeometry::Circle(circle) => compute_circle_aabb(circle, xf),
158 ShapeGeometry::Polygon(polygon) => compute_polygon_aabb(polygon, xf),
159 ShapeGeometry::Segment(segment) => compute_segment_aabb(segment, xf),
160 ShapeGeometry::ChainSegment(chain_segment) => {
161 compute_segment_aabb(&chain_segment.segment, xf)
162 }
163 }
164}
165
166pub fn get_shape_centroid(shape: &Shape) -> Vec2 {
168 match &shape.geometry {
169 ShapeGeometry::Capsule(capsule) => lerp(capsule.center1, capsule.center2, 0.5),
170 ShapeGeometry::Circle(circle) => circle.center,
171 ShapeGeometry::Polygon(polygon) => polygon.centroid,
172 ShapeGeometry::Segment(segment) => lerp(segment.point1, segment.point2, 0.5),
173 ShapeGeometry::ChainSegment(chain_segment) => lerp(
174 chain_segment.segment.point1,
175 chain_segment.segment.point2,
176 0.5,
177 ),
178 }
179}
180
181pub fn get_shape_perimeter(shape: &Shape) -> f32 {
183 match &shape.geometry {
184 ShapeGeometry::Capsule(capsule) => {
185 2.0 * length(sub(capsule.center1, capsule.center2)) + 2.0 * PI * capsule.radius
186 }
187 ShapeGeometry::Circle(circle) => 2.0 * PI * circle.radius,
188 ShapeGeometry::Polygon(polygon) => {
189 let points = &polygon.vertices;
190 let count = polygon.count as usize;
191 let mut perimeter = 2.0 * PI * polygon.radius;
192 debug_assert!(count > 0);
193 let mut prev = points[count - 1];
194 for &next in points.iter().take(count) {
195 perimeter += length(sub(next, prev));
196 prev = next;
197 }
198
199 perimeter
200 }
201 ShapeGeometry::Segment(segment) => 2.0 * length(sub(segment.point1, segment.point2)),
202 ShapeGeometry::ChainSegment(chain_segment) => {
203 2.0 * length(sub(
204 chain_segment.segment.point1,
205 chain_segment.segment.point2,
206 ))
207 }
208 }
209}
210
211pub fn get_shape_projected_perimeter(shape: &Shape, line: Vec2) -> f32 {
214 match &shape.geometry {
215 ShapeGeometry::Capsule(capsule) => {
216 let axis = sub(capsule.center2, capsule.center1);
217 let projected_length = abs_float(dot(axis, line));
218 projected_length + 2.0 * capsule.radius
219 }
220
221 ShapeGeometry::Circle(circle) => 2.0 * circle.radius,
222
223 ShapeGeometry::Polygon(polygon) => {
224 let points = &polygon.vertices;
225 let count = polygon.count as usize;
226 debug_assert!(count > 0);
227 let value = dot(points[0], line);
228 let mut lower = value;
229 let mut upper = value;
230 for point in points.iter().take(count).skip(1) {
231 let value = dot(*point, line);
232 lower = min_float(lower, value);
233 upper = max_float(upper, value);
234 }
235
236 (upper - lower) + 2.0 * polygon.radius
237 }
238
239 ShapeGeometry::Segment(segment) => {
240 let value1 = dot(segment.point1, line);
241 let value2 = dot(segment.point2, line);
242 abs_float(value2 - value1)
243 }
244
245 ShapeGeometry::ChainSegment(chain_segment) => {
246 let value1 = dot(chain_segment.segment.point1, line);
247 let value2 = dot(chain_segment.segment.point2, line);
248 abs_float(value2 - value1)
249 }
250 }
251}
252
253pub fn make_shape_distance_proxy(shape: &Shape) -> ShapeProxy {
255 match &shape.geometry {
256 ShapeGeometry::Capsule(capsule) => {
257 make_proxy(&[capsule.center1, capsule.center2], capsule.radius)
258 }
259 ShapeGeometry::Circle(circle) => make_proxy(&[circle.center], circle.radius),
260 ShapeGeometry::Polygon(polygon) => {
261 make_proxy(&polygon.vertices[..polygon.count as usize], polygon.radius)
262 }
263 ShapeGeometry::Segment(segment) => make_proxy(&[segment.point1, segment.point2], 0.0),
264 ShapeGeometry::ChainSegment(chain_segment) => make_proxy(
265 &[chain_segment.segment.point1, chain_segment.segment.point2],
266 0.0,
267 ),
268 }
269}
270
271pub fn ray_cast_shape(input: &RayCastInput, shape: &Shape, transform: Transform) -> CastOutput {
273 let local_input = RayCastInput {
274 origin: inv_transform_point(transform, input.origin),
275 translation: inv_rotate_vector(transform.q, input.translation),
276 max_fraction: input.max_fraction,
277 };
278
279 let mut output = match &shape.geometry {
280 ShapeGeometry::Capsule(capsule) => ray_cast_capsule(capsule, &local_input),
281 ShapeGeometry::Circle(circle) => ray_cast_circle(circle, &local_input),
282 ShapeGeometry::Polygon(polygon) => ray_cast_polygon(polygon, &local_input),
283 ShapeGeometry::Segment(segment) => ray_cast_segment(segment, &local_input, false),
284 ShapeGeometry::ChainSegment(chain_segment) => {
285 ray_cast_segment(&chain_segment.segment, &local_input, true)
286 }
287 };
288
289 output.point = transform_point(transform, output.point);
292 output.normal = rotate_vector(transform.q, output.normal);
293 output
294}
295
296pub fn shape_cast_shape(input: &ShapeCastInput, shape: &Shape, transform: Transform) -> CastOutput {
298 let mut output = CastOutput::default();
299
300 if input.proxy.count == 0 {
301 return output;
302 }
303
304 let mut local_input = *input;
305
306 for i in 0..local_input.proxy.count as usize {
307 local_input.proxy.points[i] = inv_transform_point(transform, input.proxy.points[i]);
308 }
309
310 local_input.translation = inv_rotate_vector(transform.q, input.translation);
311
312 match &shape.geometry {
313 ShapeGeometry::Capsule(capsule) => {
314 output = shape_cast_capsule(capsule, &local_input);
315 }
316 ShapeGeometry::Circle(circle) => {
317 output = shape_cast_circle(circle, &local_input);
318 }
319 ShapeGeometry::Polygon(polygon) => {
320 output = shape_cast_polygon(polygon, &local_input);
321 }
322 ShapeGeometry::Segment(segment) => {
323 output = shape_cast_segment(segment, &local_input);
324 }
325 ShapeGeometry::ChainSegment(chain_segment) => {
326 let mut approximate_centroid = local_input.proxy.points[0];
328 for i in 1..local_input.proxy.count as usize {
329 approximate_centroid = add(approximate_centroid, local_input.proxy.points[i]);
330 }
331
332 approximate_centroid =
333 mul_sv(1.0 / local_input.proxy.count as f32, approximate_centroid);
334
335 let edge = sub(chain_segment.segment.point2, chain_segment.segment.point1);
336 let r = sub(approximate_centroid, chain_segment.segment.point1);
337
338 if cross(r, edge) < 0.0 {
339 return output;
341 }
342
343 output = shape_cast_segment(&chain_segment.segment, &local_input);
344 }
345 }
346
347 output.point = transform_point(transform, output.point);
350 output.normal = rotate_vector(transform.q, output.normal);
351 output
352}
353
354pub fn collide_mover(
356 mover: &crate::collision::Capsule,
357 shape: &Shape,
358 transform: Transform,
359) -> PlaneResult {
360 let local_mover = crate::collision::Capsule {
361 center1: inv_transform_point(transform, mover.center1),
362 center2: inv_transform_point(transform, mover.center2),
363 radius: mover.radius,
364 };
365
366 let mut result = match &shape.geometry {
367 ShapeGeometry::Capsule(capsule) => collide_mover_and_capsule(&local_mover, capsule),
368 ShapeGeometry::Circle(circle) => collide_mover_and_circle(&local_mover, circle),
369 ShapeGeometry::Polygon(polygon) => collide_mover_and_polygon(&local_mover, polygon),
370 ShapeGeometry::Segment(segment) => collide_mover_and_segment(&local_mover, segment),
371 ShapeGeometry::ChainSegment(chain_segment) => {
372 collide_mover_and_segment(&local_mover, &chain_segment.segment)
373 }
374 };
375
376 if !result.hit {
377 return result;
378 }
379
380 result.plane.normal = rotate_vector(transform.q, result.plane.normal);
381 result
382}