#![deny(missing_docs)]
#![allow(
clippy::cast_possible_truncation,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::cast_lossless,
clippy::cast_possible_wrap,
clippy::similar_names,
clippy::many_single_char_names,
clippy::module_name_repetitions,
clippy::unreadable_literal,
clippy::large_stack_arrays,
clippy::doc_markdown
)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(all(feature = "wasm", feature = "ffi"))]
compile_error!("Features `wasm` and `ffi` are mutually exclusive. Enable only one.");
#[cfg(all(feature = "wasm", not(feature = "std")))]
compile_error!("Feature `wasm` requires `std`.");
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(test)]
extern crate self as alice_physics;
pub mod acoustic_wave;
pub mod aeroelasticity;
#[cfg(feature = "analytics")]
pub mod analytics_bridge;
pub mod animation_blend;
pub mod anisotropic;
pub mod anisotropic_friction;
#[cfg(feature = "std")]
pub mod anomaly;
pub mod articulation;
pub mod atmosphere;
pub mod audio_physics;
pub mod beam_stress;
pub mod bimaterial;
pub mod box_collider;
#[cfg(feature = "std")]
pub mod bridging;
pub mod buckling;
pub mod buoyancy_zone;
pub mod bvh;
pub mod ccd;
#[cfg(feature = "std")]
pub mod cfd_solver;
pub mod character;
pub mod character_state;
pub mod cloth;
pub mod cloth_fluid;
pub mod collider;
pub mod collision_mesh_gen;
pub mod compound;
pub mod compressible;
pub mod cone;
pub mod contact_cache;
pub mod contact_viz;
#[cfg(feature = "std")]
pub mod convex_decompose;
pub mod convex_mesh_builder;
pub mod coupled_field;
pub mod coupled_iteration;
pub mod coupling_medium;
pub mod creep_longterm;
pub mod crowd_force;
pub mod cubic_elastic_fem;
pub mod cylinder;
pub mod damping_rayleigh;
#[cfg(feature = "replay")]
pub mod db_bridge;
pub mod debug_render;
pub mod deformable;
pub mod det_math {
pub use alice_det_math::{acos64, asin64, round, round64, sin_cos, sqrt, sqrt64};
macro_rules! delegate {
($(fn $name:ident($($arg:ident: $ty:ty),*) -> $ret:ty;)*) => {
$(
#[doc = concat!("Delegates to [`alice_det_math::", stringify!($name), "`].")]
#[inline]
#[must_use]
pub fn $name($($arg: $ty),*) -> $ret {
alice_det_math::$name($($arg),*)
}
)*
};
}
delegate! {
fn sin(x: f32) -> f32;
fn cos(x: f32) -> f32;
fn exp(x: f32) -> f32;
fn ln(x: f32) -> f32;
fn powf(x: f32, y: f32) -> f32;
fn powi(x: f32, n: i32) -> f32;
fn cbrt(x: f32) -> f32;
fn hypot(x: f32, y: f32) -> f32;
fn atan(x: f32) -> f32;
fn atan2(y: f32, x: f32) -> f32;
fn asin(x: f32) -> f32;
fn acos(x: f32) -> f32;
fn tan(x: f32) -> f32;
fn tanh(x: f32) -> f32;
fn atan64(x: f64) -> f64;
fn atan2_64(y: f64, x: f64) -> f64;
fn exp64(x: f64) -> f64;
fn ln64(x: f64) -> f64;
fn powf64(x: f64, y: f64) -> f64;
}
}
#[cfg(any(feature = "ffi", feature = "wasm", feature = "python"))]
mod binding_api;
pub mod dynamic_bvh;
#[cfg(feature = "std")]
pub mod dynamic_fem;
pub mod electromagnetic;
pub mod ellipsoid;
#[cfg(feature = "std")]
pub mod erosion;
pub mod error;
pub mod euler_fv;
pub mod eulerian_grid;
pub mod event;
pub mod fatigue;
#[cfg(feature = "ffi")]
pub mod ffi;
pub mod filament_db;
pub(crate) mod body_collider;
pub mod fillet_stress;
pub mod filter;
#[cfg(feature = "std")]
pub mod flow_viz;
pub mod fluid;
#[cfg(feature = "std")]
pub mod fluid_netcode;
pub mod force;
#[cfg(feature = "std")]
pub mod fracture;
#[cfg(feature = "std")]
pub mod fsi_advanced;
#[cfg(feature = "std")]
pub mod gpu_sdf;
pub mod heatmap;
pub mod heightfield;
pub mod hyperelastic;
#[cfg(feature = "std")]
pub mod ik_physics_bridge;
pub mod interface_capture;
pub mod interpolation;
pub mod joint;
pub mod joint_extra;
pub mod kepler;
pub mod kinematic_loop;
#[cfg(feature = "std")]
pub mod laminate;
pub mod laminate_failure;
pub mod law_id;
pub mod layer_adhesion;
pub mod lift_drag;
#[cfg(feature = "std")]
pub mod linear_elastic_fem;
pub mod linear_solver;
pub mod mass_properties;
pub mod material;
pub mod math;
pub mod math_util;
pub mod maxwell_fdtd;
pub mod metric;
pub mod modal;
pub mod molecular_dynamics;
pub mod motor;
pub mod multi_world;
pub mod multiphase;
pub mod nbody;
pub mod netcode;
#[cfg(feature = "std")]
pub mod netcode_prediction;
#[cfg(feature = "neural")]
pub mod neural;
pub mod non_newtonian;
pub mod pair_potential;
pub mod particle;
#[cfg(feature = "std")]
pub mod phase_change;
#[cfg(feature = "std")]
pub mod piezoelectric;
#[cfg(feature = "std")]
pub mod pipeline;
pub mod plane_collider;
pub mod plastic;
#[cfg(feature = "std")]
pub mod pressure;
pub mod prestressed;
pub mod print_orientation;
#[cfg(feature = "std")]
pub mod print_pipeline_solver;
#[cfg(feature = "std")]
pub mod privacy;
pub mod profiling;
#[cfg(feature = "python")]
mod python;
pub mod quadratic_elastic_fem;
pub mod query;
pub mod ragdoll;
pub mod raycast;
#[cfg(feature = "replay")]
pub mod replay;
pub mod rng;
#[cfg(feature = "std")]
pub mod rolling_contact;
pub mod rope;
pub mod rope_attach;
pub mod rotor;
#[cfg(feature = "std")]
pub mod scene_io;
#[cfg(feature = "std")]
pub mod sdf_adaptive;
pub mod sdf_ccd;
pub mod sdf_character;
pub mod sdf_collider;
#[cfg(feature = "std")]
pub mod sdf_destruction;
#[cfg(feature = "std")]
pub mod sdf_fem_mesh;
pub mod sdf_force;
pub mod sdf_manifold;
#[cfg(feature = "std")]
pub mod sdf_sph;
pub mod sdf_wind_field;
pub mod semantics;
pub mod sensors;
pub mod shape;
pub mod shape_raycast;
#[cfg(feature = "std")]
pub mod sim_field;
#[cfg(feature = "std")]
pub mod sim_modifier;
pub mod static_collider;
pub mod structural_solver;
#[cfg(feature = "std")]
pub mod support_volume;
pub mod surface_tension_csf;
#[cfg(feature = "std")]
pub mod thin_wall;
pub mod vibration_wall;
pub mod warp_risk;
pub mod wave_ship;
pub mod wind_zone;
pub mod world_character;
pub mod world_participant;
pub mod world_shape_query;
pub mod physics2d;
#[cfg(feature = "gpu-solver-bridge")]
pub mod gpu_bridge;
#[cfg(feature = "std")]
pub mod sketch;
pub mod sleeping;
pub mod smoke_fire;
pub mod soft_body_cut;
pub mod solver;
pub(crate) mod gyroscopic;
#[cfg(feature = "std")]
pub(crate) mod solver_tgs;
#[cfg(feature = "std")]
pub(crate) mod solver_tgs_hooks_6dof_oriented;
#[cfg(feature = "std")]
pub(crate) mod solver_tgs_hooks_6dof_oriented_scoped;
#[cfg(feature = "std")]
pub(crate) mod solver_tgs_backend;
pub mod spatial;
pub mod spherical_terrain;
#[cfg(feature = "std")]
pub mod thermal;
pub mod thermal_stress;
pub mod torus;
#[cfg(feature = "std")]
pub mod transient_thermal;
pub mod trimesh;
pub mod turbulence;
pub mod vehicle;
pub mod vehicle_dynamics;
#[cfg(feature = "wasm")]
mod wasm;
pub mod wedge;
pub use animation_blend::{AnimationBlender, AnimationClip, BlendMode, SkeletonPose};
#[cfg(feature = "std")]
pub use anomaly::{
AnomalyCallback, AnomalyEvent, CompositeDetector, EwmaDetector, MadDetector, StreamingMedian,
ZScoreDetector,
};
pub use articulation::{ArticulatedBody, FeatherstoneSolver};
pub use audio_physics::{AudioConfig, AudioEvent, AudioGenerator, AudioMaterial};
pub use box_collider::OrientedBox;
pub use bvh::{BvhNode, BvhPrimitive, LinearBvh};
pub use ccd::{
aabb_plane_toi, capsule_plane_toi, speculative_contact, sphere_capsule_toi, CcdConfig,
};
pub use character::{CharacterConfig, CharacterController, MoveResult, PushImpulse};
pub use cloth::{Cloth, ClothConfig};
pub use cloth_fluid::{
apply_cloth_boundary_to_fluid, apply_fluid_forces_to_cloth, ClothFluidCoupling,
};
pub use collider::{Capsule, CollisionResult, ConvexHull, ScaledShape, Sphere, Support, AABB};
pub use collision_mesh_gen::{
compute_mesh_aabb, generate_collision_mesh, simplify_collision_mesh, CollisionMesh,
CollisionMeshConfig,
};
#[cfg(feature = "std")]
pub use compound::{CompoundShape, ShapeRef};
pub use cone::Cone;
pub use contact_cache::{BodyPairKey, ContactCache, ContactManifold};
pub use contact_viz::{
generate_contact_arrows, generate_friction_cones, ContactArrow, FrictionCone,
};
#[cfg(feature = "std")]
pub use convex_decompose::{DecomposeConfig, DecompositionResult};
pub use convex_mesh_builder::{build_convex_hull, compute_centroid};
pub use cylinder::Cylinder;
pub use debug_render::{debug_draw_world, DebugColor, DebugDrawData, DebugDrawFlags};
pub use deformable::{DeformableBody, DeformableConfig};
pub use dynamic_bvh::DynamicAabbTree;
pub use ellipsoid::Ellipsoid;
#[cfg(feature = "std")]
pub use erosion::{ErosionConfig, ErosionModifier, ErosionType};
pub use error::PhysicsError;
pub use event::{ContactEvent, ContactEventType, EventCollector, JointBreakEvent, TriggerEvent};
pub use filter::layers;
pub use filter::CollisionFilter;
#[cfg(feature = "std")]
pub use flow_viz::{
generate_flow_arrows, generate_streamlines, FlowArrow, FlowVizConfig, Streamlines,
};
pub use fluid::{Fluid, FluidConfig};
#[cfg(feature = "std")]
pub use fluid_netcode::{FluidDelta, FluidSnapshot};
pub use force::{apply_force_fields, ForceField, ForceFieldInstance};
#[cfg(feature = "std")]
pub use fracture::{Crack, FractureConfig, FractureModifier};
#[cfg(feature = "std")]
pub use gpu_sdf::{
batch_size, GpuDispatchConfig, GpuSdfBatch, GpuSdfInstancedBatch, GpuSdfMultiDispatch,
GpuSdfQuery, GpuSdfResult,
};
pub use heatmap::{
generate_stress_heatmap, generate_temperature_heatmap, heatmap_to_rgba, Heatmap, HeatmapConfig,
SliceAxis,
};
pub use heightfield::HeightField;
pub use interpolation::{BodySnapshot, InterpolationState, WorldSnapshot};
#[allow(deprecated)] pub use joint::{
solve_joints, solve_joints_breakable, solve_joints_breaking_on_force,
solve_joints_with_reaction_forces,
};
pub use joint::{
BallJoint, ConeTwistJoint, D6Joint, D6Motion, FixedJoint, HingeJoint, Joint, JointType,
SliderJoint, SpringJoint,
};
pub use joint_extra::{
solve_extra_joints, ExtraJoint, GearJoint, MouseJoint, PulleyJoint, RackAndPinionJoint,
WeldJoint,
};
pub use mass_properties::{
box_mass_properties, capsule_mass_properties, convex_hull_mass_properties,
cylinder_mass_properties, sphere_mass_properties, translate_inertia, MassProperties,
};
pub use material::{CombineRule, CombinedMaterial, MaterialId, MaterialTable, PhysicsMaterial};
pub use math::{simd_width, Fix128, Mat3Fix, QuatFix, Vec3Fix, SIMD_WIDTH};
pub use motor::{JointMotor, MotorMode, PdController};
pub use multi_world::{MultiWorld, Portal};
pub use netcode::{
DeterministicSimulation, FrameInput, InputApplicator, NetcodeConfig, SimulationChecksum,
SimulationSnapshot,
};
pub use particle::{LandingEvent, LandingTarget, Particle, ParticleEmitter, ParticleSystem};
#[cfg(feature = "std")]
pub use phase_change::{Phase, PhaseChangeConfig, PhaseChangeModifier};
pub use physics2d::{
BodyType2D, Contact2D, Joint2D, PhysicsConfig2D, PhysicsWorld2D, RigidBody2D, Shape2D, Vec2Fix,
};
#[cfg(feature = "std")]
pub use pipeline::{
MetricEvent, MetricPipeline, MetricRegistry, MetricSnapshot, MetricType, RingBuffer,
};
pub use plane_collider::PlaneCollider;
#[cfg(feature = "std")]
pub use pressure::{PressureConfig, PressureModifier};
#[cfg(feature = "std")]
pub use privacy::{
LaplaceNoise, PrivacyBudget, PrivateAggregator, RandomizedResponse, Rappor, XorShift64,
};
pub use profiling::{PhysicsProfiler, ProfileEntry, StepStats};
pub use query::{
batch_raycast, batch_sphere_cast, capsule_cast, overlap_aabb, overlap_aabb_bvh, overlap_sphere,
overlap_sphere_bvh, sphere_cast, BatchRayQuery, OverlapResult, ShapeCastHit,
};
pub use raycast::{
raycast_all_aabbs, raycast_all_spheres, raycast_any_aabbs, raycast_any_spheres, Ray, RayHit,
};
pub use rng::DeterministicRng;
pub use rope::{Rope, RopeConfig};
pub use rope_attach::{solve_rope_attachments, RopeAttachment};
#[cfg(feature = "std")]
pub use scene_io::{
load_scene, load_scene_json, save_scene, save_scene_json, PhysicsScene, SerializedBody,
SerializedJoint,
};
#[cfg(feature = "std")]
pub use sdf_adaptive::{AdaptiveConfig, AdaptiveSdfEvaluator};
pub use sdf_ccd::SdfCcdConfig;
pub use sdf_collider::{ClosureSdf, SdfCollider, SdfContact, SdfField};
#[cfg(feature = "std")]
pub use sdf_destruction::{DestructibleSdf, DestructionShape};
pub use sdf_force::{SdfForceField, SdfForceType};
pub use sdf_manifold::ManifoldConfig;
#[cfg(feature = "std")]
pub use sdf_manifold::SdfManifold;
pub use semantics::{PHYSICS_SEMANTICS_ID, PHYSICS_SEMANTICS_PINS};
pub use shape::{Shape, ShapeError};
#[cfg(feature = "std")]
pub use sim_field::{ScalarField3D, VectorField3D};
#[cfg(feature = "std")]
pub use sim_modifier::{ModifiedSdf, PhysicsModifier, SingleModifiedSdf};
#[cfg(feature = "std")]
pub use sketch::{CountMinSketch, DDSketch, FnvHasher, HeavyHitters, HyperLogLog, Mergeable};
pub use sleeping::{Island, IslandManager, SleepConfig, SleepData, SleepState};
pub use soft_body_cut::{cut_cloth, cut_deformable, CutPlane, CutResult};
#[cfg(feature = "std")]
pub use solver::ContactModifier;
#[cfg(feature = "std")]
pub use solver::TgsCacheStats;
pub use solver::{
BodyType, ContactConstraint, DistanceConstraint, LawCheck, PhysicsConfig, PhysicsWorld,
RigidBody, SolverBackend, StageWork, WorldCcdConfig, WorldSnapshotError,
};
pub use spatial::SpatialGrid;
#[cfg(feature = "std")]
pub use thermal::{HeatSource, ThermalConfig, ThermalModifier};
pub use torus::Torus;
pub use trimesh::{TriMesh, Triangle};
pub use vehicle::{Vehicle, VehicleConfig};
pub use wedge::Wedge;
pub mod prelude {
pub use crate::animation_blend::{AnimationBlender, AnimationClip, BlendMode, SkeletonPose};
#[cfg(feature = "std")]
pub use crate::anomaly::{
AnomalyCallback, AnomalyEvent, CompositeDetector, EwmaDetector, MadDetector,
StreamingMedian, ZScoreDetector,
};
pub use crate::articulation::{ArticulatedBody, FeatherstoneSolver};
pub use crate::audio_physics::{AudioConfig, AudioEvent, AudioGenerator, AudioMaterial};
pub use crate::box_collider::OrientedBox;
pub use crate::bvh::{BvhNode, BvhPrimitive, LinearBvh};
pub use crate::ccd::{speculative_contact, CcdConfig};
pub use crate::character::{CharacterConfig, CharacterController, MoveResult, PushImpulse};
pub use crate::cloth::{Cloth, ClothConfig};
pub use crate::cloth_fluid::{
apply_cloth_boundary_to_fluid, apply_fluid_forces_to_cloth, ClothFluidCoupling,
};
pub use crate::collider::{
Capsule, CollisionResult, ConvexHull, ScaledShape, Sphere, Support, AABB,
};
pub use crate::collision_mesh_gen::{
compute_mesh_aabb, generate_collision_mesh, simplify_collision_mesh, CollisionMesh,
CollisionMeshConfig,
};
#[cfg(feature = "std")]
pub use crate::compound::{CompoundShape, ShapeRef};
pub use crate::cone::Cone;
pub use crate::contact_cache::{BodyPairKey, ContactCache, ContactManifold};
pub use crate::contact_viz::{
generate_contact_arrows, generate_friction_cones, ContactArrow, FrictionCone,
};
#[cfg(feature = "std")]
pub use crate::convex_decompose::{DecomposeConfig, DecompositionResult};
pub use crate::convex_mesh_builder::{build_convex_hull, compute_centroid};
pub use crate::cylinder::Cylinder;
pub use crate::debug_render::{debug_draw_world, DebugColor, DebugDrawData, DebugDrawFlags};
pub use crate::deformable::{DeformableBody, DeformableConfig};
pub use crate::dynamic_bvh::DynamicAabbTree;
pub use crate::ellipsoid::Ellipsoid;
#[cfg(feature = "std")]
pub use crate::erosion::{ErosionConfig, ErosionModifier, ErosionType};
pub use crate::error::PhysicsError;
pub use crate::event::{
ContactEvent, ContactEventType, EventCollector, JointBreakEvent, TriggerEvent,
};
pub use crate::filter::layers;
pub use crate::filter::CollisionFilter;
#[cfg(feature = "std")]
pub use crate::flow_viz::{
generate_flow_arrows, generate_streamlines, FlowArrow, FlowVizConfig, Streamlines,
};
pub use crate::fluid::{Fluid, FluidConfig};
#[cfg(feature = "std")]
pub use crate::fluid_netcode::{FluidDelta, FluidSnapshot};
pub use crate::force::{apply_force_fields, ForceField, ForceFieldInstance};
#[cfg(feature = "std")]
pub use crate::fracture::{Crack, FractureConfig, FractureModifier};
#[cfg(feature = "std")]
pub use crate::gpu_sdf::{
batch_size, GpuDispatchConfig, GpuSdfBatch, GpuSdfInstancedBatch, GpuSdfMultiDispatch,
GpuSdfQuery, GpuSdfResult,
};
pub use crate::heatmap::{
generate_stress_heatmap, generate_temperature_heatmap, heatmap_to_rgba, Heatmap,
HeatmapConfig, SliceAxis,
};
pub use crate::heightfield::HeightField;
pub use crate::interpolation::{BodySnapshot, InterpolationState, WorldSnapshot};
#[allow(deprecated)] pub use crate::joint::{
solve_joints, solve_joints_breakable, solve_joints_breaking_on_force,
solve_joints_with_reaction_forces,
};
pub use crate::joint::{
BallJoint, ConeTwistJoint, D6Joint, D6Motion, FixedJoint, HingeJoint, Joint, JointType,
SliderJoint, SpringJoint,
};
pub use crate::joint_extra::{
solve_extra_joints, ExtraJoint, GearJoint, MouseJoint, PulleyJoint, RackAndPinionJoint,
WeldJoint,
};
pub use crate::mass_properties::{
box_mass_properties, capsule_mass_properties, convex_hull_mass_properties,
cylinder_mass_properties, sphere_mass_properties, translate_inertia, MassProperties,
};
pub use crate::material::{
CombineRule, CombinedMaterial, MaterialId, MaterialTable, PhysicsMaterial,
};
pub use crate::math::{simd_width, Fix128, Mat3Fix, QuatFix, Vec3Fix, SIMD_WIDTH};
pub use crate::motor::{JointMotor, MotorMode, PdController};
pub use crate::multi_world::{MultiWorld, Portal};
pub use crate::netcode::{
DeterministicSimulation, FrameInput, InputApplicator, NetcodeConfig, SimulationChecksum,
SimulationSnapshot,
};
pub use crate::particle::{
LandingEvent, LandingTarget, Particle, ParticleEmitter, ParticleSystem,
};
#[cfg(feature = "std")]
pub use crate::phase_change::{Phase, PhaseChangeConfig, PhaseChangeModifier};
#[cfg(feature = "std")]
pub use crate::pipeline::{
MetricEvent, MetricPipeline, MetricRegistry, MetricSnapshot, MetricType, RingBuffer,
};
pub use crate::plane_collider::PlaneCollider;
#[cfg(feature = "std")]
pub use crate::pressure::{PressureConfig, PressureModifier};
#[cfg(feature = "std")]
pub use crate::privacy::{
LaplaceNoise, PrivacyBudget, PrivateAggregator, RandomizedResponse, Rappor, XorShift64,
};
pub use crate::profiling::{PhysicsProfiler, ProfileEntry, StepStats};
pub use crate::query::{
batch_raycast, batch_sphere_cast, capsule_cast, overlap_aabb, overlap_aabb_bvh,
overlap_sphere, overlap_sphere_bvh, sphere_cast, BatchRayQuery, OverlapResult,
ShapeCastHit,
};
pub use crate::raycast::{
raycast_all_aabbs, raycast_all_spheres, raycast_any_aabbs, raycast_any_spheres, Ray, RayHit,
};
pub use crate::rng::DeterministicRng;
pub use crate::rope::{Rope, RopeConfig};
pub use crate::rope_attach::{solve_rope_attachments, RopeAttachment};
#[cfg(feature = "std")]
pub use crate::scene_io::{
load_scene, load_scene_json, save_scene, save_scene_json, PhysicsScene, SerializedBody,
SerializedJoint,
};
#[cfg(feature = "std")]
pub use crate::sdf_adaptive::{AdaptiveConfig, AdaptiveSdfEvaluator};
pub use crate::sdf_ccd::SdfCcdConfig;
pub use crate::sdf_collider::{ClosureSdf, SdfCollider, SdfContact, SdfField};
#[cfg(feature = "std")]
pub use crate::sdf_destruction::{DestructibleSdf, DestructionShape};
pub use crate::sdf_force::{SdfForceField, SdfForceType};
pub use crate::sdf_manifold::ManifoldConfig;
#[cfg(feature = "std")]
pub use crate::sdf_manifold::SdfManifold;
#[cfg(feature = "std")]
pub use crate::sim_field::{ScalarField3D, VectorField3D};
#[cfg(feature = "std")]
pub use crate::sim_modifier::{ModifiedSdf, PhysicsModifier, SingleModifiedSdf};
#[cfg(feature = "std")]
pub use crate::sketch::{
CountMinSketch, DDSketch, FnvHasher, HeavyHitters, HyperLogLog, Mergeable,
};
pub use crate::sleeping::{Island, IslandManager, SleepConfig, SleepData, SleepState};
pub use crate::soft_body_cut::{cut_cloth, cut_deformable, CutPlane, CutResult};
#[cfg(feature = "std")]
pub use crate::solver::ContactModifier;
#[cfg(feature = "std")]
pub use crate::solver::TgsCacheStats;
pub use crate::solver::{
BodyType, ContactConstraint, DistanceConstraint, LawCheck, PhysicsConfig, PhysicsWorld,
RigidBody, SolverBackend, StageWork, WorldCcdConfig, WorldSnapshotError,
};
pub use crate::spatial::SpatialGrid;
#[cfg(feature = "std")]
pub use crate::thermal::{HeatSource, ThermalConfig, ThermalModifier};
pub use crate::torus::Torus;
pub use crate::trimesh::{TriMesh, Triangle};
pub use crate::vehicle::{Vehicle, VehicleConfig};
pub use crate::wedge::Wedge;
}
#[cfg(all(test, feature = "std"))]
mod compile_smoke_tests {
use super::*;
#[test]
fn test_prelude_types_accessible() {
let _ = Fix128::ZERO;
let _ = Vec3Fix::ZERO;
let _ = QuatFix::IDENTITY;
let _ = Mat3Fix::IDENTITY;
let _ = PhysicsConfig::default();
let _ = CollisionFilter::default();
let _ = SleepConfig::default();
}
#[test]
fn test_error_type_accessible() {
let e = PhysicsError::InvalidBodyIndex { index: 0, count: 0 };
let _ = format!("{e}");
}
#[test]
fn test_spatial_grid_accessible() {
let mut grid = SpatialGrid::new(Fix128::ONE, 16);
grid.insert(0, Vec3Fix::ZERO);
grid.build();
let mut neighbors = Vec::new();
grid.query_neighbors_into(Vec3Fix::ZERO, Fix128::ONE, &mut neighbors);
assert!(neighbors.contains(&0));
}
#[test]
fn test_wasm_ffi_mutual_exclusion() {
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn test_basic_simulation() {
let config = PhysicsConfig::default();
let mut world = PhysicsWorld::new(config);
let mut body = RigidBody::new_dynamic(Vec3Fix::from_int(0, 100, 0), Fix128::ONE);
body.restitution = Fix128::from_ratio(5, 10);
let body_id = world.add_body(body);
let ground = RigidBody::new_static(Vec3Fix::ZERO);
world.add_body(ground);
let dt = Fix128::from_ratio(1, 60);
for _ in 0..60 {
world.step(dt);
}
let pos = world.bodies[body_id].position;
assert!(pos.y < Fix128::from_int(100), "Body should have fallen");
}
#[test]
fn test_determinism() {
fn run_simulation() -> Vec3Fix {
let config = PhysicsConfig::default();
let mut world = PhysicsWorld::new(config);
let body = RigidBody::new_dynamic(
Vec3Fix::from_int(5, 50, 3),
Fix128::from_ratio(3, 2), );
world.add_body(body);
let dt = Fix128::from_ratio(1, 60);
for _ in 0..120 {
world.step(dt);
}
world.bodies[0].position
}
let result1 = run_simulation();
let result2 = run_simulation();
assert_eq!(result1.x.hi, result2.x.hi);
assert_eq!(result1.x.lo, result2.x.lo);
assert_eq!(result1.y.hi, result2.y.hi);
assert_eq!(result1.y.lo, result2.y.lo);
assert_eq!(result1.z.hi, result2.z.hi);
assert_eq!(result1.z.lo, result2.z.lo);
}
#[test]
fn test_state_serialization() {
let config = PhysicsConfig::default();
let mut world = PhysicsWorld::new(config);
let body = RigidBody::new_dynamic(Vec3Fix::from_int(10, 20, 30), Fix128::ONE);
world.add_body(body);
let dt = Fix128::from_ratio(1, 60);
for _ in 0..30 {
world.step(dt);
}
let state = world.serialize_state();
for _ in 0..30 {
world.step(dt);
}
let pos_after = world.bodies[0].position;
world.deserialize_state(&state);
for _ in 0..30 {
world.step(dt);
}
let pos_restored = world.bodies[0].position;
assert_eq!(pos_after.x.hi, pos_restored.x.hi);
assert_eq!(pos_after.y.hi, pos_restored.y.hi);
assert_eq!(pos_after.z.hi, pos_restored.z.hi);
}
#[test]
fn test_distance_constraint() {
let config = PhysicsConfig::default();
let mut world = PhysicsWorld::new(config);
let body_a = RigidBody::new_dynamic(Vec3Fix::from_int(0, 10, 0), Fix128::ONE);
let body_b = RigidBody::new_dynamic(Vec3Fix::from_int(5, 10, 0), Fix128::ONE);
let id_a = world.add_body(body_a);
let id_b = world.add_body(body_b);
let constraint = DistanceConstraint {
body_a: id_a,
body_b: id_b,
local_anchor_a: Vec3Fix::ZERO,
local_anchor_b: Vec3Fix::ZERO,
target_distance: Fix128::from_int(5),
compliance: Fix128::ZERO,
cached_lambda: Fix128::ZERO,
};
world.add_distance_constraint(constraint);
let dt = Fix128::from_ratio(1, 120);
for _ in 0..120 {
world.step(dt);
}
let pos_a = world.bodies[id_a].position;
let pos_b = world.bodies[id_b].position;
let dist = (pos_b - pos_a).length();
let target = Fix128::from_int(5);
let error = if dist > target {
dist - target
} else {
target - dist
};
let tolerance = Fix128::from_ratio(1, 10);
assert!(
error < tolerance,
"Distance constraint violated: error = {error:?}, tolerance = {tolerance:?}"
);
}
}