aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2025-12-09 16:06:37 +0100
committerLaytan Laats <laytanlaats@hotmail.com>2025-12-09 16:06:37 +0100
commitb34fdd6260a61eeeb0fe4b3d390f4df3102fb6cc (patch)
treee96d2a7f3d64423f2ee52f5646e622cac5683cc0
parenta3f189e8969221899ffef8a58e4f5068bf33d092 (diff)
vendor/box2d: update to 3.1.1
-rw-r--r--vendor/box2d/box2d.odin95
-rwxr-xr-xvendor/box2d/build_box2d.sh2
-rw-r--r--vendor/box2d/collision.odin11
-rw-r--r--vendor/box2d/id.odin13
-rwxr-xr-xvendor/box2d/lib/box2d_wasm.obin463785 -> 465224 bytes
-rwxr-xr-xvendor/box2d/lib/box2d_wasm_simd.obin457399 -> 461780 bytes
-rw-r--r--vendor/box2d/math_functions.odin48
-rw-r--r--vendor/box2d/types.odin27
-rw-r--r--vendor/box2d/wasm.Makefile2
-rw-r--r--vendor/libc/include/math.h2
-rw-r--r--vendor/libc/math.odin5
11 files changed, 134 insertions, 71 deletions
diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin
index ad4670110..2301ed3d0 100644
--- a/vendor/box2d/box2d.odin
+++ b/vendor/box2d/box2d.odin
@@ -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) ---
diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh
index d6fb3888d..9c79ce009 100755
--- a/vendor/box2d/build_box2d.sh
+++ b/vendor/box2d/build_box2d.sh
@@ -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")"
diff --git a/vendor/box2d/collision.odin b/vendor/box2d/collision.odin
index b29e2f946..9930e0549 100644
--- a/vendor/box2d/collision.odin
+++ b/vendor/box2d/collision.odin
@@ -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,
diff --git a/vendor/box2d/id.odin b/vendor/box2d/id.odin
index cb530527a..d2465f7d7 100644
--- a/vendor/box2d/id.odin
+++ b/vendor/box2d/id.odin
@@ -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),
+ }
+}
diff --git a/vendor/box2d/lib/box2d_wasm.o b/vendor/box2d/lib/box2d_wasm.o
index fc3ed1cbd..493df4a1c 100755
--- a/vendor/box2d/lib/box2d_wasm.o
+++ b/vendor/box2d/lib/box2d_wasm.o
Binary files differ
diff --git a/vendor/box2d/lib/box2d_wasm_simd.o b/vendor/box2d/lib/box2d_wasm_simd.o
index 8b70dcedd..d7150082e 100755
--- a/vendor/box2d/lib/box2d_wasm_simd.o
+++ b/vendor/box2d/lib/box2d_wasm_simd.o
Binary files differ
diff --git a/vendor/box2d/math_functions.odin b/vendor/box2d/math_functions.odin
index c2d197f08..31c6d4090 100644
--- a/vendor/box2d/math_functions.odin
+++ b/vendor/box2d/math_functions.odin
@@ -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)
+}
diff --git a/vendor/box2d/types.odin b/vendor/box2d/types.odin
index 1ad7f379c..9e12aa1a1 100644
--- a/vendor/box2d/types.odin
+++ b/vendor/box2d/types.odin
@@ -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
diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile
index 74f4e4eff..80dd2ba14 100644
--- a/vendor/box2d/wasm.Makefile
+++ b/vendor/box2d/wasm.Makefile
@@ -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)
diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h
index fba520e4a..dd9e8e9ba 100644
--- a/vendor/libc/include/math.h
+++ b/vendor/libc/include/math.h
@@ -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) \
diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin
index 93df1fea6..26d8a917a 100644
--- a/vendor/libc/math.odin
+++ b/vendor/libc/math.odin
@@ -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)
+}