boxdd-sys: low-level FFI for the official Box2D v3 C API (vendored)boxdd: safe layer (world, bodies, shapes, joints, queries, events, debug draw)
- Safe, ergonomic Rust wrapper over the official Box2D v3 C API.
- Math interop (features:
mint/cgmath/nalgebra/glam): anyInto<Vec2>accepts the corresponding 2D vector/point types, plus arrays/tuples. - Two error-handling styles: panic-on-misuse by default, plus
try_*APIs returningApiResult<T>for recoverable errors.
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2};
let def = WorldDef::builder().gravity(Vec2::new(0.0, -9.8)).build();
let mut world = World::new(def).unwrap();
let body = world.create_body_owned(BodyBuilder::new().position([0.0, 2.0]).build());
let poly = shapes::box_polygon(0.5, 0.5);
let _shape = world.create_polygon_shape_for_owned(body.id(), &ShapeDef::default(), &poly);
world.step(1.0/60.0, 4);serde: serialization for core value/config types (Vec2,Rot,Transform,Aabb,QueryFilter, etc.).serialize: snapshot helpers (save/apply world config; take/rebuild minimal full-scene snapshot).mint: lightweight math interop types (mint::Vector2,mint::Point2, and 2D affine matrices forTransform).cgmath,nalgebra,glam: conversions with their 2D types (e.g.Vector2/Point2,UnitComplex/Isometry2,glam::Vec2).bytemuck: enablePod/Zeroablefor core math types (Vec2,Rot,Transform,Aabb) for zero-copy interop.unchecked: exposes extraunsafeunchecked APIs for hot paths (skips id validity checks; you must guarantee ids are valid).
- Enable
serializeand see exampleexamples/scene_serialize.rsfor a minimal scene round-trip. - Note: chain shapes are captured when created via this wrapper (
World::create_chain_for_id/Body::create_chain). - Note:
ShapeDefflags that have no runtime getters are captured for shapes created via this wrapper.
- From source: builds vendored Box2D C sources via
ccand uses pregenerated bindings by default.- Example:
cargo build -p boxdd.
- Example:
- System library (optional): link an existing
box2dinstalled on the system.- Via env: set
BOX2D_LIB_DIR=/path/to/liband optionallyBOXDD_SYS_LINK_KIND=static|dylib. - Via feature: enable
pkg-configand providebox2dthrough your system's package manager. - Note: crate features that affect C build (e.g.
simd-avx2,disable-simd,validate) are ignored in system mode. SetBOXDD_SYS_STRICT_FEATURES=1to fail the build if such features are enabled.
- Via env: set
git submodule update --init --recursive
cargo build
# run some examples
cargo r --example world_basics
cargo r --example joints
cargo r --example queries
cargo r --example sensors
cargo r --example testbed_imgui_glow --features imgui-glow-testbed- The
examples/folder covers worlds/bodies/shapes, joints, queries/casts, events/sensors, CCD, and debug draw.
- Three access styles:
- By value:
world.contact_events()/sensor_events()/body_events()/joint_events()return owned data for storage or cross-frame use. - Zero‑copy views:
with_*_events_view(...)iterate without allocations (borrows internal buffers). - Raw slices:
unsafe { with_*_events(...) }expose FFI slices (borrows internal buffers).
- By value:
- Example (zero‑copy views):
use boxdd::prelude::*;
let mut world = World::new(WorldDef::default()).unwrap();
world.with_contact_events_view(|begin, end, hit| {
let _ = (begin.count(), end.count(), hit.count());
});
world.with_sensor_events_view(|beg, end| {
let _ = (beg.count(), end.count());
});
world.with_body_events_view(|moves| {
for m in moves { let _ = (m.body_id(), m.fell_asleep()); }
});
world.with_joint_events_view(|j| { let _ = j.count(); });- Vendored C sources + pregenerated bindings by default (no LLVM needed on CI).
- To force bindgen: enable the
boxdd-sys/bindgenfeature, setBOXDD_SYS_FORCE_BINDGEN=1, and ensurelibclangis available. On Windows/MSVC, setLIBCLANG_PATHif needed.
- To force bindgen: enable the
- On docs.rs, the native C build is skipped.
- Safe handle methods validate ids and panic on invalid ids (prevents UB if an id becomes stale). For recoverable failures (invalid ids / calling during Box2D callbacks), use
try_*APIs. - Threading:
Worldand owned handles are!Send/!Sync. Run physics on one thread; in async runtimes preferspawn_local/LocalSet, or create the world inside a dedicated physics thread and communicate via channels.
- Local:
cargo doc --open - Online: https://docs.rs/boxdd
- See
CHANGELOG.md.
- Thanks to the Rust Box2D bindings project for prior art and inspiration: https://github.com/Bastacyclop/rust_box2d
- Huge thanks to the upstream Box2D project by Erin Catto: https://github.com/erincatto/box2d
If you're working with graphics applications in Rust, you might also be interested in:
- asset-importer - A comprehensive Rust binding for the latest Assimp 3D asset import library, providing robust 3D model loading capabilities for graphics applications
- dear-imgui - Comprehensive Dear ImGui bindings for Rust using C++ bindgen, providing immediate mode GUI capabilities for graphics applications
boxdd: MIT OR Apache-2.0boxdd-sys: MIT OR Apache-2.0
