Skip to main content

box3d_rust/geometry/
types.rs

1//! Geometry shape types from include/box3d/types.h.
2//!
3//! `CastOutput` lives in [`crate::distance`] and is re-exported from the
4//! geometry module.
5//!
6//! SPDX-FileCopyrightText: 2026 Erin Catto
7//! SPDX-License-Identifier: MIT
8
9use crate::distance::ShapeProxy;
10use crate::math_functions::{Matrix3, Plane, Vec3, MAT3_ZERO, VEC3_ZERO};
11
12/// This holds the mass data computed for a shape. (b3MassData)
13#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct MassData {
15    /// The shape mass
16    pub mass: f32,
17    /// The local center of mass position.
18    pub center: Vec3,
19    /// The inertia tensor about the shape center of mass.
20    pub inertia: Matrix3,
21}
22
23impl Default for MassData {
24    fn default() -> Self {
25        MassData {
26            mass: 0.0,
27            center: VEC3_ZERO,
28            inertia: MAT3_ZERO,
29        }
30    }
31}
32
33/// A solid sphere. (b3Sphere)
34#[derive(Debug, Clone, Copy, PartialEq, Default)]
35pub struct Sphere {
36    /// The local center
37    pub center: Vec3,
38    /// The radius
39    pub radius: f32,
40}
41
42/// A solid capsule can be viewed as two hemispheres connected by a cylinder.
43/// (b3Capsule)
44#[derive(Debug, Clone, Copy, PartialEq, Default)]
45pub struct Capsule {
46    /// Local center of the first hemisphere
47    pub center1: Vec3,
48    /// Local center of the second hemisphere
49    pub center2: Vec3,
50    /// The radius of the hemispheres
51    pub radius: f32,
52}
53
54/// Low level ray cast input data. (b3RayCastInput)
55#[derive(Debug, Clone, Copy, PartialEq, Default)]
56pub struct RayCastInput {
57    /// Start point of the ray cast.
58    pub origin: Vec3,
59    /// Translation of the ray cast. `end = start + translation`.
60    pub translation: Vec3,
61    /// The maximum fraction of the translation to consider, typically 1
62    pub max_fraction: f32,
63}
64
65/// Low level shape cast input in generic form. This allows casting an arbitrary
66/// point cloud wrapped with a radius. For example, a sphere is a single point
67/// with a non-zero radius. A capsule is two points with a non-zero radius. A box
68/// is eight points with a zero radius. (b3ShapeCastInput)
69#[derive(Debug, Clone, Copy, PartialEq, Default)]
70pub struct ShapeCastInput {
71    /// A generic query shape.
72    pub proxy: ShapeProxy,
73    /// The translation of the shape cast.
74    pub translation: Vec3,
75    /// The maximum fraction of the translation to consider, typically 1.
76    pub max_fraction: f32,
77    /// Allow shape cast to encroach when initially touching. This only works if
78    /// the radius is greater than zero.
79    pub can_encroach: bool,
80}
81
82/// The plane between a character mover and a shape. (b3PlaneResult)
83#[derive(Debug, Clone, Copy, PartialEq)]
84pub struct PlaneResult {
85    /// Outward pointing plane.
86    pub plane: Plane,
87    /// Closest point on the shape. May not be unique.
88    pub point: Vec3,
89}
90
91impl Default for PlaneResult {
92    fn default() -> Self {
93        PlaneResult {
94            plane: Plane {
95                normal: VEC3_ZERO,
96                offset: 0.0,
97            },
98            point: VEC3_ZERO,
99        }
100    }
101}
102
103/// Collision planes that can be fed to [`crate::mover::solve_planes`].
104/// Normally assembled by the user from [`PlaneResult`] values. (b3CollisionPlane)
105#[derive(Debug, Clone, Copy, PartialEq)]
106pub struct CollisionPlane {
107    /// The collision plane between the mover and some shape.
108    pub plane: Plane,
109    /// Setting this to `f32::MAX` makes the plane as rigid as possible. Lower
110    /// values can make the plane collision soft. Usually in meters.
111    pub push_limit: f32,
112    /// The push on the mover determined by `solve_planes`. Usually in meters.
113    pub push: f32,
114    /// Indicates if `clip_vector` should clip against this plane. Should be
115    /// false for soft collision.
116    pub clip_velocity: bool,
117}
118
119impl Default for CollisionPlane {
120    fn default() -> Self {
121        CollisionPlane {
122            plane: Plane {
123                normal: VEC3_ZERO,
124                offset: 0.0,
125            },
126            push_limit: 0.0,
127            push: 0.0,
128            clip_velocity: false,
129        }
130    }
131}
132
133/// Result returned by [`crate::mover::solve_planes`]. (b3PlaneSolverResult)
134#[derive(Debug, Clone, Copy, PartialEq, Default)]
135pub struct PlaneSolverResult {
136    /// The final relative translation.
137    pub delta: Vec3,
138    /// The number of iterations used by the plane solver. For diagnostics.
139    pub iteration_count: i32,
140}
141
142/// Material properties supported per triangle on meshes and height fields.
143/// (b3SurfaceMaterial)
144#[derive(Debug, Clone, Copy, PartialEq)]
145#[repr(C)]
146pub struct SurfaceMaterial {
147    /// The Coulomb (dry) friction coefficient, usually in the range [0,1].
148    pub friction: f32,
149    /// The coefficient of restitution (bounce) usually in the range [0,1].
150    pub restitution: f32,
151    /// The rolling resistance usually in the range [0,1].
152    pub rolling_resistance: f32,
153    /// The tangent velocity for conveyor belts.
154    pub tangent_velocity: Vec3,
155    /// User material identifier.
156    pub user_material_id: u64,
157    /// Custom debug draw color. Ignored if 0.
158    pub custom_color: u32,
159}
160
161impl Default for SurfaceMaterial {
162    fn default() -> Self {
163        default_surface_material()
164    }
165}
166
167/// Use this to initialize your surface material. (b3DefaultSurfaceMaterial)
168pub fn default_surface_material() -> SurfaceMaterial {
169    SurfaceMaterial {
170        friction: 0.6,
171        restitution: 0.0,
172        rolling_resistance: 0.0,
173        tangent_velocity: VEC3_ZERO,
174        user_material_id: 0,
175        custom_color: 0,
176    }
177}
178
179/// Size of C `b3SurfaceMaterial` including trailing padding to 8-byte alignment.
180pub const SURFACE_MATERIAL_SIZE: usize = 40;
181
182impl SurfaceMaterial {
183    /// Serialize to the C layout (40 bytes with padding).
184    pub fn to_bytes(self) -> [u8; SURFACE_MATERIAL_SIZE] {
185        let mut buf = [0u8; SURFACE_MATERIAL_SIZE];
186        buf[0..4].copy_from_slice(&self.friction.to_le_bytes());
187        buf[4..8].copy_from_slice(&self.restitution.to_le_bytes());
188        buf[8..12].copy_from_slice(&self.rolling_resistance.to_le_bytes());
189        buf[12..16].copy_from_slice(&self.tangent_velocity.x.to_le_bytes());
190        buf[16..20].copy_from_slice(&self.tangent_velocity.y.to_le_bytes());
191        buf[20..24].copy_from_slice(&self.tangent_velocity.z.to_le_bytes());
192        buf[24..32].copy_from_slice(&self.user_material_id.to_le_bytes());
193        buf[32..36].copy_from_slice(&self.custom_color.to_le_bytes());
194        buf
195    }
196
197    /// Parse from the C layout.
198    pub fn from_bytes(buf: &[u8]) -> Self {
199        debug_assert!(buf.len() >= SURFACE_MATERIAL_SIZE);
200        let read_f32 = |o: usize| f32::from_le_bytes(buf[o..o + 4].try_into().unwrap());
201        Self {
202            friction: read_f32(0),
203            restitution: read_f32(4),
204            rolling_resistance: read_f32(8),
205            tangent_velocity: Vec3 {
206                x: read_f32(12),
207                y: read_f32(16),
208                z: read_f32(20),
209            },
210            user_material_id: u64::from_le_bytes(buf[24..32].try_into().unwrap()),
211            custom_color: u32::from_le_bytes(buf[32..36].try_into().unwrap()),
212        }
213    }
214}
215
216/// Shape type. (b3ShapeType)
217#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
218#[repr(i32)]
219pub enum ShapeType {
220    /// A capsule is an extruded sphere.
221    #[default]
222    Capsule = 0,
223    /// A baked compound shape.
224    Compound = 1,
225    /// A height field useful for terrain.
226    Height = 2,
227    /// A convex hull.
228    Hull = 3,
229    /// A triangle soup.
230    Mesh = 4,
231    /// A sphere with an offset.
232    Sphere = 5,
233}
234
235/// Minimum and maximum extent of a shape relative to a local origin.
236/// (math_internal.h: b3ShapeExtent)
237#[derive(Debug, Clone, Copy, PartialEq, Default)]
238pub struct ShapeExtent {
239    pub min_extent: f32,
240    pub max_extent: Vec3,
241}