Skip to main content

box3d_rust/types/
shape.rs

1// Shape filter types and defaults from types.h / types.c.
2// SPDX-FileCopyrightText: 2025 Erin Catto
3// SPDX-License-Identifier: MIT
4
5use crate::core::{get_length_units_per_meter, SECRET_COOKIE};
6use crate::dynamic_tree::{DEFAULT_CATEGORY_BITS, DEFAULT_MASK_BITS};
7use crate::geometry::{default_surface_material, SurfaceMaterial};
8
9/// This is used to filter collisions. (b3Filter)
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct Filter {
12    /// The collision category bits. Normally you would just set one bit.
13    pub category_bits: u64,
14    /// The collision mask bits. Categories this shape accepts for collision.
15    pub mask_bits: u64,
16    /// Collision groups: negative never collide, positive always collide.
17    /// Zero has no effect. Non-zero group filtering always wins against masks.
18    pub group_index: i32,
19}
20
21/// Use this to initialize your filter. (b3DefaultFilter)
22pub fn default_filter() -> Filter {
23    Filter {
24        category_bits: DEFAULT_CATEGORY_BITS,
25        mask_bits: DEFAULT_MASK_BITS,
26        group_index: 0,
27    }
28}
29
30impl Default for Filter {
31    fn default() -> Self {
32        default_filter()
33    }
34}
35
36/// The query filter is used to filter collisions between queries and shapes.
37/// (b3QueryFilter)
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct QueryFilter {
40    /// The collision category bits of this query.
41    pub category_bits: u64,
42    /// The collision mask bits. Shape categories this query accepts.
43    pub mask_bits: u64,
44    /// Optional id combined with [`Self::name`] to identify this query in a recording.
45    pub id: u64,
46    /// Optional label combined with [`Self::id`] for recording. Empty means none.
47    pub name: String,
48}
49
50/// Use this to initialize your query filter. (b3DefaultQueryFilter)
51pub fn default_query_filter() -> QueryFilter {
52    QueryFilter {
53        category_bits: DEFAULT_CATEGORY_BITS,
54        mask_bits: DEFAULT_MASK_BITS,
55        id: 0,
56        name: String::new(),
57    }
58}
59
60impl Default for QueryFilter {
61    fn default() -> Self {
62        default_query_filter()
63    }
64}
65
66/// Used to create a shape. (b3ShapeDef)
67#[derive(Debug, Clone)]
68pub struct ShapeDef {
69    /// Optional shape name for debugging.
70    pub name: String,
71    /// Application-specific shape data.
72    pub user_data: u64,
73    /// Per-triangle materials for meshes. Empty means use [`Self::base_material`].
74    /// Ignored for convex shapes and compounds.
75    pub materials: Vec<SurfaceMaterial>,
76    /// The base surface material. Ignored for compound shapes.
77    pub base_material: SurfaceMaterial,
78    /// The density, usually in kg/m^3.
79    pub density: f32,
80    /// Explosion scale for `World::explode`. Non-dimensional.
81    pub explosion_scale: f32,
82    /// Contact filtering data.
83    pub filter: Filter,
84    /// Enable custom filtering. Only one of the two shapes needs to enable it.
85    pub enable_custom_filtering: bool,
86    /// A sensor shape generates overlap events but never a collision response.
87    pub is_sensor: bool,
88    /// Enable sensor events for this shape. False by default, even for sensors.
89    pub enable_sensor_events: bool,
90    /// Enable contact events. Only kinematic/dynamic; ignored for sensors.
91    pub enable_contact_events: bool,
92    /// Enable hit events. Only kinematic/dynamic; ignored for sensors.
93    pub enable_hit_events: bool,
94    /// Enable pre-solve contact events. Only dynamic; ignored for sensors.
95    pub enable_pre_solve_events: bool,
96    /// When true, static shapes scan for contacts on the next step.
97    pub invoke_contact_creation: bool,
98    /// Should the body update mass properties when this shape is created.
99    pub update_body_mass: bool,
100    /// Used internally to detect a valid definition. DO NOT SET.
101    pub internal_value: i32,
102}
103
104/// Use this to initialize your shape definition. (b3DefaultShapeDef)
105pub fn default_shape_def() -> ShapeDef {
106    let length_units = get_length_units_per_meter();
107    ShapeDef {
108        name: String::new(),
109        user_data: 0,
110        materials: Vec::new(),
111        base_material: default_surface_material(),
112        // density of water
113        density: 1000.0 / (length_units * length_units * length_units),
114        explosion_scale: 1.0,
115        filter: default_filter(),
116        enable_custom_filtering: false,
117        is_sensor: false,
118        enable_sensor_events: false,
119        enable_contact_events: false,
120        enable_hit_events: false,
121        enable_pre_solve_events: false,
122        invoke_contact_creation: true,
123        update_body_mass: true,
124        internal_value: SECRET_COOKIE,
125    }
126}
127
128impl Default for ShapeDef {
129    fn default() -> Self {
130        default_shape_def()
131    }
132}