Skip to main content

box2d_rust/types/
world.rs

1// World creation types and default from types.h / types.c.
2// SPDX-FileCopyrightText: 2023 Erin Catto
3// SPDX-License-Identifier: MIT
4
5use crate::core::{get_length_units_per_meter, SECRET_COOKIE};
6use crate::id::ShapeId;
7use crate::math_functions::{Pos, Vec2, POS_ZERO, VEC2_ZERO};
8
9/// Optional friction mixing callback. The default uses `sqrt(frictionA * frictionB)`.
10/// (b2FrictionCallback)
11///
12/// Args: `(friction_a, user_material_id_a, friction_b, user_material_id_b)`.
13pub type FrictionCallback = fn(f32, u64, f32, u64) -> f32;
14
15/// Optional restitution mixing callback. The default uses
16/// `max(restitutionA, restitutionB)`. (b2RestitutionCallback)
17pub type RestitutionCallback = fn(f32, u64, f32, u64) -> f32;
18
19/// Result from `b2World_RayCastClosest`. (b2RayResult)
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct RayResult {
22    pub shape_id: ShapeId,
23    pub point: Pos,
24    pub normal: Vec2,
25    pub fraction: f32,
26    pub node_visits: i32,
27    pub leaf_visits: i32,
28    pub hit: bool,
29}
30
31impl Default for RayResult {
32    fn default() -> Self {
33        RayResult {
34            shape_id: ShapeId::default(),
35            point: POS_ZERO,
36            normal: VEC2_ZERO,
37            fraction: 0.0,
38            node_visits: 0,
39            leaf_visits: 0,
40            hit: false,
41        }
42    }
43}
44
45/// Optional world capacities that can be used to avoid run-time allocations.
46/// (b2Capacity)
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
48pub struct Capacity {
49    /// Number of expected static shapes.
50    pub static_shape_count: i32,
51    /// Number of expected dynamic and kinematic shapes.
52    pub dynamic_shape_count: i32,
53    /// Number of expected static bodies.
54    pub static_body_count: i32,
55    /// Number of expected dynamic and kinematic bodies.
56    pub dynamic_body_count: i32,
57    /// Number of expected contacts.
58    pub contact_count: i32,
59}
60
61/// Counters that give details of the simulation size. (b2Counters)
62///
63/// `byte_count`, `stack_used`, and `task_count` are always zero in this port:
64/// there is no global allocation tracker, no arena stack allocator, and no
65/// task system in the serial Rust implementation.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
67pub struct Counters {
68    pub byte_count: i64,
69    pub body_count: i32,
70    pub shape_count: i32,
71    pub contact_count: i32,
72    pub joint_count: i32,
73    pub island_count: i32,
74    pub stack_used: i32,
75    pub static_tree_height: i32,
76    pub tree_height: i32,
77    pub task_count: i32,
78    pub color_counts: [i32; crate::constants::GRAPH_COLOR_COUNT as usize],
79
80    /// Number of contacts touched by the collide pass (graph contacts +
81    /// awake-set non-touching).
82    pub awake_contact_count: i32,
83
84    /// Number of contacts recycled in the most recent step.
85    pub recycled_contact_count: i32,
86}
87
88/// The explosion definition is used to configure options for explosions.
89/// Explosions consider shape geometry when computing the impulse.
90/// (b2ExplosionDef)
91#[derive(Debug, Clone, Copy, PartialEq)]
92pub struct ExplosionDef {
93    /// Mask bits to filter shapes
94    pub mask_bits: u64,
95
96    /// The center of the explosion in world space
97    pub position: Pos,
98
99    /// The radius of the explosion
100    pub radius: f32,
101
102    /// The falloff distance beyond the radius. Impulse is reduced to zero at
103    /// this distance.
104    pub falloff: f32,
105
106    /// Impulse per unit length. This applies an impulse according to the
107    /// shape perimeter that is facing the explosion. Explosions only apply to
108    /// circles, capsules, and polygons. This may be negative for implosions.
109    pub impulse_per_length: f32,
110}
111
112/// Use this to initialize your explosion definition. (b2DefaultExplosionDef)
113pub fn default_explosion_def() -> ExplosionDef {
114    ExplosionDef {
115        mask_bits: crate::dynamic_tree::DEFAULT_MASK_BITS,
116        position: POS_ZERO,
117        radius: 0.0,
118        falloff: 0.0,
119        impulse_per_length: 0.0,
120    }
121}
122
123impl Default for ExplosionDef {
124    fn default() -> Self {
125        default_explosion_def()
126    }
127}
128
129/// World definition used to create a simulation world. Must be initialized
130/// using [`default_world_def`]. (b2WorldDef)
131///
132/// `PartialEq` is intentionally not derived: it holds optional function-pointer
133/// callbacks, and function-pointer equality is not meaningful.
134#[derive(Debug, Clone, Copy)]
135pub struct WorldDef {
136    /// Gravity vector. Box2D has no up-vector defined.
137    pub gravity: Vec2,
138    /// Restitution speed threshold, usually in m/s. Collisions above this speed
139    /// have restitution applied (will bounce).
140    pub restitution_threshold: f32,
141    /// Threshold speed for hit events. Usually meters per second.
142    pub hit_event_threshold: f32,
143    /// Contact stiffness. Cycles per second.
144    pub contact_hertz: f32,
145    /// Contact bounciness. Non-dimensional.
146    pub contact_damping_ratio: f32,
147    /// Speed cap on overlap resolution, usually meters per second.
148    pub contact_speed: f32,
149    /// Maximum linear speed. Usually meters per second.
150    pub maximum_linear_speed: f32,
151    /// Optional mixing callback for friction.
152    pub friction_callback: Option<FrictionCallback>,
153    /// Optional mixing callback for restitution.
154    pub restitution_callback: Option<RestitutionCallback>,
155    /// Can bodies go to sleep to improve performance.
156    pub enable_sleep: bool,
157    /// Enable continuous collision.
158    pub enable_continuous: bool,
159    /// Contact softening when mass ratios are large. Experimental.
160    pub enable_contact_softening: bool,
161    /// Number of workers for multithreading, clamped to `[1, MAX_WORKERS]`.
162    pub worker_count: i32,
163    /// User data.
164    pub user_data: u64,
165    /// Optional initial capacities.
166    pub capacity: Capacity,
167    /// Used internally to detect a valid definition. DO NOT SET.
168    pub internal_value: i32,
169}
170
171/// Initialize a world definition with the default values. (b2DefaultWorldDef)
172pub fn default_world_def() -> WorldDef {
173    let length_units = get_length_units_per_meter();
174    WorldDef {
175        gravity: Vec2 { x: 0.0, y: -10.0 },
176        hit_event_threshold: 1.0 * length_units,
177        restitution_threshold: 1.0 * length_units,
178        contact_speed: 3.0 * length_units,
179        contact_hertz: 30.0,
180        contact_damping_ratio: 10.0,
181        // 400 meters per second, faster than the speed of sound
182        maximum_linear_speed: 400.0 * length_units,
183        friction_callback: None,
184        restitution_callback: None,
185        enable_sleep: true,
186        enable_continuous: true,
187        enable_contact_softening: false,
188        worker_count: 0,
189        user_data: 0,
190        capacity: Capacity::default(),
191        internal_value: SECRET_COOKIE,
192    }
193}
194
195impl Default for WorldDef {
196    fn default() -> Self {
197        default_world_def()
198    }
199}