1use crate::bitset::BitSet;
7use crate::body::get_body_transform;
8use crate::compound::overlap_compound;
9use crate::constants::MAX_SHAPE_CAST_POINTS;
10use crate::core::NULL_INDEX;
11use crate::distance::{make_proxy, ShapeProxy};
12use crate::events::{SensorBeginTouchEvent, SensorEndTouchEvent};
13use crate::geometry::{overlap_capsule, overlap_sphere, ShapeType};
14use crate::height_field::overlap_height_field;
15use crate::hull::{get_hull_points, overlap_hull};
16use crate::id::ShapeId;
17use crate::math_functions::{
18 inv_mul_transforms, min_int, to_relative_transform, transform_point, Transform, POS_ZERO,
19 TRANSFORM_IDENTITY,
20};
21use crate::mesh::{overlap_mesh, Mesh};
22use crate::shape::{shape_flags, should_shapes_collide, Shape, ShapeGeometry};
23use crate::solver_set::DISABLED_SET;
24use crate::types::BodyType;
25use crate::world::World;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct SensorHit {
30 pub sensor_id: i32,
31 pub visitor_id: i32,
32}
33
34impl Default for SensorHit {
35 fn default() -> Self {
36 SensorHit {
37 sensor_id: NULL_INDEX,
38 visitor_id: NULL_INDEX,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct Visitor {
46 pub shape_id: i32,
47 pub generation: u16,
48}
49
50impl Default for Visitor {
51 fn default() -> Self {
52 Visitor {
53 shape_id: NULL_INDEX,
54 generation: 0,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Default)]
62pub struct Sensor {
63 pub hits: Vec<Visitor>,
64 pub overlaps1: Vec<Visitor>,
65 pub overlaps2: Vec<Visitor>,
66 pub shape_id: i32,
67}
68
69impl Sensor {
70 pub fn new(shape_id: i32) -> Sensor {
71 Sensor {
72 hits: Vec::with_capacity(4),
73 overlaps1: Vec::with_capacity(16),
74 overlaps2: Vec::with_capacity(16),
75 shape_id,
76 }
77 }
78}
79
80#[derive(Debug, Clone, Default)]
82pub struct SensorTaskContext {
83 pub event_bits: BitSet,
84}
85
86fn make_shape_proxy(shape: &Shape) -> ShapeProxy {
88 match &shape.geometry {
89 ShapeGeometry::Capsule(capsule) => {
90 make_proxy(&[capsule.center1, capsule.center2], capsule.radius)
91 }
92 ShapeGeometry::Sphere(sphere) => make_proxy(&[sphere.center], sphere.radius),
93 ShapeGeometry::Hull(hull) => {
94 let points = get_hull_points(hull);
95 make_proxy(points, 0.0)
96 }
97 _ => {
98 debug_assert!(false, "make_shape_proxy: unsupported visitor shape type");
99 ShapeProxy::default()
100 }
101 }
102}
103
104fn overlap_sensor(
107 sensor_shape: &Shape,
108 sensor_transform: Transform,
109 visitor_shape: &Shape,
110 visitor_transform: Transform,
111) -> bool {
112 let proxy = make_shape_proxy(visitor_shape);
113 let relative_transform = inv_mul_transforms(sensor_transform, visitor_transform);
114
115 let mut local_proxy = ShapeProxy {
116 count: min_int(proxy.count, MAX_SHAPE_CAST_POINTS as i32),
117 radius: proxy.radius,
118 ..ShapeProxy::default()
119 };
120 for i in 0..local_proxy.count as usize {
121 local_proxy.points[i] = transform_point(relative_transform, proxy.points[i]);
122 }
123
124 match &sensor_shape.geometry {
125 ShapeGeometry::Capsule(capsule) => {
126 overlap_capsule(capsule, TRANSFORM_IDENTITY, &local_proxy)
127 }
128 ShapeGeometry::Compound(compound) => {
129 overlap_compound(compound, TRANSFORM_IDENTITY, &local_proxy)
130 }
131 ShapeGeometry::HeightField(hf) => {
132 overlap_height_field(hf, TRANSFORM_IDENTITY, &local_proxy)
133 }
134 ShapeGeometry::Hull(hull) => overlap_hull(hull, TRANSFORM_IDENTITY, &local_proxy),
135 ShapeGeometry::Mesh { data, scale } => {
136 let mesh = Mesh::new(data, *scale);
137 overlap_mesh(&mesh, TRANSFORM_IDENTITY, &local_proxy)
138 }
139 ShapeGeometry::Sphere(sphere) => overlap_sphere(sphere, TRANSFORM_IDENTITY, &local_proxy),
140 }
141}
142
143fn sensor_accepts_visitor(
145 world: &World,
146 sensor_shape: &Shape,
147 sensor_transform: Transform,
148 visitor_shape_id: i32,
149) -> bool {
150 let sensor_shape_id = sensor_shape.id;
151 if visitor_shape_id == sensor_shape_id {
152 return false;
153 }
154
155 let other_shape = &world.shapes[visitor_shape_id as usize];
156 let other_type = other_shape.shape_type();
157 let sensor_type = sensor_shape.shape_type();
158 if (other_type == ShapeType::Mesh || other_type == ShapeType::Height)
159 && (sensor_type == ShapeType::Mesh || sensor_type == ShapeType::Height)
160 {
161 return false;
162 }
163
164 if (other_shape.flags & shape_flags::ENABLE_SENSOR_EVENTS) == 0 {
165 return false;
166 }
167 if other_shape.body_id == sensor_shape.body_id {
168 return false;
169 }
170 if !should_shapes_collide(sensor_shape.filter, other_shape.filter) {
171 return false;
172 }
173
174 if (sensor_shape.flags & shape_flags::ENABLE_CUSTOM_FILTERING) != 0
175 || (other_shape.flags & shape_flags::ENABLE_CUSTOM_FILTERING) != 0
176 {
177 if let Some(custom_filter_fcn) = world.custom_filter_fcn {
178 let id_a = ShapeId {
179 index1: sensor_shape_id + 1,
180 world0: world.world_id,
181 generation: sensor_shape.generation,
182 };
183 let id_b = ShapeId {
184 index1: visitor_shape_id + 1,
185 world0: world.world_id,
186 generation: other_shape.generation,
187 };
188 if !custom_filter_fcn(world, id_a, id_b, world.custom_filter_context) {
189 return false;
190 }
191 }
192 }
193
194 let other_transform =
195 to_relative_transform(get_body_transform(world, other_shape.body_id), POS_ZERO);
196 overlap_sensor(sensor_shape, sensor_transform, other_shape, other_transform)
197}
198
199fn sensor_task(world: &mut World, start_index: usize, end_index: usize) {
201 debug_assert!(start_index < end_index);
202
203 for sensor_index in start_index..end_index {
204 {
205 let sensor = &mut world.sensors[sensor_index];
206 std::mem::swap(&mut sensor.overlaps1, &mut sensor.overlaps2);
207 sensor.overlaps2.clear();
208 sensor.overlaps2.append(&mut sensor.hits);
209 }
210
211 let shape_id = world.sensors[sensor_index].shape_id;
212 let body_id = world.shapes[shape_id as usize].body_id;
213 let body_set_index = world.bodies[body_id as usize].set_index;
214 let sensor_events_enabled =
215 (world.shapes[shape_id as usize].flags & shape_flags::ENABLE_SENSOR_EVENTS) != 0;
216
217 if body_set_index == DISABLED_SET || !sensor_events_enabled {
218 if !world.sensors[sensor_index].overlaps1.is_empty() {
219 world.sensor_task_contexts[0]
220 .event_bits
221 .set_bit(sensor_index as u32);
222 }
223 continue;
224 }
225
226 let transform = to_relative_transform(get_body_transform(world, body_id), POS_ZERO);
227 debug_assert!(world.shapes[shape_id as usize].sensor_index == sensor_index as i32);
228
229 let query_bounds = world.shapes[shape_id as usize].aabb;
230 let mask_bits = world.shapes[shape_id as usize].filter.mask_bits;
231
232 let mut candidates = Vec::new();
233 for tree_index in 0..BodyType::Dynamic as usize + 1 {
234 world.broad_phase.trees[tree_index].query(
235 query_bounds,
236 mask_bits,
237 false,
238 |_proxy_id, user_data| {
239 candidates.push(user_data as i32);
240 true
241 },
242 );
243 }
244
245 for visitor_shape_id in candidates {
246 let accepted = {
247 let sensor_shape = &world.shapes[shape_id as usize];
248 sensor_accepts_visitor(world, sensor_shape, transform, visitor_shape_id)
249 };
250 if accepted {
251 let generation = world.shapes[visitor_shape_id as usize].generation;
252 world.sensors[sensor_index].overlaps2.push(Visitor {
253 shape_id: visitor_shape_id,
254 generation,
255 });
256 }
257 }
258
259 world.sensors[sensor_index]
260 .overlaps2
261 .sort_unstable_by_key(|a| a.shape_id);
262
263 {
264 let overlaps = &mut world.sensors[sensor_index].overlaps2;
265 let mut unique_count = 0usize;
266 for i in 0..overlaps.len() {
267 if unique_count == 0 || overlaps[i].shape_id != overlaps[unique_count - 1].shape_id
268 {
269 overlaps[unique_count] = overlaps[i];
270 unique_count += 1;
271 }
272 }
273 overlaps.truncate(unique_count);
274 }
275
276 let count1 = world.sensors[sensor_index].overlaps1.len();
277 let count2 = world.sensors[sensor_index].overlaps2.len();
278 if count1 != count2 {
279 world.sensor_task_contexts[0]
280 .event_bits
281 .set_bit(sensor_index as u32);
282 } else {
283 let changed = (0..count1).any(|i| {
284 let s1 = world.sensors[sensor_index].overlaps1[i];
285 let s2 = world.sensors[sensor_index].overlaps2[i];
286 s1.shape_id != s2.shape_id || s1.generation != s2.generation
287 });
288 if changed {
289 world.sensor_task_contexts[0]
290 .event_bits
291 .set_bit(sensor_index as u32);
292 }
293 }
294 }
295}
296
297fn publish_sensor_events(world: &mut World) {
298 let bits: Vec<u64> = {
299 let bit_set = &world.sensor_task_contexts[0].event_bits;
300 (0..bit_set.block_count())
301 .map(|k| bit_set.block(k))
302 .collect()
303 };
304 let world_id = world.world_id;
305 let end_index = world.end_event_array_index as usize;
306
307 for (k, mut word) in bits.into_iter().enumerate() {
308 while word != 0 {
309 let ctz = word.trailing_zeros();
310 let sensor_index = (64 * k as u32 + ctz) as usize;
311
312 let shape_id = world.sensors[sensor_index].shape_id;
313 let sensor_generation = world.shapes[shape_id as usize].generation;
314 let sensor_id = ShapeId {
315 index1: shape_id + 1,
316 world0: world_id,
317 generation: sensor_generation,
318 };
319
320 let count1 = world.sensors[sensor_index].overlaps1.len();
321 let count2 = world.sensors[sensor_index].overlaps2.len();
322
323 let mut index1 = 0usize;
324 let mut index2 = 0usize;
325 while index1 < count1 && index2 < count2 {
326 let r1 = world.sensors[sensor_index].overlaps1[index1];
327 let r2 = world.sensors[sensor_index].overlaps2[index2];
328 if r1.shape_id == r2.shape_id {
329 if r1.generation < r2.generation {
330 world.sensor_end_events[end_index].push(SensorEndTouchEvent {
331 sensor_shape_id: sensor_id,
332 visitor_shape_id: ShapeId {
333 index1: r1.shape_id + 1,
334 world0: world_id,
335 generation: r1.generation,
336 },
337 });
338 index1 += 1;
339 } else if r1.generation > r2.generation {
340 world.sensor_begin_events.push(SensorBeginTouchEvent {
341 sensor_shape_id: sensor_id,
342 visitor_shape_id: ShapeId {
343 index1: r2.shape_id + 1,
344 world0: world_id,
345 generation: r2.generation,
346 },
347 });
348 index2 += 1;
349 } else {
350 index1 += 1;
351 index2 += 1;
352 }
353 } else if r1.shape_id < r2.shape_id {
354 world.sensor_end_events[end_index].push(SensorEndTouchEvent {
355 sensor_shape_id: sensor_id,
356 visitor_shape_id: ShapeId {
357 index1: r1.shape_id + 1,
358 world0: world_id,
359 generation: r1.generation,
360 },
361 });
362 index1 += 1;
363 } else {
364 world.sensor_begin_events.push(SensorBeginTouchEvent {
365 sensor_shape_id: sensor_id,
366 visitor_shape_id: ShapeId {
367 index1: r2.shape_id + 1,
368 world0: world_id,
369 generation: r2.generation,
370 },
371 });
372 index2 += 1;
373 }
374 }
375
376 while index1 < count1 {
377 let r1 = world.sensors[sensor_index].overlaps1[index1];
378 world.sensor_end_events[end_index].push(SensorEndTouchEvent {
379 sensor_shape_id: sensor_id,
380 visitor_shape_id: ShapeId {
381 index1: r1.shape_id + 1,
382 world0: world_id,
383 generation: r1.generation,
384 },
385 });
386 index1 += 1;
387 }
388
389 while index2 < count2 {
390 let r2 = world.sensors[sensor_index].overlaps2[index2];
391 world.sensor_begin_events.push(SensorBeginTouchEvent {
392 sensor_shape_id: sensor_id,
393 visitor_shape_id: ShapeId {
394 index1: r2.shape_id + 1,
395 world0: world_id,
396 generation: r2.generation,
397 },
398 });
399 index2 += 1;
400 }
401
402 word &= word - 1;
403 }
404 }
405}
406
407pub fn overlap_sensors(world: &mut World) {
409 let sensor_count = world.sensors.len();
410 if sensor_count == 0 {
411 return;
412 }
413
414 debug_assert!(!world.sensor_task_contexts.is_empty());
415 world.sensor_task_contexts[0]
416 .event_bits
417 .set_bit_count_and_clear(sensor_count as u32);
418
419 sensor_task(world, 0, sensor_count);
420 publish_sensor_events(world);
421}
422
423pub fn destroy_sensor(world: &mut World, sensor_shape_id: i32) {
426 let sensor_index = world.shapes[sensor_shape_id as usize].sensor_index;
427 debug_assert!(sensor_index != NULL_INDEX);
428
429 let world_id = world.world_id;
430 let generation = world.shapes[sensor_shape_id as usize].generation;
431 let end_index = world.end_event_array_index as usize;
432
433 let overlaps: Vec<_> = world.sensors[sensor_index as usize].overlaps2.clone();
434 for visitor in overlaps {
435 world.sensor_end_events[end_index].push(SensorEndTouchEvent {
436 sensor_shape_id: ShapeId {
437 index1: sensor_shape_id + 1,
438 world0: world_id,
439 generation,
440 },
441 visitor_shape_id: ShapeId {
442 index1: visitor.shape_id + 1,
443 world0: world_id,
444 generation: visitor.generation,
445 },
446 });
447 }
448
449 world.sensors[sensor_index as usize].hits.clear();
450 world.sensors[sensor_index as usize].overlaps1.clear();
451 world.sensors[sensor_index as usize].overlaps2.clear();
452
453 let last = world.sensors.len() as i32 - 1;
454 world.sensors.swap_remove(sensor_index as usize);
455 if sensor_index < last {
456 let moved_shape_id = world.sensors[sensor_index as usize].shape_id;
457 world.shapes[moved_shape_id as usize].sensor_index = sensor_index;
458 }
459}