boxddd-sys 0.4.0

Low-level FFI bindings for Box3D built from vendored upstream sources
Documentation
use std::ffi::c_void;
use std::mem::{align_of, offset_of, size_of};

use boxddd_sys::ffi;

#[cfg(target_pointer_width = "32")]
const _: () = {
    assert!(size_of::<ffi::b3SurfaceMaterial>() == 40);
    assert!(offset_of!(ffi::b3SurfaceMaterial, padding) == 36);
    assert!(size_of::<ffi::b3HullData>() == 144);
    assert!(size_of::<ffi::b3BoxHull>() == 648);
    assert!(offset_of!(ffi::b3BoxHull, vx) == 456);
    assert!(offset_of!(ffi::b3BoxHull, nz) == 616);
    assert!(size_of::<ffi::b3ShapeDef>() == 104);
    assert!(offset_of!(ffi::b3ShapeDef, baseMaterial) == 16);
    assert!(offset_of!(ffi::b3ShapeDef, enableSpeculativeContact) == 96);
    assert!(offset_of!(ffi::b3ShapeDef, internalValue) == 100);
    assert!(size_of::<ffi::b3DebugDraw>() == 88);
    assert!(offset_of!(ffi::b3DebugDraw, drawingBounds) == 36);
    assert!(offset_of!(ffi::b3DebugDraw, drawSleep) == 73);
    assert!(offset_of!(ffi::b3DebugDraw, drawAnchorA) == 76);
    assert!(offset_of!(ffi::b3DebugDraw, context) == 84);
};

#[test]
fn representative_public_api_symbols_are_bound() {
    let _world_step: unsafe extern "C" fn(ffi::b3WorldId, f32, i32) = ffi::b3World_Step;
    let _body_transform: unsafe extern "C" fn(ffi::b3BodyId) -> ffi::b3WorldTransform =
        ffi::b3Body_GetTransform;
    let _sphere_shape: unsafe extern "C" fn(
        ffi::b3BodyId,
        *const ffi::b3ShapeDef,
        *const ffi::b3Sphere,
    ) -> ffi::b3ShapeId = ffi::b3CreateSphereShape;
    let _distance_joint: unsafe extern "C" fn() -> ffi::b3DistanceJointDef =
        ffi::b3DefaultDistanceJointDef;
    let _query_filter: unsafe extern "C" fn() -> ffi::b3QueryFilter = ffi::b3DefaultQueryFilter;
    let _recording: unsafe extern "C" fn(ffi::b3WorldId, *mut ffi::b3Recording) =
        ffi::b3World_StartRecording;
    let _mover: unsafe extern "C" fn(
        ffi::b3WorldId,
        ffi::b3Pos,
        *const ffi::b3Capsule,
        ffi::b3QueryFilter,
        ffi::b3PlaneResultFcn,
        *mut std::ffi::c_void,
    ) = ffi::b3World_CollideMover;
    let _collision: unsafe extern "C" fn(
        *mut ffi::b3LocalManifold,
        i32,
        *const ffi::b3Sphere,
        *const ffi::b3Sphere,
        ffi::b3Transform,
    ) = ffi::b3CollideSpheres;
    let _triangle_hull: unsafe extern "C" fn(
        *mut ffi::b3LocalManifold,
        i32,
        ffi::b3Vec3,
        ffi::b3Vec3,
        ffi::b3Vec3,
        i32,
        *const ffi::b3HullData,
        *mut ffi::b3SATCache,
        bool,
    ) = ffi::b3CollideTriangleAndHull;
    let _baked_compound: unsafe extern "C" fn(
        ffi::b3BodyId,
        *mut ffi::b3ShapeDef,
        *const ffi::b3CompoundData,
    ) -> ffi::b3ShapeId = ffi::b3CreateBakedCompoundShape;
    let _local_center: unsafe extern "C" fn(ffi::b3BodyId) -> ffi::b3Vec3 =
        ffi::b3Body_GetLocalCenter;
    let _world_center: unsafe extern "C" fn(ffi::b3BodyId) -> ffi::b3Pos =
        ffi::b3Body_GetWorldCenter;
    let _fast_rotation: unsafe extern "C" fn(ffi::b3BodyId, bool) = ffi::b3Body_AllowFastRotation;
    let _shape_name: unsafe extern "C" fn(ffi::b3ShapeId) -> *const std::ffi::c_char =
        ffi::b3Shape_GetName;
    let _sub_step: unsafe extern "C" fn(*mut ffi::b3RecPlayer) = ffi::b3RecPlayer_SubStepFrame;
}

