Ver código fonte

box2d: update to 3.1.0

Laytan Laats 3 meses atrás
pai
commit
e086151fcd

Diferenças do arquivo suprimidas por serem muito extensas
+ 355 - 183
vendor/box2d/box2d.odin


+ 3 - 3
vendor/box2d/build_box2d.sh

@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 set -eu
 
-VERSION="3.0.0"
+VERSION="3.1.0"
 RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz"
 
 cd "$(odin root)"/vendor/box2d
@@ -75,5 +75,5 @@ if [[ $? -ne 0 ]]; then
 fi
 set -e
 
-rm -rf v3.0.0.tar.gz
-rm -rf box2d-3.0.0
+rm -rf "v$VERSION.tar.gz"
+rm -rf box2d-"$VERSION"

+ 142 - 125
vendor/box2d/collision.odin

@@ -5,9 +5,9 @@ import "core:c"
 
 // The maximum number of vertices on a convex polygon. Changing this affects performance even if you
 //	don't use more vertices.
-maxPolygonVertices :: 8
+MAX_POLYGON_VERTICES :: 8
 
-// Low level ray-cast input data
+// Low level ray cast input data
 RayCastInput :: struct {
 	// Start point of the ray cast
 	origin:      Vec2,
@@ -19,27 +19,37 @@ RayCastInput :: struct {
 	maxFraction: f32,
 }
 
-// Low level shape cast input in generic form. This allows casting an arbitrary point
-//	cloud wrap with a radius. For example, a circle is a single point with a non-zero radius.
-//	A capsule is two points with a non-zero radius. A box is four points with a zero radius.
-ShapeCastInput :: struct {
-	// A point cloud to cast
-	points:      [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+// A distance proxy is used by the GJK algorithm. It encapsulates any shape.
+// You can provide between 1 and MAX_POLYGON_VERTICES and a radius.
+ShapeProxy :: struct {
+	// The point cloud
+	points: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`,
 
-	// The number of points
-	count:       i32,
+	// The number of points. Must be greater than 0.
+	count:  c.int,
 
-	// The radius around the point cloud
-	radius:      f32,
+	// The external radius of the point cloud. May be zero.
+	radius: f32,
+}
+
+// Low level shape cast input in generic form. This allows casting an arbitrary point
+// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius.
+// A capsule is two points with a non-zero radius. A box is four points with a zero radius.
+ShapeCastInput :: struct {
+	// A generic shape
+	proxy:       ShapeProxy,
 
 	// The translation of the shape cast
 	translation: Vec2,
 
 	// The maximum fraction of the translation to consider, typically 1
 	maxFraction: f32,
+
+	// Allow shape cast to encroach when initially touching. This only works if the radius is greater than zero.
+	canEncroach: bool,
 }
 
-// Low level ray-cast or shape-cast output data
+// Low level ray cast or shape-cast output data
 CastOutput :: struct {
 	// The surface normal at the hit point
 	normal:     Vec2,
@@ -51,7 +61,7 @@ CastOutput :: struct {
 	fraction:   f32,
 
 	// The number of iterations used
-	iterations: i32,
+	iterations: c.int,
 
 	// Did the cast hit?
 	hit:        bool,
@@ -93,16 +103,16 @@ Capsule :: struct {
 
 // A solid convex polygon. It is assumed that the interior of the polygon is to
 // the left of each edge.
-// Polygons have a maximum number of vertices equal to maxPolygonVertices.
+// Polygons have a maximum number of vertices equal to MAX_POLYGON_VERTICES.
 // In most cases you should not need many vertices for a convex polygon.
-//	@warning DO NOT fill this out manually, instead use a helper function like
-//	b2MakePolygon or b2MakeBox.
+// @warning DO NOT fill this out manually, instead use a helper function like
+// b2MakePolygon or b2MakeBox.
 Polygon :: struct {
 	// The polygon vertices
-	vertices: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+	vertices: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`,
 
 	// The outward normal vectors of the polygon sides
-	normals:  [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+	normals:  [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`,
 
 	// The centroid of the polygon
 	centroid: Vec2,
@@ -111,7 +121,7 @@ Polygon :: struct {
 	radius:   f32,
 
 	// The number of polygon vertices
-	count:    i32,
+	count:    c.int,
 }
 
 // A line segment with two-sided collision.
@@ -123,10 +133,10 @@ Segment :: struct {
 	point2: Vec2,
 }
 
-// A smooth line segment with one-sided collision. Only collides on the right side.
+// A line segment with one-sided collision. Only collides on the right side.
 // Several of these are generated for a chain shape.
 // ghost1 -> point1 -> point2 -> ghost2
-SmoothSegment :: struct {
+ChainSegment :: struct {
 	// The tail ghost vertex
 	ghost1:  Vec2,
 
@@ -137,7 +147,7 @@ SmoothSegment :: struct {
 	ghost2:  Vec2,
 
 	// The owning chain shape index (internal usage only)
-	chainId: i32,
+	chainId: c.int,
 }
 
 
@@ -145,10 +155,10 @@ SmoothSegment :: struct {
 //	@warning Do not modify these values directly, instead use b2ComputeHull()
 Hull :: struct {
 	// The final points of the hull
-	points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+	points: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`,
 
 	// The number of points
-	count:  i32,
+	count:  c.int,
 }
 
 /**
@@ -178,21 +188,11 @@ SegmentDistanceResult :: struct {
 	distanceSquared: f32,
 }
 
-// A distance proxy is used by the GJK algorithm. It encapsulates any shape.
-DistanceProxy :: struct {
-	// The point cloud
-	points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
-
-	// The number of points
-	count:  i32,
-
-	// The external radius of the point cloud
-	radius: f32,
-}
-
-// Used to warm start b2Distance. Set count to zero on first call or
-//	use zero initialization.
-DistanceCache :: struct {
+// Used to warm start the GJK simplex. If you call this function multiple times with nearby
+// transforms this might improve performance. Otherwise you can zero initialize this.
+// The distance cache must be initialized to zero on the first call.
+// Users should generally just zero initialize this structure for each call.
+SimplexCache :: struct {
 	// The number of stored simplex points
 	count: u16,
 
@@ -203,15 +203,15 @@ DistanceCache :: struct {
 	indexB: [3]u8 `fmt:"v,count"`,
 }
 
-emptyDistanceCache :: DistanceCache{}
+emptySimplexCache :: SimplexCache{}
 
 // Input for b2ShapeDistance
 DistanceInput :: struct {
 	// The proxy for shape A
-	proxyA: DistanceProxy,
+	proxyA: ShapeProxy,
 
 	// The proxy for shape B
-	proxyB: DistanceProxy,
+	proxyB: ShapeProxy,
 
 	// The world transform for shape A
 	transformA: Transform,
@@ -227,6 +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
 	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
@@ -234,28 +235,29 @@ DistanceOutput :: struct {
 
 // Simplex vertex for debugging the GJK algorithm
 SimplexVertex :: struct {
-	wA:     Vec2, // support point in proxyA
-	wB:     Vec2, // support point in proxyB
-	w:      Vec2, // wB - wA
-	a:      f32,  // barycentric coordinate for closest point
-	indexA: i32,  // wA index
-	indexB: i32,  // wB index
+	wA:     Vec2,  // support point in proxyA
+	wB:     Vec2,  // support point in proxyB
+	w:      Vec2,  // wB - wA
+	a:      f32,   // barycentric coordinate for closest point
+	indexA: c.int, // wA index
+	indexB: c.int, // wB index
 }
 
 // Simplex from the GJK algorithm
 Simplex :: struct {
 	v1, v2, v3: SimplexVertex `fmt:"v,count"`, // vertices
-	count: i32, // number of valid vertices
+	count: c.int, // number of valid vertices
 }
 
 // Input parameters for b2ShapeCast
 ShapeCastPairInput :: struct {
-	proxyA:       DistanceProxy, // The proxy for shape A
-	proxyB:       DistanceProxy, // The proxy for shape B
+	proxyA:       ShapeProxy, // The proxy for shape A
+	proxyB:       ShapeProxy, // The proxy for shape B
 	transformA:   Transform, // The world transform for shape A
 	transformB:   Transform, // The world transform for shape B
 	translationB: Vec2, // The translation of shape B
 	maxFraction:  f32, // The fraction of the translation to consider, typically 1
+	canEncroach:  bool, // Allows shapes with a radius to move slightly closer if already touching
 }
 
 
@@ -272,11 +274,11 @@ Sweep :: struct {
 
 // Input parameters for b2TimeOfImpact
 TOIInput :: struct {
-	proxyA: DistanceProxy, // The proxy for shape A
-	proxyB: DistanceProxy, // The proxy for shape B
-	sweepA: Sweep,         // The movement of shape A
-	sweepB: Sweep,         // The movement of shape B
-	tMax:   f32,           // Defines the sweep interval [0, tMax]
+	proxyA:      ShapeProxy, // The proxy for shape A
+	proxyB:      ShapeProxy, // The proxy for shape B
+	sweepA:      Sweep,      // The movement of shape A
+	sweepB:      Sweep,      // The movement of shape B
+	maxFraction: f32,        // Defines the sweep interval [0, maxFraction]
 }
 
 // Describes the TOI output
@@ -290,8 +292,8 @@ TOIState :: enum c.int {
 
 // Output parameters for b2TimeOfImpact.
 TOIOutput :: struct {
-	state: TOIState, // The type of result
-	t:     f32,      // The time of the collision
+	state:    TOIState, // The type of result
+	fraction: f32,      // The sweep time of the collision
 }
 
 
@@ -301,26 +303,30 @@ TOIOutput :: struct {
  * @brief Functions for colliding pairs of shapes
  */
 
-// A manifold point is a contact point belonging to a contact
-// manifold. It holds details related to the geometry and dynamics
-// of the contact points.
+// A manifold point is a contact point belonging to a contact manifold.
+// It holds details related to the geometry and dynamics of the contact points.
+// Box2D uses speculative collision so some contact points may be separated.
+// You may use the totalNormalImpulse to determine if there was an interaction during
+// the time step.
 ManifoldPoint :: struct {
 	// Location of the contact point in world space. Subject to precision loss at large coordinates.
 	//	@note Should only be used for debugging.
 	point:            Vec2,
 
-	// Location of the contact point relative to bodyA's origin in world space
-	//	@note When used internally to the Box2D solver, these are relative to the center of mass.
+	// Location of the contact point relative to shapeA's origin in world space
+	//	@note When used internally to the Box2D solver, this is relative to the body center of mass.
 	anchorA:          Vec2,
 
-	// Location of the contact point relative to bodyB's origin in world space
+	// Location of the contact point relative to shapeB's origin in world space
+	// @note When used internally to the Box2D solver, this is relative to the body center of mass.
 	anchorB:          Vec2,
 
 	// The separation of the contact point, negative if penetrating
 	separation:       f32,
 
-	// The impulse along the manifold normal vector.
-	normalImpulse:    f32,
+	// The total normal impulse applied across sub-stepping and restitution. This is important
+	// to identify speculative contact points that had an interaction in the time step.
+	totalNormalImpulse: f32,
 
 	// The friction impulse
 	tangentImpulse:   f32,
@@ -340,16 +346,21 @@ ManifoldPoint :: struct {
 	persisted:        bool,
 }
 
-// A contact manifold describes the contact points between colliding shapes
+// A contact manifold describes the contact points between colliding shapes.
+// @note Box2D uses speculative collision so some contact points may be separated.
 Manifold :: struct {
+	// The unit normal vector in world space, points from shape A to bodyB
+	normal:         Vec2,
+
+	// Angular impulse applied for rolling resistance. N * m * s = kg * m^2 / s
+	rollingImpulse: f32,
+
 	// The manifold points, up to two are possible in 2D
-	points:     [2]ManifoldPoint,
+	points:         [2]ManifoldPoint,
 
-	// The unit normal vector in world space, points from shape A to bodyB
-	normal:     Vec2,
 
 	// The number of contacts points, will be 0, 1, or 2
-	pointCount: i32,
+	pointCount:     c.int,
 }
 
 
@@ -364,63 +375,17 @@ Manifold :: struct {
  * A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
  * A dynamic tree arranges data in a binary tree to accelerate
  * queries such as AABB queries and ray casts. Leaf nodes are proxies
- * with an AABB. These are used to hold a user collision object, such as a reference to a b2Shape.
+ * with an AABB. These are used to hold a user collision object.
  * Nodes are pooled and relocatable, so I use node indices rather than pointers.
  * The dynamic tree is made available for advanced users that would like to use it to organize
  * spatial game data besides rigid bodies.
- *
- * @note This is an advanced feature and normally not used by applications directly.
  */
 
-// The default category bit for a tree proxy. Used for collision filtering.
-defaultCategoryBits :: 0x00000001
-
-// Convenience mask bits to use when you don't need collision filtering and just want
-//	all results.
-defaultMaskBits :: 0xFFFFFFFF
-
-// A node in the dynamic tree. This is private data placed here for performance reasons.
-// 16 + 16 + 8 + pad(8)
-TreeNode :: struct {
-	// The node bounding box
-	aabb: AABB, // 16
-
-	// Category bits for collision filtering
-	categoryBits: u32, // 4
-
-	using _: struct #raw_union {
-		// The node parent index
-		parent: i32,
-
-		// The node freelist next index
-		next:   i32,
-	}, // 4
-
-	// Child 1 index
-	child1: i32, // 4
-
-	// Child 2 index
-	child2: i32, // 4
-
-	// User data
-	// todo could be union with child index
-	userData: i32, // 4
-
-	// Leaf = 0, free node = -1
-	height: i16, // 2
-
-	// Has the AABB been enlarged?
-	enlarged: bool, // 1
-
-	// Padding for clarity
-	_: [9]byte,
-}
-
 // The dynamic tree structure. This should be considered private data.
 // It is placed here for performance reasons.
 DynamicTree :: struct {
 	// The tree nodes
-	nodes:           [^]TreeNode `fmt"v,nodeCount"`,
+	nodes:           rawptr,
 
 	// The root index
 	root:            i32,
@@ -453,16 +418,25 @@ DynamicTree :: struct {
 	rebuildCapacity: i32,
 }
 
+// These are performance results returned by dynamic tree queries.
+TreeStats :: struct {
+	// Number of internal nodes visited during the query
+	nodeVisits: c.int,
+
+	// Number of leaf nodes visited during the query
+	leafVisits: c.int,
+}
+
 // This function receives proxies found in the AABB query.
 // @return true if the query should continue
-TreeQueryCallbackFcn     :: #type proc "c" (proxyId: i32, userData: i32, ctx: rawptr) -> bool
+TreeQueryCallbackFcn     :: #type proc "c" (proxyId: i32, userData: u64, ctx: rawptr) -> bool
 
-// This function receives clipped ray-cast input for a proxy. The function
+// This function receives clipped ray cast input for a proxy. The function
 // returns the new ray fraction.
-// - return a value of 0 to terminate the ray-cast
+// - return a value of 0 to terminate the ray cast
 // - return a value less than input->maxFraction to clip the ray
 // - return a value of input->maxFraction to continue the ray cast without clipping
-TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32
+TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxyId: i32, userData: u64, ctx: rawptr) -> f32
 
 
 // This function receives clipped raycast input for a proxy. The function
@@ -470,4 +444,47 @@ TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxy
 // - return a value of 0 to terminate the ray cast
 // - return a value less than input->maxFraction to clip the ray
 // - return a value of input->maxFraction to continue the ray cast without clipping
-TreeRayCastCallbackFcn   :: #type proc "c" (#by_ptr input: RayCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32
+TreeRayCastCallbackFcn   :: #type proc "c" (#by_ptr input: RayCastInput, proxyId: i32, userData: u64, ctx: rawptr) -> f32
+
+/**@}*/
+
+/**
+ * @defgroup character Character mover
+ * Character movement solver
+ * @{
+ */
+
+/// These are the collision planes returned from b2World_CollideMover
+PlaneResult :: struct {
+	// The collision plane between the mover and convex shape
+	plane: Plane,
+
+	// Did the collision register a hit? If not this plane should be ignored.
+	hit:   bool,
+}
+
+// These are collision planes that can be fed to b2SolvePlanes. Normally
+// this is assembled by the user from plane results in b2PlaneResult
+CollisionPlane :: struct {
+	// The collision plane between the mover and some shape
+	plane:        Plane,
+
+	// Setting this to FLT_MAX makes the plane as rigid as possible. Lower values can
+	// make the plane collision soft. Usually in meters.
+	pushLimit:    f32,
+
+	// The push on the mover determined by b2SolvePlanes. Usually in meters.
+	push:         f32,
+
+	// Indicates if b2ClipVector should clip against this plane. Should be false for soft collision.
+	clipVelocity: bool,
+}
+
+// Result returned by b2SolvePlanes
+PlaneSolverResult :: struct {
+	// The final position of the mover
+	position:       Vec2,
+
+	// The number of iterations used by the plane solver. For diagnostics.
+	iterationCount: i32,
+}

+ 21 - 20
vendor/box2d/id.odin

@@ -23,45 +23,46 @@ import "base:intrinsics"
 
 /// World id references a world instance. This should be treated as an opaque handle.
 WorldId :: struct {
-	index1:   u16,
-	revision: u16,
+	index1:     u16,
+	generation: u16,
 }
 
 /// Body id references a body instance. This should be treated as an opaque handle.
 BodyId :: struct {
-	index1:   i32,
-	world0:   u16,
-	revision: u16,
+	index1:     i32,
+	world0:     u16,
+	generation: u16,
 }
 
 /// Shape id references a shape instance. This should be treated as an opaque handle.
 ShapeId :: struct {
-	index1:   i32,
-	world0:   u16,
-	revision: u16,
+	index1:     i32,
+	world0:     u16,
+	generation: u16,
+}
+
+/// Chain id references a chain instances. This should be treated as an opaque handle.
+ChainId :: struct {
+	index1:     i32,
+	world0:     u16,
+	generation: u16,
 }
 
 /// Joint id references a joint instance. This should be treated as an opaque handle.
 JointId :: struct {
-	index1:   i32,
-	world0:   u16,
-	revision: u16,
+	index1:     i32,
+	world0:     u16,
+	generation: u16,
 }
 
-/// Chain id references a chain instances. This should be treated as an opaque handle.
-ChainId :: struct {
-	index1:   i32,
-	world0:   u16,
-	revision: u16,
-}
 
 /// Use these to make your identifiers null.
 /// You may also use zero initialization to get null.
 nullWorldId :: WorldId{}
 nullBodyId  :: BodyId{}
 nullShapeId :: ShapeId{}
-nullJointId :: JointId{}
 nullChainId :: ChainId{}
+nullJointId :: JointId{}
 
 /// Macro to determine if any id is null.
 IS_NULL :: #force_inline proc "c" (id: $T) -> bool
@@ -82,6 +83,6 @@ ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool
 	where intrinsics.type_is_struct(T),
 	      intrinsics.type_has_field(T, "index1"),
 	      intrinsics.type_has_field(T, "world0"),
-	      intrinsics.type_has_field(T, "revision") {
-	return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.revision == id2.revision
+	      intrinsics.type_has_field(T, "generation") {
+	return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation
 }

BIN
vendor/box2d/lib/box2d_darwin_amd64_avx2.a


BIN
vendor/box2d/lib/box2d_darwin_amd64_sse2.a


BIN
vendor/box2d/lib/box2d_darwin_arm64.a


BIN
vendor/box2d/lib/box2d_wasm.o


BIN
vendor/box2d/lib/box2d_wasm_simd.o


+ 195 - 90
vendor/box2d/math_functions.odin

@@ -3,9 +3,18 @@ package vendor_box2d
 import "core:c"
 import "core:math"
 
-pi :: 3.14159265359
+EPSILON :: 1e-23
 
 Vec2 :: [2]f32
+
+// Cosine and sine pair
+// This uses a custom implementation designed for cross-platform determinism
+CosSin :: struct {
+	// cosine and sine
+	cosine: f32,
+	sine:   f32,
+}
+
 Rot :: struct {
 	c, s: f32, // cosine and sine
 }
@@ -21,60 +30,79 @@ AABB :: struct {
 	upperBound: Vec2,
 }
 
+// separation = dot(normal, point) - offset
+Plane :: struct {
+	normal: Vec2,
+	offset: f32,
+}
+
+PI :: math.PI
+
 Vec2_zero          :: Vec2{0, 0}
 Rot_identity       :: Rot{1, 0}
 Transform_identity :: Transform{{0, 0}, {1, 0}}
 Mat22_zero         :: Mat22{0, 0, 0, 0}
 
-
-// @return the minimum of two floats
+// @return the minimum of two integers
 @(deprecated="Prefer the built-in 'min(a, b)'", require_results)
-MinFloat :: proc "c" (a, b: f32) -> f32 {
+MinInt :: proc "c" (a, b: c.int) -> c.int {
 	return min(a, b)
 }
 
-// @return the maximum of two floats
+// @return the maximum of two integers
 @(deprecated="Prefer the built-in 'max(a, b)'", require_results)
-MaxFloat :: proc "c" (a, b: f32) -> f32 {
+MaxInt :: proc "c" (a, b: c.int) -> c.int {
 	return max(a, b)
 }
 
-// @return the absolute value of a float
+// @return the absolute value of an integer
 @(deprecated="Prefer the built-in 'abs(a)'", require_results)
-AbsFloat :: proc "c" (a: f32) -> f32 {
+AbsInt :: proc "c" (a: c.int) -> c.int {
 	return abs(a)
 }
 
-// @return a f32 clamped between a lower and upper bound
+// @return an integer clamped between a lower and upper bound
 @(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results)
-ClampFloat :: proc "c" (a, lower, upper: f32) -> f32 {
+ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int {
 	return clamp(a, lower, upper)
 }
 
-// @return the minimum of two integers
+
+// @return the minimum of two floats
 @(deprecated="Prefer the built-in 'min(a, b)'", require_results)
-MinInt :: proc "c" (a, b: c.int) -> c.int {
+MinFloat :: proc "c" (a, b: f32) -> f32 {
 	return min(a, b)
 }
 
-// @return the maximum of two integers
+// @return the maximum of two floats
 @(deprecated="Prefer the built-in 'max(a, b)'", require_results)
-MaxInt :: proc "c" (a, b: c.int) -> c.int {
+MaxFloat :: proc "c" (a, b: f32) -> f32 {
 	return max(a, b)
 }
 
-// @return the absolute value of an integer
+// @return the absolute value of a float
 @(deprecated="Prefer the built-in 'abs(a)'", require_results)
-AbsInt :: proc "c" (a: c.int) -> c.int {
+AbsFloat :: proc "c" (a: f32) -> f32 {
 	return abs(a)
 }
 
-// @return an integer clamped between a lower and upper bound
+// @return a f32 clamped between a lower and upper bound
 @(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results)
-ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int {
+ClampFloat :: proc "c" (a, lower, upper: f32) -> f32 {
 	return clamp(a, lower, upper)
 }
 
+@(require_results)
+Atan2 :: proc "c" (y, x: f32) -> f32 {
+	return math.atan2(y, x)
+}
+
+@(require_results)
+ComputeCosSin :: proc "c" (radians: f32) -> (res: CosSin) {
+	res.sine, res.cosine = math.sincos(radians)
+	return
+}
+
 // Vector dot product
 @(require_results)
 Dot :: proc "c" (a, b: Vec2) -> f32 {
@@ -198,12 +226,6 @@ Length :: proc "c" (v: Vec2) -> f32 {
 	return math.sqrt(v.x * v.x + v.y * v.y)
 }
 
-// Get the length squared of this vector
-@(require_results)
-LengthSquared :: proc "c" (v: Vec2) -> f32 {
-	return v.x * v.x + v.y * v.y
-}
-
 // Get the distance between two points
 @(require_results)
 Distance :: proc "c" (a, b: Vec2) -> f32 {
@@ -212,6 +234,64 @@ Distance :: proc "c" (a, b: Vec2) -> f32 {
 	return math.sqrt(dx * dx + dy * dy)
 }
 
+@(require_results)
+Normalize :: proc "c" (v: Vec2) -> Vec2 {
+	length := Length(v)
+	if length < EPSILON {
+		return Vec2_zero
+	}
+	invLength := 1 / length
+	return invLength * v
+}
+
+@(require_results)
+IsNormalized :: proc "c" (v: Vec2) -> bool {
+	aa := Dot(v, v)
+	return abs(1. - aa) < 10. * EPSILON
+}
+
+@(require_results)
+NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 {
+	length := Length(v)
+	if length < 1e-23 {
+		panic("zero-length Vec2")
+	}
+	invLength := 1 / length
+	return invLength * v
+}
+
+@(require_results)
+GetLengthAndNormalize :: proc "c" (v: Vec2) -> (length: f32, vn: Vec2) {
+	length = Length(v)
+	if length < 1e-23 {
+		return
+	}
+	invLength := 1 / length
+	vn = invLength * v
+	return
+}
+
+// Integration rotation from angular velocity
+//	@param q1 initial rotation
+//	@param deltaAngle the angular displacement in radians
+@(require_results)
+IntegrateRotation :: proc "c" (q1: Rot, deltaAngle: f32) -> Rot {
+	// dc/dt = -omega * sin(t)
+	// ds/dt = omega * cos(t)
+	// c2 = c1 - omega * h * s1
+	// s2 = s1 + omega * h * c1
+	q2 := Rot{q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c}
+	mag := math.sqrt(q2.s * q2.s + q2.c * q2.c)
+	invMag := f32(mag > 0.0 ? 1 / mag : 0.0)
+	return {q2.c * invMag, q2.s * invMag}
+}
+
+// Get the length squared of this vector
+@(require_results)
+LengthSquared :: proc "c" (v: Vec2) -> f32 {
+	return v.x * v.x + v.y * v.y
+}
+
 // Get the distance squared between points
 @(require_results)
 DistanceSquared :: proc "c" (a, b: Vec2) -> f32 {
@@ -222,28 +302,38 @@ DistanceSquared :: proc "c" (a, b: Vec2) -> f32 {
 // Make a rotation using an angle in radians
 @(require_results)
 MakeRot :: proc "c" (angle: f32) -> Rot {
-	// todo determinism
-	return {math.cos(angle), math.sin(angle)}
+	cs := ComputeCosSin(angle)
+	return Rot{c=cs.cosine, s=cs.sine}
 }
 
-// Normalize rotation
+// Compute the rotation between two unit vectors
 @(require_results)
-NormalizeRot :: proc "c" (q: Rot) -> Rot {
-	mag := math.sqrt(q.s * q.s + q.c * q.c)
-	invMag := f32(mag > 0.0 ? 1.0 / mag : 0.0)
-	return {q.c * invMag, q.s * invMag}
+ComputeRotationBetweenUnitVectors :: proc(v1, v2: Vec2) -> Rot {
+	return NormalizeRot({
+		c = Dot(v1, v2),
+		s = Cross(v1, v2),
+	})
 }
 
 // Is this rotation normalized?
 @(require_results)
-IsNormalized :: proc "c" (q: Rot) -> bool {
+IsNormalizedRot :: proc "c" (q: Rot) -> bool {
 	// larger tolerance due to failure on mingw 32-bit
 	qq := q.s * q.s + q.c * q.c
 	return 1.0 - 0.0006 < qq && qq < 1 + 0.0006
 }
 
+// Normalize rotation
+@(require_results)
+NormalizeRot :: proc "c" (q: Rot) -> Rot {
+	mag := math.sqrt(q.s * q.s + q.c * q.c)
+	invMag := f32(mag > 0.0 ? 1.0 / mag : 0.0)
+	return {q.c * invMag, q.s * invMag}
+}
+
 // Normalized linear interpolation
 // https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
+// https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
 @(require_results)
 NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot {
 	omt := 1 - t
@@ -253,21 +343,6 @@ NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot {
 	})
 }
 
-// Integration rotation from angular velocity
-//	@param q1 initial rotation
-//	@param deltaAngle the angular displacement in radians
-@(require_results)
-IntegrateRotation :: proc "c" (q1: Rot, deltaAngle: f32) -> Rot {
-	// dc/dt = -omega * sin(t)
-	// ds/dt = omega * cos(t)
-	// c2 = c1 - omega * h * s1
-	// s2 = s1 + omega * h * c1
-	q2 := Rot{q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c}
-	mag := math.sqrt(q2.s * q2.s + q2.c * q2.c)
-	invMag := f32(mag > 0.0 ? 1 / mag : 0.0)
-	return {q2.c * invMag, q2.s * invMag}
-}
-
 // Compute the angular velocity necessary to rotate between two rotations over a give time
 //	@param q1 initial rotation
 //	@param q2 final rotation
@@ -291,8 +366,7 @@ ComputeAngularVelocity :: proc "c" (q1: Rot, q2: Rot, inv_h: f32) -> f32 {
 // Get the angle in radians in the range [-pi, pi]
 @(require_results)
 Rot_GetAngle :: proc "c" (q: Rot) -> f32 {
-	// todo determinism
-	return math.atan2(q.s, q.c)
+	return Atan2(q.s, q.c)
 }
 
 // Get the x-axis
@@ -338,18 +412,34 @@ RelativeAngle :: proc "c" (b, a: Rot) -> f32 {
 	// cos(b - a) = bc * ac + bs * as
 	s := b.s * a.c - b.c * a.s
 	c := b.c * a.c + b.s * a.s
-	return math.atan2(s, c)
+	return Atan2(s, c)
 }
 
 // Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi]
 @(require_results)
-UnwindAngle :: proc "c" (angle: f32) -> f32 {
-	if angle < -pi {
-		return angle + 2.0 * pi
-	} else if angle > pi {
-		return angle - 2.0 * pi
+UnwindAngle :: proc "c" (radians: f32) -> f32 {
+	if radians < -PI {
+		return radians + 2.0 * PI
+	} else if radians > PI {
+		return radians - 2.0 * PI
 	}
-	return angle
+	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
 }
 
 // Rotate a vector
@@ -380,6 +470,9 @@ InvTransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 {
 	return {t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy}
 }
 
+// Multiply two transforms. If the result is applied to a point p local to frame B,
+// the transform would first convert p to a point local to frame A, then into a point
+// in the world frame.
 // v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
 //    = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
 @(require_results)
@@ -389,6 +482,7 @@ MulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) {
 	return
 }
 
+// Creates a transform that converts a local point in frame B to a local point in frame A.
 // v2 = A.q' * (B.q * v1 + B.p - A.p)
 //    = A.q' * B.q * v1 + A.q' * (B.p - A.p)
 @(require_results)
@@ -469,54 +563,65 @@ AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) {
 	return
 }
 
+// Compute the bounding box of an array of circles
 @(require_results)
-Float_IsValid :: proc "c" (a: f32) -> bool {
-	math.is_nan(a) or_return
-	math.is_inf(a) or_return
-	return true
+MakeAABB :: proc "c" (points: []Vec2, radius: f32) -> AABB {
+	a := AABB{points[0], points[0]}
+	for point in points {
+		a.lowerBound = Min(a.lowerBound, point)
+		a.upperBound = Max(a.upperBound, point)
+	}
+
+	r := Vec2{radius, radius}
+	a.lowerBound = a.lowerBound - r
+	a.upperBound = a.upperBound + r
+
+	return a
 }
 
+// Signed separation of a point from a plane
 @(require_results)
-Vec2_IsValid :: proc "c" (v: Vec2) -> bool {
-	(math.is_nan(v.x) || math.is_nan(v.y)) or_return
-	(math.is_inf(v.x) || math.is_inf(v.y)) or_return
-	return true
+PlaneSeparation :: proc "c" (plane: Plane, point: Vec2) -> f32 {
+	return Dot(plane.normal, point) - plane.offset
 }
 
 @(require_results)
-Rot_IsValid :: proc "c" (q: Rot) -> bool {
-	(math.is_nan(q.s) || math.is_nan(q.c)) or_return
-	(math.is_inf(q.s) || math.is_inf(q.c)) or_return
-	return IsNormalized(q)
+IsValidFloat :: proc "c" (a: f32) -> bool {
+	#partial switch math.classify(a) {
+	case .NaN, .Inf, .Neg_Inf: return false
+	case:                      return true
+	}
 }
 
 @(require_results)
-Normalize :: proc "c" (v: Vec2) -> Vec2 {
-	length := Length(v)
-	if length < 1e-23 {
-		return Vec2_zero
-	}
-	invLength := 1 / length
-	return invLength * v
+IsValidVec2 :: proc "c" (v: Vec2) -> bool {
+	IsValidFloat(v.x) or_return
+	IsValidFloat(v.y) or_return
+	return true
 }
 
 @(require_results)
-NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 {
-	length := Length(v)
-	if length < 1e-23 {
-		panic("zero-length Vec2")
-	}
-	invLength := 1 / length
-	return invLength * v
+IsValidRotation :: proc "c" (q: Rot) -> bool {
+	IsValidFloat(q.s) or_return
+	IsValidFloat(q.c) or_return
+	return IsNormalizedRot(q)
 }
 
+// Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound.
 @(require_results)
-GetLengthAndNormalize :: proc "c" (v: Vec2) -> (length: f32, vn: Vec2) {
-	length = Length(v)
-	if length < 1e-23 {
-		return
-	}
-	invLength := 1 / length
-	vn = invLength * v
-	return
+IsValidAABB :: proc "c" (aabb: AABB) -> bool {
+	IsValidVec2(aabb.lowerBound) or_return
+	IsValidVec2(aabb.upperBound) or_return
+	(aabb.upperBound.x >= aabb.lowerBound.x) or_return
+	(aabb.upperBound.y >= aabb.lowerBound.y) or_return
+	return true
+}
+
+// Is this a valid plane? Normal is a unit vector. Not Nan or infinity.
+@(require_results)
+IsValidPlane :: proc "c" (plane: Plane) -> bool {
+	IsValidFloat(plane.offset) or_return
+	IsValidVec2(plane.normal)  or_return
+	IsNormalized(plane.normal) or_return
+	return true
 }

+ 349 - 232
vendor/box2d/types.odin

@@ -37,14 +37,28 @@ EnqueueTaskCallback :: #type proc "c" (task: TaskCallback, itemCount: i32, minRa
 //	@ingroup world
 FinishTaskCallback :: #type proc "c" (userTask: rawptr, userContext: rawptr)
 
+// Optional friction mixing callback. This intentionally provides no context objects because this is called
+// from a worker thread.
+// @warning This function should not attempt to modify Box2D state or user application state.
+// @ingroup world
+FrictionCallback :: #type proc "c" (frictionA: f32, userMaterialIdA: i32, frictionB: f32, userMaterialIdB: i32)
+
+// Optional restitution mixing callback. This intentionally provides no context objects because this is called
+// from a worker thread.
+// @warning This function should not attempt to modify Box2D state or user application state.
+// @ingroup world
+RestitutionCallback :: #type proc "c" (restitutionA: f32, userMaterialIdA: i32, restitutuionB: f32, userMaterialIdB: i32)
+
 // Result from b2World_RayCastClosest
 // @ingroup world
 RayResult :: struct {
-	shapeId:  ShapeId,
-	point:    Vec2,
-	normal:   Vec2,
-	fraction: f32,
-	hit:      bool,
+	shapeId:    ShapeId,
+	point:      Vec2,
+	normal:     Vec2,
+	fraction:   f32,
+	nodeVisits: i32,
+	leafVisits: i32,
+	hit:        bool,
 }
 
 // World definition used to create a simulation world.
@@ -54,37 +68,53 @@ WorldDef :: struct {
 	// Gravity vector. Box2D has no up-vector defined.
 	gravity: Vec2,
 
-	// Restitution velocity threshold, usually in m/s. Collisions above this
+	// Restitution speed threshold, usually in m/s. Collisions above this
 	// speed have restitution applied (will bounce).
 	restitutionThreshold: f32,
 
-	// This parameter controls how fast overlap is resolved and has units of meters per second
-	contactPushoutVelocity: f32,
-
-	// Threshold velocity for hit events. Usually meters per second.
+	// Threshold speed for hit events. Usually meters per second.
 	hitEventThreshold: f32,
 
-	// Contact stiffness. Cycles per second.
+	// Contact stiffness. Cycles per second. Increasing this increases the speed of overlap recovery, but can introduce jitter.
 	contactHertz: f32,
 
-	// Contact bounciness. Non-dimensional.
+	// Contact bounciness. Non-dimensional. You can speed up overlap recovery by decreasing this with
+	// the trade-off that overlap resolution becomes more energetic.
 	contactDampingRatio: f32,
 
+	// This parameter controls how fast overlap is resolved and usually has units of meters per second. This only
+	// puts a cap on the resolution speed. The resolution speed is increased by increasing the hertz and/or
+	// 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,
+
+	// Optional mixing callback for friction. The default uses sqrt(frictionA * frictionB).
+	frictionCallback: FrictionCallback,
+
+	// Optional mixing callback for restitution. The default uses max(restitutionA, restitutionB).
+	restitutionCallback: RestitutionCallback,
+
 	// Can bodies go to sleep to improve performance
 	enableSleep: bool,
 
 	// Enable continuous collision
-	enableContinous: bool,
+	enableContinuous: bool,
 
 	// Number of workers to use with the provided task system. Box2D performs best when using only
-	//	performance cores and accessing a single L2 cache. Efficiency cores and hyper-threading provide
-	//	little benefit and may even harm performance.
+	// performance cores and accessing a single L2 cache. Efficiency cores and hyper-threading provide
+	// little benefit and may even harm performance.
+	// @note Box2D does not create threads. This is the number of threads your applications has created
+	// that you are allocating to b2World_Step.
+	// @warning Do not modify the default value unless you are also providing a task system and providing
+	// task callbacks (enqueueTask and finishTask).
 	workerCount: i32,
 
 	// Function to spawn tasks
@@ -96,6 +126,9 @@ WorldDef :: struct {
 	// User context that is provided to enqueueTask and finishTask
 	userTaskContext: rawptr,
 
+	// User data
+	userData: rawptr,
+
 	// Used internally to detect a valid definition. DO NOT SET.
 	internalValue: i32,
 }
@@ -138,20 +171,20 @@ BodyDef :: struct {
 	// The initial world rotation of the body. Use b2MakeRot() if you have an angle.
 	rotation: Rot,
 
-	// The initial linear velocity of the body's origin. Typically in meters per second.
+	// The initial linear velocity of the body's origin. Usually in meters per second.
 	linearVelocity: Vec2,
 
 	// The initial angular velocity of the body. Radians per second.
 	angularVelocity: f32,
 
-	// Linear damping is use to reduce the linear velocity. The damping parameter
+	// Linear damping is used to reduce the linear velocity. The damping parameter
 	// can be larger than 1 but the damping effect becomes sensitive to the
 	// time step when the damping parameter is large.
 	//	Generally linear damping is undesirable because it makes objects move slowly
 	//	as if they are f32ing.
 	linearDamping: f32,
 
-	// Angular damping is use to reduce the angular velocity. The damping parameter
+	// Angular damping is used to reduce the angular velocity. The damping parameter
 	// can be larger than 1.0f but the damping effect becomes sensitive to the
 	// time step when the damping parameter is large.
 	//	Angular damping can be use slow down rotating bodies.
@@ -160,9 +193,12 @@ BodyDef :: struct {
 	// Scale the gravity applied to this body. Non-dimensional.
 	gravityScale: f32,
 
-	// Sleep velocity threshold, default is 0.05 meter per second
+	// Sleep speed threshold, default is 0.05 meters per second
 	sleepThreshold: f32,
 
+	// Optional body name for debugging. Up to 32 characters (excluding null termination)
+	name: cstring,
+
 	// Use this to store application specific body data.
 	userData: rawptr,
 
@@ -184,10 +220,6 @@ BodyDef :: struct {
 	// Used to disable a body. A disabled body does not move or collide.
 	isEnabled: bool,
 
-	// Automatically compute mass and related properties on this body from shapes.
-	// Triggers whenever a shape is add/removed/changed. Default is true.
-	automaticMass: bool,
-
 	// This allows this body to bypass rotational speed limits. Should only be used
 	// for circular objects, like wheels.
 	allowFastRotation: bool,
@@ -204,7 +236,7 @@ Filter :: struct {
 	// The collision category bits. Normally you would just set one bit. The category bits should
 	//	represent your application object types. For example:
 	//	@code{.odin}
-	//	My_Categories :: enum u32 {
+	//	My_Categories :: enum u64 {
 	//		Static  = 0x00000001,
 	//		Dynamic = 0x00000002,
 	//		Debris  = 0x00000004,
@@ -213,16 +245,16 @@ Filter :: struct {
 	//	};
 	//	@endcode
 	//      Or use a bit_set.
-	categoryBits: u32,
+	categoryBits: u64,
 
 	// The collision mask bits. This states the categories that this
 	// shape would accept for collision.
 	//	For example, you may want your player to only collide with static objects
 	//	and other players.
 	//	@code{.odin}
-	//	maskBits = u32(My_Categories.Static | My_Categories.Player);
+	//	maskBits = u64(My_Categories.Static | My_Categories.Player);
 	//	@endcode
-	maskBits: u32,
+	maskBits: u64,
 
 	// Collision groups allow a certain group of objects to never collide (negative)
 	// or always collide (positive). A group index of zero has no effect. Non-zero group filtering
@@ -240,11 +272,11 @@ Filter :: struct {
 // @ingroup shape
 QueryFilter :: struct {
 	// The collision category bits of this query. Normally you would just set one bit.
-	categoryBits: u32,
+	categoryBits: u64,
 
 	// The collision mask bits. This states the shape categories that this
 	// query would accept for collision.
-	maskBits: u32,
+	maskBits: u64,
 }
 
 
@@ -263,13 +295,37 @@ ShapeType :: enum c.int {
 	// A convex polygon
 	polygonShape,
 
-	// A smooth segment owned by a chain shape
-	smoothSegmentShape,
+	// A line segment owned by a chain shape
+	chainSegmentShape,
 }
 
 // The number of shape types
 shapeTypeCount :: len(ShapeType)
 
+// Surface materials allow chain shapes to have per segment surface properties.
+// @ingroup shape
+SurfaceMaterial :: struct {
+	// The Coulomb (dry) friction coefficient, usually in the range [0,1].
+	friction: f32,
+
+	// The coefficient of restitution (bounce) usually in the range [0,1].
+	// https://en.wikipedia.org/wiki/Coefficient_of_restitution
+	restitution: f32,
+
+	// The rolling resistance usually in the range [0,1].
+	rollingResistance: f32,
+
+	// The tangent speed for conveyor belts
+	tangentSpeed: f32,
+
+	// User material identifier. This is passed with query results and to friction and restitution
+	// combining functions. It is not used internally.
+	userMaterialId: i32,
+
+	// Custom debug draw color.
+	customColor: u32,
+}
+
 // Used to create a shape.
 // This is a temporary object used to bundle shape creation parameters. You may use
 //	the same shape definition to create multiple shapes.
@@ -279,58 +335,61 @@ ShapeDef :: struct {
 	// Use this to store application specific shape data.
 	userData: rawptr,
 
-	// The Coulomb (dry) friction coefficient, usually in the range [0,1].
-	friction: f32,
-
-	// The restitution (bounce) usually in the range [0,1].
-	restitution: f32,
+	// The surface material for this shape.
+	material: SurfaceMaterial,
 
 	// The density, usually in kg/m^2.
+	// This is not part of the surface material because this is for the interior, which may have
+	// other considerations, such as being hollow. For example a wood barrel may be hollow or full of water.
 	density: f32,
 
 	// Collision filtering data.
 	filter: Filter,
 
-	// Custom debug draw color.
-	customColor: u32,
-
 	// A sensor shape generates overlap events but never generates a collision response.
+	// Sensors do not have continuous collision. Instead, use a ray or shape cast for those scenarios.
+	// Sensors still contribute to the body mass if they have non-zero density.
+	// @note Sensor events are disabled by default.
+	// @see enableSensorEvents
 	isSensor: bool,
 
-	// Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	// Enable sensor events for this shape. This applies to sensors and non-sensors. False by default, even for sensors.
 	enableSensorEvents: bool,
 
-	// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default.
 	enableContactEvents: bool,
 
-	// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default.
 	enableHitEvents: bool,
 
 	// Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive
 	//	and must be carefully handled due to threading. Ignored for sensors.
 	enablePreSolveEvents: bool,
 
-	// Normally shapes on static bodies don't invoke contact creation when they are added to the world. This overrides
-	//	that behavior and causes contact creation. This significantly slows down static body creation which can be important
-	//	when there are many static shapes.
-	forceContactCreation: bool,
+	// When shapes are created they will scan the environment for collision the next time step. This can significantly slow down
+	// static body creation when there are many static shapes.
+	// This is flag is ignored for dynamic and kinematic shapes which always invoke contact creation.
+	invokeContactCreation: bool,
+
+	// Should the body update the mass properties when this shape is created. Default is true.
+	updateBodyMass: bool,
 
 	// Used internally to detect a valid definition. DO NOT SET.
 	internalValue: i32,
 }
 
 
-// Used to create a chain of edges. This is designed to eliminate ghost collisions with some limitations.
+// Used to create a chain of line segments. This is designed to eliminate ghost collisions with some limitations.
 //	- chains are one-sided
 //	- chains have no mass and should be used on static bodies
-//	- chains have a counter-clockwise winding order
+//	- chains have a counter-clockwise winding order (normal points right of segment direction)
 //	- chains are either a loop or open
 // - a chain must have at least 4 points
-//	- the distance between any two points must be greater than b2_linearSlop
+//	- the distance between any two points must be greater than B2_LINEAR_SLOP
 //	- a chain shape should not self intersect (this is not validated)
 //	- an open chain shape has NO COLLISION on the first and final edge
 //	- you may overlap two open chains on their first three and/or last three points to get smooth collision
-//	- a chain shape creates multiple smooth edges shapes on the body
+//	- a chain shape creates multiple line segment shapes on the body
 // https://en.wikipedia.org/wiki/Polygonal_chain
 // Must be initialized using b2DefaultChainDef().
 //	@warning Do not use chain shapes unless you understand the limitations. This is an advanced feature.
@@ -345,11 +404,12 @@ ChainDef :: struct {
 	// The point count, must be 4 or more.
 	count: i32,
 
-	// The friction coefficient, usually in the range [0,1].
-	friction: f32,
+	// Surface materials for each segment. These are cloned.
+	materials: [^]SurfaceMaterial `fmt:"v,materialCount"`,
 
-	// The restitution (elasticity) usually in the range [0,1].
-	restitution: f32,
+	// The material count. Must be 1 or count. This allows you to provide one
+	// material for all segments or a unique material per segment.
+	materialCount: i32,
 
 	// Contact filtering data.
 	filter: Filter,
@@ -357,6 +417,9 @@ ChainDef :: struct {
 	// Indicates a closed chain formed by connecting the first and last points
 	isLoop: bool,
 
+	// Enable sensors to detect this chain. False by default.
+	enableSensorEvents: bool,
+
 	// Used internally to detect a valid definition. DO NOT SET.
 	internalValue: i32,
 }
@@ -369,29 +432,28 @@ Profile :: struct {
 	pairs:               f32,
 	collide:             f32,
 	solve:               f32,
-	buildIslands:        f32,
+	mergeIslands:        f32,
+	prepareStages:       f32,
 	solveConstraints:    f32,
-	prepareTasks:        f32,
-	solverTasks:         f32,
 	prepareConstraints:  f32,
 	integrateVelocities: f32,
 	warmStart:           f32,
-	solveVelocities:     f32,
+	solveImpulses:       f32,
 	integratePositions:  f32,
-	relaxVelocities:     f32,
+	relaxImpulses:       f32,
 	applyRestitution:    f32,
 	storeImpulses:       f32,
-	finalizeBodies:      f32,
 	splitIslands:        f32,
-	sleepIslands:        f32,
+	transforms:          f32,
 	hitEvents:           f32,
-	broadphase:          f32,
-	continuous:          f32,
+	refit:               f32,
+	bullets:             f32,
+	sleepIslands:        f32,
+	sensors:             f32,
 }
 
 // Counters that give details of the simulation size.
 Counters :: struct {
-	staticBodyCount:  i32,
 	bodyCount:        i32,
 	shapeCount:       i32,
 	contactCount:     i32,
@@ -413,6 +475,7 @@ Counters :: struct {
 // @ingroup joint
 JointType :: enum c.int {
 	distanceJoint,
+	filterJoint,
 	motorJoint,
 	mouseJoint,
 	prismaticJoint,
@@ -526,7 +589,7 @@ MotorJointDef :: struct {
 // applying huge forces. This also applies rotation constraint heuristic to improve control.
 // @ingroup mouse_joint
 MouseJointDef :: struct {
-	// The first attached body.
+	// The first attached body. This is assumed to be static.
 	bodyIdA: BodyId,
 
 	// The second attached body.
@@ -554,6 +617,22 @@ MouseJointDef :: struct {
 	internalValue: i32,
 }
 
+// A filter joint is used to disable collision between two specific bodies.
+//
+// @ingroup filter_joint
+FilterJointDef :: struct {
+	/// The first attached body.
+	bodyIdA: BodyId,
+
+	/// The second attached body.
+	bodyIdB: BodyId,
+
+	/// User data pointer
+	userData: rawptr,
+
+	/// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
 
 // Prismatic joint definition
 //
@@ -660,10 +739,10 @@ RevoluteJointDef :: struct {
 	// A flag to enable joint limits
 	enableLimit: bool,
 
-	// The lower angle for the joint limit in radians
+	// The lower angle for the joint limit in radians. Minimum of -0.95*pi radians.
 	lowerAngle: f32,
 
-	// The upper angle for the joint limit in radians
+	// The upper angle for the joint limit in radians. Maximum of 0.95*pi radians.
 	upperAngle: f32,
 
 	// A flag to enable the joint motor
@@ -794,6 +873,27 @@ WheelJointDef :: struct {
 	internalValue: i32,
 }
 
+// The explosion definition is used to configure options for explosions. Explosions
+// consider shape geometry when computing the impulse.
+// @ingroup world
+ExplosionDef :: struct {
+	/// Mask bits to filter shapes
+	maskBits: u64,
+
+	/// The center of the explosion in world space
+	position: Vec2,
+
+	/// The radius of the explosion
+	radius: f32,
+
+	/// The falloff distance beyond the radius. Impulse is reduced to zero at this distance.
+	falloff: f32,
+
+	/// Impulse per unit length. This applies an impulse according to the shape perimeter that
+	/// is facing the explosion. Explosions only apply to circles, capsules, and polygons. This
+	/// may be negative for implosions.
+	impulsePerLength: f32,
+}
 
 /**
  * @defgroup events Events
@@ -822,11 +922,18 @@ SensorBeginTouchEvent :: struct {
 }
 
 // An end touch event is generated when a shape stops overlapping a sensor shape.
+// These include things like setting the transform, destroying a body or shape, or changing
+// a filter. You will also get an end event if the sensor or visitor are destroyed.
+// Therefore you should always confirm the shape id is valid using b2Shape_IsValid.
 SensorEndTouchEvent :: struct {
 	// The id of the sensor shape
+	// @warning this shape may have been destroyed
+	// @see b2Shape_IsValid
 	sensorShapeId: ShapeId,
 
 	// The id of the dynamic shape that stopped touching the sensor shape
+	// @warning this shape may have been destroyed
+	// @see b2Shape_IsValid
 	visitorShapeId: ShapeId,
 }
 
@@ -854,14 +961,25 @@ ContactBeginTouchEvent :: struct {
 
 	// Id of the second shape
 	shapeIdB: ShapeId,
+
+	// The initial contact manifold. This is recorded before the solver is called,
+	// so all the impulses will be zero.
+	manifold: Manifold,
 }
 
 // An end touch event is generated when two shapes stop touching.
+// You will get an end event if you do anything that destroys contacts previous to the last
+// world step. These include things like setting the transform, destroying a body
+// or shape, or changing a filter or body type.
 ContactEndTouchEvent :: struct {
 	// Id of the first shape
+	// @warning this shape may have been destroyed
+	// @see b2Shape_IsValid
 	shapeIdA: ShapeId,
 
 	// Id of the second shape
+	// @warning this shape may have been destroyed
+	// @see b2Shape_IsValid
 	shapeIdB: ShapeId,
 }
 
@@ -998,201 +1116,191 @@ OverlapResultFcn :: #type proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool
 //	@ingroup world
 CastResultFcn :: #type proc "c" (shapeId: ShapeId, point: Vec2, normal: Vec2, fraction: f32, ctx: rawptr) -> f32
 
-// These colors are used for debug draw.
-//	See https://www.rapidtables.com/web/color/index.html
+// Used to collect collision planes for character movers.
+// Return true to continue gathering planes.
+PlaneResultFcn :: #type proc "c" (shapeId: ShapeId, plane: ^PlaneResult, ctx: rawptr)
+
+// These colors are used for debug draw and mostly match the named SVG colors.
+// See https://www.rapidtables.com/web/color/index.html
+// https://johndecember.com/html/spec/colorsvg.html
+// https://upload.wikimedia.org/wikipedia/commons/2/2b/SVG_Recognized_color_keyword_names.svg
 HexColor :: enum c.int {
-	AliceBlue            = 0xf0f8ff,
-	AntiqueWhite         = 0xfaebd7,
-	Aqua                 = 0x00ffff,
-	Aquamarine           = 0x7fffd4,
-	Azure                = 0xf0ffff,
-	Beige                = 0xf5f5dc,
-	Bisque               = 0xffe4c4,
+	AliceBlue            = 0xF0F8FF,
+	AntiqueWhite         = 0xFAEBD7,
+	Aqua                 = 0x00FFFF,
+	Aquamarine           = 0x7FFFD4,
+	Azure                = 0xF0FFFF,
+	Beige                = 0xF5F5DC,
+	Bisque               = 0xFFE4C4,
 	Black                = 0x000000,
-	BlanchedAlmond       = 0xffebcd,
-	Blue                 = 0x0000ff,
-	BlueViolet           = 0x8a2be2,
-	Brown                = 0xa52a2a,
-	Burlywood            = 0xdeb887,
-	CadetBlue            = 0x5f9ea0,
-	Chartreuse           = 0x7fff00,
-	Chocolate            = 0xd2691e,
-	Coral                = 0xff7f50,
-	CornflowerBlue       = 0x6495ed,
-	Cornsilk             = 0xfff8dc,
-	Crimson              = 0xdc143c,
-	Cyan                 = 0x00ffff,
-	DarkBlue             = 0x00008b,
-	DarkCyan             = 0x008b8b,
-	DarkGoldenrod        = 0xb8860b,
-	DarkGray             = 0xa9a9a9,
+	BlanchedAlmond       = 0xFFEBCD,
+	Blue                 = 0x0000FF,
+	BlueViolet           = 0x8A2BE2,
+	Brown                = 0xA52A2A,
+	Burlywood            = 0xDEB887,
+	CadetBlue            = 0x5F9EA0,
+	Chartreuse           = 0x7FFF00,
+	Chocolate            = 0xD2691E,
+	Coral                = 0xFF7F50,
+	CornflowerBlue       = 0x6495ED,
+	Cornsilk             = 0xFFF8DC,
+	Crimson              = 0xDC143C,
+	Cyan                 = 0x00FFFF,
+	DarkBlue             = 0x00008B,
+	DarkCyan             = 0x008B8B,
+	DarkGoldenRod        = 0xB8860B,
+	DarkGray             = 0xA9A9A9,
 	DarkGreen            = 0x006400,
-	DarkKhaki            = 0xbdb76b,
-	DarkMagenta          = 0x8b008b,
-	DarkOliveGreen       = 0x556b2f,
-	DarkOrange           = 0xff8c00,
-	DarkOrchid           = 0x9932cc,
-	DarkRed              = 0x8b0000,
-	DarkSalmon           = 0xe9967a,
-	DarkSeaGreen         = 0x8fbc8f,
-	DarkSlateBlue        = 0x483d8b,
-	DarkSlateGray        = 0x2f4f4f,
-	DarkTurquoise        = 0x00ced1,
-	DarkViolet           = 0x9400d3,
-	DeepPink             = 0xff1493,
-	DeepSkyBlue          = 0x00bfff,
+	DarkKhaki            = 0xBDB76B,
+	DarkMagenta          = 0x8B008B,
+	DarkOliveGreen       = 0x556B2F,
+	DarkOrange           = 0xFF8C00,
+	DarkOrchid           = 0x9932CC,
+	DarkRed              = 0x8B0000,
+	DarkSalmon           = 0xE9967A,
+	DarkSeaGreen         = 0x8FBC8F,
+	DarkSlateBlue        = 0x483D8B,
+	DarkSlateGray        = 0x2F4F4F,
+	DarkTurquoise        = 0x00CED1,
+	DarkViolet           = 0x9400D3,
+	DeepPink             = 0xFF1493,
+	DeepSkyBlue          = 0x00BFFF,
 	DimGray              = 0x696969,
-	DodgerBlue           = 0x1e90ff,
-	Firebrick            = 0xb22222,
-	FloralWhite          = 0xfffaf0,
-	ForestGreen          = 0x228b22,
-	Fuchsia              = 0xff00ff,
-	Gainsboro            = 0xdcdcdc,
-	GhostWhite           = 0xf8f8ff,
-	Gold                 = 0xffd700,
-	Goldenrod            = 0xdaa520,
-	Gray                 = 0xbebebe,
-	Gray1                = 0x1a1a1a,
-	Gray2                = 0x333333,
-	Gray3                = 0x4d4d4d,
-	Gray4                = 0x666666,
-	Gray5                = 0x7f7f7f,
-	Gray6                = 0x999999,
-	Gray7                = 0xb3b3b3,
-	Gray8                = 0xcccccc,
-	Gray9                = 0xe5e5e5,
-	Green                = 0x00ff00,
-	GreenYellow          = 0xadff2f,
-	Honeydew             = 0xf0fff0,
-	HotPink              = 0xff69b4,
-	IndianRed            = 0xcd5c5c,
-	Indigo               = 0x4b0082,
-	Ivory                = 0xfffff0,
-	Khaki                = 0xf0e68c,
-	Lavender             = 0xe6e6fa,
-	LavenderBlush        = 0xfff0f5,
-	LawnGreen            = 0x7cfc00,
-	LemonChiffon         = 0xfffacd,
-	LightBlue            = 0xadd8e6,
-	LightCoral           = 0xf08080,
-	LightCyan            = 0xe0ffff,
-	LightGoldenrod       = 0xeedd82,
-	LightGoldenrodYellow = 0xfafad2,
-	LightGray            = 0xd3d3d3,
-	LightGreen           = 0x90ee90,
-	LightPink            = 0xffb6c1,
-	LightSalmon          = 0xffa07a,
-	LightSeaGreen        = 0x20b2aa,
-	LightSkyBlue         = 0x87cefa,
-	LightSlateBlue       = 0x8470ff,
+	DodgerBlue           = 0x1E90FF,
+	FireBrick            = 0xB22222,
+	FloralWhite          = 0xFFFAF0,
+	ForestGreen          = 0x228B22,
+	Fuchsia              = 0xFF00FF,
+	Gainsboro            = 0xDCDCDC,
+	GhostWhite           = 0xF8F8FF,
+	Gold                 = 0xFFD700,
+	GoldenRod            = 0xDAA520,
+	Gray                 = 0x808080,
+	Green                = 0x008000,
+	GreenYellow          = 0xADFF2F,
+	HoneyDew             = 0xF0FFF0,
+	HotPink              = 0xFF69B4,
+	IndianRed            = 0xCD5C5C,
+	Indigo               = 0x4B0082,
+	Ivory                = 0xFFFFF0,
+	Khaki                = 0xF0E68C,
+	Lavender             = 0xE6E6FA,
+	LavenderBlush        = 0xFFF0F5,
+	LawnGreen            = 0x7CFC00,
+	LemonChiffon         = 0xFFFACD,
+	LightBlue            = 0xADD8E6,
+	LightCoral           = 0xF08080,
+	LightCyan            = 0xE0FFFF,
+	LightGoldenRodYellow = 0xFAFAD2,
+	LightGray            = 0xD3D3D3,
+	LightGreen           = 0x90EE90,
+	LightPink            = 0xFFB6C1,
+	LightSalmon          = 0xFFA07A,
+	LightSeaGreen        = 0x20B2AA,
+	LightSkyBlue         = 0x87CEFA,
 	LightSlateGray       = 0x778899,
-	LightSteelBlue       = 0xb0c4de,
-	LightYellow          = 0xffffe0,
-	Lime                 = 0x00ff00,
-	LimeGreen            = 0x32cd32,
-	Linen                = 0xfaf0e6,
-	Magenta              = 0xff00ff,
-	Maroon               = 0xb03060,
-	MediumAquamarine     = 0x66cdaa,
-	MediumBlue           = 0x0000cd,
-	MediumOrchid         = 0xba55d3,
-	MediumPurple         = 0x9370db,
-	MediumSeaGreen       = 0x3cb371,
-	MediumSlateBlue      = 0x7b68ee,
-	MediumSpringGreen    = 0x00fa9a,
-	MediumTurquoise      = 0x48d1cc,
-	MediumVioletRed      = 0xc71585,
+	LightSteelBlue       = 0xB0C4DE,
+	LightYellow          = 0xFFFFE0,
+	Lime                 = 0x00FF00,
+	LimeGreen            = 0x32CD32,
+	Linen                = 0xFAF0E6,
+	Magenta              = 0xFF00FF,
+	Maroon               = 0x800000,
+	MediumAquaMarine     = 0x66CDAA,
+	MediumBlue           = 0x0000CD,
+	MediumOrchid         = 0xBA55D3,
+	MediumPurple         = 0x9370DB,
+	MediumSeaGreen       = 0x3CB371,
+	MediumSlateBlue      = 0x7B68EE,
+	MediumSpringGreen    = 0x00FA9A,
+	MediumTurquoise      = 0x48D1CC,
+	MediumVioletRed      = 0xC71585,
 	MidnightBlue         = 0x191970,
-	MintCream            = 0xf5fffa,
-	MistyRose            = 0xffe4e1,
-	Moccasin             = 0xffe4b5,
-	NavajoWhite          = 0xffdead,
+	MintCream            = 0xF5FFFA,
+	MistyRose            = 0xFFE4E1,
+	Moccasin             = 0xFFE4B5,
+	NavajoWhite          = 0xFFDEAD,
 	Navy                 = 0x000080,
-	NavyBlue             = 0x000080,
-	OldLace              = 0xfdf5e6,
+	OldLace              = 0xFDF5E6,
 	Olive                = 0x808000,
-	OliveDrab            = 0x6b8e23,
-	Orange               = 0xffa500,
-	OrangeRed            = 0xff4500,
-	Orchid               = 0xda70d6,
-	PaleGoldenrod        = 0xeee8aa,
-	PaleGreen            = 0x98fb98,
-	PaleTurquoise        = 0xafeeee,
-	PaleVioletRed        = 0xdb7093,
-	PapayaWhip           = 0xffefd5,
-	PeachPuff            = 0xffdab9,
-	Peru                 = 0xcd853f,
-	Pink                 = 0xffc0cb,
-	Plum                 = 0xdda0dd,
-	PowderBlue           = 0xb0e0e6,
-	Purple               = 0xa020f0,
+	OliveDrab            = 0x6B8E23,
+	Orange               = 0xFFA500,
+	OrangeRed            = 0xFF4500,
+	Orchid               = 0xDA70D6,
+	PaleGoldenRod        = 0xEEE8AA,
+	PaleGreen            = 0x98FB98,
+	PaleTurquoise        = 0xAFEEEE,
+	PaleVioletRed        = 0xDB7093,
+	PapayaWhip           = 0xFFEFD5,
+	PeachPuff            = 0xFFDAB9,
+	Peru                 = 0xCD853F,
+	Pink                 = 0xFFC0CB,
+	Plum                 = 0xDDA0DD,
+	PowderBlue           = 0xB0E0E6,
+	Purple               = 0x800080,
 	RebeccaPurple        = 0x663399,
-	Red                  = 0xff0000,
-	RosyBrown            = 0xbc8f8f,
-	RoyalBlue            = 0x4169e1,
-	SaddleBrown          = 0x8b4513,
-	Salmon               = 0xfa8072,
-	SandyBrown           = 0xf4a460,
-	SeaGreen             = 0x2e8b57,
-	Seashell             = 0xfff5ee,
-	Sienna               = 0xa0522d,
-	Silver               = 0xc0c0c0,
-	SkyBlue              = 0x87ceeb,
-	SlateBlue            = 0x6a5acd,
+	Red                  = 0xFF0000,
+	RosyBrown            = 0xBC8F8F,
+	RoyalBlue            = 0x4169E1,
+	SaddleBrown          = 0x8B4513,
+	Salmon               = 0xFA8072,
+	SandyBrown           = 0xF4A460,
+	SeaGreen             = 0x2E8B57,
+	SeaShell             = 0xFFF5EE,
+	Sienna               = 0xA0522D,
+	Silver               = 0xC0C0C0,
+	SkyBlue              = 0x87CEEB,
+	SlateBlue            = 0x6A5ACD,
 	SlateGray            = 0x708090,
-	Snow                 = 0xfffafa,
-	SpringGreen          = 0x00ff7f,
-	SteelBlue            = 0x4682b4,
-	Tan                  = 0xd2b48c,
+	Snow                 = 0xFFFAFA,
+	SpringGreen          = 0x00FF7F,
+	SteelBlue            = 0x4682B4,
+	Tan                  = 0xD2B48C,
 	Teal                 = 0x008080,
-	Thistle              = 0xd8bfd8,
-	Tomato               = 0xff6347,
-	Turquoise            = 0x40e0d0,
-	Violet               = 0xee82ee,
-	VioletRed            = 0xd02090,
-	Wheat                = 0xf5deb3,
-	White                = 0xffffff,
-	WhiteSmoke           = 0xf5f5f5,
-	Yellow               = 0xffff00,
-	YellowGreen          = 0x9acd32,
-	Box2DRed             = 0xdc3132,
-	Box2DBlue            = 0x30aebf,
-	Box2DGreen           = 0x8cc924,
-	Box2DYellow          = 0xffee8c,
+	Thistle              = 0xD8BFD8,
+	Tomato               = 0xFF6347,
+	Turquoise            = 0x40E0D0,
+	Violet               = 0xEE82EE,
+	Wheat                = 0xF5DEB3,
+	White                = 0xFFFFFF,
+	WhiteSmoke           = 0xF5F5F5,
+	Yellow               = 0xFFFF00,
+	YellowGreen          = 0x9ACD32,
+	Box2DRed             = 0xDC3132,
+	Box2DBlue            = 0x30AEBF,
+	Box2DGreen           = 0x8CC924,
+	Box2DYellow          = 0xFFEE8C,
 }
 
 // This struct holds callbacks you can implement to draw a Box2D world.
 //	@ingroup world
 DebugDraw :: struct {
 	// Draw a closed polygon provided in CCW order.
-	DrawPolygon: proc "c" (vertices: [^]Vec2, vertexCount: c.int, color: HexColor, ctx: rawptr),
+	DrawPolygonFcn: proc "c" (vertices: [^]Vec2, vertexCount: c.int, color: HexColor, ctx: rawptr),
 
 	// Draw a solid closed polygon provided in CCW order.
-	DrawSolidPolygon: proc "c" (transform: Transform, vertices: [^]Vec2, vertexCount: c.int, radius: f32, colr: HexColor, ctx: rawptr ),
+	DrawSolidPolygonFcn: proc "c" (transform: Transform, vertices: [^]Vec2, vertexCount: c.int, radius: f32, colr: HexColor, ctx: rawptr ),
 
 	// Draw a circle.
-	DrawCircle: proc "c" (center: Vec2, radius: f32, color: HexColor, ctx: rawptr),
+	DrawCircleFcn: proc "c" (center: Vec2, radius: f32, color: HexColor, ctx: rawptr),
 
 	// Draw a solid circle.
-	DrawSolidCircle: proc "c" (transform: Transform, radius: f32, color: HexColor, ctx: rawptr),
-
-	// Draw a capsule.
-	DrawCapsule: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr),
+	DrawSolidCircleFcn: proc "c" (transform: Transform, radius: f32, color: HexColor, ctx: rawptr),
 
 	// Draw a solid capsule.
-	DrawSolidCapsule: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr),
+	DrawSolidCapsuleFcn: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr),
 
 	// Draw a line segment.
-	DrawSegment: proc "c" (p1, p2: Vec2, color: HexColor, ctx: rawptr),
+	DrawSegmentFcn: proc "c" (p1, p2: Vec2, color: HexColor, ctx: rawptr),
 
 	// Draw a transform. Choose your own length scale.
-	DrawTransform: proc "c" (transform: Transform, ctx: rawptr),
+	DrawTransformFcn: proc "c" (transform: Transform, ctx: rawptr),
 
 	// Draw a point.
-	DrawPoint: proc "c" (p: Vec2, size: f32, color: HexColor, ctx: rawptr),
+	DrawPointFcn: proc "c" (p: Vec2, size: f32, color: HexColor, ctx: rawptr),
 
-	// Draw a string.
-	DrawString: proc "c" (p: Vec2, s: cstring, ctx: rawptr),
+	// Draw a string in world space.
+	DrawStringFcn: proc "c" (p: Vec2, s: cstring, color: HexColor, ctx: rawptr),
 
 	// Bounds to use if restricting drawing to a rectangular region
 	drawingBounds: AABB,
@@ -1210,11 +1318,14 @@ DebugDraw :: struct {
 	drawJointExtras: bool,
 
 	// Option to draw the bounding boxes for shapes
-	drawAABBs: bool,
+	drawBounds: bool,
 
 	// Option to draw the mass and center of mass of dynamic bodies
 	drawMass: bool,
 
+	// Option to draw body names
+	drawBodyNames: bool,
+
 	// Option to draw contact points
 	drawContacts: bool,
 
@@ -1227,9 +1338,15 @@ DebugDraw :: struct {
 	// Option to draw contact normal impulses
 	drawContactImpulses: bool,
 
+	// Option to draw contact feature ids
+	drawContactFeatures: bool,
+
 	// Option to draw contact friction impulses
 	drawFrictionImpulses: bool,
 
+	// Option to draw islands as bounding boxes
+	drawIslands: bool,
+
 	// User context that is passed as an argument to drawing callback functions
 	userContext: rawptr,
-}
+}

+ 4 - 4
vendor/box2d/wasm.Makefile

@@ -7,20 +7,20 @@
 # CC = $(shell brew --prefix llvm)/bin/clang
 # LD = $(shell brew --prefix llvm)/bin/wasm-ld
 
-VERSION   = 3.0.0
+VERSION   = 3.1.0
 SRCS      = $(wildcard box2d-$(VERSION)/src/*.c)
 OBJS_SIMD = $(SRCS:.c=_simd.o)
 OBJS      = $(SRCS:.c=.o)
 SYSROOT   = $(shell odin root)/vendor/libc
-CFLAGS    = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
+CFLAGS    = -Ibox2d-$(VERSION)/include --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
 
 all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
 
 %.o: %.c
-	$(CC) -c $(CFLAGS) $< -o $@
+	$(CC) -c $(CFLAGS) -DBOX2D_DISABLE_SIMD $< -o $@
 
 %_simd.o: %.c
-	$(CC) -c $(CFLAGS) -msimd128 $< -o $@
+	$(CC) -c $(CFLAGS) -DBOX2D_DISABLE_SIMD -msimd128 $< -o $@
 
 lib/box2d_wasm.o: $(OBJS)
 	$(LD) -r -o lib/box2d_wasm.o $(OBJS)

+ 3 - 3
vendor/libc/include/math.h

@@ -47,19 +47,19 @@ bool __isnanf(float);
 bool __isnand(double);
 #define isnan(x)                                           \
     ( sizeof(x) == sizeof(float)  ? __isnanf((float)(x))   \
-    :                             : __isnand((double)(x)))
+                                  : __isnand((double)(x)))
 
 bool __isinff(float);
 bool __isinfd(double);
 #define isinf(x)                                           \
     ( sizeof(x) == sizeof(float)  ? __isinff((float)(x))   \
-    :                             : __isinfd((double)(x)))
+                                  : __isinfd((double)(x)))
 
 bool __isfinitef(float);
 bool __isfinited(double);
 #define isfinite(x)                                           \
     ( sizeof(x) == sizeof(float)  ? __isfinitef((float)(x))   \
-    :                             : __isfinited((double)(x)))
+                                  : __isfinited((double)(x)))
 
 #ifdef __cplusplus
 }

+ 23 - 0
vendor/libc/include/sched.h

@@ -0,0 +1,23 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
+#include <stdint.h>
+
+#define CLOCK_MONOTONIC 1
+
+struct timespec
+{
+    int64_t tv_sec;
+    int64_t tv_nsec;
+};
+
+int clock_gettime(int clockid, struct timespec *tp);
+
+int sched_yield();
+
+#ifdef __cplusplus
+}
+#endif

+ 30 - 0
vendor/libc/sched.odin

@@ -0,0 +1,30 @@
+package odin_libc
+
+import "core:time"
+
+Clock :: enum i32 {
+	Monotonic = 1,
+}
+
+Time_Spec :: struct {
+	tv_sec:  i64,
+	tv_nsec: i64,
+}
+
+@(require, linkage="strong", link_name="clock_gettime")
+clock_gettine :: proc "c" (clockid: Clock, tp: ^Time_Spec) -> i32 {
+	switch clockid {
+	case .Monotonic:
+		tick := time.tick_now()
+		tp.tv_sec = tick._nsec/1e9
+		tp.tv_nsec = tick._nsec%1e9/1000
+		return 0
+
+	case: return -1
+	}
+}
+
+@(require, linkage="strong", link_name="sched_yield")
+sched_yield :: proc "c" () -> i32 {
+	return 0
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff