1use crate::bitset::BitSet;
25use crate::body::Body;
26use crate::broad_phase::BroadPhase;
27use crate::constraint_graph::ConstraintGraph;
28use crate::contact::Contact;
29use crate::events::{
30 BodyMoveEvent, ContactBeginTouchEvent, ContactEndTouchEvent, ContactHitEvent, JointEvent,
31 SensorBeginTouchEvent, SensorEndTouchEvent,
32};
33use crate::id::ShapeId;
34use crate::id_pool::IdPool;
35use crate::island::Island;
36use crate::joint::Joint;
37use crate::math_functions::{Pos, Vec2};
38use crate::sensor::{Sensor, SensorHit, SensorTaskContext};
39use crate::shape::{ChainShape, Shape};
40use crate::solver_set::SolverSet;
41use crate::types::{Capacity, FrictionCallback, RestitutionCallback};
42
43pub type CustomFilterFcn = fn(ShapeId, ShapeId, u64) -> bool;
47
48pub type PreSolveFcn = fn(ShapeId, ShapeId, Pos, Vec2, u64) -> bool;
52
53#[derive(Debug, Clone, Copy, PartialEq, Default)]
55pub struct Profile {
56 pub step: f32,
57 pub pairs: f32,
58 pub collide: f32,
59 pub solve: f32,
60 pub solver_setup: f32,
61 pub constraints: f32,
62 pub prepare_constraints: f32,
63 pub integrate_velocities: f32,
64 pub warm_start: f32,
65 pub solve_impulses: f32,
66 pub integrate_positions: f32,
67 pub relax_impulses: f32,
68 pub apply_restitution: f32,
69 pub store_impulses: f32,
70 pub split_islands: f32,
71 pub transforms: f32,
72 pub sensor_hits: f32,
73 pub joint_events: f32,
74 pub hit_events: f32,
75 pub refit: f32,
76 pub bullets: f32,
77 pub sleep_islands: f32,
78 pub sensors: f32,
79}
80
81#[derive(Debug, Clone, Default)]
83pub struct TaskContext {
84 pub sensor_hits: Vec<SensorHit>,
86
87 pub contact_state_bit_set: BitSet,
90
91 pub hit_event_bit_set: BitSet,
93
94 pub has_hit_events: bool,
97
98 pub joint_state_bit_set: BitSet,
101
102 pub enlarged_sim_bit_set: BitSet,
105
106 pub awake_island_bit_set: BitSet,
108
109 pub split_sleep_time: f32,
111 pub split_island_id: i32,
112
113 pub recycled_contact_count: i32,
115}
116
117#[derive(Debug)]
120pub struct World {
121 pub broad_phase: BroadPhase,
122 pub constraint_graph: ConstraintGraph,
123
124 pub body_id_pool: IdPool,
127
128 pub bodies: Vec<Body>,
130
131 pub solver_set_id_pool: IdPool,
133
134 pub solver_sets: Vec<SolverSet>,
137
138 pub joint_id_pool: IdPool,
140
141 pub joints: Vec<Joint>,
144
145 pub contact_id_pool: IdPool,
147
148 pub contacts: Vec<Contact>,
151
152 pub island_id_pool: IdPool,
154
155 pub islands: Vec<Island>,
157
158 pub shape_id_pool: IdPool,
159 pub chain_id_pool: IdPool,
160
161 pub shapes: Vec<Shape>,
163 pub chain_shapes: Vec<ChainShape>,
164
165 pub sensors: Vec<Sensor>,
167
168 pub task_contexts: Vec<TaskContext>,
170 pub sensor_task_contexts: Vec<SensorTaskContext>,
171
172 pub body_move_events: Vec<BodyMoveEvent>,
173 pub sensor_begin_events: Vec<SensorBeginTouchEvent>,
174 pub contact_begin_events: Vec<ContactBeginTouchEvent>,
175
176 pub sensor_end_events: [Vec<SensorEndTouchEvent>; 2],
179 pub contact_end_events: [Vec<ContactEndTouchEvent>; 2],
180 pub end_event_array_index: i32,
181
182 pub contact_hit_events: Vec<ContactHitEvent>,
183 pub joint_events: Vec<JointEvent>,
184
185 pub debug_body_set: BitSet,
187 pub debug_joint_set: BitSet,
188 pub debug_contact_set: BitSet,
189 pub debug_island_set: BitSet,
190
191 pub step_index: u64,
193
194 pub split_island_id: i32,
196
197 pub gravity: Vec2,
198 pub hit_event_threshold: f32,
199 pub restitution_threshold: f32,
200 pub max_linear_speed: f32,
201 pub contact_speed: f32,
202 pub contact_hertz: f32,
203 pub contact_damping_ratio: f32,
204 pub contact_recycle_distance: f32,
205
206 pub friction_callback: Option<FrictionCallback>,
207 pub restitution_callback: Option<RestitutionCallback>,
208
209 pub generation: u16,
210
211 pub profile: Profile,
212
213 pub max_capacity: Capacity,
214
215 pub pre_solve_fcn: Option<PreSolveFcn>,
216 pub pre_solve_context: u64,
217
218 pub custom_filter_fcn: Option<CustomFilterFcn>,
219 pub custom_filter_context: u64,
220
221 pub worker_count: i32,
222
223 pub user_data: u64,
224
225 pub inv_h: f32,
227
228 pub inv_dt: f32,
230
231 pub world_id: u16,
232
233 pub enable_sleep: bool,
234 pub locked: bool,
235 pub enable_warm_starting: bool,
236 pub enable_contact_softening: bool,
237 pub enable_continuous: bool,
238 pub enable_speculative: bool,
239 pub in_use: bool,
240
241 pub recording: Option<crate::recording::Recording>,
244}
245
246pub fn default_friction_callback(
249 friction_a: f32,
250 _material_a: u64,
251 friction_b: f32,
252 _material_b: u64,
253) -> f32 {
254 (friction_a * friction_b).sqrt()
255}
256
257pub fn default_restitution_callback(
260 restitution_a: f32,
261 _material_a: u64,
262 restitution_b: f32,
263 _material_b: u64,
264) -> f32 {
265 crate::math_functions::max_float(restitution_a, restitution_b)
266}
267
268impl World {
269 pub fn new(def: &crate::types::WorldDef) -> World {
277 use crate::constants::contact_recycle_distance;
278 use crate::constraint_graph::ConstraintGraph;
279 use crate::math_functions::max_int;
280
281 debug_assert!(def.internal_value == crate::core::SECRET_COOKIE);
282
283 let body_capacity = max_int(
284 16,
285 def.capacity.static_body_count + def.capacity.dynamic_body_count,
286 ) as usize;
287 let shape_capacity = max_int(
288 16,
289 def.capacity.static_shape_count + def.capacity.dynamic_shape_count,
290 ) as usize;
291 let contact_capacity = max_int(16, def.capacity.contact_count) as usize;
292
293 let mut solver_set_id_pool = IdPool::new();
294 let mut solver_sets: Vec<SolverSet> = Vec::with_capacity(8);
295
296 let mut set = SolverSet {
299 set_index: solver_set_id_pool.alloc_id(),
300 ..Default::default()
301 };
302 set.body_sims
303 .reserve(max_int(16, def.capacity.static_body_count) as usize);
304 solver_sets.push(set);
305 debug_assert!(
306 solver_sets[crate::solver_set::STATIC_SET as usize].set_index
307 == crate::solver_set::STATIC_SET
308 );
309
310 solver_sets.push(SolverSet {
312 set_index: solver_set_id_pool.alloc_id(),
313 ..Default::default()
314 });
315 debug_assert!(
316 solver_sets[crate::solver_set::DISABLED_SET as usize].set_index
317 == crate::solver_set::DISABLED_SET
318 );
319
320 let mut awake = SolverSet {
322 set_index: solver_set_id_pool.alloc_id(),
323 ..Default::default()
324 };
325 awake
326 .body_sims
327 .reserve(max_int(16, def.capacity.dynamic_body_count) as usize);
328 awake
329 .body_states
330 .reserve(max_int(16, def.capacity.dynamic_body_count) as usize);
331 awake.contact_sims.reserve(contact_capacity);
332 solver_sets.push(awake);
333 debug_assert!(
334 solver_sets[crate::solver_set::AWAKE_SET as usize].set_index
335 == crate::solver_set::AWAKE_SET
336 );
337
338 World {
339 broad_phase: BroadPhase::new(&def.capacity),
340 constraint_graph: ConstraintGraph::new(&def.capacity),
341 body_id_pool: IdPool::new(),
342 bodies: Vec::with_capacity(body_capacity),
343 solver_set_id_pool,
344 solver_sets,
345 joint_id_pool: IdPool::new(),
346 joints: Vec::with_capacity(16),
347 contact_id_pool: IdPool::new(),
348 contacts: Vec::with_capacity(contact_capacity),
349 island_id_pool: IdPool::new(),
350 islands: Vec::with_capacity(max_int(16, def.capacity.dynamic_body_count) as usize),
351 shape_id_pool: IdPool::new(),
352 chain_id_pool: IdPool::new(),
353 shapes: Vec::with_capacity(shape_capacity),
354 chain_shapes: Vec::with_capacity(4),
355 sensors: Vec::with_capacity(4),
356 task_contexts: vec![TaskContext::default()],
358 sensor_task_contexts: vec![SensorTaskContext::default()],
359 body_move_events: Vec::with_capacity(4),
360 sensor_begin_events: Vec::with_capacity(4),
361 contact_begin_events: Vec::with_capacity(4),
362 sensor_end_events: [Vec::with_capacity(4), Vec::with_capacity(4)],
363 contact_end_events: [Vec::with_capacity(4), Vec::with_capacity(4)],
364 end_event_array_index: 0,
365 contact_hit_events: Vec::with_capacity(4),
366 joint_events: Vec::with_capacity(4),
367 debug_body_set: BitSet::new(256),
368 debug_joint_set: BitSet::new(256),
369 debug_contact_set: BitSet::new(256),
370 debug_island_set: BitSet::new(256),
371 step_index: 0,
372 split_island_id: crate::core::NULL_INDEX,
373 gravity: def.gravity,
374 hit_event_threshold: def.hit_event_threshold,
375 restitution_threshold: def.restitution_threshold,
376 max_linear_speed: def.maximum_linear_speed,
377 contact_speed: def.contact_speed,
378 contact_hertz: def.contact_hertz,
379 contact_damping_ratio: def.contact_damping_ratio,
380 contact_recycle_distance: contact_recycle_distance(),
381 friction_callback: Some(def.friction_callback.unwrap_or(default_friction_callback)),
382 restitution_callback: Some(
383 def.restitution_callback
384 .unwrap_or(default_restitution_callback),
385 ),
386 generation: 0,
387 profile: Profile::default(),
388 max_capacity: def.capacity,
389 pre_solve_fcn: None,
390 pre_solve_context: 0,
391 custom_filter_fcn: None,
392 custom_filter_context: 0,
393 worker_count: 1,
394 user_data: def.user_data,
395 inv_h: 0.0,
396 inv_dt: 0.0,
397 world_id: 0,
398 enable_sleep: def.enable_sleep,
399 locked: false,
400 enable_warm_starting: true,
401 enable_contact_softening: def.enable_contact_softening,
402 enable_continuous: def.enable_continuous,
403 enable_speculative: true,
404 in_use: true,
405 recording: None,
406 }
407 }
408
409 pub fn validate_solver_sets(&self) {
416 if !cfg!(debug_assertions) {
418 return;
419 }
420
421 use crate::core::NULL_INDEX;
422
423 let mut active_body_count = 0;
424 for (set_index, set) in self.solver_sets.iter().enumerate() {
425 if set.set_index == NULL_INDEX {
426 debug_assert!(set.body_sims.is_empty());
428 debug_assert!(set.body_states.is_empty());
429 debug_assert!(set.island_sims.is_empty());
430 continue;
431 }
432
433 debug_assert!(set.set_index == set_index as i32);
434
435 if set_index == crate::solver_set::AWAKE_SET as usize {
436 debug_assert!(set.body_sims.len() == set.body_states.len());
437 } else {
438 debug_assert!(set.body_states.is_empty());
439 }
440
441 for (local_index, sim) in set.body_sims.iter().enumerate() {
442 let body = &self.bodies[sim.body_id as usize];
443 debug_assert!(body.set_index == set_index as i32);
444 debug_assert!(body.local_index == local_index as i32);
445 debug_assert!(body.id == sim.body_id);
446 let _ = (body, local_index);
447 }
448 active_body_count += set.body_sims.len() as i32;
449
450 for (local_index, island_sim) in set.island_sims.iter().enumerate() {
451 let island = &self.islands[island_sim.island_id as usize];
452 debug_assert!(island.set_index == set_index as i32);
453 debug_assert!(island.local_index == local_index as i32);
454 let _ = (island, local_index);
455 }
456 }
457
458 debug_assert!(active_body_count == self.body_id_pool.id_count());
459 let _ = active_body_count;
460 }
461}
462
463mod api;
464mod collide;
465mod draw;
466mod query;
467mod step;
468
469pub use api::*;
470pub use draw::*;
471pub use query::*;
472pub use step::*;