#[test]
fn default_filter_bits_preserve_the_upstream_u64_contract() {
    let category_bits: u64 = ffi::B3_DEFAULT_CATEGORY_BITS;
    let mask_bits: u64 = ffi::B3_DEFAULT_MASK_BITS;

    assert_eq!(category_bits, u64::MAX);
    assert_eq!(mask_bits, u64::MAX);
}

#[test]
fn selected_abi_mode_matches_runtime_library() {
    let is_double = unsafe { ffi::b3IsDoublePrecision() };

    #[cfg(feature = "double-precision")]
    {
        assert!(is_double);
        assert_eq!(size_of::<ffi::b3Pos>(), 24);
        assert_eq!(align_of::<ffi::b3Pos>(), 8);
        assert_eq!(size_of::<ffi::b3WorldTransform>(), 40);
    }

    #[cfg(not(feature = "double-precision"))]
    {
        assert!(!is_double);
        assert_eq!(size_of::<ffi::b3Pos>(), size_of::<ffi::b3Vec3>());
        assert_eq!(align_of::<ffi::b3Pos>(), align_of::<ffi::b3Vec3>());
        assert_eq!(
            size_of::<ffi::b3WorldTransform>(),
            size_of::<ffi::b3Transform>()
        );
    }
}

#[test]
fn representative_layouts_match_the_pinned_headers() {
    assert_eq!(size_of::<ffi::b3WorldId>(), 4);
    assert_eq!(size_of::<ffi::b3BodyId>(), 8);
    assert_eq!(size_of::<ffi::b3ShapeId>(), 8);
    assert_eq!(size_of::<ffi::b3JointId>(), 8);
    assert_eq!(size_of::<ffi::b3Vec3>(), 12);
    assert_eq!(size_of::<ffi::b3Quat>(), 16);
    assert_eq!(size_of::<ffi::b3SurfaceMaterial>(), 40);
    assert_eq!(align_of::<ffi::b3SurfaceMaterial>(), 8);
    assert_eq!(offset_of!(ffi::b3SurfaceMaterial, padding), 36);

    assert_eq!(size_of::<ffi::b3HullData>(), 144);
    assert_eq!(align_of::<ffi::b3HullData>(), 8);
    assert_eq!(offset_of!(ffi::b3HullData, planeOffset), 124);
    assert_eq!(offset_of!(ffi::b3HullData, faceOffset), 128);
    assert_eq!(offset_of!(ffi::b3HullData, soaVertexOffset), 132);
    assert_eq!(offset_of!(ffi::b3HullData, soaNormalOffset), 136);
    assert_eq!(offset_of!(ffi::b3HullData, padding), 140);

    assert_eq!(size_of::<ffi::b3BoxHull>(), 648);
    assert_eq!(align_of::<ffi::b3BoxHull>(), 8);
    assert_eq!(offset_of!(ffi::b3BoxHull, base), 0);
    assert_eq!(offset_of!(ffi::b3BoxHull, boxVertices), 144);
    assert_eq!(offset_of!(ffi::b3BoxHull, boxPoints), 152);
    assert_eq!(offset_of!(ffi::b3BoxHull, boxEdges), 248);
    assert_eq!(offset_of!(ffi::b3BoxHull, boxPlanes), 344);
    assert_eq!(offset_of!(ffi::b3BoxHull, boxFaces), 440);
    assert_eq!(offset_of!(ffi::b3BoxHull, padding), 446);
    assert_eq!(offset_of!(ffi::b3BoxHull, vx), 456);
    assert_eq!(offset_of!(ffi::b3BoxHull, vy), 488);
    assert_eq!(offset_of!(ffi::b3BoxHull, vz), 520);
    assert_eq!(offset_of!(ffi::b3BoxHull, nx), 552);
    assert_eq!(offset_of!(ffi::b3BoxHull, ny), 584);
    assert_eq!(offset_of!(ffi::b3BoxHull, nz), 616);

    #[cfg(target_pointer_width = "64")]
    {
        assert_eq!(size_of::<ffi::b3ShapeDef>(), 120);
        assert_eq!(align_of::<ffi::b3ShapeDef>(), 8);
        assert_eq!(offset_of!(ffi::b3ShapeDef, name), 0);
        assert_eq!(offset_of!(ffi::b3ShapeDef, baseMaterial), 32);
        assert_eq!(offset_of!(ffi::b3ShapeDef, enableSpeculativeContact), 112);
        assert_eq!(offset_of!(ffi::b3ShapeDef, internalValue), 116);

        assert_eq!(size_of::<ffi::b3DebugDraw>(), 128);
        assert_eq!(align_of::<ffi::b3DebugDraw>(), 8);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawingBounds), 72);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawMass), 108);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawSleep), 109);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawAnchorA), 112);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawIslands), 117);
        assert_eq!(offset_of!(ffi::b3DebugDraw, context), 120);
    }

    #[cfg(target_pointer_width = "32")]
    {
        assert_eq!(size_of::<ffi::b3ShapeDef>(), 104);
        assert_eq!(align_of::<ffi::b3ShapeDef>(), 8);
        assert_eq!(offset_of!(ffi::b3ShapeDef, name), 0);
        assert_eq!(offset_of!(ffi::b3ShapeDef, baseMaterial), 16);
        assert_eq!(offset_of!(ffi::b3ShapeDef, enableSpeculativeContact), 96);
        assert_eq!(offset_of!(ffi::b3ShapeDef, internalValue), 100);

        assert_eq!(size_of::<ffi::b3DebugDraw>(), 88);
        assert_eq!(align_of::<ffi::b3DebugDraw>(), 4);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawingBounds), 36);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawMass), 72);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawSleep), 73);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawAnchorA), 76);
        assert_eq!(offset_of!(ffi::b3DebugDraw, drawIslands), 81);
        assert_eq!(offset_of!(ffi::b3DebugDraw, context), 84);
    }
}

#[test]
fn changed_defaults_and_by_value_returns_match_the_pinned_runtime() {
    let material = unsafe { ffi::b3DefaultSurfaceMaterial() };
    assert_eq!(material.friction, 0.6);
    assert_eq!(material.padding, 0);

    let shape = unsafe { ffi::b3DefaultShapeDef() };
    assert!(shape.name.is_null());
    assert!(shape.userData.is_null());
    assert!(shape.materials.is_null());
    assert_eq!(shape.materialCount, 0);
    assert_eq!(shape.baseMaterial.padding, 0);
    assert!(shape.invokeContactCreation);
    assert!(shape.updateBodyMass);
    assert!(shape.enableSpeculativeContact);

    let draw = unsafe { ffi::b3DefaultDebugDraw() };
    let draw_shape: Option<
        unsafe extern "C" fn(*mut c_void, ffi::b3WorldTransform, ffi::b3HexColor, *mut c_void),
    > = draw.DrawShapeFcn;
    assert!(draw_shape.is_some());
    assert!(!draw.drawSleep);
    assert!(!draw.drawAnchorA);
    assert!(draw.context.is_null());

    let hull = unsafe { ffi::b3MakeCubeHull(1.0) };
    assert_eq!(hull.base.vertexCount, 8);
    assert_eq!(hull.base.edgeCount, 24);
    assert_eq!(hull.base.faceCount, 6);
    assert_eq!(
        hull.base.vertexOffset as usize,
        offset_of!(ffi::b3BoxHull, boxVertices)
    );
    assert_eq!(
        hull.base.pointOffset as usize,
        offset_of!(ffi::b3BoxHull, boxPoints)
    );
    assert_eq!(
        hull.base.edgeOffset as usize,
        offset_of!(ffi::b3BoxHull, boxEdges)
    );
    assert_eq!(
        hull.base.planeOffset as usize,
        offset_of!(ffi::b3BoxHull, boxPlanes)
    );
    assert_eq!(
        hull.base.faceOffset as usize,
        offset_of!(ffi::b3BoxHull, boxFaces)
    );
    assert_eq!(
        hull.base.soaVertexOffset as usize,
        offset_of!(ffi::b3BoxHull, vx)
    );
    assert_eq!(
        hull.base.soaNormalOffset as usize,
        offset_of!(ffi::b3BoxHull, nx)
    );
    assert_eq!(hull.base.padding, 0);
    assert_eq!(hull.padding, [0; 10]);
}