mod api;
mod draw;
mod dump;
mod query;
mod step;
mod validate;
pub use api::*;
pub use draw::*;
pub use dump::*;
pub use query::*;
use crate::bitset::BitSet;
use crate::body::Body;
use crate::broad_phase::BroadPhase;
use crate::constants::CONTACT_MANIFOLD_COUNT_BUCKETS;
use crate::constraint_graph::ConstraintGraph;
use crate::contact::Contact;
use crate::debug_draw::{
CreateDebugShapeCallback, DebugLine, DebugPoint, DestroyDebugShapeCallback,
DEBUG_LINE_CAPACITY, DEBUG_POINT_CAPACITY,
};
use crate::events::{
BodyMoveEvent, ContactBeginTouchEvent, ContactEndTouchEvent, ContactHitEvent, JointEvent,
SensorBeginTouchEvent, SensorEndTouchEvent,
};
use crate::hull::HullDatabase;
use crate::id::ShapeId;
use crate::id_pool::IdPool;
use crate::island::Island;
use crate::joint::Joint;
use crate::math_functions::Vec3;
use crate::name_cache::NameCache;
use crate::sensor::{Sensor, SensorHit, SensorTaskContext};
use crate::shape::Shape;
use crate::solver_set::SolverSet;
use crate::types::{Capacity, FrictionCallback, RestitutionCallback};
pub type CustomFilterFcn = fn(&World, ShapeId, ShapeId, u64) -> bool;
pub type PreSolveFcn =
fn(ShapeId, ShapeId, crate::math_functions::Pos, crate::math_functions::Vec3, u64) -> bool;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Profile {
pub step: f32,
pub pairs: f32,
pub collide: f32,
pub solve: f32,
pub solver_setup: f32,
pub constraints: f32,
pub prepare_constraints: f32,
pub integrate_velocities: f32,
pub warm_start: f32,
pub solve_impulses: f32,
pub integrate_positions: f32,
pub relax_impulses: f32,
pub apply_restitution: f32,
pub store_impulses: f32,
pub split_islands: f32,
pub transforms: f32,
pub sensor_hits: f32,
pub joint_events: f32,
pub hit_events: f32,
pub refit: f32,
pub bullets: f32,
pub sleep_islands: f32,
pub sensors: f32,
}
#[derive(Debug, Clone)]
pub struct TaskContext {
pub sensor_hits: Vec<SensorHit>,
pub contact_state_bit_set: BitSet,
pub joint_state_bit_set: BitSet,
pub hit_event_bit_set: BitSet,
pub has_hit_events: bool,
pub enlarged_sim_bit_set: BitSet,
pub awake_island_bit_set: BitSet,
pub split_sleep_time: f32,
pub split_island_id: i32,
pub sat_call_count: i32,
pub sat_cache_hit_count: i32,
pub distance_iterations: i32,
pub push_back_iterations: i32,
pub root_iterations: i32,
pub recycled_contact_count: i32,
pub manifold_counts: [i32; CONTACT_MANIFOLD_COUNT_BUCKETS],
pub points: [DebugPoint; DEBUG_POINT_CAPACITY],
pub point_count: usize,
pub lines: [DebugLine; DEBUG_LINE_CAPACITY],
pub line_count: usize,
}
impl Default for TaskContext {
fn default() -> Self {
TaskContext {
sensor_hits: Vec::new(),
contact_state_bit_set: BitSet::default(),
joint_state_bit_set: BitSet::default(),
hit_event_bit_set: BitSet::default(),
has_hit_events: false,
enlarged_sim_bit_set: BitSet::default(),
awake_island_bit_set: BitSet::default(),
split_sleep_time: 0.0,
split_island_id: 0,
sat_call_count: 0,
sat_cache_hit_count: 0,
distance_iterations: 0,
push_back_iterations: 0,
root_iterations: 0,
recycled_contact_count: 0,
manifold_counts: [0; CONTACT_MANIFOLD_COUNT_BUCKETS],
points: [DebugPoint::default(); DEBUG_POINT_CAPACITY],
point_count: 0,
lines: [DebugLine::default(); DEBUG_LINE_CAPACITY],
line_count: 0,
}
}
}
#[derive(Debug)]
pub struct World {
pub broad_phase: BroadPhase,
pub constraint_graph: ConstraintGraph,
pub body_id_pool: IdPool,
pub bodies: Vec<Body>,
pub solver_set_id_pool: IdPool,
pub solver_sets: Vec<SolverSet>,
pub joint_id_pool: IdPool,
pub joints: Vec<Joint>,
pub contact_id_pool: IdPool,
pub contacts: Vec<Contact>,
pub island_id_pool: IdPool,
pub islands: Vec<Island>,
pub shape_id_pool: IdPool,
pub shapes: Vec<Shape>,
pub hull_database: HullDatabase,
pub names: NameCache,
pub sensors: Vec<Sensor>,
pub task_contexts: Vec<TaskContext>,
pub sensor_task_contexts: Vec<SensorTaskContext>,
pub body_move_events: Vec<BodyMoveEvent>,
pub sensor_begin_events: Vec<SensorBeginTouchEvent>,
pub contact_begin_events: Vec<ContactBeginTouchEvent>,
pub sensor_end_events: [Vec<SensorEndTouchEvent>; 2],
pub contact_end_events: [Vec<ContactEndTouchEvent>; 2],
pub end_event_array_index: i32,
pub contact_hit_events: Vec<ContactHitEvent>,
pub joint_events: Vec<JointEvent>,
pub debug_body_set: BitSet,
pub debug_joint_set: BitSet,
pub debug_contact_set: BitSet,
pub debug_island_set: BitSet,
pub step_index: u64,
pub split_island_id: i32,
pub gravity: Vec3,
pub hit_event_threshold: f32,
pub restitution_threshold: f32,
pub max_linear_speed: f32,
pub contact_speed: f32,
pub contact_hertz: f32,
pub contact_damping_ratio: f32,
pub contact_recycle_distance: f32,
pub friction_callback: Option<FrictionCallback>,
pub restitution_callback: Option<RestitutionCallback>,
pub generation: u16,
pub profile: Profile,
pub sat_call_count: i32,
pub sat_cache_hit_count: i32,
pub manifold_counts: [i32; CONTACT_MANIFOLD_COUNT_BUCKETS],
pub max_capacity: Capacity,
pub pre_solve_fcn: Option<PreSolveFcn>,
pub pre_solve_context: u64,
pub custom_filter_fcn: Option<CustomFilterFcn>,
pub custom_filter_context: u64,
pub create_debug_shape: Option<CreateDebugShapeCallback>,
pub destroy_debug_shape: Option<DestroyDebugShapeCallback>,
pub user_debug_shape_context: u64,
pub worker_count: i32,
pub user_data: u64,
pub inv_h: f32,
pub inv_dt: f32,
pub world_id: u16,
pub enable_sleep: bool,
pub locked: bool,
pub enable_warm_starting: bool,
pub enable_continuous: bool,
pub enable_speculative: bool,
pub in_use: bool,
pub recording: Option<*mut crate::recording::Recording>,
}
pub fn default_friction_callback(
friction_a: f32,
_material_a: u64,
friction_b: f32,
_material_b: u64,
) -> f32 {
(friction_a * friction_b).sqrt()
}
pub fn default_restitution_callback(
restitution_a: f32,
_material_a: u64,
restitution_b: f32,
_material_b: u64,
) -> f32 {
crate::math_functions::max_float(restitution_a, restitution_b)
}
impl World {
pub fn new(def: &crate::types::WorldDef) -> World {
use crate::constants::{
contact_recycle_distance, linear_slop, mesh_rest_offset, speculative_distance,
};
use crate::core::{NULL_INDEX, SECRET_COOKIE};
use crate::math_functions::max_int;
use crate::solver_set::{AWAKE_SET, DISABLED_SET, STATIC_SET};
debug_assert!(def.internal_value == SECRET_COOKIE);
debug_assert!(linear_slop() <= mesh_rest_offset());
debug_assert!(mesh_rest_offset() < speculative_distance());
use crate::contact::initialize_contact_registers;
initialize_contact_registers();
let body_capacity = max_int(
16,
def.capacity.static_body_count + def.capacity.dynamic_body_count,
) as usize;
let shape_capacity = max_int(
16,
def.capacity.static_shape_count + def.capacity.dynamic_shape_count,
) as usize;
let contact_capacity = max_int(16, def.capacity.contact_count) as usize;
let mut solver_set_id_pool = IdPool::new();
let mut solver_sets: Vec<SolverSet> = Vec::with_capacity(8);
let mut set = SolverSet {
set_index: solver_set_id_pool.alloc_id(),
..Default::default()
};
set.body_sims
.reserve(max_int(16, def.capacity.static_body_count) as usize);
solver_sets.push(set);
debug_assert!(solver_sets[STATIC_SET as usize].set_index == STATIC_SET);
solver_sets.push(SolverSet {
set_index: solver_set_id_pool.alloc_id(),
..Default::default()
});
debug_assert!(solver_sets[DISABLED_SET as usize].set_index == DISABLED_SET);
let mut awake = SolverSet {
set_index: solver_set_id_pool.alloc_id(),
..Default::default()
};
awake
.body_sims
.reserve(max_int(16, def.capacity.dynamic_body_count) as usize);
awake
.body_states
.reserve(max_int(16, def.capacity.dynamic_body_count) as usize);
awake.contact_indices.reserve(contact_capacity);
solver_sets.push(awake);
debug_assert!(solver_sets[AWAKE_SET as usize].set_index == AWAKE_SET);
World {
broad_phase: BroadPhase::new(&def.capacity),
constraint_graph: ConstraintGraph::new(16),
body_id_pool: IdPool::new(),
bodies: Vec::with_capacity(body_capacity),
solver_set_id_pool,
solver_sets,
joint_id_pool: IdPool::new(),
joints: Vec::with_capacity(16),
contact_id_pool: IdPool::new(),
contacts: Vec::with_capacity(contact_capacity),
island_id_pool: IdPool::new(),
islands: Vec::with_capacity(max_int(16, def.capacity.dynamic_body_count) as usize),
shape_id_pool: IdPool::new(),
shapes: Vec::with_capacity(shape_capacity),
hull_database: HullDatabase::new(),
names: NameCache::new(),
sensors: Vec::with_capacity(4),
task_contexts: vec![TaskContext::default()],
sensor_task_contexts: vec![SensorTaskContext::default()],
body_move_events: Vec::with_capacity(4),
sensor_begin_events: Vec::with_capacity(4),
contact_begin_events: Vec::with_capacity(4),
sensor_end_events: [Vec::with_capacity(4), Vec::with_capacity(4)],
contact_end_events: [Vec::with_capacity(4), Vec::with_capacity(4)],
end_event_array_index: 0,
contact_hit_events: Vec::with_capacity(4),
joint_events: Vec::with_capacity(4),
debug_body_set: BitSet::new(256),
debug_joint_set: BitSet::new(256),
debug_contact_set: BitSet::new(256),
debug_island_set: BitSet::new(256),
step_index: 0,
split_island_id: NULL_INDEX,
gravity: def.gravity,
hit_event_threshold: def.hit_event_threshold,
restitution_threshold: def.restitution_threshold,
max_linear_speed: def.maximum_linear_speed,
contact_speed: def.contact_speed,
contact_hertz: def.contact_hertz,
contact_damping_ratio: def.contact_damping_ratio,
contact_recycle_distance: contact_recycle_distance(),
friction_callback: Some(def.friction_callback.unwrap_or(default_friction_callback)),
restitution_callback: Some(
def.restitution_callback
.unwrap_or(default_restitution_callback),
),
generation: 0,
profile: Profile::default(),
sat_call_count: 0,
sat_cache_hit_count: 0,
manifold_counts: [0; CONTACT_MANIFOLD_COUNT_BUCKETS],
max_capacity: def.capacity,
pre_solve_fcn: None,
pre_solve_context: 0,
custom_filter_fcn: None,
custom_filter_context: 0,
create_debug_shape: def.create_debug_shape,
destroy_debug_shape: def.destroy_debug_shape,
user_debug_shape_context: def.user_debug_shape_context,
worker_count: 1,
user_data: def.user_data,
inv_h: 0.0,
inv_dt: 0.0,
world_id: 0,
enable_sleep: def.enable_sleep,
locked: false,
enable_warm_starting: true,
enable_continuous: def.enable_continuous,
enable_speculative: true,
in_use: true,
recording: None,
}
}
pub fn enable_continuous(&mut self, flag: bool) {
debug_assert!(!self.locked);
if self.locked {
return;
}
self.enable_continuous = flag;
}
pub fn is_continuous_enabled(&self) -> bool {
self.enable_continuous
}
pub fn get_sensor_events(&self) -> crate::events::SensorEvents<'_> {
let end_event_array_index = 1 - self.end_event_array_index;
crate::events::SensorEvents {
begin_events: &self.sensor_begin_events,
end_events: &self.sensor_end_events[end_event_array_index as usize],
}
}
}