box3d_rust/events.rs
1// Port of the event types from include/box3d/types.h (events group).
2//
3// The C aggregate views (b3SensorEvents, b3ContactEvents, b3BodyEvents,
4// b3JointEvents) are pointer+count pairs over world-owned arrays. The Rust
5// world API returns slices; BodyEvents/JointEvents collapse to a single
6// slice while SensorEvents/ContactEvents keep grouping structs because they
7// bundle several arrays.
8//
9// SPDX-FileCopyrightText: 2025 Erin Catto
10// SPDX-License-Identifier: MIT
11
12use crate::id::{BodyId, ContactId, JointId, ShapeId};
13use crate::manifold::Manifold;
14use crate::math_functions::{Pos, Vec3, WorldTransform};
15
16/// The contact data for solid shape pairs. Manifolds are an owned snapshot of
17/// the contact's current manifolds (C exposes a transient pointer).
18/// (b3ContactData)
19#[derive(Debug, Clone, PartialEq)]
20pub struct ContactData {
21 /// The contact id. May become orphaned; use contact_is_valid before other use.
22 pub contact_id: ContactId,
23 /// The first shape id.
24 pub shape_id_a: ShapeId,
25 /// The second shape id.
26 pub shape_id_b: ShapeId,
27 /// Contact manifolds (owned copy; C: const b3Manifold* + manifoldCount).
28 pub manifolds: Vec<Manifold>,
29}
30
31/// A begin-touch event is generated when a shape starts to overlap a sensor
32/// shape. (b3SensorBeginTouchEvent)
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct SensorBeginTouchEvent {
35 /// The id of the sensor shape
36 pub sensor_shape_id: ShapeId,
37 /// The id of the shape that began touching the sensor shape
38 pub visitor_shape_id: ShapeId,
39}
40
41/// An end touch event is generated when a shape stops overlapping a sensor
42/// shape. Always confirm the shape id is valid before use. (b3SensorEndTouchEvent)
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub struct SensorEndTouchEvent {
45 /// The id of the sensor shape. @warning may have been destroyed
46 pub sensor_shape_id: ShapeId,
47 /// The id of the shape that stopped touching. @warning may have been destroyed
48 pub visitor_shape_id: ShapeId,
49}
50
51/// Sensor events buffered in the world for the current time step.
52/// Borrowed from world storage; invalidated by the next `World::step`.
53/// (b3SensorEvents)
54#[derive(Debug, Clone, Copy)]
55pub struct SensorEvents<'a> {
56 /// Array of sensor begin touch events
57 pub begin_events: &'a [SensorBeginTouchEvent],
58 /// Array of sensor end touch events (previous double-buffer slot)
59 pub end_events: &'a [SensorEndTouchEvent],
60}
61
62/// A begin-touch event is generated when two shapes begin touching.
63/// (b3ContactBeginTouchEvent)
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub struct ContactBeginTouchEvent {
66 /// Id of the first shape
67 pub shape_id_a: ShapeId,
68 /// Id of the second shape
69 pub shape_id_b: ShapeId,
70 /// The transient contact id. May be destroyed automatically when the world
71 /// is modified or simulated.
72 pub contact_id: ContactId,
73}
74
75/// An end touch event is generated when two shapes stop touching.
76/// (b3ContactEndTouchEvent)
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct ContactEndTouchEvent {
79 /// Id of the first shape. @warning may have been destroyed
80 pub shape_id_a: ShapeId,
81 /// Id of the second shape. @warning may have been destroyed
82 pub shape_id_b: ShapeId,
83 /// Id of the contact. @warning may have been destroyed
84 pub contact_id: ContactId,
85}
86
87/// A hit touch event is generated when two shapes collide faster than the hit
88/// speed threshold. (b3ContactHitEvent)
89#[derive(Debug, Clone, Copy, PartialEq)]
90pub struct ContactHitEvent {
91 /// Id of the first shape
92 pub shape_id_a: ShapeId,
93 /// Id of the second shape
94 pub shape_id_b: ShapeId,
95 /// Id of the contact. @warning may have been destroyed
96 pub contact_id: ContactId,
97 /// Point where the shapes hit, a mid-point between the two surfaces.
98 pub point: Pos,
99 /// Normal vector pointing from shape A to shape B
100 pub normal: Vec3,
101 /// The speed the shapes are approaching. Always positive.
102 pub approach_speed: f32,
103 /// User material on shape A
104 pub user_material_id_a: u64,
105 /// User material on shape B
106 pub user_material_id_b: u64,
107}
108
109/// Body move event, triggered when a body moves due to simulation. Not
110/// reported for bodies moved by the user. (b3BodyMoveEvent)
111#[derive(Debug, Clone, Copy, PartialEq)]
112pub struct BodyMoveEvent {
113 pub user_data: u64,
114 pub transform: WorldTransform,
115 pub body_id: BodyId,
116 pub fell_asleep: bool,
117}
118
119/// Joint event, reported for awake joints whose force and/or torque exceed the
120/// threshold. (b3JointEvent)
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub struct JointEvent {
123 /// The joint id
124 pub joint_id: JointId,
125 /// The user data from the joint for convenience
126 pub user_data: u64,
127}
128
129/// Contact events buffered in the world after a time step. (b3ContactEvents)
130#[derive(Debug, Clone, Copy)]
131pub struct ContactEvents<'a> {
132 pub begin_events: &'a [ContactBeginTouchEvent],
133 pub end_events: &'a [ContactEndTouchEvent],
134 pub hit_events: &'a [ContactHitEvent],
135}