ソースを参照

Merge pull request #4074 from odin-lang/vendor/box2d

`vendor:box2d`
gingerBill 1 年間 前
コミット
4c19f507ff

+ 4 - 1
examples/all/all_vendor_windows.odin

@@ -1,4 +1,7 @@
 package all
 
 import wgpu "vendor:wgpu"
-_ :: wgpu
+import b2 "vendor:box2d"
+
+_ :: wgpu
+_ :: b2

+ 21 - 0
vendor/box2d/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Erin Catto
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 32 - 0
vendor/box2d/README.md

@@ -0,0 +1,32 @@
+![Box2D Logo](https://box2d.org/images/logo.svg)
+
+# Status
+[![Build Status](https://github.com/erincatto/box2c/actions/workflows/build.yml/badge.svg)](https://github.com/erincatto/box2c/actions)
+
+# Box2D v3.0 Notes
+This repository is beta and ready for testing. It should build on recent versions of clang and gcc. However, you will need the latest Visual Studio version for C11 atomics to compile (17.8.3+).
+
+AVX2 CPU support is assumed. You can turn this off in the CMake options and use SSE2 instead.
+
+# Box2D
+Box2D is a 2D physics engine for games.
+
+## Contributing
+Please do not submit pull requests with new features or core library changes. Instead, please file an issue first for discussion. For bugs, I prefer detailed bug reports over pull requests.
+
+# Giving Feedback
+Please visit the discussions tab, file an issue, or start a chat on discord.
+
+## Community
+- [Discord](https://discord.gg/NKYgCBP)
+
+## License
+Box2D is developed by Erin Catto, and uses the [MIT license](https://en.wikipedia.org/wiki/MIT_License).
+
+## Sponsorship
+Support development of Box2D through [Github Sponsors](https://github.com/sponsors/erincatto)
+
+## Ports, wrappers, and Bindings
+- https://github.com/odin-lang/Odin/tree/master/vendor/box2d
+- https://github.com/EnokViking/Box2DBeef
+- https://github.com/HolyBlackCat/box2cpp

+ 1510 - 0
vendor/box2d/box2d.odin

@@ -0,0 +1,1510 @@
+package vendor_box2d
+
+import "base:intrinsics"
+import "core:c"
+
+@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
+
+when ODIN_OS == .Windows {
+	@(private) LIB_PATH :: "lib/box2d_windows_amd64_" + VECTOR_EXT + ".lib"
+} else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
+	@(private) LIB_PATH :: "lib/box2d_darwin_arm64.a"
+} else when ODIN_OS == .Darwin {
+	@(private) LIB_PATH :: "lib/box2d_darwin_amd64_" + VECTOR_EXT + ".a"
+} else when ODIN_ARCH == .amd64 {
+	@(private) LIB_PATH :: "lib/box2d_other_amd64_" + VECTOR_EXT + ".a"
+} else {
+	@(private) LIB_PATH :: "lib/box2d_other.a"
+}
+
+when !#exists(LIB_PATH) {
+	#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
+}
+
+foreign import lib {
+	LIB_PATH,
+}
+
+
+// Prototype for user allocation function
+//	@param size the allocation size in bytes
+//	@param alignment the required alignment, guaranteed to be a power of 2
+AllocFcn :: #type proc "c" (size: u32, alignment: i32) -> rawptr
+
+// Prototype for user free function
+//	@param mem the memory previously allocated through `b2AllocFcn`
+FreeFcn :: #type proc "c" (mem: rawptr)
+
+// Prototype for the user assert callback. Return 0 to skip the debugger break.
+AssertFcn :: #type proc "c" (condition, file_name: cstring, line_number: i32) -> i32
+
+// Version numbering scheme.
+//
+// See https://semver.org/
+Version :: struct {
+	major:    i32, // Significant changes
+	minor:    i32, // Incremental changes
+	revision: i32, // Bug fixes
+}
+
+when ODIN_OS == .Windows {
+	// Timer for profiling. This has platform specific code and may
+	// not work on every platform.
+	Timer :: struct {
+		start: i64,
+	}
+} else when ODIN_OS == .Linux || ODIN_OS == .Darwin {
+	// Timer for profiling. This has platform specific code and may
+	// not work on every platform.
+	Timer :: struct {
+		start_sec:  u64,
+		start_usec: u64,
+	}
+} else {
+	// Timer for profiling. This has platform specific code and may
+	// not work on every platform.
+	Timer :: struct {
+		dummy: i32,
+	}
+}
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// This allows the user to override the allocation functions. These should be
+	//	set during application startup.
+	SetAllocator :: proc(allocFcn: AllocFcn, freefcn: FreeFcn) ---
+	// @return the total bytes allocated by Box2D
+	GetByteCount :: proc() -> c.int ---
+	// Override the default assert callback
+	//	@param assertFcn a non-null assert callback
+	SetAssertFcn :: proc(assertfcn: AssertFcn) ---
+
+
+	CreateTimer             :: proc() -> Timer ---
+	GetTicks                :: proc(timer: ^Timer) -> i64 ---
+	GetMilliseconds         :: proc(#by_ptr timer: Timer) -> f32 ---
+	GetMillisecondsAndReset :: proc(timer: ^Timer) -> f32 ---
+	SleepMilliseconds       :: proc(milliseconds: c.int)  ---
+	Yield                   :: proc() ---
+
+
+	// Box2D bases all length units on meters, but you may need different units for your game.
+	// You can set this value to use different units. This should be done at application startup
+	//	and only modified once. Default value is 1.
+	//	@warning This must be modified before any calls to Box2D
+	SetLengthUnitsPerMeter :: proc(lengthUnits: f32) ---
+
+	// Get the current length units per meter.
+	GetLengthUnitsPerMeter :: proc() -> f32 ---
+}
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Use this to initialize your world definition
+	// @ingroup world
+	DefaultWorldDef          :: proc() -> WorldDef ---
+
+	// Use this to initialize your body definition
+	// @ingroup body
+	DefaultBodyDef           :: proc() -> BodyDef ---
+
+	// Use this to initialize your filter
+	// @ingroup shape
+	DefaultFilter            :: proc() -> Filter ---
+
+	// Use this to initialize your query filter
+	// @ingroup shape
+	DefaultQueryFilter       :: proc() -> QueryFilter ---
+
+	// Use this to initialize your shape definition
+	// @ingroup shape
+	DefaultShapeDef          :: proc() -> ShapeDef ---
+
+	// Use this to initialize your chain definition
+	// @ingroup shape
+	DefaultChainDef          :: proc() -> ChainDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroup distance_joint
+	DefaultDistanceJointDef  :: proc() -> DistanceJointDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroup motor_joint
+	DefaultMotorJointDef     :: proc() -> MotorJointDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroup mouse_joint
+	DefaultMouseJointDef     :: proc() -> MouseJointDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroupd prismatic_joint
+	DefaultPrismaticJointDef :: proc() -> PrismaticJointDef ---
+
+	// Use this to initialize your joint definition.
+	// @ingroup revolute_joint
+	DefaultRevoluteJointDef  :: proc() -> RevoluteJointDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroup weld_joint
+	DefaultWeldJointDef      :: proc() -> WeldJointDef ---
+
+	// Use this to initialize your joint definition
+	// @ingroup wheel_joint
+	DefaultWheelJointDef     :: proc() -> WheelJointDef ---
+}
+
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Validate ray cast input data (NaN, etc)
+	IsValidRay         :: proc(#by_ptr input: RayCastInput) -> bool ---
+
+	// Make a convex polygon from a convex hull. This will assert if the hull is not valid.
+	// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull
+	MakePolygon        :: proc(#by_ptr hull: Hull, radius: f32) -> Polygon ---
+
+	// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid.
+	// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull
+	MakeOffsetPolygon  :: proc(#by_ptr hull: Hull, radius: f32, transform: Transform) -> Polygon ---
+
+	// Make a square polygon, bypassing the need for a convex hull.
+	MakeSquare         :: proc(h: f32) -> Polygon ---
+
+	// Make a box (rectangle) polygon, bypassing the need for a convex hull.
+	MakeBox            :: proc(hx, hy: f32) -> Polygon ---
+
+	// Make a rounded box, bypassing the need for a convex hull.
+	MakeRoundedBox     :: proc(hx, hy: f32, radius: f32) -> Polygon ---
+
+	// Make an offset box, bypassing the need for a convex hull.
+	MakeOffsetBox      :: proc(hx, hy: f32, center: Vec2, angle: f32) -> Polygon ---
+
+	// Transform a polygon. This is useful for transferring a shape from one body to another.
+	TransformPolygon   :: proc(transform: Transform, #by_ptr polygon: Polygon) -> Polygon ---
+
+	// Compute mass properties of a circle
+	ComputeCircleMass  :: proc(#by_ptr shape: Circle, density: f32) -> MassData ---
+
+	// Compute mass properties of a capsule
+	ComputeCapsuleMass :: proc(#by_ptr shape: Capsule, density: f32) -> MassData ---
+
+	// Compute mass properties of a polygon
+	ComputePolygonMass :: proc(#by_ptr shape: Polygon, density: f32) -> MassData ---
+
+	// Compute the bounding box of a transformed circle
+	ComputeCircleAABB  :: proc(#by_ptr shape: Circle, transform: Transform) -> AABB ---
+
+	// Compute the bounding box of a transformed capsule
+	ComputeCapsuleAABB :: proc(#by_ptr shape: Capsule, transform: Transform) -> AABB ---
+
+	// Compute the bounding box of a transformed polygon
+	ComputePolygonAABB :: proc(#by_ptr shape: Polygon, transform: Transform) -> AABB ---
+
+	// Compute the bounding box of a transformed line segment
+	ComputeSegmentAABB :: proc(#by_ptr shape: Segment, transform: Transform) -> AABB ---
+
+	// Test a point for overlap with a circle in local space
+	PointInCircle      :: proc(point: Vec2, #by_ptr shape: Circle) -> bool ---
+
+	// Test a point for overlap with a capsule in local space
+	PointInCapsule     :: proc(point: Vec2, #by_ptr shape: Capsule) -> bool ---
+
+	// Test a point for overlap with a convex polygon in local space
+	PointInPolygon     :: proc(point: Vec2, #by_ptr shape: Polygon) -> bool ---
+
+	// Ray cast versus circle in shape local space. Initial overlap is treated as a miss.
+	RayCastCircle      :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Circle) -> CastOutput ---
+
+	// Ray cast versus capsule in shape local space. Initial overlap is treated as a miss.
+	RayCastCapsule     :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Capsule) -> CastOutput ---
+
+	// Ray cast versus segment in shape local space. Optionally treat the segment as one-sided with hits from
+	// the left side being treated as a miss.
+	RayCastSegment     :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Segment, oneSided: bool) -> CastOutput ---
+
+	// Ray cast versus polygon in shape local space. Initial overlap is treated as a miss.
+	RayCastPolygon     :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Polygon) -> CastOutput ---
+
+	// Shape cast versus a circle. Initial overlap is treated as a miss.
+	ShapeCastCircle    :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Circle) -> CastOutput ---
+
+	// Shape cast versus a capsule. Initial overlap is treated as a miss.
+	ShapeCastCapsule   :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Capsule) -> CastOutput ---
+
+	// Shape cast versus a line segment. Initial overlap is treated as a miss.
+	ShapeCastSegment   :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Segment) -> CastOutput ---
+
+	// Shape cast versus a convex polygon. Initial overlap is treated as a miss.
+	ShapeCastPolygon   :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Polygon) -> CastOutput ---
+}
+
+
+// Compute the convex hull of a set of points. Returns an empty hull if it fails.
+// Some failure cases:
+// - all points very close together
+// - all points on a line
+// - less than 3 points
+// - more than maxPolygonVertices points
+// This welds close points and removes collinear points.
+//	@warning Do not modify a hull once it has been computed
+ComputeHull :: proc "c" (points: []Vec2) -> Hull {
+	foreign lib {
+		b2ComputeHull :: proc "c" (points: [^]Vec2, count: i32) -> Hull ---
+	}
+	return b2ComputeHull(raw_data(points), i32(len(points)))
+}
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// This determines if a hull is valid. Checks for:
+	// - convexity
+	// - collinear points
+	// This is expensive and should not be called at runtime.
+	ValidateHull :: proc(#by_ptr hull: Hull) -> bool ---
+}
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Compute the distance between two line segments, clamping at the end points if needed.
+	SegmentDistance :: proc(p1, q1: Vec2, p2, q2: Vec2) -> SegmentDistanceResult ---
+}
+
+// Compute the closest points between two shapes represented as point clouds.
+// DistanceCache cache is input/output. On the first call set DistanceCache.count to zero.
+//	The underlying GJK algorithm may be debugged by passing in debug simplexes and capacity. You may pass in NULL and 0 for these.
+ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: []Simplex) -> DistanceOutput {
+	foreign lib {
+		b2ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: [^]Simplex, simplexCapacity: c.int) -> DistanceOutput ---
+	}
+	return b2ShapeDistance(cache, input, raw_data(simplexes), i32(len(simplexes)))
+}
+
+
+// Make a proxy for use in GJK and related functions.
+MakeProxy :: proc "c" (vertices: []Vec2, radius: f32) -> DistanceProxy {
+	foreign lib {
+		b2MakeProxy :: proc "c" (vertices: [^]Vec2, count: i32, radius: f32) -> DistanceProxy ---
+	}
+	return b2MakeProxy(raw_data(vertices), i32(len(vertices)), radius)
+}
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction.
+	ShapeCast :: proc(#by_ptr input: ShapeCastPairInput) -> CastOutput ---
+
+	// Evaluate the transform sweep at a specific time.
+	GetSweepTransform :: proc(#by_ptr sweep: Sweep, time: f32) -> Transform ---
+
+	// Compute the upper bound on time before two shapes penetrate. Time is represented as
+	// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
+	// non-tunneling collisions. If you change the time interval, you should call this function
+	// again.
+	TimeOfImpact :: proc(#by_ptr input: TOIInput) -> TOIOutput ---
+}
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Compute the contact manifold between two circles
+	CollideCircles                 :: proc(#by_ptr circleA: Circle, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between a capsule and circle
+	CollideCapsuleAndCircle        :: proc(#by_ptr capsuleA: Capsule, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between an segment and a circle
+	CollideSegmentAndCircle        :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between a polygon and a circle
+	CollidePolygonAndCircle        :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between a capsule and circle
+	CollideCapsules                :: proc(#by_ptr capsuleA: Capsule, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between an segment and a capsule
+	CollideSegmentAndCapsule       :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between a polygon and capsule
+	CollidePolygonAndCapsule       :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between two polygons
+	CollidePolygons                :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between an segment and a polygon
+	CollideSegmentAndPolygon       :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between a smooth segment and a circle
+	CollideSmoothSegmentAndCircle  :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
+
+	// Compute the contact manifold between an segment and a capsule
+	CollideSmoothSegmentAndCapsule :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform, cache: ^DistanceCache) -> Manifold ---
+
+	// Compute the contact manifold between a smooth segment and a rounded polygon
+	CollideSmoothSegmentAndPolygon :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform, cache: ^DistanceCache) -> Manifold ---
+}
+
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Constructing the tree initializes the node pool.
+	DynamicTree_Create          :: proc() -> DynamicTree ---
+
+	// Destroy the tree, freeing the node pool.
+	DynamicTree_Destroy         :: proc(tree: ^DynamicTree) ---
+
+	// Create a proxy. Provide an AABB and a userData value.
+	DynamicTree_CreateProxy     :: proc(tree: ^DynamicTree, aabb: AABB, categoryBits: u32, userData: i32) -> i32 ---
+
+	// Destroy a proxy. This asserts if the id is invalid.
+	DynamicTree_DestroyProxy    :: proc(tree: ^DynamicTree, proxyId: i32) ---
+
+	// Move a proxy to a new AABB by removing and reinserting into the tree.
+	DynamicTree_MoveProxy       :: proc(tree: ^DynamicTree, proxyId: i32, aabb: AABB) ---
+
+	// Enlarge a proxy and enlarge ancestors as necessary.
+	DynamicTree_EnlargeProxy    :: proc(tree: ^DynamicTree, proxyId: i32, aabb: AABB) ---
+
+	// Query an AABB for overlapping proxies. The callback class
+	// is called for each proxy that overlaps the supplied AABB.
+	DynamicTree_Query           :: proc(#by_ptr tree: DynamicTree, aabb: AABB, maskBits: u32, callback: TreeQueryCallbackFcn, ctx: rawptr) ---
+
+	// Ray-cast against the proxies in the tree. This relies on the callback
+	// to perform a exact ray-cast in the case were the proxy contains a shape.
+	// The callback also performs the any collision filtering. This has performance
+	// roughly equal to k * log(n), where k is the number of collisions and n is the
+	// number of proxies in the tree.
+	//	Bit-wise filtering using mask bits can greatly improve performance in some scenarios.
+	//	@param tree the dynamic tree to ray cast
+	// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1)
+	//	@param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0 ---`
+	// @param callback a callback class that is called for each proxy that is hit by the ray
+	//	@param context user context that is passed to the callback
+	DynamicTree_RayCast         :: proc(#by_ptr tree: DynamicTree, #by_ptr input: RayCastInput, maskBits: u32, callback: TreeRayCastCallbackFcn, ctx: rawptr) ---
+
+	// Ray-cast against the proxies in the tree. This relies on the callback
+	// to perform a exact ray-cast in the case were the proxy contains a shape.
+	// The callback also performs the any collision filtering. This has performance
+	// roughly equal to k * log(n), where k is the number of collisions and n is the
+	// number of proxies in the tree.
+	//	@param tree the dynamic tree to ray cast
+	// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+	//	@param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0 ---`
+	// @param callback a callback class that is called for each proxy that is hit by the shape
+	//	@param context user context that is passed to the callback
+	DynamicTree_ShapeCast       :: proc(#by_ptr tree: DynamicTree, #by_ptr input: ShapeCastInput, maskBits: u32, callback: TreeShapeCastCallbackFcn, ctx: rawptr) ---
+
+	// Validate this tree. For testing.
+	DynamicTree_Validate        :: proc(#by_ptr tree: DynamicTree) ---
+
+	// Compute the height of the binary tree in O(N) time. Should not be
+	// called often.
+	DynamicTree_GetHeight       :: proc(#by_ptr tree: DynamicTree) -> c.int ---
+
+	// Get the maximum balance of the tree. The balance is the difference in height of the two children of a node.
+	DynamicTree_GetMaxBalance   :: proc(#by_ptr tree: DynamicTree) -> c.int ---
+
+	// Get the ratio of the sum of the node areas to the root area.
+	DynamicTree_GetAreaRatio    :: proc(#by_ptr tree: DynamicTree) -> f32 ---
+
+	// Build an optimal tree. Very expensive. For testing.
+	DynamicTree_RebuildBottomUp :: proc(tree: ^DynamicTree) ---
+
+	// Get the number of proxies created
+	DynamicTree_GetProxyCount   :: proc(#by_ptr tree: DynamicTree) -> c.int ---
+
+	// Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted.
+	DynamicTree_Rebuild         :: proc(tree: ^DynamicTree, fullBuild: bool) -> c.int ---
+
+	// Shift the world origin. Useful for large worlds.
+	// The shift formula is: position -= newOrigin
+	// @param tree the tree to shift
+	// @param newOrigin the new origin with respect to the old origin
+	DynamicTree_ShiftOrigin     :: proc(tree: ^DynamicTree, newOrigin: Vec2) ---
+
+	// Get the number of bytes used by this tree
+	DynamicTree_GetByteCount    :: proc(#by_ptr tree: DynamicTree) -> c.int ---
+}
+
+// Get proxy user data
+// @return the proxy user data or 0 if the id is invalid
+DynamicTree_GetUserData :: #force_inline proc "contextless" (tree: DynamicTree, proxyId: i32) -> i32 {
+	return tree.nodes[proxyId].userData
+}
+
+// Get the AABB of a proxy
+DynamicTree_GetAABB :: #force_inline proc "contextless" (tree: DynamicTree, proxyId: i32) -> AABB {
+	return tree.nodes[proxyId].aabb
+}
+
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	/**
+	 * @defgroup world World
+	 * These functions allow you to create a simulation world.
+	 *
+	 * You can add rigid bodies and joint constraints to the world and run the simulation. You can get contact
+	 * information to get contact points and normals as well as events. You can query to world, checking for overlaps and casting rays
+	 * or shapes. There is also debugging information such as debug draw, timing information, and counters. You can find documentation
+	 * here: https://box2d.org/
+	 */
+
+	// Create a world for rigid body simulation. A world contains bodies, shapes, and constraints. You make create
+	//	up to 128 worlds. Each world is completely independent and may be simulated in parallel.
+	//	@return the world id.
+	CreateWorld                   :: proc(#by_ptr def: WorldDef) -> WorldId ---
+
+	// Destroy a world
+	DestroyWorld                  :: proc(worldId: WorldId) ---
+
+	// World id validation. Provides validation for up to 64K allocations.
+	World_IsValid                 :: proc(id: WorldId) -> bool ---
+
+	// Simulate a world for one time step. This performs collision detection, integration, and constraint solution.
+	// @param worldId The world to simulate
+	// @param timeStep The amount of time to simulate, this should be a fixed number. Typically 1/60.
+	// @param subStepCount The number of sub-steps, increasing the sub-step count can increase accuracy. Typically 4.
+	World_Step                    :: proc(worldId: WorldId, timeStep: f32 , subStepCount: c.int) ---
+
+	// Call this to draw shapes and other debug draw data
+	World_Draw                    :: proc(worldId: WorldId, draw: DebugDraw) ---
+
+	// Get the body events for the current time step. The event data is transient. Do not store a reference to this data.
+	World_GetBodyEvents           :: proc(worldId: WorldId) -> BodyEvents ---
+
+	// Get sensor events for the current time step. The event data is transient. Do not store a reference to this data.
+	World_GetSensorEvents         :: proc(worldId: WorldId) -> SensorEvents ---
+
+	// Get contact events for this current time step. The event data is transient. Do not store a reference to this data.
+	World_GetContactEvents        :: proc(worldId: WorldId) -> ContactEvents ---
+
+	// Overlap test for all shapes that *potentially* overlap the provided AABB
+	World_OverlapAABB             :: proc(worldId: WorldId, aabb: AABB, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) ---
+
+	// Overlap test for for all shapes that overlap the provided circle
+	World_OverlapCircle           :: proc(worldId: WorldId, #by_ptr circle: Circle, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) ---
+
+	// Overlap test for all shapes that overlap the provided capsule
+	World_OverlapCapsule          :: proc(worldId: WorldId, #by_ptr capsule: Capsule, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) ---
+
+	// Overlap test for all shapes that overlap the provided polygon
+	World_OverlapPolygon          :: proc(worldId: WorldId, #by_ptr polygon: Polygon, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) ---
+
+	// 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.
+	//	@param worldId The world to cast the ray against
+	//	@param origin The start point of the ray
+	//	@param translation The translation of the ray from the start point to the end point
+	//	@param filter Contains bit flags to filter unwanted shapes from the results
+	// @param fcn A user implemented callback function
+	// @param context A user context that is passed along to the callback function
+	//	@note The callback function may receive shapes in any order
+	World_CastRay                 :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) ---
+
+	// Cast a ray into the world to collect the closest hit. This is a convenience function.
+	// 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 ---
+
+	// Cast a circle through the world. Similar to a cast ray except that a circle is cast instead of a point.
+	World_CastCircle              :: proc(worldId: WorldId, #by_ptr circle: Circle, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) ---
+
+	// Cast a capsule through the world. Similar to a cast ray except that a capsule is cast instead of a point.
+	World_CastCapsule             :: proc(worldId: WorldId, #by_ptr capsule: Capsule, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) ---
+
+	// Cast a polygon through the world. Similar to a cast ray except that a polygon is cast instead of a point.
+	World_CastPolygon             :: proc(worldId: WorldId, #by_ptr polygon: Polygon, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) ---
+
+	// Enable/disable sleep. If your application does not need sleeping, you can gain some performance
+	//	by disabling sleep completely at the world level.
+	//	@see WorldDef
+	World_EnableSleeping          :: proc(worldId: WorldId, flag: bool) ---
+
+	// Enable/disable continuous collision between dynamic and static bodies. Generally you should keep continuous
+	// collision enabled to prevent fast moving objects from going through static objects. The performance gain from
+	//	disabling continuous collision is minor.
+	//	@see WorldDef
+	World_EnableContinuous        :: proc(worldId: WorldId, flag: bool) ---
+
+	// Adjust the restitution threshold. It is recommended not to make this value very small
+	//	because it will prevent bodies from sleeping. Typically in meters per second.
+	//	@see WorldDef
+	World_SetRestitutionThreshold :: proc(worldId: WorldId, value: f32) ---
+
+	// Adjust the hit event threshold. This controls the collision velocity needed to generate a b2ContactHitEvent.
+	// Typically in meters per second.
+	//	@see WorldDef::hitEventThreshold
+	World_SetHitEventThreshold    :: proc(worldId: WorldId, value: f32) ---
+
+	// Register the custom filter callback. This is optional.
+	World_SetCustomFilterCallback :: proc(worldId: WorldId, fcn: CustomFilterFcn, ctx: rawptr) ---
+
+	// Register the pre-solve callback. This is optional.
+	World_SetPreSolveCallback     :: proc(worldId: WorldId, fcn: PreSolveFcn, ctx: rawptr) ---
+
+	// Set the gravity vector for the entire world. Box2D has no concept of an up direction and this
+	// is left as a decision for the application. Typically in m/s^2.
+	//	@see WorldDef
+	World_SetGravity              :: proc(worldId: WorldId, gravity: Vec2) ---
+
+	// Get the gravity vector
+	World_GetGravity              :: proc(worldId: WorldId) -> Vec2 ---
+
+	// Apply a radial explosion
+	//	@param worldId The world id
+	//	@param position The center of the explosion
+	//	@param radius The radius of the explosion
+	//	@param impulse The impulse of the explosion, typically in kg * m / s or N * s.
+	World_Explode                 :: proc(worldId: WorldId, position: Vec2, radius: f32, impulse: f32) ---
+
+	// Adjust contact 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)
+	// @param pushVelocity The maximum contact constraint push out velocity (meters per second)
+	//	@note Advanced feature
+	World_SetContactTuning        :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, pushVelocity: f32) ---
+
+	// Enable/disable constraint warm starting. Advanced feature for testing. Disabling
+	//	sleeping greatly reduces stability and provides no performance gain.
+	World_EnableWarmStarting      :: proc(worldId: WorldId, flag: bool) ---
+
+	// Get the current world performance profile
+	World_GetProfile              :: proc(worldId: WorldId) -> Profile ---
+
+	// Get world counters and sizes
+	World_GetCounters             :: proc(worldId: WorldId) -> Counters ---
+
+	// Dump memory stats to box2d_memory.txt
+	World_DumpMemoryStats         :: proc(worldId: WorldId) ---
+}
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	/**
+	 * @defgroup body Body
+	 * This is the body API.
+	 */
+
+	// Create a rigid body given a definition. No reference to the definition is retained. So you can create the definition
+	//	on the stack and pass it as a pointer.
+	//	@code{.odin}
+	//	body_def := b2.DefaultBodyDef()
+	//	my_body_id =: b2.CreateBody(my_world_id, body_def)
+	//	@endcode
+	// @warning This function is locked during callbacks.
+	CreateBody                      :: proc(worldId: WorldId, #by_ptr def: BodyDef) -> BodyId ---
+
+	// Destroy a rigid body given an id. This destroys all shapes and joints attached to the body.
+	//	Do not keep references to the associated shapes and joints.
+	DestroyBody                     :: proc(bodyId: BodyId) ---
+
+	// Body identifier validation. Can be used to detect orphaned ids. Provides validation for up to 64K allocations.
+	Body_IsValid                    :: proc(id: BodyId) -> bool ---
+
+	// Get the body type: static, kinematic, or dynamic
+	Body_GetType                    :: proc(bodyId: BodyId) -> BodyType ---
+
+	// Change the body type. This is an expensive operation. This automatically updates the mass
+	//	properties regardless of the automatic mass setting.
+	Body_SetType                    :: proc(bodyId: BodyId, type: BodyType) ---
+
+	// Set the user data for a body
+	Body_SetUserData                :: proc(bodyId: BodyId, userData: rawptr) ---
+
+	// Get the user data stored in a body
+	Body_GetUserData                :: proc(bodyId: BodyId) -> rawptr ---
+
+	// Get the world position of a body. This is the location of the body origin.
+	Body_GetPosition                :: proc(bodyId: BodyId) -> Vec2 ---
+
+	// Get the world rotation of a body as a cosine/sine pair (complex number)
+	Body_GetRotation                :: proc(bodyId: BodyId) -> Rot ---
+
+	// Get the world transform of a body.
+	Body_GetTransform               :: proc(bodyId: BodyId) -> Transform ---
+
+	// Set the world transform of a body. This acts as a teleport and is fairly expensive.
+	// @note Generally you should create a body with then intended transform.
+	//	@see BodyDef::position and BodyDef::angle
+	Body_SetTransform               :: proc(bodyId: BodyId, position: Vec2, rotation: Rot) ---
+
+	// Get a local point on a body given a world point
+	Body_GetLocalPoint              :: proc(bodyId: BodyId, worldPoint: Vec2) -> Vec2 ---
+
+	// Get a world point on a body given a local point
+	Body_GetWorldPoint              :: proc(bodyId: BodyId, localPoint: Vec2) -> Vec2 ---
+
+	// Get a local vector on a body given a world vector
+	Body_GetLocalVector             :: proc(bodyId: BodyId, worldVector: Vec2) -> Vec2 ---
+
+	// Get a world vector on a body given a local vector
+	Body_GetWorldVector             :: proc(bodyId: BodyId, localVector: Vec2) -> Vec2 ---
+
+	// Get the linear velocity of a body's center of mass. Typically in meters per second.
+	Body_GetLinearVelocity          :: proc(bodyId: BodyId) -> Vec2 ---
+
+	// Get the angular velocity of a body in radians per second
+	Body_GetAngularVelocity         :: proc(bodyId: BodyId) -> f32 ---
+
+	// Set the linear velocity of a body. Typically in meters per second.
+	Body_SetLinearVelocity          :: proc(bodyId: BodyId, linearVelocity: Vec2) ---
+
+	// Set the angular velocity of a body in radians per second
+	Body_SetAngularVelocity         :: proc(bodyId: BodyId, angularVelocity: f32) ---
+
+	// Apply a force at a world point. If the force is not applied at the center of mass,
+	// it will generate a torque and affect the angular velocity. This optionally wakes up the body.
+	//	The force is ignored if the body is not awake.
+	//	@param bodyId The body id
+	// @param force The world force vector, typically in newtons (N)
+	// @param point The world position of the point of application
+	// @param wake Option to wake up the body
+	Body_ApplyForce                 :: proc(bodyId: BodyId, force: Vec2, point: Vec2, wake: bool) ---
+
+	// Apply a force to the center of mass. This optionally wakes up the body.
+	//	The force is ignored if the body is not awake.
+	//	@param bodyId The body id
+	// @param force the world force vector, usually in newtons (N).
+	// @param wake also wake up the body
+	Body_ApplyForceToCenter         :: proc(bodyId: BodyId, force: Vec2, wake: bool) ---
+
+	// Apply a torque. This affects the angular velocity without affecting the linear velocity.
+	//	This optionally wakes the body. The torque is ignored if the body is not awake.
+	//	@param bodyId The body id
+	// @param torque about the z-axis (out of the screen), typically in N*m.
+	// @param wake also wake up the body
+	Body_ApplyTorque                :: proc(bodyId: BodyId, torque: f32, wake: bool) ---
+
+	// Apply an impulse at a point. This immediately modifies the velocity.
+	// It also modifies the angular velocity if the point of application
+	// is not at the center of mass. This optionally wakes the body.
+	// The impulse is ignored if the body is not awake.
+	//	@param bodyId The body id
+	// @param impulse the world impulse vector, typically in N*s or kg*m/s.
+	// @param point the world position of the point of application.
+	// @param wake also wake up the body
+	//	@warning This should be used for one-shot impulses. If you need a steady force,
+	// use a force instead, which will work better with the sub-stepping solver.
+	Body_ApplyLinearImpulse         :: proc(bodyId: BodyId, impulse: Vec2, point: Vec2, wake: bool) ---
+
+	// Apply an impulse to the center of mass. This immediately modifies the velocity.
+	// The impulse is ignored if the body is not awake. This optionally wakes the body.
+	//	@param bodyId The body id
+	// @param impulse the world impulse vector, typically in N*s or kg*m/s.
+	// @param wake also wake up the body
+	//	@warning This should be used for one-shot impulses. If you need a steady force,
+	// use a force instead, which will work better with the sub-stepping solver.
+	Body_ApplyLinearImpulseToCenter :: proc(bodyId: BodyId, impulse: Vec2, wake: bool) ---
+
+	// Apply an angular impulse. The impulse is ignored if the body is not awake.
+	// This optionally wakes the body.
+	//	@param bodyId The body id
+	// @param impulse the angular impulse, typically in units of kg*m*m/s
+	// @param wake also wake up the body
+	//	@warning This should be used for one-shot impulses. If you need a steady force,
+	// use a force instead, which will work better with the sub-stepping solver.
+	Body_ApplyAngularImpulse        :: proc(bodyId: BodyId, impulse: f32, wake: bool) ---
+
+	// Get the mass of the body, typically in kilograms
+	Body_GetMass                    :: proc(bodyId: BodyId) -> f32 ---
+
+	// Get the inertia tensor of the body, typically in kg*m^2
+	Body_GetInertiaTensor           :: proc(bodyId: BodyId) -> f32 ---
+
+	// Get the center of mass position of the body in local space
+	Body_GetLocalCenterOfMass       :: proc(bodyId: BodyId) -> Vec2 ---
+
+	// Get the center of mass position of the body in world space
+	Body_GetWorldCenterOfMass       :: proc(bodyId: BodyId) -> Vec2 ---
+
+	// Override the body's mass properties. Normally this is computed automatically using the
+	//	shape geometry and density. This information is lost if a shape is added or removed or if the
+	//	body type changes.
+	Body_SetMassData                :: proc(bodyId: BodyId, massData: MassData) ---
+
+	// Get the mass data for a body
+	Body_GetMassData                :: proc(bodyId: BodyId) -> MassData ---
+
+	// This update the mass properties to the sum of the mass properties of the shapes.
+	// This normally does not need to be called unless you called SetMassData to override
+	// the mass and you later want to reset the mass.
+	//	You may also use this when automatic mass computation has been disabled.
+	//	You should call this regardless of body type.
+	Body_ApplyMassFromShapes        :: proc(bodyId: BodyId) ---
+
+	// Set the automatic mass setting. Normally this is set in BodyDef before creation.
+	//	@see BodyDef::automaticMass
+	Body_SetAutomaticMass           :: proc(bodyId: BodyId, automaticMass: bool ) ---
+
+	// Get the automatic mass setting
+	Body_GetAutomaticMass           :: proc(bodyId: BodyId) -> bool ---
+
+	// Adjust the linear damping. Normally this is set in BodyDef before creation.
+	Body_SetLinearDamping           :: proc(bodyId: BodyId, linearDamping: f32) ---
+
+	// Get the current linear damping.
+	Body_GetLinearDamping           :: proc(bodyId: BodyId) -> f32 ---
+
+	// Adjust the angular damping. Normally this is set in BodyDef before creation.
+	Body_SetAngularDamping          :: proc(bodyId: BodyId, angularDamping: f32) ---
+
+	// Get the current angular damping.
+	Body_GetAngularDamping          :: proc(bodyId: BodyId) -> f32 ---
+
+	// Adjust the gravity scale. Normally this is set in BodyDef before creation.
+	//	@see BodyDef::gravityScale
+	Body_SetGravityScale            :: proc(bodyId: BodyId, gravityScale: f32) ---
+
+	// Get the current gravity scale
+	Body_GetGravityScale            :: proc(bodyId: BodyId) -> f32 ---
+
+	// @return true if this body is awake
+	Body_IsAwake                    :: proc(bodyId: BodyId) -> bool ---
+
+	// Wake a body from sleep. This wakes the entire island the body is touching.
+	//	@warning Putting a body to sleep will put the entire island of bodies touching this body to sleep,
+	//	which can be expensive and possibly unintuitive.
+	Body_SetAwake                   :: proc(bodyId: BodyId, awake: bool) ---
+
+	// Enable or disable sleeping for this body. If sleeping is disabled the body will wake.
+	Body_EnableSleep                :: proc(bodyId: BodyId, enableSleep: bool) ---
+
+	// Returns true if sleeping is enabled for this body
+	Body_IsSleepEnabled             :: proc(bodyId: BodyId) -> bool ---
+
+	// Set the sleep threshold, typically in meters per second
+	Body_SetSleepThreshold          :: proc(bodyId: BodyId, sleepVelocity: f32) ---
+
+	// Get the sleep threshold, typically in meters per second.
+	Body_GetSleepThreshold          :: proc(bodyId: BodyId) -> f32 ---
+
+	// Returns true if this body is enabled
+	Body_IsEnabled                  :: proc(bodyId: BodyId) -> bool ---
+
+	// Disable a body by removing it completely from the simulation. This is expensive.
+	Body_Disable                    :: proc(bodyId: BodyId) ---
+
+	// Enable a body by adding it to the simulation. This is expensive.
+	Body_Enable                     :: proc(bodyId: BodyId) ---
+
+	// Set this body to have fixed rotation. This causes the mass to be reset in all cases.
+	Body_SetFixedRotation           :: proc(bodyId: BodyId, flag: bool) ---
+
+	// Does this body have fixed rotation?
+	Body_IsFixedRotation            :: proc(bodyId: BodyId) -> bool ---
+
+	// Set this body to be a bullet. A bullet does continuous collision detection
+	// against dynamic bodies (but not other bullets).
+	Body_SetBullet                  :: proc(bodyId: BodyId, flag: bool) ---
+
+	// Is this body a bullet?
+	Body_IsBullet                   :: proc(bodyId: BodyId) -> bool ---
+
+	// Enable/disable hit events on all shapes
+	//	@see b2ShapeDef::enableHitEvents
+	Body_EnableHitEvents            :: proc(bodyId: BodyId, enableHitEvents: bool) ---
+
+	// Get the number of shapes on this body
+	Body_GetShapeCount              :: proc(bodyId: BodyId) -> c.int ---
+
+	// Get the number of joints on this body
+	Body_GetJointCount              :: proc(bodyId: BodyId) -> c.int ---
+
+	// Get the maximum capacity required for retrieving all the touching contacts on a body
+	Body_GetContactCapacity         :: proc(bodyId: BodyId) -> c.int ---
+
+	// Get the current world AABB that contains all the attached shapes. Note that this may not encompass the body origin.
+	//	If there are no shapes attached then the returned AABB is empty and centered on the body origin.
+	Body_ComputeAABB                :: proc(bodyId: BodyId) -> AABB ---
+}
+
+// Get the shape ids for all shapes on this body, up to the provided capacity.
+//	@returns the number of shape ids stored in the user array
+Body_GetShapes :: proc "c" (bodyId: BodyId, shapeArray: []ShapeId) -> c.int {
+	foreign lib {
+		b2Body_GetShapes :: proc "c" (bodyId: BodyId, shapeArray: [^]ShapeId, capacity: c.int) -> c.int ---
+	}
+	return b2Body_GetShapes(bodyId, raw_data(shapeArray), c.int(len(shapeArray)))
+
+}
+
+// Get the joint ids for all joints on this body, up to the provided capacity
+//	@returns the number of joint ids stored in the user array
+Body_GetJoints :: proc "c" (bodyId: BodyId, jointArray: []JointId) -> c.int {
+	foreign lib {
+		b2Body_GetJoints :: proc "c" (bodyId: BodyId, jointArray: [^]JointId, capacity: c.int) -> c.int ---
+	}
+	return b2Body_GetJoints(bodyId, raw_data(jointArray), c.int(len(jointArray)))
+
+}
+
+// Get the touching contact data for a body
+Body_GetContactData :: proc "c" (bodyId: BodyId, contactData: []ContactData) -> c.int {
+	foreign lib {
+		b2Body_GetContactData :: proc "c" (bodyId: BodyId, contactData: [^]ContactData, capacity: c.int) -> c.int ---
+	}
+	return b2Body_GetContactData(bodyId, raw_data(contactData), c.int(len(contactData)))
+
+}
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	/**
+	 * @defgroup shape Shape
+	 * Functions to create, destroy, and access.
+	 * Shapes bind raw geometry to bodies and hold material properties including friction and restitution.
+	 */
+
+	// Create a circle shape and attach it to a body. The shape definition and geometry are fully cloned.
+	// Contacts are not created until the next time step.
+	//	@return the shape id for accessing the shape
+	CreateCircleShape              :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr circle: Circle) -> ShapeId ---
+
+	// Create a line segment shape and attach it to a body. The shape definition and geometry are fully cloned.
+	// Contacts are not created until the next time step.
+	//	@return the shape id for accessing the shape
+	CreateSegmentShape             :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr segment: Segment) -> ShapeId ---
+
+	// Create a capsule shape and attach it to a body. The shape definition and geometry are fully cloned.
+	// Contacts are not created until the next time step.
+	//	@return the shape id for accessing the shape
+	CreateCapsuleShape             :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr capsule: Capsule) -> ShapeId ---
+
+	// Create a polygon shape and attach it to a body. The shape definition and geometry are fully cloned.
+	// Contacts are not created until the next time step.
+	//	@return the shape id for accessing the shape
+	CreatePolygonShape             :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr polygon: Polygon) -> ShapeId ---
+
+	// Destroy a shape
+	DestroyShape                   :: proc(shapeId: ShapeId) ---
+
+	// Shape identifier validation. Provides validation for up to 64K allocations.
+	Shape_IsValid                  :: proc(id: ShapeId) -> bool ---
+
+	// Get the type of a shape
+	Shape_GetType                  :: proc(shapeId: ShapeId) -> ShapeType ---
+
+	// Get the id of the body that a shape is attached to
+	Shape_GetBody                  :: proc(shapeId: ShapeId) -> BodyId ---
+
+	// Returns true If the shape is a sensor
+	Shape_IsSensor                 :: proc(shapeId: ShapeId) -> bool ---
+
+	// Set the user data for a shape
+	Shape_SetUserData              :: proc(shapeId: ShapeId, userData: rawptr) ---
+
+	// Get the user data for a shape. This is useful when you get a shape id
+	//	from an event or query.
+	Shape_GetUserData              :: proc(shapeId: ShapeId) -> rawptr ---
+
+	// Set the mass density of a shape, typically in kg/m^2.
+	//	This will not update the mass properties on the parent body.
+	//	@see b2ShapeDef::density, b2Body_ApplyMassFromShapes
+	Shape_SetDensity               :: proc(shapeId: ShapeId, density: f32) ---
+
+	// Get the density of a shape, typically in kg/m^2
+	Shape_GetDensity               :: proc(shapeId: ShapeId) -> f32 ---
+
+	// Set the friction on a shape
+	//	@see b2ShapeDef::friction
+	Shape_SetFriction              :: proc(shapeId: ShapeId, friction: f32) ---
+
+	// Get the friction of a shape
+	Shape_GetFriction              :: proc(shapeId: ShapeId) -> f32 ---
+
+	// Set the shape restitution (bounciness)
+	//	@see b2ShapeDef::restitution
+	Shape_SetRestitution           :: proc(shapeId: ShapeId, restitution: f32) ---
+
+	// Get the shape restitution
+	Shape_GetRestitution           :: proc(shapeId: ShapeId) -> f32 ---
+
+	// Get the shape filter
+	Shape_GetFilter                :: proc(shapeId: ShapeId) -> Filter ---
+
+	// Set the current filter. This is almost as expensive as recreating the shape.
+	//	@see b2ShapeDef::filter
+	Shape_SetFilter                :: proc(shapeId: ShapeId, filter: Filter) ---
+
+	// Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	//	@see b2ShapeDef::isSensor
+	Shape_EnableSensorEvents       :: proc(shapeId: ShapeId, flag: bool) ---
+
+	// Returns true if sensor events are enabled
+	Shape_AreSensorEventsEnabled   :: proc(shapeId: ShapeId) -> bool ---
+
+	// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	//	@see b2ShapeDef::enableContactEvents
+	Shape_EnableContactEvents      :: proc(shapeId: ShapeId, flag: bool) ---
+
+	// Returns true if contact events are enabled
+	Shape_AreContactEventsEnabled  :: proc(shapeId: ShapeId) -> bool ---
+
+	// Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive
+	//	and must be carefully handled due to multithreading. Ignored for sensors.
+	//	@see b2PreSolveFcn
+	Shape_EnablePreSolveEvents     :: proc(shapeId: ShapeId, flag: bool) ---
+
+	// Returns true if pre-solve events are enabled
+	Shape_ArePreSolveEventsEnabled :: proc(shapeId: ShapeId) -> bool ---
+
+	// Enable contact hit events for this shape. Ignored for sensors.
+	//	@see WorldDef.hitEventThreshold
+	Shape_EnableHitEvents          :: proc(shapeId: ShapeId, flag: bool) ---
+
+	// Returns true if hit events are enabled
+	Shape_AreHitEventsEnabled      :: proc(shapeId: ShapeId) -> bool ---
+
+	// Test a point for overlap with a shape
+	Shape_TestPoint                :: proc(shapeId: ShapeId, point: Vec2) -> bool ---
+
+	// Ray cast a shape directly
+	Shape_RayCast                  :: proc(shapeId: ShapeId, origin: Vec2, translation: Vec2) -> CastOutput ---
+
+	// Get a copy of the shape's circle. Asserts the type is correct.
+	Shape_GetCircle                :: proc(shapeId: ShapeId) -> Circle ---
+
+	// Get a copy of the shape's line segment. Asserts the type is correct.
+	Shape_GetSegment               :: proc(shapeId: ShapeId) -> Segment ---
+
+	// Get a copy of the shape's smooth line segment. These come from chain shapes.
+	// Asserts the type is correct.
+	Shape_GetSmoothSegment         :: proc(shapeId: ShapeId) -> SmoothSegment ---
+
+	// Get a copy of the shape's capsule. Asserts the type is correct.
+	Shape_GetCapsule               :: proc(shapeId: ShapeId) -> Capsule ---
+
+	// Get a copy of the shape's convex polygon. Asserts the type is correct.
+	Shape_GetPolygon               :: proc(shapeId: ShapeId) -> Polygon ---
+
+	// Allows you to change a shape to be a circle or update the current circle.
+	// This does not modify the mass properties.
+	//	@see b2Body_ApplyMassFromShapes
+	Shape_SetCircle                :: proc(shapeId: ShapeId, #by_ptr circle: Circle) ---
+
+	// Allows you to change a shape to be a capsule or update the current capsule.
+	// This does not modify the mass properties.
+	//	@see b2Body_ApplyMassFromShapes
+	Shape_SetCapsule               :: proc(shapeId: ShapeId, #by_ptr capsule: Capsule) ---
+
+	// Allows you to change a shape to be a segment or update the current segment.
+	Shape_SetSegment               :: proc(shapeId: ShapeId, #by_ptr segment: Segment) ---
+
+	// Allows you to change a shape to be a polygon or update the current polygon.
+	// This does not modify the mass properties.
+	//	@see b2Body_ApplyMassFromShapes
+	Shape_SetPolygon               :: proc(shapeId: ShapeId, #by_ptr polygon: Polygon) ---
+
+	// Get the parent chain id if the shape type is b2_smoothSegmentShape, otherwise
+	// returns b2_nullChainId.
+	Shape_GetParentChain           :: proc(shapeId: ShapeId) -> ChainId ---
+
+	// Get the maximum capacity required for retrieving all the touching contacts on a shape
+	Shape_GetContactCapacity       :: proc(shapeId: ShapeId) -> c.int ---
+
+	// Get the current world AABB
+	Shape_GetAABB                  :: proc(shapeId: ShapeId) -> AABB ---
+
+	// Get the closest point on a shape to a target point. Target and result are in world space.
+	Shape_GetClosestPoint          :: proc(shapeId: ShapeId, target: Vec2) -> Vec2 ---
+}
+
+// Get the touching contact data for a shape. The provided shapeId will be either shapeIdA or shapeIdB on the contact data.
+Shape_GetContactData :: proc "c" (shapeId: ShapeId, contactData: []ContactData) -> c.int {
+	foreign lib {
+		b2Shape_GetContactData :: proc "c" (shapeId: ShapeId, contactData: [^]ContactData, capacity: c.int) -> c.int ---
+	}
+	return b2Shape_GetContactData(shapeId, raw_data(contactData), c.int(len(contactData)))
+}
+
+
+@(link_prefix="b2", default_calling_convention="c")
+foreign lib {
+	// Chain Shape
+
+	// Create a chain shape
+	//	@see b2ChainDef for details
+	CreateChain          :: proc(bodyId: BodyId, #by_ptr def: ChainDef) -> ChainId ---
+
+	// Destroy a chain shape
+	DestroyChain         :: proc(chainId: ChainId) ---
+
+	// Set the chain friction
+	// @see b2ChainDef::friction
+	Chain_SetFriction    :: proc(chainId: ChainId, friction: f32) ---
+
+	// Set the chain restitution (bounciness)
+	// @see b2ChainDef::restitution
+	Chain_SetRestitution :: proc(chainId: ChainId, restitution: f32) ---
+
+	// Chain identifier validation. Provides validation for up to 64K allocations.
+	Chain_IsValid        :: proc(id: ChainId) -> bool ---
+
+	/**
+	 * @defgroup joint Joint
+	 * @brief Joints allow you to connect rigid bodies together while allowing various forms of relative motions.
+	 */
+
+	// Destroy a joint
+	DestroyJoint              :: proc(jointId: JointId) ---
+
+	// Joint identifier validation. Provides validation for up to 64K allocations.
+	Joint_IsValid             :: proc(id: JointId) -> bool ---
+
+	// Get the joint type
+	Joint_GetType             :: proc(jointId: JointId) -> JointType ---
+
+	// Get body A id on a joint
+	Joint_GetBodyA            :: proc(jointId: JointId) -> BodyId ---
+
+	// Get body B id on a joint
+	Joint_GetBodyB            :: proc(jointId: JointId) -> BodyId ---
+
+	// Get the local anchor on bodyA
+	Joint_GetLocalAnchorA     :: proc(jointId: JointId) -> Vec2 ---
+
+	// Get the local anchor on bodyB
+	Joint_GetLocalAnchorB     :: proc(jointId: JointId) -> Vec2 ---
+
+	// Toggle collision between connected bodies
+	Joint_SetCollideConnected :: proc(jointId: JointId, shouldCollide: bool) ---
+
+	// Is collision allowed between connected bodies?
+	Joint_GetCollideConnected :: proc(jointId: JointId) -> bool ---
+
+	// Set the user data on a joint
+	Joint_SetUserData         :: proc(jointId: JointId, userData: rawptr) ---
+
+	// Get the user data on a joint
+	Joint_GetUserData         :: proc(jointId: JointId) -> rawptr ---
+
+	// Wake the bodies connect to this joint
+	Joint_WakeBodies          :: proc(jointId: JointId) ---
+
+	// Get the current constraint force for this joint
+	Joint_GetConstraintForce  :: proc(jointId: JointId) -> Vec2 ---
+
+	// Get the current constraint torque for this joint
+	Joint_GetConstraintTorque :: proc(jointId: JointId) -> f32 ---
+
+	/**
+	 * @defgroup distance_joint Distance Joint
+	 * @brief Functions for the distance joint.
+	 */
+
+	// Create a distance joint
+	//	@see b2DistanceJointDef for details
+	CreateDistanceJoint                 :: proc(worldId: WorldId, #by_ptr def: DistanceJointDef) -> JointId ---
+
+	// Set the rest length of a distance joint
+	// @param jointId The id for a distance joint
+	// @param length The new distance joint length
+	DistanceJoint_SetLength             :: proc(jointId: JointId, length: f32) ---
+
+	// Get the rest length of a distance joint
+	DistanceJoint_GetLength             :: proc(jointId: JointId) -> f32 ---
+
+	// Enable/disable the distance joint spring. When disabled the distance joint is rigid.
+	DistanceJoint_EnableSpring          :: proc(jointId: JointId, enableSpring: bool) ---
+
+	// Is the distance joint spring enabled?
+	DistanceJoint_IsSpringEnabled       :: proc(jointId: JointId) -> bool ---
+
+	// Set the spring stiffness in Hertz
+	DistanceJoint_SetSpringHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Set the spring damping ratio, non-dimensional
+	DistanceJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the spring Hertz
+	DistanceJoint_GetHertz              :: proc(jointId: JointId) -> f32 ---
+
+	// Get the spring damping ratio
+	DistanceJoint_GetDampingRatio       :: proc(jointId: JointId) -> f32 ---
+
+	// Enable joint limit. The limit only works if the joint spring is enabled. Otherwise the joint is rigid
+	//	and the limit has no effect.
+	DistanceJoint_EnableLimit           :: proc(jointId: JointId, enableLimit: bool) ---
+
+	// Is the distance joint limit enabled?
+	DistanceJoint_IsLimitEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Set the minimum and maximum length parameters of a distance joint
+	DistanceJoint_SetLengthRange        :: proc(jointId: JointId, minLength, maxLength: f32) ---
+
+	// Get the distance joint minimum length
+	DistanceJoint_GetMinLength          :: proc(jointId: JointId) -> f32 ---
+
+	// Get the distance joint maximum length
+	DistanceJoint_GetMaxLength          :: proc(jointId: JointId) -> f32 ---
+
+	// Get the current length of a distance joint
+	DistanceJoint_GetCurrentLength      :: proc(jointId: JointId) -> f32 ---
+
+	// Enable/disable the distance joint motor
+	DistanceJoint_EnableMotor           :: proc(jointId: JointId, enableMotor: bool) ---
+
+	// Is the distance joint motor enabled?
+	DistanceJoint_IsMotorEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Set the distance joint motor speed, typically in meters per second
+	DistanceJoint_SetMotorSpeed         :: proc(jointId: JointId, motorSpeed: f32) ---
+
+	// Get the distance joint motor speed, typically in meters per second
+	DistanceJoint_GetMotorSpeed         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the distance joint maximum motor force, typically in newtons
+	DistanceJoint_SetMaxMotorForce      :: proc(jointId: JointId, force: f32) ---
+
+	// Get the distance joint maximum motor force, typically in newtons
+	DistanceJoint_GetMaxMotorForce      :: proc(jointId: JointId) -> f32 ---
+
+	// Get the distance joint current motor force, typically in newtons
+	DistanceJoint_GetMotorForce         :: proc(jointId: JointId) -> f32 ---
+
+	/**
+	 * @defgroup motor_joint Motor Joint
+	 * @brief Functions for the motor joint.
+	 *
+	 * The motor joint is used to drive the relative transform between two bodies. It takes
+	 * a relative position and rotation and applies the forces and torques needed to achieve
+	 * that relative transform over time.
+	 */
+
+	// Create a motor joint
+	//	@see b2MotorJointDef for details
+	CreateMotorJoint               :: proc(worldId: WorldId, def: MotorJointDef) -> JointId ---
+
+	// Set the motor joint linear offset target
+	MotorJoint_SetLinearOffset     :: proc(jointId: JointId, linearOffset: Vec2) ---
+
+	// Get the motor joint linear offset target
+	MotorJoint_GetLinearOffset     :: proc(jointId: JointId) -> Vec2 ---
+
+	// Set the motor joint angular offset target in radians
+	MotorJoint_SetAngularOffset    :: proc(jointId: JointId, angularOffset: f32) ---
+
+	// Get the motor joint angular offset target in radians
+	MotorJoint_GetAngularOffset    :: proc(jointId: JointId) -> f32 ---
+
+	// Set the motor joint maximum force, typically in newtons
+	MotorJoint_SetMaxForce         :: proc(jointId: JointId, maxForce: f32) ---
+
+	// Get the motor joint maximum force, typically in newtons
+	MotorJoint_GetMaxForce         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the motor joint maximum torque, typically in newton-meters
+	MotorJoint_SetMaxTorque        :: proc(jointId: JointId, maxTorque: f32) ---
+
+	// Get the motor joint maximum torque, typically in newton-meters
+	MotorJoint_GetMaxTorque        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the motor joint correction factor, typically in [0, 1]
+	MotorJoint_SetCorrectionFactor :: proc(jointId: JointId, correctionFactor: f32) ---
+
+	// Get the motor joint correction factor, typically in [0, 1]
+	MotorJoint_GetCorrectionFactor :: proc(jointId: JointId) -> f32 ---
+
+	/**@}*/
+
+	/**
+	 * @defgroup mouse_joint Mouse Joint
+	 * @brief Functions for the mouse joint.
+	 *
+	 * The mouse joint is designed for use in the samples application, but you may find it useful in applications where
+	 * the user moves a rigid body with a cursor.
+	 */
+
+	// Create a mouse joint
+	//	@see b2MouseJointDef for details
+	CreateMouseJoint                 :: proc(worldId: WorldId, #by_ptr def: MouseJointDef) -> JointId ---
+
+	// Set the mouse joint target
+	MouseJoint_SetTarget             :: proc(jointId: JointId, target: Vec2) ---
+
+	// Get the mouse joint target
+	MouseJoint_GetTarget             :: proc(jointId: JointId) -> Vec2 ---
+
+	// Set the mouse joint spring stiffness in Hertz
+	MouseJoint_SetSpringHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the mouse joint spring stiffness in Hertz
+	MouseJoint_GetSpringHertz        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the mouse joint spring damping ratio, non-dimensional
+	MouseJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the mouse joint damping ratio, non-dimensional
+	MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
+
+	// Set the mouse joint maximum force, typically in newtons
+	MouseJoint_SetMaxForce           :: proc(jointId: JointId, maxForce: f32) ---
+
+	// Get the mouse joint maximum force, typically in newtons
+	MouseJoint_GetMaxForce           :: proc(jointId: JointId) -> f32 ---
+
+	/**@}*/
+
+	/**
+	 * @defgroup prismatic_joint Prismatic Joint
+	 * @brief A prismatic joint allows for translation along a single axis with no rotation.
+	 *
+	 * The prismatic joint is useful for things like pistons and moving platforms, where you want a body to translate
+	 * along an axis and have no rotation. Also called a *slider* joint.
+	 */
+
+	// Create a prismatic (slider) joint.
+	//	@see b2PrismaticJointDef for details
+	CreatePrismaticJoint                 :: proc(worldId: WorldId, #by_ptr def: PrismaticJointDef) -> JointId ---
+
+	// Enable/disable the joint spring.
+	PrismaticJoint_EnableSpring          :: proc(jointId: JointId, enableSpring: bool) ---
+
+	// Is the prismatic joint spring enabled or not?
+	PrismaticJoint_IsSpringEnabled       :: proc(jointId: JointId) -> bool ---
+
+	// Set the prismatic joint stiffness in Hertz.
+	// This should usually be less than a quarter of the simulation rate. For example, if the simulation
+	// runs at 60Hz then the joint stiffness should be 15Hz or less.
+	PrismaticJoint_SetSpringHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the prismatic joint stiffness in Hertz
+	PrismaticJoint_GetSpringHertz        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the prismatic joint damping ratio (non-dimensional)
+	PrismaticJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the prismatic spring damping ratio (non-dimensional)
+	PrismaticJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
+
+	// Enable/disable a prismatic joint limit
+	PrismaticJoint_EnableLimit           :: proc(jointId: JointId, enableLimit: bool) ---
+
+	// Is the prismatic joint limit enabled?
+	PrismaticJoint_IsLimitEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Get the prismatic joint lower limit
+	PrismaticJoint_GetLowerLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Get the prismatic joint upper limit
+	PrismaticJoint_GetUpperLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the prismatic joint limits
+	PrismaticJoint_SetLimits             :: proc(jointId: JointId, lower, upper: f32) ---
+
+	// Enable/disable a prismatic joint motor
+	PrismaticJoint_EnableMotor           :: proc(jointId: JointId, enableMotor: bool) ---
+
+	// Is the prismatic joint motor enabled?
+	PrismaticJoint_IsMotorEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Set the prismatic joint motor speed, typically in meters per second
+	PrismaticJoint_SetMotorSpeed         :: proc(jointId: JointId, motorSpeed: f32) ---
+
+	// Get the prismatic joint motor speed, typically in meters per second
+	PrismaticJoint_GetMotorSpeed         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the prismatic joint maximum motor force, typically in newtons
+	PrismaticJoint_SetMaxMotorForce      :: proc(jointId: JointId, force: f32) ---
+
+	// Get the prismatic joint maximum motor force, typically in newtons
+	PrismaticJoint_GetMaxMotorForce      :: proc(jointId: JointId) -> f32 ---
+
+	// Get the prismatic joint current motor force, typically in newtons
+	PrismaticJoint_GetMotorForce         :: proc(jointId: JointId) -> f32 ---
+
+	/**
+	 * @defgroup revolute_joint Revolute Joint
+	 * @brief A revolute joint allows for relative rotation in the 2D plane with no relative translation.
+	 *
+	 * The revolute joint is probably the most common joint. It can be used for ragdolls and chains.
+	 * Also called a *hinge* or *pin* joint.
+	 */
+
+	// Create a revolute joint
+	//	@see b2RevoluteJointDef for details
+	CreateRevoluteJoint                 :: proc(worldId: WorldId, #by_ptr def: RevoluteJointDef) -> JointId ---
+
+	// Enable/disable the revolute joint spring
+	RevoluteJoint_EnableSpring          :: proc(jointId: JointId, enableSpring: bool) ---
+
+	// Set the revolute joint spring stiffness in Hertz
+	RevoluteJoint_SetSpringHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the revolute joint spring stiffness in Hertz
+	RevoluteJoint_GetSpringHertz        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the revolute joint spring damping ratio, non-dimensional
+	RevoluteJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the revolute joint spring damping ratio, non-dimensional
+	RevoluteJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
+
+	// Get the revolute joint current angle in radians relative to the reference angle
+	//	@see b2RevoluteJointDef::referenceAngle
+	RevoluteJoint_GetAngle              :: proc(jointId: JointId) -> f32 ---
+
+	// Enable/disable the revolute joint limit
+	RevoluteJoint_EnableLimit           :: proc(jointId: JointId, enableLimit: bool) ---
+
+	// Is the revolute joint limit enabled?
+	RevoluteJoint_IsLimitEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Get the revolute joint lower limit in radians
+	RevoluteJoint_GetLowerLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Get the revolute joint upper limit in radians
+	RevoluteJoint_GetUpperLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the revolute joint limits in radians
+	RevoluteJoint_SetLimits             :: proc(jointId: JointId, lower, upper: f32) ---
+
+	// Enable/disable a revolute joint motor
+	RevoluteJoint_EnableMotor           :: proc(jointId: JointId, enableMotor: bool) ---
+
+	// Is the revolute joint motor enabled?
+	RevoluteJoint_IsMotorEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Set the revolute joint motor speed in radians per second
+	RevoluteJoint_SetMotorSpeed         :: proc(jointId: JointId, motorSpeed: f32) ---
+
+	// Get the revolute joint motor speed in radians per second
+	RevoluteJoint_GetMotorSpeed         :: proc(jointId: JointId) -> f32 ---
+
+	// Get the revolute joint current motor torque, typically in newton-meters
+	RevoluteJoint_GetMotorTorque        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the revolute joint maximum motor torque, typically in newton-meters
+	RevoluteJoint_SetMaxMotorTorque     :: proc(jointId: JointId, torque: f32) ---
+
+	// Get the revolute joint maximum motor torque, typically in newton-meters
+	RevoluteJoint_GetMaxMotorTorque     :: proc(jointId: JointId) -> f32 ---
+
+	/**@}*/
+
+	/**
+	 * @defgroup weld_joint Weld Joint
+	 * @brief A weld joint fully constrains the relative transform between two bodies while allowing for springiness
+	 *
+	 * A weld joint constrains the relative rotation and translation between two bodies. Both rotation and translation
+	 * can have damped springs.
+	 *
+	 * @note The accuracy of weld joint is limited by the accuracy of the solver. Long chains of weld joints may flex.
+	 */
+
+	// Create a weld joint
+	//	@see b2WeldJointDef for details
+	CreateWeldJoint                  :: proc(worldId: WorldId, #by_ptr def: WeldJointDef) -> JointId ---
+
+	// Set the weld joint linear stiffness in Hertz. 0 is rigid.
+	WeldJoint_SetLinearHertz         :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the weld joint linear stiffness in Hertz
+	WeldJoint_GetLinearHertz         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the weld joint linear damping ratio (non-dimensional)
+	WeldJoint_SetLinearDampingRatio  :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the weld joint linear damping ratio (non-dimensional)
+	WeldJoint_GetLinearDampingRatio  :: proc(jointId: JointId) -> f32 ---
+
+	// Set the weld joint angular stiffness in Hertz. 0 is rigid.
+	WeldJoint_SetAngularHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the weld joint angular stiffness in Hertz
+	WeldJoint_GetAngularHertz        :: proc(jointId: JointId) -> f32 ---
+
+	// Set weld joint angular damping ratio, non-dimensional
+	WeldJoint_SetAngularDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the weld joint angular damping ratio, non-dimensional
+	WeldJoint_GetAngularDampingRatio :: proc(jointId: JointId) -> f32 ---
+
+	/**
+	 * @defgroup wheel_joint Wheel Joint
+	 * The wheel joint can be used to simulate wheels on vehicles.
+	 *
+	 * The wheel joint restricts body B to move along a local axis in body A. Body B is free to
+	 * rotate. Supports a linear spring, linear limits, and a rotational motor.
+	 *
+	 */
+
+	// Create a wheel joint
+	//	@see b2WheelJointDef for details
+	CreateWheelJoint                 :: proc(worldId: WorldId, #by_ptr def: WheelJointDef) -> JointId ---
+
+	// Enable/disable the wheel joint spring
+	WheelJoint_EnableSpring          :: proc(jointId: JointId, enableSpring: bool) ---
+
+	// Is the wheel joint spring enabled?
+	WheelJoint_IsSpringEnabled       :: proc(jointId: JointId) -> bool ---
+
+	// Set the wheel joint stiffness in Hertz
+	WheelJoint_SetSpringHertz        :: proc(jointId: JointId, hertz: f32) ---
+
+	// Get the wheel joint stiffness in Hertz
+	WheelJoint_GetSpringHertz        :: proc(jointId: JointId) -> f32 ---
+
+	// Set the wheel joint damping ratio, non-dimensional
+	WheelJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) ---
+
+	// Get the wheel joint damping ratio, non-dimensional
+	WheelJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 ---
+
+	// Enable/disable the wheel joint limit
+	WheelJoint_EnableLimit           :: proc(jointId: JointId, enableLimit: bool) ---
+
+	// Is the wheel joint limit enabled?
+	WheelJoint_IsLimitEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Get the wheel joint lower limit
+	WheelJoint_GetLowerLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Get the wheel joint upper limit
+	WheelJoint_GetUpperLimit         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the wheel joint limits
+	WheelJoint_SetLimits             :: proc(jointId: JointId, lower, upper: f32) ---
+
+	// Enable/disable the wheel joint motor
+	WheelJoint_EnableMotor           :: proc(jointId: JointId, enableMotor: bool) ---
+
+	// Is the wheel joint motor enabled?
+	WheelJoint_IsMotorEnabled        :: proc(jointId: JointId) -> bool ---
+
+	// Set the wheel joint motor speed in radians per second
+	WheelJoint_SetMotorSpeed         :: proc(jointId: JointId, motorSpeed: f32) ---
+
+	// Get the wheel joint motor speed in radians per second
+	WheelJoint_GetMotorSpeed         :: proc(jointId: JointId) -> f32 ---
+
+	// Set the wheel joint maximum motor torque, typically in newton-meters
+	WheelJoint_SetMaxMotorTorque     :: proc(jointId: JointId, torque: f32) ---
+
+	// Get the wheel joint maximum motor torque, typically in newton-meters
+	WheelJoint_GetMaxMotorTorque     :: proc(jointId: JointId) -> f32 ---
+
+	// Get the wheel joint current motor torque, typically in newton-meters
+	WheelJoint_GetMotorTorque        :: proc(jointId: JointId) -> f32 ---
+}
+
+
+
+IsValid :: proc{
+	Float_IsValid,
+	Vec2_IsValid,
+	Rot_IsValid,
+	World_IsValid,
+	Body_IsValid,
+	Shape_IsValid,
+	Chain_IsValid,
+	Joint_IsValid,
+
+	IsValidRay,
+}

+ 72 - 0
vendor/box2d/build_box2d.sh

@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+set -eu
+
+VERSION="3.0.0"
+RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz"
+
+cd "$(odin root)"/vendor/box2d
+
+curl -O -L "$RELEASE"
+tar -xzvf "v$VERSION.tar.gz"
+
+cd "box2d-$VERSION"
+
+DISABLE_FLAGS="-DBOX2D_SAMPLES=OFF -DBOX2D_VALIDATE=OFF -DBOX2D_UNIT_TESTS=OFF"
+
+case "$(uname -s)" in
+Darwin)
+	export MACOSX_DEPLOYMENT_TARGET="11" 
+
+	case "$(uname -m)" in
+	"x86_64" | "amd64")
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_avx2.a
+
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_sse2.a
+		;;
+	*)
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_darwin_arm64.a
+		;;
+	esac
+	;;
+*)
+	case "$(uname -m)" in
+	"x86_64" | "amd64")
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_other_amd64_avx2.a
+
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_other_amd64_sse2.a
+		;;
+	*)
+		rm -rf build
+		mkdir build
+		cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
+		cmake --build build
+		cp build/src/libbox2d.a ../lib/box2d_other.a
+		;;
+	esac
+	;;
+esac
+
+cd ..
+
+rm -rf v3.0.0.tar.gz
+rm -rf box2d-3.0.0

+ 473 - 0
vendor/box2d/collision.odin

@@ -0,0 +1,473 @@
+package vendor_box2d
+
+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
+
+// Low level ray-cast input data
+RayCastInput :: struct {
+	// Start point of the ray cast
+	origin:      Vec2,
+
+	// Translation of the ray cast
+	translation: Vec2,
+
+	// The maximum fraction of the translation to consider, typically 1
+	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"`,
+
+	// The number of points
+	count:       i32,
+
+	// The radius around the point cloud
+	radius:      f32,
+
+	// The translation of the shape cast
+	translation: Vec2,
+
+	// The maximum fraction of the translation to consider, typically 1
+	maxFraction: f32,
+}
+
+// Low level ray-cast or shape-cast output data
+CastOutput :: struct {
+	// The surface normal at the hit point
+	normal:     Vec2,
+
+	// The surface hit point
+	point:      Vec2,
+
+	// The fraction of the input translation at collision
+	fraction:   f32,
+
+	// The number of iterations used
+	iterations: i32,
+
+	// Did the cast hit?
+	hit:        bool,
+}
+
+// This holds the mass data computed for a shape.
+MassData :: struct {
+	// The mass of the shape, usually in kilograms.
+	mass:              f32,
+
+	// The position of the shape's centroid relative to the shape's origin.
+	center:            Vec2,
+
+	// The rotational inertia of the shape about the local origin.
+	rotationalInertia: f32,
+}
+
+// A solid circle
+Circle :: struct {
+	// The local center
+	center: Vec2,
+
+	// The radius
+	radius: f32,
+}
+
+// A solid capsule can be viewed as two semicircles connected
+//	by a rectangle.
+Capsule :: struct {
+	// Local center of the first semicircle
+	center1: Vec2,
+
+	// Local center of the second semicircle
+	center2: Vec2,
+
+	// The radius of the semicircles
+	radius:  f32,
+}
+
+// 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.
+// 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.
+Polygon :: struct {
+	// The polygon vertices
+	vertices: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+
+	// The outward normal vectors of the polygon sides
+	normals:  [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+
+	// The centroid of the polygon
+	centroid: Vec2,
+
+	// The external radius for rounded polygons
+	radius:   f32,
+
+	// The number of polygon vertices
+	count:    i32,
+}
+
+// A line segment with two-sided collision.
+Segment :: struct {
+	// The first point
+	point1: Vec2,
+
+	// The second point
+	point2: Vec2,
+}
+
+// A smooth 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 {
+	// The tail ghost vertex
+	ghost1:  Vec2,
+
+	// The line segment
+	segment: Segment,
+
+	// The head ghost vertex
+	ghost2:  Vec2,
+
+	// The owning chain shape index (internal usage only)
+	chainId: i32,
+}
+
+
+// A convex hull. Used to create convex polygons.
+//	@warning Do not modify these values directly, instead use b2ComputeHull()
+Hull :: struct {
+	// The final points of the hull
+	points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
+
+	// The number of points
+	count:  i32,
+}
+
+/**
+ * @defgroup distance Distance
+ * Functions for computing the distance between shapes.
+ *
+ * These are advanced functions you can use to perform distance calculations. There
+ * are functions for computing the closest points between shapes, doing linear shape casts,
+ * and doing rotational shape casts. The latter is called time of impact (TOI).
+ */
+
+// Result of computing the distance between two line segments
+SegmentDistanceResult :: struct {
+	// The closest point on the first segment
+	closest1:        Vec2,
+
+	// The closest point on the second segment
+	closest2:        Vec2,
+
+	// The barycentric coordinate on the first segment
+	fraction1:       f32,
+
+	// The barycentric coordinate on the second segment
+	fraction2:       f32,
+
+	// The squared distance between the closest points
+	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 {
+	// The number of stored simplex points
+	count: u16,
+
+	// The cached simplex indices on shape A
+	indexA: [3]u8 `fmt:"v,count"`,
+
+	// The cached simplex indices on shape B
+	indexB: [3]u8 `fmt:"v,count"`,
+}
+
+emptyDistanceCache :: DistanceCache{}
+
+// Input for b2ShapeDistance
+DistanceInput :: struct {
+	// The proxy for shape A
+	proxyA: DistanceProxy,
+
+	// The proxy for shape B
+	proxyB: DistanceProxy,
+
+	// The world transform for shape A
+	transformA: Transform,
+
+	// The world transform for shape B
+	transformB: Transform,
+
+	// Should the proxy radius be considered?
+	useRadii: bool,
+}
+
+// Output for b2ShapeDistance
+DistanceOutput :: struct {
+	pointA:       Vec2, // Closest point on shapeA
+	pointB:       Vec2, // Closest point on shapeB
+	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
+}
+
+// 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
+}
+
+// Simplex from the GJK algorithm
+Simplex :: struct {
+	v1, v2, v3: SimplexVertex `fmt:"v,count"`, // vertices
+	count: i32, // number of valid vertices
+}
+
+// Input parameters for b2ShapeCast
+ShapeCastPairInput :: struct {
+	proxyA:       DistanceProxy, // The proxy for shape A
+	proxyB:       DistanceProxy, // 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
+}
+
+
+// This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin,
+// which may not coincide with the center of mass. However, to support dynamics we must interpolate the center of mass
+// position.
+Sweep :: struct {
+	localCenter: Vec2, // Local center of mass position
+	c1:          Vec2, // Starting center of mass world position
+	c2:          Vec2, // Ending center of mass world position
+	q1:          Rot,  // Starting world rotation
+	q2:          Rot,  // Ending world rotation
+}
+
+// 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]
+}
+
+// Describes the TOI output
+TOIState :: enum c.int {
+	Unknown,
+	Failed,
+	Overlapped,
+	Hit,
+	Separated,
+}
+
+// Output parameters for b2TimeOfImpact.
+TOIOutput :: struct {
+	state: TOIState, // The type of result
+	t:     f32,      // The time of the collision
+}
+
+
+
+/**
+ * @defgroup collision Collision
+ * @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.
+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.
+	anchorA:          Vec2,
+
+	// Location of the contact point relative to bodyB's origin in world space
+	anchorB:          Vec2,
+
+	// The separation of the contact point, negative if penetrating
+	separation:       f32,
+
+	// The impulse along the manifold normal vector.
+	normalImpulse:    f32,
+
+	// The friction impulse
+	tangentImpulse:   f32,
+
+	// The maximum normal impulse applied during sub-stepping
+	//	todo not sure this is needed
+	maxNormalImpulse: f32,
+
+	// Relative normal velocity pre-solve. Used for hit events. If the normal impulse is
+	// zero then there was no hit. Negative means shapes are approaching.
+	normalVelocity:   f32,
+
+	// Uniquely identifies a contact point between two shapes
+	id:               u16,
+
+	// Did this contact point exist the previous step?
+	persisted:        bool,
+}
+
+// A contact manifold describes the contact points between colliding shapes
+Manifold :: struct {
+	// The manifold points, up to two are possible in 2D
+	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,
+}
+
+
+/**
+ * @defgroup tree Dynamic Tree
+ * The dynamic tree is a binary AABB tree to organize and query large numbers of geometric objects
+ *
+ * Box2D uses the dynamic tree internally to sort collision shapes into a binary bounding volume hierarchy.
+ * This data structure may have uses in games for organizing other geometry data and may be used independently
+ * of Box2D rigid body simulation.
+ *
+ * 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.
+ * 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"`,
+
+	// The root index
+	root:            i32,
+
+	// The number of nodes
+	nodeCount:       i32,
+
+	// The allocated node space
+	nodeCapacity:    i32,
+
+	// Node free list
+	freeList:        i32,
+
+	// Number of proxies created
+	proxyCount:      i32,
+
+	// Leaf indices for rebuild
+	leafIndices:     [^]i32,
+
+	// Leaf bounding boxes for rebuild
+	leafBoxes:       [^]AABB,
+
+	// Leaf bounding box centers for rebuild
+	leafCenters:     [^]Vec2,
+
+	// Bins for sorting during rebuild
+	binIndices:      [^]i32,
+
+	// Allocated space for rebuilding
+	rebuildCapacity: i32,
+}
+
+// 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
+
+// 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 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
+
+
+// This function receives clipped raycast input for a proxy. The function
+// returns the new ray fraction.
+// - 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

+ 87 - 0
vendor/box2d/id.odin

@@ -0,0 +1,87 @@
+package vendor_box2d
+
+import "base:intrinsics"
+
+/**
+ * @defgroup id Ids
+ * These ids serve as handles to internal Box2D objects.
+ * These should be considered opaque data and passed by value.
+ * Include this header if you need the id types and not the whole Box2D API.
+ * All ids are considered null if initialized to zero.
+ *
+ * For example in Odin:
+ *
+ * @code{.odin}
+ * worldId := b2.WorldId{}
+ * @endcode
+ *
+ * This is considered null.
+ *
+ * @warning Do not use the internals of these ids. They are subject to change. Ids should be treated as opaque objects.
+ * @warning You should use ids to access objects in Box2D. Do not access files within the src folder. Such usage is unsupported.
+ */
+
+/// World id references a world instance. This should be treated as an opaque handle.
+WorldId :: struct {
+	index1:   u16,
+	revision: u16,
+}
+
+/// Body id references a body instance. This should be treated as an opaque handle.
+BodyId :: struct {
+	index1:   i32,
+	world0:   u16,
+	revision: u16,
+}
+
+/// Shape id references a shape instance. This should be treated as an opaque handle.
+ShapeId :: struct {
+	index1:   i32,
+	world0:   u16,
+	revision: u16,
+}
+
+/// Joint id references a joint instance. This should be treated as an opaque handle.
+JointId :: struct {
+	index1:   i32,
+	world0:   u16,
+	revision: 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{}
+
+/// Macro to determine if any id is null.
+IS_NULL :: #force_inline proc "c" (id: $T) -> bool
+	where intrinsics.type_is_struct(T),
+	      intrinsics.type_has_field(T, "index1") {
+	return id.index1 == 0
+}
+
+/// Macro to determine if any id is non-null.
+IS_NON_NULL :: #force_inline proc "c" (id: $T) -> bool
+	where intrinsics.type_is_struct(T),
+	      intrinsics.type_has_field(T, "index1") {
+	return id.index1 != 0
+}
+
+/// Compare two ids for equality. Doesn't work for b2WorldId.
+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
+}

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_windows_amd64_avx2.lib


BIN
vendor/box2d/lib/box2d_windows_amd64_sse2.lib


+ 522 - 0
vendor/box2d/math_functions.odin

@@ -0,0 +1,522 @@
+package vendor_box2d
+
+import "core:c"
+import "core:math"
+
+pi :: 3.14159265359
+
+Vec2 :: [2]f32
+Rot :: struct {
+	c, s: f32, // cosine and sine
+}
+
+Transform :: struct {
+	p: Vec2,
+	q: Rot,
+}
+
+Mat22 :: matrix[2, 2]f32
+AABB :: struct {
+	lowerBound: Vec2,
+	upperBound: Vec2,
+}
+
+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
+@(deprecated="Prefer the built-in 'min(a, b)'", require_results)
+MinFloat :: proc "c" (a, b: f32) -> f32 {
+	return min(a, b)
+}
+
+// @return the maximum of two floats
+@(deprecated="Prefer the built-in 'max(a, b)'", require_results)
+MaxFloat :: proc "c" (a, b: f32) -> f32 {
+	return max(a, b)
+}
+
+// @return the absolute value of a float
+@(deprecated="Prefer the built-in 'abs(a)'", require_results)
+AbsFloat :: proc "c" (a: f32) -> f32 {
+	return abs(a)
+}
+
+// @return a f32 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 {
+	return clamp(a, lower, upper)
+}
+
+// @return the minimum of two integers
+@(deprecated="Prefer the built-in 'min(a, b)'", require_results)
+MinInt :: proc "c" (a, b: c.int) -> c.int {
+	return min(a, b)
+}
+
+// @return the maximum of two integers
+@(deprecated="Prefer the built-in 'max(a, b)'", require_results)
+MaxInt :: proc "c" (a, b: c.int) -> c.int {
+	return max(a, b)
+}
+
+// @return the absolute value of an integer
+@(deprecated="Prefer the built-in 'abs(a)'", require_results)
+AbsInt :: proc "c" (a: c.int) -> c.int {
+	return abs(a)
+}
+
+// @return an integer 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 {
+	return clamp(a, lower, upper)
+}
+
+// Vector dot product
+@(require_results)
+Dot :: proc "c" (a, b: Vec2) -> f32 {
+	return a.x * b.x + a.y * b.y
+}
+
+// Vector cross product. In 2D this yields a scalar.
+@(require_results)
+Cross :: proc "c" (a, b: Vec2) -> f32 {
+	return a.x * b.y - a.y * b.x
+}
+
+// Perform the cross product on a vector and a scalar. In 2D this produces a vector.
+@(require_results)
+CrossVS :: proc "c" (v: Vec2, s: f32) -> Vec2 {
+	return {s * v.y, -s * v.x}
+}
+
+// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
+@(require_results)
+CrossSV :: proc "c" (s: f32, v: Vec2) -> Vec2 {
+	return {-s * v.y, s * v.x}
+}
+
+// Get a left pointing perpendicular vector. Equivalent to b2CrossSV(1, v)
+@(require_results)
+LeftPerp :: proc "c" (v: Vec2) -> Vec2 {
+	return {-v.y, v.x}
+}
+
+// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1)
+@(require_results)
+RightPerp :: proc "c" (v: Vec2) -> Vec2 {
+	return {v.y, -v.x}
+}
+
+// Vector addition
+@(deprecated="Prefer 'a + b'", require_results)
+Add :: proc "c" (a, b: Vec2) -> Vec2 {
+	return a + b
+}
+
+// Vector subtraction
+@(deprecated="Prefer 'a - b'", require_results)
+Sub :: proc "c" (a, b: Vec2) -> Vec2 {
+	return a - b
+}
+
+// Vector negation
+@(deprecated="Prefer '-a'", require_results)
+Neg :: proc "c" (a: Vec2) -> Vec2 {
+	return -a
+}
+
+// Vector linear interpolation
+// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
+@(require_results)
+Lerp :: proc "c" (a, b: Vec2, t: f32) -> Vec2 {
+	return {(1 - t) * a.x + t * b.x, (1 - t) * a.y + t * b.y}
+}
+
+// Component-wise multiplication
+@(deprecated="Prefer 'a * b'", require_results)
+Mul :: proc "c" (a, b: Vec2) -> Vec2 {
+	return a * b
+}
+
+// Multiply a scalar and vector
+@(deprecated="Prefer 's * v'", require_results)
+MulSV :: proc "c" (s: f32, v: Vec2) -> Vec2 {
+	return s * v
+}
+
+// a + s * b
+@(deprecated="Prefer 'a + s * b'", require_results)
+MulAdd :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
+	return a + s * b
+}
+
+// a - s * b
+@(deprecated="Prefer 'a - s * b'", require_results)
+MulSub :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
+	return a - s * b
+}
+
+// Component-wise absolute vector
+@(require_results)
+Abs :: proc "c" (a: Vec2) -> (b: Vec2) {
+	b.x = abs(a.x)
+	b.y = abs(a.y)
+	return
+}
+
+// Component-wise minimum vector
+@(require_results)
+Min :: proc "c" (a, b: Vec2) -> (c: Vec2) {
+	c.x = min(a.x, b.x)
+	c.y = min(a.y, b.y)
+	return
+}
+
+// Component-wise maximum vector
+@(require_results)
+Max :: proc "c" (a, b: Vec2) -> (c: Vec2) {
+	c.x = max(a.x, b.x)
+	c.y = max(a.y, b.y)
+	return
+}
+
+// Component-wise clamp vector v into the range [a, b]
+@(require_results)
+Clamp :: proc "c" (v: Vec2, a, b: Vec2) -> (c: Vec2) {
+	c.x = clamp(v.x, a.x, b.x)
+	c.y = clamp(v.y, a.y, b.y)
+	return
+}
+
+// Get the length of this vector (the norm)
+@(require_results)
+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 {
+	dx := b.x - a.x
+	dy := b.y - a.y
+	return math.sqrt(dx * dx + dy * dy)
+}
+
+// Get the distance squared between points
+@(require_results)
+DistanceSquared :: proc "c" (a, b: Vec2) -> f32 {
+	c := Vec2{b.x - a.x, b.y - a.y}
+	return c.x * c.x + c.y * c.y
+}
+
+// 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)}
+}
+
+// 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}
+}
+
+// Is this rotation normalized?
+@(require_results)
+IsNormalized :: 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
+}
+
+// Normalized linear interpolation
+// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
+@(require_results)
+NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot {
+	omt := 1 - t
+	return NormalizeRot({
+		omt * q1.c + t * q2.c,
+		omt * q1.s + t * q2.s,
+	})
+}
+
+// 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
+//	@param inv_h inverse time step
+@(require_results)
+ComputeAngularVelocity :: proc "c" (q1: Rot, q2: Rot, inv_h: f32) -> f32 {
+	// ds/dt = omega * cos(t)
+	// dc/dt = -omega * sin(t)
+	// s2 = s1 + omega * h * c1
+	// c2 = c1 - omega * h * s1
+
+	// omega * h * s1 = c1 - c2
+	// omega * h * c1 = s2 - s1
+	// omega * h = (c1 - c2) * s1 + (s2 - s1) * c1
+	// omega * h = s1 * c1 - c2 * s1 + s2 * c1 - s1 * c1
+	// omega * h = s2 * c1 - c2 * s1 = sin(a2 - a1) ~= a2 - a1 for small delta
+	omega := inv_h * (q2.s * q1.c - q2.c * q1.s)
+	return omega
+}
+
+// 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)
+}
+
+// Get the x-axis
+@(require_results)
+Rot_GetXAxis :: proc "c" (q: Rot) -> Vec2 {
+	return {q.c, q.s}
+}
+
+// Get the y-axis
+@(require_results)
+Rot_GetYAxis :: proc "c" (q: Rot) -> Vec2 {
+	return {-q.s, q.c}
+}
+
+// Multiply two rotations: q * r
+@(require_results)
+MulRot :: proc "c" (q, r: Rot) -> (qr: Rot) {
+	// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
+	// [qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]
+	// s(q + r) = qs * rc + qc * rs
+	// c(q + r) = qc * rc - qs * rs
+	qr.s = q.s * r.c + q.c * r.s
+	qr.c = q.c * r.c - q.s * r.s
+	return
+}
+
+// Transpose multiply two rotations: qT * r
+@(require_results)
+InvMulRot :: proc "c" (q, r: Rot) -> (qr: Rot) {
+	// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
+	// [-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]
+	// s(q - r) = qc * rs - qs * rc
+	// c(q - r) = qc * rc + qs * rs
+	qr.s = q.c * r.s - q.s * r.c
+	qr.c = q.c * r.c + q.s * r.s
+	return
+}
+
+// relative angle between b and a (rot_b * inv(rot_a))
+@(require_results)
+RelativeAngle :: proc "c" (b, a: Rot) -> f32 {
+	// sin(b - a) = bs * ac - bc * as
+	// 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)
+}
+
+// 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
+	}
+	return angle
+}
+
+// Rotate a vector
+@(require_results)
+RotateVector :: proc "c" (q: Rot, v: Vec2) -> Vec2 {
+	return {q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y}
+}
+
+// Inverse rotate a vector
+@(require_results)
+InvRotateVector :: proc "c" (q: Rot, v: Vec2) -> Vec2 {
+	return {q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y}
+}
+
+// Transform a point (e.g. local space to world space)
+@(require_results)
+TransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 {
+	x := (t.q.c * p.x - t.q.s * p.y) + t.p.x
+	y := (t.q.s * p.x + t.q.c * p.y) + t.p.y
+	return {x, y}
+}
+
+// Inverse transform a point (e.g. world space to local space)
+@(require_results)
+InvTransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 {
+	vx := p.x - t.p.x
+	vy := p.y - t.p.y
+	return {t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy}
+}
+
+// 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)
+MulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) {
+	C.q = MulRot(A.q, B.q)
+	C.p = RotateVector(A.q, B.p) + A.p
+	return
+}
+
+// v2 = A.q' * (B.q * v1 + B.p - A.p)
+//    = A.q' * B.q * v1 + A.q' * (B.p - A.p)
+@(require_results)
+InvMulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) {
+	C.q = InvMulRot(A.q, B.q)
+	C.p = InvRotateVector(A.q, B.p-A.p)
+	return
+}
+
+// Multiply a 2-by-2 matrix times a 2D vector
+@(deprecated="Prefer 'A * v'", require_results)
+MulMV :: proc "c" (A: Mat22, v: Vec2) -> Vec2 {
+	return A * v
+}
+
+// Get the inverse of a 2-by-2 matrix
+@(require_results)
+GetInverse22 :: proc "c" (A: Mat22) -> Mat22 {
+	a := A[0, 0]
+	b := A[0, 1]
+	c := A[1, 0]
+	d := A[1, 1]
+	det := a * d - b * c
+	if det != 0.0 {
+		det = 1 / det
+	}
+
+	return Mat22{
+		 det * d, -det * b,
+		-det * c,  det * a,
+	}
+}
+
+// Solve A * x = b, where b is a column vector. This is more efficient
+// than computing the inverse in one-shot cases.
+@(require_results)
+Solve22 :: proc "c" (A: Mat22, b: Vec2) -> Vec2 {
+	a11 := A[0, 0]
+	a12 := A[0, 1]
+	a21 := A[1, 0]
+	a22 := A[1, 1]
+	det := a11 * a22 - a12 * a21
+	if det != 0.0 {
+		det = 1 / det
+	}
+	return {det * (a22 * b.x - a12 * b.y), det * (a11 * b.y - a21 * b.x)}
+}
+
+// Does a fully contain b
+@(require_results)
+AABB_Contains :: proc "c" (a, b: AABB) -> bool {
+	(a.lowerBound.x <= b.lowerBound.x) or_return
+	(a.lowerBound.y <= b.lowerBound.y) or_return
+	(b.upperBound.x <= a.upperBound.x) or_return
+	(b.upperBound.y <= a.upperBound.y) or_return
+	return true
+}
+
+// Get the center of the AABB.
+@(require_results)
+AABB_Center :: proc "c" (a: AABB) -> Vec2 {
+	return {0.5 * (a.lowerBound.x + a.upperBound.x), 0.5 * (a.lowerBound.y + a.upperBound.y)}
+}
+
+// Get the extents of the AABB (half-widths).
+@(require_results)
+AABB_Extents :: proc "c" (a: AABB) -> Vec2 {
+	return {0.5 * (a.upperBound.x - a.lowerBound.x), 0.5 * (a.upperBound.y - a.lowerBound.y)}
+}
+
+// Union of two AABBs
+@(require_results)
+AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) {
+	c.lowerBound.x = min(a.lowerBound.x, b.lowerBound.x)
+	c.lowerBound.y = min(a.lowerBound.y, b.lowerBound.y)
+	c.upperBound.x = max(a.upperBound.x, b.upperBound.x)
+	c.upperBound.y = max(a.upperBound.y, b.upperBound.y)
+	return
+}
+
+@(require_results)
+Float_IsValid :: proc "c" (a: f32) -> bool {
+	math.is_nan(a) or_return
+	math.is_inf(a) or_return
+	return true
+}
+
+@(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
+}
+
+@(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)
+}
+
+@(require_results)
+Normalize :: proc "c" (v: Vec2) -> Vec2 {
+	length := Length(v)
+	if length < 1e-23 {
+		return Vec2_zero
+	}
+	invLength := 1 / length
+	return invLength * v
+}
+
+@(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
+}

+ 1231 - 0
vendor/box2d/types.odin

@@ -0,0 +1,1231 @@
+package vendor_box2d
+
+import "core:c"
+
+// Task interface
+// This is prototype for a Box2D task. Your task system is expected to invoke the Box2D task with these arguments.
+// The task spans a range of the parallel-for: [startIndex, endIndex)
+// The worker index must correctly identify each worker in the user thread pool, expected in [0, workerCount).
+//	A worker must only exist on only one thread at a time and is analogous to the thread index.
+// The task context is the context pointer sent from Box2D when it is enqueued.
+//	The startIndex and endIndex are expected in the range [0, itemCount) where itemCount is the argument to b2EnqueueTaskCallback
+// below. Box2D expects startIndex < endIndex and will execute a loop like this:
+//
+//	@code{.odin}
+// 	for i in startIndex ..< endIndex {
+//		DoWork()
+//	}
+//	@endcode
+//	@ingroup world
+TaskCallback :: #type proc "c" (startIndex, endIndex: i32, workerIndex: u32, taskContext: rawptr)
+
+
+// These functions can be provided to Box2D to invoke a task system. These are designed to work well with enkiTS.
+// Returns a pointer to the user's task object. May be nullptr. A nullptr indicates to Box2D that the work was executed
+//	serially within the callback and there is no need to call b2FinishTaskCallback.
+//	The itemCount is the number of Box2D work items that are to be partitioned among workers by the user's task system.
+//	This is essentially a parallel-for. The minRange parameter is a suggestion of the minimum number of items to assign
+//	per worker to reduce overhead. For example, suppose the task is small and that itemCount is 16. A minRange of 8 suggests
+//	that your task system should split the work items among just two workers, even if you have more available.
+//	In general the range [startIndex, endIndex) send to TaskCallback should obey:
+//	endIndex - startIndex >= minRange
+//	The exception of course is when itemCount < minRange.
+//	@ingroup world
+EnqueueTaskCallback :: #type proc "c" (task: TaskCallback, itemCount: i32, minRange: i32, taskContext: rawptr, userContext: rawptr) -> rawptr
+
+// Finishes a user task object that wraps a Box2D task.
+//	@ingroup world
+FinishTaskCallback :: #type proc "c" (userTask: rawptr, userContext: rawptr)
+
+// Result from b2World_RayCastClosest
+// @ingroup world
+RayResult :: struct {
+	shapeId:  ShapeId,
+	point:    Vec2,
+	normal:   Vec2,
+	fraction: f32,
+	hit:      bool,
+}
+
+// World definition used to create a simulation world.
+// Must be initialized using b2DefaultWorldDef().
+// @ingroup world
+WorldDef :: struct {
+	// Gravity vector. Box2D has no up-vector defined.
+	gravity: Vec2,
+
+	// Restitution velocity 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.
+	hitEventThreshold: f32,
+
+	// Contact stiffness. Cycles per second.
+	contactHertz: f32,
+
+	// Contact bounciness. Non-dimensional.
+	contactDampingRatio: f32,
+
+	// Joint stiffness. Cycles per second.
+	jointHertz: f32,
+
+	// Joint bounciness. Non-dimensional.
+	jointDampingRatio: f32,
+
+	// Can bodies go to sleep to improve performance
+	enableSleep: bool,
+
+	// Enable continuous collision
+	enableContinous: 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.
+	workerCount: i32,
+
+	// Function to spawn tasks
+	enqueueTask: EnqueueTaskCallback,
+
+	// Function to finish a task
+	finishTask: FinishTaskCallback,
+
+	// User context that is provided to enqueueTask and finishTask
+	userTaskContext: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+
+
+// The body simulation type.
+// Each body is one of these three types. The type determines how the body behaves in the simulation.
+// @ingroup body
+BodyType :: enum c.int {
+	// zero mass, zero velocity, may be manually moved
+	staticBody = 0,
+
+	// zero mass, velocity set by user, moved by solver
+	kinematicBody = 1,
+
+	// positive mass, velocity determined by forces, moved by solver
+	dynamicBody = 2,
+
+}
+
+// number of body types
+bodyTypeCount :: len(BodyType)
+
+// A body definition holds all the data needed to construct a rigid body.
+// You can safely re-use body definitions. Shapes are added to a body after construction.
+//	Body definitions are temporary objects used to bundle creation parameters.
+// Must be initialized using b2DefaultBodyDef().
+// @ingroup body
+BodyDef :: struct {
+	// The body type: static, kinematic, or dynamic.
+	type: BodyType,
+
+	// The initial world position of the body. Bodies should be created with the desired position.
+	// @note Creating bodies at the origin and then moving them nearly doubles the cost of body creation, especially
+	//	if the body is moved after shapes have been added.
+	position: Vec2,
+
+	// 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.
+	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
+	// 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
+	// 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.
+	angularDamping: f32,
+
+	// Scale the gravity applied to this body. Non-dimensional.
+	gravityScale: f32,
+
+	// Sleep velocity threshold, default is 0.05 meter per second
+	sleepThreshold: f32,
+
+	// Use this to store application specific body data.
+	userData: rawptr,
+
+	// Set this flag to false if this body should never fall asleep.
+	enableSleep: bool,
+
+	// Is this body initially awake or sleeping?
+	isAwake: bool,
+
+	// Should this body be prevented from rotating? Useful for characters.
+	fixedRotation: bool,
+
+	// Treat this body as high speed object that performs continuous collision detection
+	// against dynamic and kinematic bodies, but not other bullet bodies.
+	//	@warning Bullets should be used sparingly. They are not a solution for general dynamic-versus-dynamic
+	//	continuous collision. They may interfere with joint constraints.
+	isBullet: bool,
+
+	// 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,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// This is used to filter collision on shapes. It affects shape-vs-shape collision
+//	and shape-versus-query collision (such as b2World_CastRay).
+// @ingroup shape
+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 {
+	//		Static  = 0x00000001,
+	//		Dynamic = 0x00000002,
+	//		Debris  = 0x00000004,
+	//		Player  = 0x00000008,
+	//		// etc
+	//	};
+	//	@endcode
+	//      Or use a bit_set.
+	categoryBits: u32,
+
+	// 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);
+	//	@endcode
+	maskBits: u32,
+
+	// 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
+	// always wins against the mask bits.
+	//	For example, you may want ragdolls to collide with other ragdolls but you don't want
+	//	ragdoll self-collision. In this case you would give each ragdoll a unique negative group index
+	//	and apply that group index to all shapes on the ragdoll.
+	groupIndex: i32,
+}
+
+
+// The query filter is used to filter collisions between queries and shapes. For example,
+//	you may want a ray-cast representing a projectile to hit players and the static environment
+//	but not debris.
+// @ingroup shape
+QueryFilter :: struct {
+	// The collision category bits of this query. Normally you would just set one bit.
+	categoryBits: u32,
+
+	// The collision mask bits. This states the shape categories that this
+	// query would accept for collision.
+	maskBits: u32,
+}
+
+
+// Shape type
+// @ingroup shape
+ShapeType :: enum c.int {
+	// A circle with an offset
+	circleShape,
+
+	// A capsule is an extruded circle
+	capsuleShape,
+
+	// A line segment
+	segmentShape,
+
+	// A convex polygon
+	polygonShape,
+
+	// A smooth segment owned by a chain shape
+	smoothSegmentShape,
+}
+
+// The number of shape types
+shapeTypeCount :: len(ShapeType)
+
+// 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.
+// Must be initialized using b2DefaultShapeDef().
+// @ingroup shape
+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 density, usually in kg/m^2.
+	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.
+	isSensor: bool,
+
+	// Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	enableSensorEvents: bool,
+
+	// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	enableContactEvents: bool,
+
+	// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
+	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,
+
+	// 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.
+//	- chains are one-sided
+//	- chains have no mass and should be used on static bodies
+//	- chains have a counter-clockwise winding order
+//	- 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
+//	- 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
+// 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.
+// @ingroup shape
+ChainDef :: struct {
+	// Use this to store application specific shape data.
+	userData: rawptr,
+
+	// An array of at least 4 points. These are cloned and may be temporary.
+	points: [^]Vec2 `fmt:"v,count"`,
+
+	// The point count, must be 4 or more.
+	count: i32,
+
+	// The friction coefficient, usually in the range [0,1].
+	friction: f32,
+
+	// The restitution (elasticity) usually in the range [0,1].
+	restitution: f32,
+
+	// Contact filtering data.
+	filter: Filter,
+
+	// Indicates a closed chain formed by connecting the first and last points
+	isLoop: bool,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+//! @cond
+// Profiling data. Times are in milliseconds.
+Profile :: struct {
+	step:                f32,
+	pairs:               f32,
+	collide:             f32,
+	solve:               f32,
+	buildIslands:        f32,
+	solveConstraints:    f32,
+	prepareTasks:        f32,
+	solverTasks:         f32,
+	prepareConstraints:  f32,
+	integrateVelocities: f32,
+	warmStart:           f32,
+	solveVelocities:     f32,
+	integratePositions:  f32,
+	relaxVelocities:     f32,
+	applyRestitution:    f32,
+	storeImpulses:       f32,
+	finalizeBodies:      f32,
+	splitIslands:        f32,
+	sleepIslands:        f32,
+	hitEvents:           f32,
+	broadphase:          f32,
+	continuous:          f32,
+}
+
+// Counters that give details of the simulation size.
+Counters :: struct {
+	staticBodyCount:  i32,
+	bodyCount:        i32,
+	shapeCount:       i32,
+	contactCount:     i32,
+	jointCount:       i32,
+	islandCount:      i32,
+	stackUsed:        i32,
+	staticTreeHeight: i32,
+	treeHeight:       i32,
+	byteCount:        i32,
+	taskCount:        i32,
+	colorCounts:      [12]i32,
+}
+//! @endcond
+
+// Joint type enumeration
+//
+// This is useful because all joint types use b2JointId and sometimes you
+// want to get the type of a joint.
+// @ingroup joint
+JointType :: enum c.int {
+	distanceJoint,
+	motorJoint,
+	mouseJoint,
+	prismaticJoint,
+	revoluteJoint,
+	weldJoint,
+	wheelJoint,
+}
+
+// Distance joint definition
+//
+// This requires defining an anchor point on both
+// bodies and the non-zero distance of the distance joint. The definition uses
+// local anchor points so that the initial configuration can violate the
+// constraint slightly. This helps when saving and loading a game.
+// @ingroup distance_joint
+DistanceJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// The local anchor point relative to bodyA's origin
+	localAnchorA: Vec2,
+
+	// The local anchor point relative to bodyB's origin
+	localAnchorB: Vec2,
+
+	// The rest length of this joint. Clamped to a stable minimum value.
+	length: f32,
+
+	// Enable the distance constraint to behave like a spring. If false
+	//	then the distance joint will be rigid, overriding the limit and motor.
+	enableSpring: bool,
+
+	// The spring linear stiffness Hertz, cycles per second
+	hertz: f32,
+
+	// The spring linear damping ratio, non-dimensional
+	dampingRatio: f32,
+
+	// Enable/disable the joint limit
+	enableLimit: bool,
+
+	// Minimum length. Clamped to a stable minimum value.
+	minLength: f32,
+
+	// Maximum length. Must be greater than or equal to the minimum length.
+	maxLength: f32,
+
+	// Enable/disable the joint motor
+	enableMotor: bool,
+
+	// The maximum motor force, usually in newtons
+	maxMotorForce: f32,
+
+	// The desired motor speed, usually in meters per second
+	motorSpeed: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// A motor joint is used to control the relative motion between two bodies
+//
+// A typical usage is to control the movement of a dynamic body with respect to the ground.
+// @ingroup motor_joint
+MotorJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// Position of bodyB minus the position of bodyA, in bodyA's frame
+	linearOffset: Vec2,
+
+	// The bodyB angle minus bodyA angle in radians
+	angularOffset: f32,
+
+	// The maximum motor force in newtons
+	maxForce: f32,
+
+	// The maximum motor torque in newton-meters
+	maxTorque: f32,
+
+	// Position correction factor in the range [0,1]
+	correctionFactor: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// A mouse joint is used to make a point on a body track a specified world point.
+//
+// This a soft constraint and allows the constraint to stretch without
+// applying huge forces. This also applies rotation constraint heuristic to improve control.
+// @ingroup mouse_joint
+MouseJointDef :: struct {
+	// The first attached body.
+	bodyIdA: BodyId,
+
+	// The second attached body.
+	bodyIdB: BodyId,
+
+	// The initial target point in world space
+	target: Vec2,
+
+	// Stiffness in hertz
+	hertz: f32,
+
+	// Damping ratio, non-dimensional
+	dampingRatio: f32,
+
+	// Maximum force, typically in newtons
+	maxForce: f32,
+
+	// Set this flag to true if the attached bodies should collide.
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// Prismatic joint definition
+//
+// This requires defining a line of motion using an axis and an anchor point.
+// The definition uses local anchor points and a local axis so that the initial
+// configuration can violate the constraint slightly. The joint translation is zero
+// when the local anchor points coincide in world space.
+// @ingroup prismatic_joint
+PrismaticJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// The local anchor point relative to bodyA's origin
+	localAnchorA: Vec2,
+
+	// The local anchor point relative to bodyB's origin
+	localAnchorB: Vec2,
+
+	// The local translation unit axis in bodyA
+	localAxisA: Vec2,
+
+	// The constrained angle between the bodies: bodyB_angle - bodyA_angle
+	referenceAngle: f32,
+
+	// Enable a linear spring along the prismatic joint axis
+	enableSpring: bool,
+
+	// The spring stiffness Hertz, cycles per second
+	hertz: f32,
+
+	// The spring damping ratio, non-dimensional
+	dampingRatio: f32,
+
+	// Enable/disable the joint limit
+	enableLimit: bool,
+
+	// The lower translation limit
+	lowerTranslation: f32,
+
+	// The upper translation limit
+	upperTranslation: f32,
+
+	// Enable/disable the joint motor
+	enableMotor: bool,
+
+	// The maximum motor force, typically in newtons
+	maxMotorForce: f32,
+
+	// The desired motor speed, typically in meters per second
+	motorSpeed: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// Revolute joint definition
+//
+// This requires defining an anchor point where the bodies are joined.
+// The definition uses local anchor points so that the
+// initial configuration can violate the constraint slightly. You also need to
+// specify the initial relative angle for joint limits. This helps when saving
+// and loading a game.
+// The local anchor points are measured from the body's origin
+// rather than the center of mass because:
+// 1. you might not know where the center of mass will be
+// 2. if you add/remove shapes from a body and recompute the mass, the joints will be broken
+// @ingroup revolute_joint
+RevoluteJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// The local anchor point relative to bodyA's origin
+	localAnchorA: Vec2,
+
+	// The local anchor point relative to bodyB's origin
+	localAnchorB: Vec2,
+
+	// The bodyB angle minus bodyA angle in the reference state (radians).
+	// This defines the zero angle for the joint limit.
+	referenceAngle: f32,
+
+	// Enable a rotational spring on the revolute hinge axis
+	enableSpring: bool,
+
+	// The spring stiffness Hertz, cycles per second
+	hertz: f32,
+
+	// The spring damping ratio, non-dimensional
+	dampingRatio: f32,
+
+	// A flag to enable joint limits
+	enableLimit: bool,
+
+	// The lower angle for the joint limit in radians
+	lowerAngle: f32,
+
+	// The upper angle for the joint limit in radians
+	upperAngle: f32,
+
+	// A flag to enable the joint motor
+	enableMotor: bool,
+
+	// The maximum motor torque, typically in newton-meters
+	maxMotorTorque: f32,
+
+	// The desired motor speed in radians per second
+	motorSpeed: f32,
+
+	// Scale the debug draw
+	drawSize: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// Weld joint definition
+//
+// A weld joint connect to bodies together rigidly. This constraint provides springs to mimic
+//	soft-body simulation.
+// @note The approximate solver in Box2D cannot hold many bodies together rigidly
+// @ingroup weld_joint
+WeldJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// The local anchor point relative to bodyA's origin
+	localAnchorA: Vec2,
+
+	// The local anchor point relative to bodyB's origin
+	localAnchorB: Vec2,
+
+	// The bodyB angle minus bodyA angle in the reference state (radians)
+	referenceAngle: f32,
+
+	// Linear stiffness expressed as Hertz (cycles per second). Use zero for maximum stiffness.
+	linearHertz: f32,
+
+	// Angular stiffness as Hertz (cycles per second). Use zero for maximum stiffness.
+	angularHertz: f32,
+
+	// Linear damping ratio, non-dimensional. Use 1 for critical damping.
+	linearDampingRatio: f32,
+
+	// Linear damping ratio, non-dimensional. Use 1 for critical damping.
+	angularDampingRatio: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+// Wheel joint definition
+//
+// This requires defining a line of motion using an axis and an anchor point.
+// The definition uses local  anchor points and a local axis so that the initial
+// configuration can violate the constraint slightly. The joint translation is zero
+// when the local anchor points coincide in world space.
+// @ingroup wheel_joint
+WheelJointDef :: struct {
+	// The first attached body
+	bodyIdA: BodyId,
+
+	// The second attached body
+	bodyIdB: BodyId,
+
+	// The local anchor point relative to bodyA's origin
+	localAnchorA: Vec2,
+
+	// The local anchor point relative to bodyB's origin
+	localAnchorB: Vec2,
+
+	// The local translation unit axis in bodyA
+	localAxisA: Vec2,
+
+	// Enable a linear spring along the local axis
+	enableSpring: bool,
+
+	// Spring stiffness in Hertz
+	hertz: f32,
+
+	// Spring damping ratio, non-dimensional
+	dampingRatio: f32,
+
+	// Enable/disable the joint linear limit
+	enableLimit: bool,
+
+	// The lower translation limit
+	lowerTranslation: f32,
+
+	// The upper translation limit
+	upperTranslation: f32,
+
+	// Enable/disable the joint rotational motor
+	enableMotor: bool,
+
+	// The maximum motor torque, typically in newton-meters
+	maxMotorTorque: f32,
+
+	// The desired motor speed in radians per second
+	motorSpeed: f32,
+
+	// Set this flag to true if the attached bodies should collide
+	collideConnected: bool,
+
+	// User data pointer
+	userData: rawptr,
+
+	// Used internally to detect a valid definition. DO NOT SET.
+	internalValue: i32,
+}
+
+
+/**
+ * @defgroup events Events
+ * World event types.
+ *
+ * Events are used to collect events that occur during the world time step. These events
+ * are then available to query after the time step is complete. This is preferable to callbacks
+ * because Box2D uses multithreaded simulation.
+ *
+ * Also when events occur in the simulation step it may be problematic to modify the world, which is
+ * often what applications want to do when events occur.
+ *
+ * With event arrays, you can scan the events in a loop and modify the world. However, you need to be careful
+ * that some event data may become invalid. There are several samples that show how to do this safely.
+ *
+ * @{
+ */
+
+// A begin touch event is generated when a shape starts to overlap a sensor shape.
+SensorBeginTouchEvent :: struct {
+	// The id of the sensor shape
+	sensorShapeId: ShapeId,
+
+	// The id of the dynamic shape that began touching the sensor shape
+	visitorShapeId: ShapeId,
+}
+
+// An end touch event is generated when a shape stops overlapping a sensor shape.
+SensorEndTouchEvent :: struct {
+	// The id of the sensor shape
+	sensorShapeId: ShapeId,
+
+	// The id of the dynamic shape that stopped touching the sensor shape
+	visitorShapeId: ShapeId,
+}
+
+// Sensor events are buffered in the Box2D world and are available
+//	as begin/end overlap event arrays after the time step is complete.
+//	Note: these may become invalid if bodies and/or shapes are destroyed
+SensorEvents :: struct {
+	// Array of sensor begin touch events
+	beginEvents: [^]SensorBeginTouchEvent `fmt:"v,beginCount"`,
+
+	// Array of sensor end touch events
+	endEvents: [^]SensorEndTouchEvent `fmt:"v,endCount"`,
+
+	// The number of begin touch events
+	beginCount: i32,
+
+	// The number of end touch events
+	endCount: i32,
+}
+
+// A begin touch event is generated when two shapes begin touching.
+ContactBeginTouchEvent :: struct {
+	// Id of the first shape
+	shapeIdA: ShapeId,
+
+	// Id of the second shape
+	shapeIdB: ShapeId,
+}
+
+// An end touch event is generated when two shapes stop touching.
+ContactEndTouchEvent :: struct {
+	// Id of the first shape
+	shapeIdA: ShapeId,
+
+	// Id of the second shape
+	shapeIdB: ShapeId,
+}
+
+// A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold.
+ContactHitEvent :: struct {
+	// Id of the first shape
+	shapeIdA: ShapeId,
+
+	// Id of the second shape
+	shapeIdB: ShapeId,
+
+	// Point where the shapes hit
+	point: Vec2,
+
+	// Normal vector pointing from shape A to shape B
+	normal: Vec2,
+
+	// The speed the shapes are approaching. Always positive. Typically in meters per second.
+	approachSpeed: f32,
+}
+
+// Contact events are buffered in the Box2D world and are available
+//	as event arrays after the time step is complete.
+//	Note: these may become invalid if bodies and/or shapes are destroyed
+ContactEvents :: struct {
+	// Array of begin touch events
+	beginEvents: [^]ContactBeginTouchEvent `fmt:"v,beginCount"`,
+
+	// Array of end touch events
+	endEvents: [^]ContactEndTouchEvent `fmt:"v,endCount"`,
+
+	// Array of hit events
+	hitEvents: [^]ContactHitEvent `fmt:"v,hitCount"`,
+
+	// Number of begin touch events
+	beginCount: i32,
+
+	// Number of end touch events
+	endCount: i32,
+
+	// Number of hit events
+	hitCount: i32,
+}
+
+// Body move events triggered when a body moves.
+// Triggered when a body moves due to simulation. Not reported for bodies moved by the user.
+// This also has a flag to indicate that the body went to sleep so the application can also
+// sleep that actor/entity/object associated with the body.
+// On the other hand if the flag does not indicate the body went to sleep then the application
+// can treat the actor/entity/object associated with the body as awake.
+//	This is an efficient way for an application to update game object transforms rather than
+//	calling functions such as b2Body_GetTransform() because this data is delivered as a contiguous array
+//	and it is only populated with bodies that have moved.
+//	@note If sleeping is disabled all dynamic and kinematic bodies will trigger move events.
+BodyMoveEvent :: struct {
+	transform:  Transform,
+	bodyId:     BodyId,
+	userData:   rawptr,
+	fellAsleep: bool,
+}
+
+// Body events are buffered in the Box2D world and are available
+//	as event arrays after the time step is complete.
+//	Note: this date becomes invalid if bodies are destroyed
+BodyEvents :: struct {
+	// Array of move events
+	moveEvents: [^]BodyMoveEvent `fmt:"v,moveCount"`,
+
+	// Number of move events
+	moveCount: i32,
+
+}
+
+// The contact data for two shapes. By convention the manifold normal points
+//	from shape A to shape B.
+//	@see b2Shape_GetContactData() and b2Body_GetContactData()
+ContactData :: struct {
+	shapeIdA: ShapeId,
+	shapeIdB: ShapeId,
+	manifold: Manifold,
+}
+
+/**@}*/
+
+// Prototype for a contact filter callback.
+// This is called when a contact pair is considered for collision. This allows you to
+//	perform custom logic to prevent collision between shapes. This is only called if
+//	one of the two shapes has custom filtering enabled. @see b2ShapeDef.
+// Notes:
+//	- this function must be thread-safe
+//	- this is only called if one of the two shapes has enabled custom filtering
+// - this is called only for awake dynamic bodies
+//	Return false if you want to disable the collision
+//	@warning Do not attempt to modify the world inside this callback
+//	@ingroup world
+CustomFilterFcn :: #type proc "c" (shapeIdA, shapeIdB: ShapeId, ctx: rawptr) -> bool
+
+// Prototype for a pre-solve callback.
+// This is called after a contact is updated. This allows you to inspect a
+// contact before it goes to the solver. If you are careful, you can modify the
+// contact manifold (e.g. modify the normal).
+// Notes:
+//	- this function must be thread-safe
+//	- this is only called if the shape has enabled pre-solve events
+// - this is called only for awake dynamic bodies
+// - this is not called for sensors
+// - the supplied manifold has impulse values from the previous step
+//	Return false if you want to disable the contact this step
+//	@warning Do not attempt to modify the world inside this callback
+//	@ingroup world
+PreSolveFcn :: #type proc "c" (shapeIdA, shapeIdB: ShapeId, manifold: ^Manifold, ctx: rawptr) -> bool
+
+// Prototype callback for overlap queries.
+// Called for each shape found in the query.
+// @see b2World_QueryAABB
+// @return false to terminate the query.
+//	@ingroup world
+OverlapResultFcn :: #type proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool
+
+// Prototype callback for ray 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
+// @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 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
+//	@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
+HexColor :: enum c.int {
+	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,
+	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,
+	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,
+	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,
+	MidnightBlue         = 0x191970,
+	MintCream            = 0xf5fffa,
+	MistyRose            = 0xffe4e1,
+	Moccasin             = 0xffe4b5,
+	NavajoWhite          = 0xffdead,
+	Navy                 = 0x000080,
+	NavyBlue             = 0x000080,
+	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,
+	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,
+	SlateGray            = 0x708090,
+	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,
+}
+
+// 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),
+
+	// 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 ),
+
+	// Draw a circle.
+	DrawCircle: 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),
+
+	// Draw a solid capsule.
+	DrawSolidCapsule: 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),
+
+	// Draw a transform. Choose your own length scale.
+	DrawTransform: proc "c" (transform: Transform, ctx: rawptr),
+
+	// Draw a point.
+	DrawPoint: proc "c" (p: Vec2, size: f32, color: HexColor, ctx: rawptr),
+
+	// Draw a string.
+	DrawString: proc "c" (p: Vec2, s: cstring, ctx: rawptr),
+
+	// Bounds to use if restricting drawing to a rectangular region
+	drawingBounds: AABB,
+
+	// Option to restrict drawing to a rectangular region. May suffer from unstable depth sorting.
+	useDrawingBounds: bool,
+
+	// Option to draw shapes
+	drawShapes: bool,
+
+	// Option to draw joints
+	drawJoints: bool,
+
+	// Option to draw additional information for joints
+	drawJointExtras: bool,
+
+	// Option to draw the bounding boxes for shapes
+	drawAABBs: bool,
+
+	// Option to draw the mass and center of mass of dynamic bodies
+	drawMass: bool,
+
+	// Option to draw contact points
+	drawContacts: bool,
+
+	// Option to visualize the graph coloring used for contacts and joints
+	drawGraphColors: bool,
+
+	// Option to draw contact normals
+	drawContactNormals: bool,
+
+	// Option to draw contact normal impulses
+	drawContactImpulses: bool,
+
+	// Option to draw contact friction impulses
+	drawFrictionImpulses: bool,
+
+	// User context that is passed as an argument to drawing callback functions
+	userContext: rawptr,
+}