vendor/box2d: update to 3.1.1

This commit is contained in:
Laytan Laats
2025-12-09 16:06:37 +01:00
parent a3f189e896
commit b34fdd6260
11 changed files with 134 additions and 71 deletions

View File

@@ -4,6 +4,8 @@ package vendor_box2d
import "base:intrinsics"
import "core:c"
_ :: intrinsics
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
@(private) VECTOR_EXT :: "_simd" when #config(VENDOR_BOX2D_ENABLE_SIMD128, intrinsics.has_target_feature("simd128")) else ""
} else {
@@ -331,7 +333,7 @@ MakeOffsetProxy :: proc "c" (points: []Vec2, radius: f32, position: Vec2, rotati
@(link_prefix="b2", default_calling_convention="c", require_results)
foreign lib {
// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction.
// You may optionally supply an array to hold debug data.
// Initially touching shapes are treated as a miss.
ShapeCast :: proc(#by_ptr input: ShapeCastPairInput) -> CastOutput ---
// Evaluate the transform sweep at a specific time.
@@ -481,12 +483,12 @@ foreign lib {
*/
@(require_results)
SolvePlanes :: proc(position: Vec2, planes: []CollisionPlane) -> PlaneSolverResult {
SolvePlanes :: proc(targetDelta: Vec2, planes: []CollisionPlane) -> PlaneSolverResult {
foreign lib {
b2SolvePlanes :: proc "c" (position: Vec2, planes: [^]CollisionPlane, count: i32) -> PlaneSolverResult ---
b2SolvePlanes :: proc "c" (targetDelta: Vec2, planes: [^]CollisionPlane, count: i32) -> PlaneSolverResult ---
}
return b2SolvePlanes(position, raw_data(planes), i32(len(planes)))
return b2SolvePlanes(targetDelta, raw_data(planes), i32(len(planes)))
}
@(require_results)
@@ -550,7 +552,6 @@ foreign lib {
// Cast a ray into the world to collect shapes in the path of the ray.
// Your callback function controls whether you get the closest point, any point, or n-points.
// The ray-cast ignores shapes that contain the starting point.
// @note The callback function may receive shapes in any order
// @param worldId The world to cast the ray against
// @param origin The start point of the ray
@@ -561,7 +562,7 @@ foreign lib {
// @return traversal performance counters
World_CastRay :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats ---
// Cast a ray into the world to collect the closest hit. This is a convenience function.
// Cast a ray into the world to collect the closest hit. This is a convenience function. Ignores initial overlap.
// This is less general than b2World_CastRay() and does not allow for custom filtering.
World_CastRayClosest :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter) -> RayResult ---
@@ -637,13 +638,6 @@ foreign lib {
// @note Advanced feature
World_SetContactTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, pushSpeed: f32) ---
// Adjust joint tuning parameters
// @param worldId The world id
// @param hertz The contact stiffness (cycles per second)
// @param dampingRatio The contact bounciness with 1 being critical damping (non-dimensional)
// @note Advanced feature
World_SetJointTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32) ---
// Set the maximum linear speed. Usually in m/s.
World_SetMaximumLinearSpeed :: proc(worldId: WorldId, maximumLinearSpeed: f32) ---
@@ -771,6 +765,7 @@ foreign lib {
// Set the velocity to reach the given transform after a given time step.
// The result will be close but maybe not exact. This is meant for kinematic bodies.
// The target is not applied if the velocity would be below the sleep threshold.
// This will automatically wake the body if asleep.
Body_SetTargetTransform :: proc(bodyId: BodyId, target: Transform, timeStep: f32) ---
@@ -1068,6 +1063,12 @@ foreign lib {
// Get the shape material identifier
Shape_GetMaterial :: proc(shapeId: ShapeId) -> c.int ---
// Set the shape surface material
Shape_SetSurfaceMaterial :: proc(shapeId: ShapeId, surfaceMaterial: SurfaceMaterial) ---
// Get the shape surface material
Shape_GetSurfaceMaterial :: proc(shapeId: ShapeId) -> SurfaceMaterial ---
// Get the shape filter
Shape_GetFilter :: proc(shapeId: ShapeId) -> Filter ---
@@ -1258,12 +1259,30 @@ foreign lib {
// Get the world that owns this joint
Joint_GetWorld :: proc(jointId: JointId) -> WorldId ---
// Set the local anchor on bodyA
Joint_SetLocalAnchorA :: proc(jointId: JointId, localAnchor: Vec2) ---
// Get the local anchor on bodyA
Joint_GetLocalAnchorA :: proc(jointId: JointId) -> Vec2 ---
// Set the local anchor on bodyB
Joint_SetLocalAnchorB :: proc(jointId: JointId, localAnchor: Vec2) ---
// Get the local anchor on bodyB
Joint_GetLocalAnchorB :: proc(jointId: JointId) -> Vec2 ---
// Get the joint reference angle in radians (revolute, prismatic, and weld)
Joint_GetReferenceAngle :: proc(jointId: JointId) -> f32 ---
// Set the joint reference angle in radians, must be in [-pi,pi]. (revolute, prismatic, and weld)
Joint_SetReferenceAngle :: proc(jointId: JointId, angleInRadians: f32) ---
// Set the local axis on bodyA (prismatic and wheel)
Joint_SetLocalAxisA :: proc(jointId: JointId, localAxis: Vec2) ---
// Get the local axis on bodyA (prismatic and wheel)
Joint_GetLocalAxisA :: proc(jointId: JointId) -> Vec2 ---
// Toggle collision between connected bodies
Joint_SetCollideConnected :: proc(jointId: JointId, shouldCollide: bool) ---
@@ -1285,6 +1304,21 @@ foreign lib {
// Get the current constraint torque for this joint. Usually in Newton * meters.
Joint_GetConstraintTorque :: proc(jointId: JointId) -> f32 ---
// Get the current linear separation error for this joint. Does not consider admissible movement. Usually in meters.
Joint_GetLinearSeparation :: proc(jointId: JointId) -> f32 ---
// Get the current angular separation error for this joint. Does not consider admissible movement. Usually in meters.
Joint_GetAngularSeparation :: proc(jointId: JointId) -> f32 ---
// Get the joint constraint tuning. Advanced feature.
Joint_GetConstraintTuning :: proc(jointId: JointId, hertz: ^f32, dampingRatio: ^f32) ---
// Set the joint constraint tuning. Advanced feature.
// @param jointId the joint
// @param hertz the stiffness in Hertz (cycles per second)
// @param dampingRatio the non-dimensional damping ratio (one for critical damping)
Joint_SetConstraintTuning :: proc(jointId: JointId, hertz: f32, dampingRatio: f32) ---
/**
* @defgroup distance_joint Distance Joint
* @brief Functions for the distance joint.
@@ -1379,7 +1413,8 @@ foreign lib {
// Get the motor joint linear offset target
MotorJoint_GetLinearOffset :: proc(jointId: JointId) -> Vec2 ---
// Set the motor joint angular offset target in radians
// Set the motor joint angular offset target in radians. This angle will be unwound
// so the motor will drive along the shortest arc.
MotorJoint_SetAngularOffset :: proc(jointId: JointId, angularOffset: f32) ---
// Get the motor joint angular offset target in radians
@@ -1415,31 +1450,37 @@ foreign lib {
// Create a mouse joint
// @see b2MouseJointDef for details
CreateMouseJoint :: proc(worldId: WorldId, #by_ptr def: MouseJointDef) -> JointId ---
CreateMouseJoint :: proc(worldId: WorldId, #by_ptr def: MouseJointDef) -> JointId ---
// Set the mouse joint target
MouseJoint_SetTarget :: proc(jointId: JointId, target: Vec2) ---
MouseJoint_SetTarget :: proc(jointId: JointId, target: Vec2) ---
// Get the mouse joint target
MouseJoint_GetTarget :: proc(jointId: JointId) -> Vec2 ---
MouseJoint_GetTarget :: proc(jointId: JointId) -> Vec2 ---
// Set the mouse joint spring stiffness in Hertz
MouseJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) ---
MouseJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) ---
// Get the mouse joint spring stiffness in Hertz
MouseJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 ---
MouseJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 ---
// Set the mouse joint spring damping ratio, non-dimensional
MouseJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
MouseJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
// Get the mouse joint damping ratio, non-dimensional
MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
// Set the prismatic joint sprint target angle, usually in meters
PrismaticJoint_SetTargetTranslation :: proc(jointId: JointId, translation: f32) ---
// Get the prismatic joint sprint target translation, usually in meters
PrismaticJoint_GetTargetTranslation :: proc(jointId: JointId) -> f32 ---
// Set the mouse joint maximum force, usually in newtons
MouseJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) ---
MouseJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) ---
// Get the mouse joint maximum force, usually in newtons
MouseJoint_GetMaxForce :: proc(jointId: JointId) -> f32 ---
MouseJoint_GetMaxForce :: proc(jointId: JointId) -> f32 ---
/**@}*/
@@ -1585,7 +1626,7 @@ foreign lib {
RevoluteJoint_GetUpperLimit :: proc(jointId: JointId) -> f32 ---
// Set the revolute joint limits in radians. It is expected that lower <= upper
// and that -0.95 * B2_PI <= lower && upper <= -0.95 * B2_PI.
// and that -0.99 * B2_PI <= lower && upper <= -0.99 * B2_PI.
RevoluteJoint_SetLimits :: proc(jointId: JointId, lower, upper: f32) ---
// Enable/disable a revolute joint motor
@@ -1625,12 +1666,6 @@ foreign lib {
// @see b2WeldJointDef for details
CreateWeldJoint :: proc(worldId: WorldId, #by_ptr def: WeldJointDef) -> JointId ---
// Get the weld joint reference angle in radians
WeldJoint_GetReferenceAngle :: proc(jointId: JointId) -> f32 ---
// Set the weld joint reference angle in radians, must be in [-pi,pi].
WeldJoint_SetReferenceAngle :: proc(jointId: JointId, angleInRadians: f32) ---
// Set the weld joint linear stiffness in Hertz. 0 is rigid.
WeldJoint_SetLinearHertz :: proc(jointId: JointId, hertz: f32) ---

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -eu
VERSION="3.1.0"
VERSION="3.1.1"
RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz"
cd "$(dirname "$0")"

View File

@@ -49,7 +49,7 @@ ShapeCastInput :: struct {
canEncroach: bool,
}
// Low level ray cast or shape-cast output data
// Low level ray cast or shape-cast output data. Returns a zero fraction and normal in the case of initial overlap.
CastOutput :: struct {
// The surface normal at the hit point
normal: Vec2,
@@ -227,7 +227,7 @@ DistanceInput :: struct {
DistanceOutput :: struct {
pointA: Vec2, // Closest point on shapeA
pointB: Vec2, // Closest point on shapeB
normal: Vec2, // Normal vector that points from A to B
normal: Vec2, // Normal vector that points from A to B. Invalid if distance is zero.
distance: f32, // The final distance, zero if overlapped
iterations: i32, // Number of GJK iterations used
simplexCount: i32, // The number of simplexes stored in the simplex array
@@ -459,6 +459,9 @@ PlaneResult :: struct {
// The collision plane between the mover and convex shape
plane: Plane,
// The collision point on the shape.
point: Vec2,
// Did the collision register a hit? If not this plane should be ignored.
hit: bool,
}
@@ -482,8 +485,8 @@ CollisionPlane :: struct {
// Result returned by b2SolvePlanes
PlaneSolverResult :: struct {
// The final position of the mover
position: Vec2,
// The translation of the mover
translation: Vec2,
// The number of iterations used by the plane solver. For diagnostics.
iterationCount: i32,

13
vendor/box2d/id.odin vendored
View File

@@ -86,3 +86,16 @@ ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool
intrinsics.type_has_field(T, "generation") {
return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation
}
// Store a world id into a u32.
StoreWorldId :: #force_inline proc "c" (id: WorldId) -> u32 {
return (u32(id.index1) << 16) | u32(id.generation)
}
// Load a u32 into a world id.
LoadWorldId :: #force_inline proc "c" (x: u32) -> WorldId {
return {
u16(x >> 16),
u16(x),
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -415,31 +415,10 @@ RelativeAngle :: proc "c" (b, a: Rot) -> f32 {
return Atan2(s, c)
}
// Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi]
// Convert any angle into the range [-pi, pi]
@(require_results)
UnwindAngle :: proc "c" (radians: f32) -> f32 {
if radians < -PI {
return radians + 2.0 * PI
} else if radians > PI {
return radians - 2.0 * PI
}
return radians
}
// Convert any into the range [-pi, pi] (slow)
@(require_results)
UnwindLargeAngle :: proc "c" (radians: f32) -> f32 {
radians := radians
for radians > PI {
radians -= 2. * PI
}
for radians < -PI {
radians += 2. * PI
}
return radians
return math.remainder(radians, 2. * PI)
}
// Rotate a vector
@@ -563,6 +542,17 @@ AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) {
return
}
// Do a and b overlap
@(require_results)
AABB_Overlaps :: proc "c" (a, b: AABB) -> bool {
return !(
b.lowerBound.x > a.upperBound.x ||
b.lowerBound.y > a.upperBound.y ||
a.lowerBound.x > b.upperBound.x ||
a.lowerBound.y > b.upperBound.y \
)
}
// Compute the bounding box of an array of circles
@(require_results)
MakeAABB :: proc "c" (points: []Vec2, radius: f32) -> AABB {
@@ -625,3 +615,15 @@ IsValidPlane :: proc "c" (plane: Plane) -> bool {
IsNormalized(plane.normal) or_return
return true
}
// One-dimensional mass-spring-damper simulation. Returns the new velocity given the position and time step.
// You can then compute the new position using:
// position += timeStep * newVelocity
// This drives towards a zero position. By using implicit integration we get a stable solution
// that doesn't require transcendental functions.
@(require_results)
b2SpringDamper :: proc "c" (hertz, dampingRatio, position, velocity, timeStep: f32) -> f32 {
omega := 2. * PI * hertz
omegaH := omega * timeStep
return (velocity - omega * omegaH * position) / (1. + 2. * dampingRatio * omegaH + omegaH * omegaH)
}

View File

@@ -50,6 +50,7 @@ FrictionCallback :: #type proc "c" (frictionA: f32, userMaterialIdA: i32, fricti
RestitutionCallback :: #type proc "c" (restitutionA: f32, userMaterialIdA: i32, restitutionB: f32, userMaterialIdB: i32) -> f32
// Result from b2World_RayCastClosest
// If there is initial overlap the fraction and normal will be zero while the point is an arbitrary point in the overlap region.
// @ingroup world
RayResult :: struct {
shapeId: ShapeId,
@@ -87,12 +88,6 @@ WorldDef :: struct {
// decreasing the damping ratio.
maxContactPushSpeed: f32,
// Joint stiffness. Cycles per second.
jointHertz: f32,
// Joint bounciness. Non-dimensional.
jointDampingRatio: f32,
// Maximum linear speed. Usually meters per second.
maximumLinearSpeed: f32,
@@ -660,6 +655,10 @@ PrismaticJointDef :: struct {
// The constrained angle between the bodies: bodyB_angle - bodyA_angle
referenceAngle: f32,
// The target translation for the joint in meters. The spring-damper will drive
// to this translation.
targetTranslation: f32,
// Enable a linear spring along the prismatic joint axis
enableSpring: bool,
@@ -743,10 +742,10 @@ RevoluteJointDef :: struct {
// A flag to enable joint limits
enableLimit: bool,
// The lower angle for the joint limit in radians. Minimum of -0.95*pi radians.
// The lower angle for the joint limit in radians. Minimum of -0.99*pi radians.
lowerAngle: f32,
// The upper angle for the joint limit in radians. Maximum of 0.95*pi radians.
// The upper angle for the joint limit in radians. Maximum of 0.99*pi radians.
upperAngle: f32,
// A flag to enable the joint motor
@@ -988,6 +987,7 @@ ContactEndTouchEvent :: struct {
}
// A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold.
// This may be reported for speculative contacts that have a confirmed impulse.
ContactHitEvent :: struct {
// Id of the first shape
shapeIdA: ShapeId,
@@ -995,7 +995,9 @@ ContactHitEvent :: struct {
// Id of the second shape
shapeIdB: ShapeId,
// Point where the shapes hit
// Point where the shapes hit at the beginning of the time step.
// This is a mid-point between the two surfaces. It could be at speculative
// point where the two shapes were not touching at the beginning of the time step.
point: Vec2,
// Normal vector pointing from shape A to shape B
@@ -1103,17 +1105,18 @@ PreSolveFcn :: #type proc "c" (shapeIdA, shapeIdB: ShapeId, manifold: ^Manifold,
// @ingroup world
OverlapResultFcn :: #type proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool
// Prototype callback for ray casts.
// Prototype callback for ray and shape casts.
// Called for each shape found in the query. You control how the ray cast
// proceeds by returning a f32:
// return -1: ignore this shape and continue
// return 0: terminate the ray cast
// return fraction: clip the ray to this point
// return 1: don't clip the ray and continue
// A cast with initial overlap will return a zero fraction and a zero normal.
// @param shapeId the shape hit by the ray
// @param point the point of initial intersection
// @param normal the normal vector at the point of intersection
// @param fraction the fraction along the ray at the point of intersection
// @param normal the normal vector at the point of intersection, zero for a shape cast with initial overlap
// @param fraction the fraction along the ray at the point of intersection, zero for a shape cast with initial overlap
// @param context the user context
// @return -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue
// @see b2World_CastRay

View File

@@ -7,7 +7,7 @@
# CC = $(shell brew --prefix llvm)/bin/clang
# LD = $(shell brew --prefix llvm)/bin/wasm-ld
VERSION = 3.1.0
VERSION = 3.1.1
SRCS = $(wildcard box2d-$(VERSION)/src/*.c)
OBJS_SIMD = $(SRCS:.c=_simd.o)
OBJS = $(SRCS:.c=.o)

View File

@@ -43,6 +43,8 @@ double tan(double);
double atan2(double, double);
double modf(double, double*);
float remainderf(float x, float y);
bool __isnanf(float);
bool __isnand(double);
#define isnan(x) \

View File

@@ -204,3 +204,8 @@ modf :: proc "c" (num: f64, iptr: ^f64) -> f64 {
iptr^ = integral
return fractional
}
@(require, linkage="strong", link_name="remainderf")
remainderf :: proc "c" (x, y: f32) -> f32 {
return math.remainder(x, y)
}