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}