diff --git a/vendor/box3d/box3d.odin b/vendor/box3d/box3d.odin new file mode 100644 index 000000000..fe9f591af --- /dev/null +++ b/vendor/box3d/box3d.odin @@ -0,0 +1,1820 @@ +// Bindings for Box3D +package vendor_box3d + +import "base:intrinsics" +import "base:runtime" +import "core:c" + +ENABLE_VALIDATION :: false + +@(export) +foreign import lib { + "box3d.lib", +} + +// This is used to indicate null for interfaces that work with indices instead of pointers +NULL_INDEX :: -1 + +// 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 :: proc "c" (size, alignment: i32) -> rawptr + +// Prototype for user free function. +// @param mem the memory previously allocated through `AllocFcn` +FreeFcn :: proc "c" (mem: rawptr) + +// Prototype for the user assert callback. Return 0 to skip the debugger break. +AssertFcn :: proc "c" (condition: cstring, fileName: cstring, lineNumber: c.int) -> c.int + +// Prototype for user log callback. Used to log warnings. +LogFcn :: proc "c" (message: rawptr) + + +BREAKPOINT :: intrinsics.debug_trap + +@(link_prefix="b3", default_calling_convention="c", require_results) +foreign lib { + // This allows the user to override the allocation functions. These should be + // set during application startup. + SetAllocator :: proc(allocFcn: AllocFcn, freeFcn: FreeFcn) --- + + // Total bytes allocated by Box3D + GetByteCount :: proc() -> i32 --- + + // Override the default assert callback. + // @param assertFcn a non-null assert callback + SetAssertFcn :: proc(assertFcn: AssertFcn) --- + + // Internal assertion handler. Allows for host intervention. + InternalAssert :: proc(condition: cstring, fileName: cstring, lineNumber: c.int) -> c.int --- + + // Override the default logging callback. + SetLogFcn :: proc(logFcn: LogFcn) --- +} + +// Version numbering scheme. +// See https://semver.org/ +Version :: struct { + // Significant changes + major: c.int, + + // Incremental changes + minor: c.int, + + // Bug fixes + revision: c.int, +} + +HASH_INIT :: 5381 + +@(link_prefix="b3", default_calling_convention="c", require_results) +foreign lib { + // Get the current version of Box3D + GetVersion :: proc() -> Version --- + + // @return true if the library was built with BOX3D_DOUBLE_PRECISION (large world mode) + IsDoublePrecision :: proc() -> bool --- + + // Get the absolute number of system ticks. The value is platform specific. + GetTicks :: proc() -> u64 --- + + // Get the milliseconds passed from an initial tick value. + GetMilliseconds :: proc(ticks: u64) -> f32 --- + + // Get the milliseconds passed from an initial tick value. + GetMillisecondsAndReset :: proc(ticks: ^u64) -> f32 --- + + // Yield to be used in a busy loop. + Yield :: proc() --- + + // Sleep the current thread for a number of milliseconds. + Sleep :: proc(milliseconds: c.int) --- + + // Simple djb2 hash function for determinism testing + Hash :: proc(hash: u32, data: [^]u8, count: c.int) -> u32 --- + + // Dump file support functions + WriteBinaryFile :: proc(data: rawptr, size: c.int, fileName: cstring) --- + ReadBinaryFile :: proc(prefix: cstring, fileName: cstring, memSize: ^c.int) -> rawptr --- +} + + +@(disabled=ODIN_DISABLE_ASSERT) +ASSERT :: proc "c" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { + if !condition { + @(cold) + internal :: proc "c" (message: string, loc: runtime.Source_Code_Location) { + _ = InternalAssert(cstring(raw_data(message)), cstring(raw_data(loc.file_path)), loc.line) + } + internal(message, loc) + } +} + +@(disabled=!ENABLE_VALIDATION) +VALIDATE :: proc "c" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { + ASSERT(condition, message, loc) +} + + + +/** + * @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 the 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/ + * @{ + */ + + // Opaque recording handle. Create with CreateRecording, destroy with DestroyRecording. +Recording :: struct{} + + +// Opaque incremental replay player with a keyframe ring for O(interval) backward seek. +RecPlayer :: struct{} + +// Summary of a recording, read once at open so a viewer can frame and label it. +RecPlayerInfo :: struct { + frameCount: c.int, // total recorded steps + workerCount: c.int, // worker count requested for the replay world + timeStep: f32, // dt of the recorded steps + subStepCount: c.int, // recorded sub-steps + lengthScale: f32, // length units per meter in effect when recorded + bounds: AABB, // accumulated world bounds over the recording, zero-extent if unavailable +} + +// The kind of a recorded spatial query, matching the public query and cast functions. +RecQueryType :: enum c.int { + OverlapAABB, + OverlapShape, + CastRay, + CastShape, + CastRayClosest, + CastMover, + CollideMover, +} + +// A spatial query recorded during a replayed frame, exposed for inspection. +RecQueryInfo :: struct { + type: RecQueryType, + filter: QueryFilter, + aabb: AABB, // world-space bounds of the query, swept for casts + origin: Pos, // query origin (zero for overlap AABB) + translation: Vec3, // ray and cast translation + hitCount: c.int, // number of recorded results + key: u64, // identity key, the hash of (id, name), 0 if untagged + id: u64, // query id, 0 if none + name: cstring, // query label, NULL if none +} + +// One result of a recorded spatial query. +RecQueryHit :: struct { + shape: ShapeId, + point: Pos, + normal: Vec3, + fraction: f32, +} + + +@(link_prefix="b3", default_calling_convention="c", require_results) +foreign lib { + // Create a world for rigid body simulation. A world contains bodies, shapes, and constraints. You may 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) --- + + // Get the current number of worlds + GetWorldCount :: proc() -> c.int --- + + // Get the maximum number of simultaneous worlds that have been created + GetMaxWorldCount :: proc() -> c.int --- + + // 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. Usually 1/60. + // @param subStepCount The number of sub-steps, increasing the sub-step count can increase accuracy. Usually 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, maskBits: u64) --- + + // Get the world's bounds. This is the bounding box that covers the current simulation. May have a small + // amount of padding. + World_GetBounds :: proc(worldId: WorldId) -> AABB --- + + // 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 --- + + // Get the joint events for the current time step. The event data is transient. Do not store a reference to this data. + World_GetJointEvents :: proc(worldId: WorldId) -> JointEvents --- + + // Overlap test for all shapes that *potentially* overlap the provided AABB + World_OverlapAABB :: proc(worldId: WorldId, aabb: AABB, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) -> TreeStats --- + + // Overlap test for all shapes that overlap the provided shape proxy. The proxy points are relative + // to the world origin, which lets the query stay precise far from the world origin. + World_OverlapShape :: proc(worldId: WorldId, origin: Pos, #by_ptr proxy: ShapeProxy, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) -> TreeStats --- + + // 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. + // @note The callback function may receive shapes in any order + // @param worldId The world to cast the ray against + // @param origin The start point of the ray + // @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 + // @return traversal performance counters + World_CastRay :: proc(worldId: WorldId, origin: Pos, translation: Vec3, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats --- + + // Cast a ray into the world to collect the closest hit. This is a convenience function. Ignores initial overlap. + // This is less general than World_CastRay() and does not allow for custom filtering. + World_CastRayClosest :: proc(worldId: WorldId, origin: Pos, translation: Vec3, filter: QueryFilter) -> RayResult --- + + // Cast a shape through the world. Similar to a cast ray except that a shape is cast instead of a point. + // The proxy points are relative to the origin and the hit points come back as world positions, so the + // cast stays precise far from the world origin. + // @see World_CastRay + World_CastShape :: proc(worldId: WorldId, origin: Pos, #by_ptr proxy: ShapeProxy, translation: Vec3, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats --- + + // Cast a capsule mover through the world. This is a special shape cast that handles sliding along other shapes while reducing + // clipping. This is not a good source of information about what the mover is touching. Instead use the planes returned by + // World_CollideMover. + // @param worldId World to cast the mover against + // @param origin World position the mover capsule is relative to + // @param mover Capsule mover, relative to the origin + // @param translation Desired mover translation + // @param filter Contains bit flags to filter unwanted shapes from the results + // @param fcn Optional callback for custom shape filtering + // @param context A user context that is passed along to the callback function + // @return the translation fraction + World_CastMover :: proc(worldId: WorldId, origin: Pos, #by_ptr mover: Capsule, translation: Vec3, filter: QueryFilter, fcn: MoverFilterFcn, ctx: rawptr) -> f32 --- + + // Collide a capsule mover with the world, gathering collision planes that can be fed to SolvePlanes. Useful for + // kinematic character movement. The mover and the returned planes are relative to the origin. + World_CollideMover :: proc(worldId: WorldId, origin: Pos, #by_ptr mover: Capsule, filter: QueryFilter, fcn: PlaneResultFcn, 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) --- + + // Is body sleeping enabled? + World_IsSleepingEnabled :: proc(worldId: WorldId) -> 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) --- + + // Is continuous collision enabled? + World_IsContinuousEnabled :: proc(worldId: WorldId) -> bool --- + + // Adjust the restitution threshold. It is recommended not to make this value very small + // because it will prevent bodies from sleeping. Usually in meters per second. + // @see WorldDef + World_SetRestitutionThreshold :: proc(worldId: WorldId, value: f32) --- + + // Get the restitution speed threshold. Usually in meters per second. + World_GetRestitutionThreshold :: proc(worldId: WorldId) -> f32 --- + + // Adjust the hit event threshold. This controls the collision speed needed to generate a ContactHitEvent. + // Usually in meters per second. + // @see WorldDef::hitEventThreshold + World_SetHitEventThreshold :: proc(worldId: WorldId, value: f32) --- + + // Get the hit event speed threshold. Usually in meters per second. + World_GetHitEventThreshold :: proc(worldId: WorldId) -> 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. Box3D has no concept of an up direction and this + // is left as a decision for the application. Usually in m/s^2. + // @see WorldDef + World_SetGravity :: proc(worldId: WorldId, gravity: Vec3) --- + + // Get the gravity vector + World_GetGravity :: proc(worldId: WorldId) -> Vec3 --- + + // Apply a radial explosion + // @param worldId The world id + // @param explosionDef The explosion definition + World_Explode :: proc(worldId: WorldId, #by_ptr explosionDef: ExplosionDef) --- + + // 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 contactSpeed The maximum contact constraint push out speed (meters per second) + // @note Advanced feature + World_SetContactTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, contactSpeed: f32) --- + + // Set the contact point recycling distance. Setting this to zero disables contact point recycling. + // Usually in meters. + World_SetContactRecycleDistance :: proc(worldId: WorldId, recycleDistance: f32) --- + + // Get the contact point recycling distance. Usually in meters. + World_GetContactRecycleDistance :: proc(worldId: WorldId) -> f32 --- + + // Set the maximum linear speed. Usually in m/s. + World_SetMaximumLinearSpeed :: proc(worldId: WorldId, maximumLinearSpeed: f32) --- + + // Get the maximum linear speed. Usually in m/s. + World_GetMaximumLinearSpeed :: proc(worldId: WorldId) -> f32 --- + + // Enable/disable constraint warm starting. Advanced feature for testing. Disabling + // warm starting greatly reduces stability and provides no performance gain. + World_EnableWarmStarting :: proc(worldId: WorldId, flag: bool) --- + + // Is constraint warm starting enabled? + World_IsWarmStartingEnabled :: proc(worldId: WorldId) -> bool --- + + // Get the number of awake bodies + World_GetAwakeBodyCount :: proc(worldId: WorldId) -> c.int --- + + // Get the current world performance profile + World_GetProfile :: proc(worldId: WorldId) -> Profile --- + + // Get world counters and sizes + World_GetCounters :: proc(worldId: WorldId) -> Counters --- + + // Get max capacity. This can be used with WorldDef to avoid run-time allocations and copies + World_GetMaxCapacity :: proc(worldId: WorldId) -> Capacity --- + + // Set the user data pointer. + World_SetUserData :: proc(worldId: WorldId, userData: rawptr) --- + + // Get the user data pointer. + World_GetUserData :: proc(worldId: WorldId) --- + + // Set the friction callback. Passing NULL resets to default. + World_SetFrictionCallback :: proc(worldId: WorldId, callback: FrictionCallback) --- + + // Set the restitution callback. Passing NULL resets to default. + World_SetRestitutionCallback :: proc(worldId: WorldId, callback: RestitutionCallback) --- + + // Set the worker count. Must be in the range [1, B3_MAX_WORKERS] + World_SetWorkerCount :: proc(worldId: WorldId, count: c.int) --- + + // Get the worker count. + World_GetWorkerCount :: proc(worldId: WorldId) -> c.int --- + + // Dump memory stats to log. + World_DumpMemoryStats :: proc(worldId: WorldId) --- + + // Dump shape bounds to box3d_bounds.txt + World_DumpShapeBounds :: proc(worldId: WorldId, type: BodyType) --- + + // This is for internal testing + World_RebuildStaticTree :: proc(worldId: WorldId) --- + + // This is for internal testing + World_EnableSpeculative :: proc(worldId: WorldId, flag: bool) --- + + // Dump world to a text file. Saves only awake bodies and associated static bodies. + // Meshes are saved to binary m files. + World_DumpAwake :: proc(worldId: WorldId) --- + + // Dump world to a text file. Meshes are saved to binary m files. + World_Dump :: proc(worldId: WorldId) --- + + /** + * @defgroup recording Recording + * @brief Record and replay world state for debugging. + * @{ + */ + + // Create a recording buffer with an optional initial byte capacity. + // Pass 0 to use the default (64 KiB). The buffer grows on demand. + // @return a new recording, owned by the caller + CreateRecording :: proc(byteCapacity: c.int) -> Recording --- + + // Destroy a recording and free its buffer. + // @param recording may be NULL + DestroyRecording :: proc(recording: ^Recording) --- + + // Get a pointer to the raw recording bytes. + // Valid until the recording buffer is modified or destroyed. + // @param recording the recording handle + // @return pointer to the byte buffer, or NULL if no bytes have been written + Recording_GetData :: proc(#by_ptr recording: Recording) -> [^]u8 --- + + // Get the number of bytes currently in the recording buffer. + // @param recording the recording handle + Recording_GetSize :: proc(#by_ptr recording: Recording) -> c.int --- + + // Begin recording world mutations into the provided buffer. + // The buffer is reset on each call so a single Recording can be reused for multiple sessions. + // @param worldId the world to record + // @param recording the recording handle to write into + World_StartRecording :: proc(worldId: WorldId, recording: ^Recording) --- + + // End the current recording session. Writes the trailing geometry registry and + // backpatches the header. The buffer remains valid until the recording is destroyed. + // @param worldId the world currently being recorded + World_StopRecording :: proc(worldId: WorldId) --- + + // Save the recording buffer to a file. Returns true on success. + // @param recording the recording to save + // @param path file path to write + SaveRecordingToFile :: proc(#by_ptr recording: Recording, path: cstring) -> bool --- + + // Load a recording from a file. Returns NULL on failure (file not found, wrong magic). + // The caller owns the returned recording and must destroy it with DestroyRecording. + // @param path file path to read + LoadRecordingFromFile :: proc(path: cstring) -> Recording --- + + // Replay a recording from memory and verify it reproduces the same world-state hashes. + // Stands up a fresh world, restores the seed snapshot, replays every op, and checks each embedded + // StateHash record. Returns true if replay completed without id mismatches or hash divergences. + // @param data pointer to recording bytes + // @param size byte count of the recording + // @param workerCount reserved for future multithreaded replay; pass 1 for now + ValidateReplay :: proc(data: rawptr, size: c.int, workerCount: c.int) -> bool --- + + + // Create a player over a recording. Owns a private copy of the bytes. + // @param data pointer to recording bytes + // @param size byte count of the recording + // @param workerCount worker count for the replay world; pass 1 to match a serial recording. + // Replaying at a different count re-partitions the constraint graph, so the StateHash check + // becomes a cross-thread determinism test. Adjustable later with RecPlayer_SetWorkerCount. + // @return a new player, or NULL on bad header or deserialization failure + RecPlayer_Create :: proc(data: rawptr, size: c.int, workerCount: c.int) -> RecPlayer --- + + // Destroy the player and free all memory. Restores the previous global length scale. + RecPlayer_Destroy :: proc(player: ^RecPlayer) --- + + // Advance one frame: dispatch ops until the next Step completes. + // @return true when a frame was stepped, false at end-of-recording + RecPlayer_StepFrame :: proc(player: ^RecPlayer) -> bool --- + + // Rewind to frame 0 (in-place restore so the world id stays stable). + RecPlayer_Restart :: proc(player: ^RecPlayer) --- + + // Seek to a specific frame. Forward seek steps op-by-op; backward seek restores + // the nearest keyframe then re-steps the remaining gap. + RecPlayer_SeekFrame :: proc(player: ^RecPlayer, targetFrame: c.int) --- + + // @return the world currently driven by this player + RecPlayer_GetWorldId :: proc(#by_ptr player: RecPlayer) -> WorldId --- + + // @return the last fully-stepped frame index (0 before any step) + RecPlayer_GetFrame :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // @return total number of recorded frames + RecPlayer_GetFrameCount :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // @return true when the op stream is exhausted + RecPlayer_IsAtEnd :: proc(#by_ptr player: RecPlayer) -> bool --- + + // @return true when any StateHash mismatch has been detected + RecPlayer_HasDiverged :: proc(#by_ptr player: RecPlayer) -> bool --- + + // @return a summary of the recording read at open: frame count, recorded tuning, and bounds + RecPlayer_GetInfo :: proc(#by_ptr player: RecPlayer) -> RecPlayerInfo --- + + // @return the first frame at which replay diverged, or -1 if it has not diverged + RecPlayer_GetDivergeFrame :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // Set the worker count of the replay world. Clamped to [1, B3_MAX_WORKERS]. Applied to the live + // world at once and reused whenever the player rebuilds its world on Restart or a backward seek. + // Replaying at a different count than recorded re-partitions the constraint graph, so the StateHash + // check becomes a cross-thread determinism test. + RecPlayer_SetWorkerCount :: proc(player: ^RecPlayer, count: c.int) --- + + // Tune the keyframe ring used to speed up backward seeking. A keyframe is a periodic snapshot the + // player restores from instead of replaying from the start, trading memory for seek speed. + // @param player the recording player + // @param budgetBytes memory cap for the kept snapshots; the spacing widens to stay under it + // @param minIntervalFrames finest spacing between keyframes, in frames + // A zero budget or a non-positive interval keeps that value. Clears the existing ring, so call + // RecPlayer_Restart afterward to repopulate it under the new policy. + RecPlayer_SetKeyframePolicy :: proc(player: ^RecPlayer, budgetBytes: uint, minIntervalFrames: c.int) --- + + // @return the keyframe memory budget in bytes + RecPlayer_GetKeyframeBudget :: proc(#by_ptr player: RecPlayer) -> uint --- + + // @return the finest keyframe spacing in frames + RecPlayer_GetKeyframeMinInterval :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // @return the current keyframe spacing in frames; starts at the min interval and doubles as the + // ring evicts to stay under budget, so it reflects the effective backward-seek granularity now + RecPlayer_GetKeyframeInterval :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // @return the memory currently held by keyframe snapshots, in bytes + RecPlayer_GetKeyframeBytes :: proc(#by_ptr player: RecPlayer) -> uint --- + + // @return the number of bodies tracked in creation order (including holes for destroyed bodies) + RecPlayer_GetBodyCount :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // Resolve a creation ordinal to the live body id at the current frame. + // @return the body id, or a null id if that ordinal is out of range or its body is destroyed + RecPlayer_GetBodyId :: proc(#by_ptr player: RecPlayer, index: c.int) -> BodyId --- + + // Wire host debug-shape callbacks into the player's replay world so a renderer can build + // per-shape draw resources (the 3D sample needs this or the replay world draws nothing). + // Rebuilds the current world under the new callbacks and rewinds to frame 0, so call it + // once right after RecPlayer_Create and re-read the world id afterward. The callbacks + // persist across Restart and backward seeks, which recreate the world internally. + // @param player the player to configure + // @param createDebugShape called when a replayed shape is added; returns a user draw handle + // @param destroyDebugShape called when a replayed shape is removed; may be NULL + // @param context user context passed to both callbacks + RecPlayer_SetDebugShapeCallbacks :: proc(player: ^RecPlayer, createDebugShape: CreateDebugShapeCallback, destroyDebugShape: DestroyDebugShapeCallback, ctx: rawptr) --- + + // Draw the spatial queries recorded during the most recently replayed frame, layered on top of the + // world. Call after World_Draw. NULL draw function pointers are skipped. + // @param player a valid player handle + // @param draw debug draw callbacks + // @param queryIndex index of the frame query to draw, or -1 to draw all of them + // @param selectedIndex index of the query to emphasize (reserved color plus a label), or -1 for none + RecPlayer_DrawFrameQueries :: proc(player: ^RecPlayer, draw: ^DebugDraw, queryIndex: c.int, selectedIndex: c.int) --- + + + // @return the number of spatial queries recorded for the most recently replayed frame + RecPlayer_GetFrameQueryCount :: proc(#by_ptr player: RecPlayer) -> c.int --- + + // Get a recorded query from the most recently replayed frame by index. + RecPlayer_GetFrameQuery :: proc(#by_ptr player: RecPlayer, index: c.int) -> RecQueryInfo --- + + // Get one result of a recorded query from the most recently replayed frame. + RecPlayer_GetFrameQueryHit :: proc(#by_ptr player: RecPlayer, queryIndex: c.int, hitIndex: c.int) -> RecQueryHit --- + + /**@}*/ // recording + + /** @} */ // world + + /** + * @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{.c} + // BodyDef bodyDef = DefaultBodyDef(); + // BodyId myBodyId = CreateBody(myWorldId, &bodyDef); + // @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. A valid body exists in a world and is non-null. + // This 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 body name. Up to B3_BODY_NAME_LENGTH characters including null termination. + Body_SetName :: proc(bodyId: BodyId, name: cstring) --- + + // Get the body name. + Body_GetName :: proc(bodyId: BodyId) -> cstring --- + + // 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) --- + + // Get the world position of a body. This is the location of the body origin. + Body_GetPosition :: proc(bodyId: BodyId) -> Pos --- + + // Get the world rotation of a body as a quaternion + Body_GetRotation :: proc(bodyId: BodyId) -> Quat --- + + // Get the world transform of a body. + Body_GetTransform :: proc(bodyId: BodyId) -> WorldTransform --- + + // Set the world transform of a body. This acts as a teleport and is fairly expensive. + // @note Generally you should create a body with the intended transform. + // @see BodyDef::position and BodyDef::rotation + Body_SetTransform :: proc(bodyId: BodyId, position: Pos, rotation: Quat) --- + + // Get a local point on a body given a world point + Body_GetLocalPoint :: proc(bodyId: BodyId, worldPoint: Pos) -> Vec3 --- + + // Get a world point on a body given a local point + Body_GetWorldPoint :: proc(bodyId: BodyId, localPoint: Vec3) -> Pos --- + + // Get a local vector on a body given a world vector + Body_GetLocalVector :: proc(bodyId: BodyId, worldVector: Vec3) -> Vec3 --- + + // Get a world vector on a body given a local vector + Body_GetWorldVector :: proc(bodyId: BodyId, localVector: Vec3) -> Vec3 --- + + // Get the linear velocity of a body's center of mass. Usually in meters per second. + Body_GetLinearVelocity :: proc(bodyId: BodyId) -> Vec3 --- + + // Get the angular velocity of a body in radians per second + Body_GetAngularVelocity :: proc(bodyId: BodyId) -> Vec3 --- + + // Set the linear velocity of a body. Usually in meters per second. + Body_SetLinearVelocity :: proc(bodyId: BodyId, linearVelocity: Vec3) --- + + // Set the angular velocity of a body in radians per second + Body_SetAngularVelocity :: proc(bodyId: BodyId, angularVelocity: Vec3) --- + + // Set the velocity to reach the given transform after a given time step. + // The result will be close but maybe not exact. This is meant for kinematic bodies. + // The target is not applied if the velocity would be below the sleep threshold. + // This will optionally wake the body if asleep, but only if the movement is significant. + Body_SetTargetTransform :: proc(bodyId: BodyId, target: WorldTransform, timeStep: f32, wake: bool) --- + + // Get the linear velocity of a local point attached to a body. Usually in meters per second. + Body_GetLocalPointVelocity :: proc(bodyId: BodyId, localPoint: Vec3) -> Vec3 --- + + // Get the linear velocity of a world point attached to a body. Usually in meters per second. + Body_GetWorldPointVelocity :: proc(bodyId: BodyId, worldPoint: Pos) -> Vec3 --- + + // 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, usually 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: Vec3, point: Pos, 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: Vec3, 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 the world torque vector, usually in N*m. + // @param wake also wake up the body + Body_ApplyTorque :: proc(bodyId: BodyId, torque: Vec3, 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, usually 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: Vec3, point: Pos, 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, usually 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: Vec3, wake: bool) --- + + // Apply an angular impulse in world space. The impulse is ignored if the body is not awake. + // This optionally wakes the body. + // @param bodyId The body id + // @param impulse the world angular impulse vector, usually 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 torque, + // use a torque instead, which will work better with the sub-stepping solver. + Body_ApplyAngularImpulse :: proc(bodyId: BodyId, impulse: Vec3, wake: bool) --- + + // Get the mass of the body, usually in kilograms + Body_GetMass :: proc(bodyId: BodyId) -> f32 --- + + // Get the rotational inertia of the body in local space, usually in kg*m^2 + Body_GetLocalRotationalInertia :: proc(bodyId: BodyId) -> Matrix3 --- + + // Get the inverse mass of the body, usually in 1/kilograms + Body_GetInverseMass :: proc(bodyId: BodyId) -> f32 --- + + // Get the inverse rotational inertia of the body in world space, usually in 1/kg*m^2 + Body_GetWorldInverseRotationalInertia :: proc(bodyId: BodyId) -> Matrix3 --- + + // Get the center of mass position of the body in local space + Body_GetLocalCenterOfMass :: proc(bodyId: BodyId) -> Vec3 --- + + // Get the center of mass position of the body in world space + Body_GetWorldCenterOfMass :: proc(bodyId: BodyId) -> Pos --- + + // 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 updates 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) --- + + // 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, usually in meters per second + Body_SetSleepThreshold :: proc(bodyId: BodyId, sleepThreshold: f32) --- + + // Get the sleep threshold, usually 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 the motion locks on this body. + Body_SetMotionLocks :: proc(bodyId: BodyId, locks: MotionLocks) --- + + // Get the motion locks for this body. + Body_GetMotionLocks :: proc(bodyId: BodyId) -> MotionLocks --- + + // 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 or disable contact recycling for this body. Contact recycling is a performance optimization + // that reuses contact manifolds when bodies move slightly. Disabling it can avoid ghost collisions + // on characters at the cost of higher per-step work. Existing contacts retain their prior setting; + // only contacts created after this call see the new value. + // @see BodyDef::enableContactRecycling + Body_EnableContactRecycling :: proc(bodyId: BodyId, flag: bool) --- + + // Is contact recycling enabled on this body? + Body_IsContactRecyclingEnabled :: proc(bodyId: BodyId) -> bool --- + + // Enable/disable hit events on all shapes + // @see ShapeDef::enableHitEvents + Body_EnableHitEvents :: proc(bodyId: BodyId, enableHitEvents: bool) --- + + // Get the world that owns this body + Body_GetWorld :: proc(bodyId: BodyId) -> WorldId --- + + // Get the number of shapes on this body + Body_GetShapeCount :: proc(bodyId: BodyId) -> c.int --- + + // 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(bodyId: BodyId, shapeArray: [^]ShapeId, capacity: c.int) -> c.int --- + + // Get the number of joints on this body + Body_GetJointCount :: proc(bodyId: BodyId) -> c.int --- + + // 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(bodyId: BodyId, jointArray: [^]JointId, capacity: c.int) -> 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 touching contact data for a body + Body_GetContactData :: proc(bodyId: BodyId, contactData: [^]ContactData, capacity: c.int) -> 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 closest point on a body to a world target. + Body_GetClosestPoint :: proc(bodyId: BodyId, result: ^Vec3, target: Vec3) -> f32 --- + + // Cast a ray at a specific body using a specified body transform. + Body_CastRay :: proc(bodyId: BodyId, origin: Pos, translation: Vec3, filter: QueryFilter, maxFraction: f32, bodyTransform: WorldTransform) -> BodyCastResult --- + + // Cast a shape at a specific body using a specified body transform. + Body_CastShape :: proc(bodyId: BodyId, origin: Pos, #by_ptr proxy: ShapeProxy, translation: Vec3, filter: QueryFilter, maxFraction: f32, canEncroach: b32, bodyTransform: WorldTransform) -> BodyCastResult --- + + // Overlap a shape with a specific body using a specified body transform. + Body_OverlapShape :: proc(bodyId: BodyId, origin: Pos, #by_ptr proxy: ShapeProxy, filter: QueryFilter, bodyTransform: WorldTransform) -> bool --- + + // Collide a character mover with a specific body using a specified body transform. + Body_CollideMover :: proc(bodyId: BodyId, bodyPlanes: [^]BodyPlaneResult, planeCapacity: c.int, origin: Pos, #by_ptr mover: Capsule, filter: QueryFilter, bodyTransform: WorldTransform) -> c.int --- + + /** @} */ // body + + /** + * @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 + CreateSphereShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr sphere: Sphere) -> 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 convex hull shape and attach it to a body. The shape definition is fully cloned. Contacts are not created + // until the next time step. + // @return the shape id for accessing the shape + CreateHullShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr hull: HullData) -> ShapeId --- + + // Create a convex hull shape and attach it to a body. The hull is cloned then transformed with scale applied first. + // Use this for non-uniform or mirrored scale or a baked local transform. The baked result is shared through the + // world hull database. 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 + CreateTransformedHullShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr hull: HullData, transform: Transform, scale: Vec3) -> ShapeId --- + + // Create a mesh hull shape and attach it to a body. The shape definition is fully cloned but the mesh is not. + // Contacts are not created until the next time step. + // Mesh collision only creates contacts on static bodies. + // @warning this holds reference to the input mesh data which must remain valid for the lifetime of this shape + // @return the shape id for accessing the shape + CreateMeshShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr mesh: MeshData, scale: Vec3) -> ShapeId --- + + // Create a height-field shape and attach it to a body. The shape definition is fully cloned but the height field is not. + // Contacts are not created until the next time step. + // Height field is only allowed on static bodies. + // @warning this holds reference to the input height field which must remain valid for the lifetime of this shape + // @return the shape id for accessing the shape + CreateHeightFieldShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr heightField: HeightFieldData) -> ShapeId --- + + // Compound shapes are only allowed on static bodies. + CreateCompoundShape :: proc(bodyId: BodyId, def: ^ShapeDef, #by_ptr compound: CompoundData) -> ShapeId --- + + // Destroy a shape. You may defer the body mass update which can improve performance if several shapes on a + // body are destroyed at once. + // @see Body_ApplyMassFromShapes + DestroyShape :: proc(shapeId: ShapeId, updateBodyMass: bool) --- + + // 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 --- + + // Get the world that owns this shape + Shape_GetWorld :: proc(shapeId: ShapeId) -> WorldId --- + + // 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) --- + + // Set the mass density of a shape, usually in kg/m^3. + // This will optionally update the mass properties on the parent body. + // @see ShapeDef::density, Body_ApplyMassFromShapes + Shape_SetDensity :: proc(shapeId: ShapeId, density: f32, updateBodyMass: bool) --- + + // Get the density of a shape, usually in kg/m^3 + Shape_GetDensity :: proc(shapeId: ShapeId) -> f32 --- + + // Set the friction on a shape + Shape_SetFriction :: proc(shapeId: ShapeId, friction: f32) --- + + // Get the friction of a shape + Shape_GetFriction :: proc(shapeId: ShapeId) -> f32 --- + + // Set the shape restitution (bounciness) + Shape_SetRestitution :: proc(shapeId: ShapeId, restitution: f32) --- + + // Get the shape restitution + Shape_GetRestitution :: proc(shapeId: ShapeId) -> f32 --- + + // Set the shape base surface material. Does not change per triangle materials. + Shape_SetSurfaceMaterial :: proc(shapeId: ShapeId, surfaceMaterial: SurfaceMaterial) --- + + // Get the base shape surface material. + Shape_GetSurfaceMaterial :: proc(shapeId: ShapeId) -> SurfaceMaterial --- + + // Get the number of mesh surface materials. + Shape_GetMeshMaterialCount :: proc(shapeId: ShapeId) -> c.int --- + + // Set a surface material for a mesh shape. + Shape_SetMeshMaterial :: proc(shapeId: ShapeId, surfaceMaterial: SurfaceMaterial, index: c.int) --- + + // Get a surface material for a mesh shape + Shape_GetMeshSurfaceMaterial :: proc(shapeId: ShapeId, index: c.int) -> SurfaceMaterial --- + + // Get the shape filter + Shape_GetFilter :: proc(shapeId: ShapeId) -> Filter --- + + // Set the current filter. This is almost as expensive as recreating the shape. + // @see ShapeDef::filter + // @param shapeId the shape + // @param filter the new filter + // @param invokeContacts if true then the shape will have all contacts recomputed the next time step (expensive) + Shape_SetFilter :: proc(shapeId: ShapeId, filter: Filter, invokeContacts: bool) --- + + // Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. + // @see ShapeDef::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 ShapeDef::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 PreSolveFcn + 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 --- + + // Ray cast a shape directly. The ray runs from origin to origin + translation and the hit point + // comes back as a world position, so the cast stays precise far from the world origin. + Shape_RayCast :: proc(shapeId: ShapeId, origin: Pos, translation: Vec3) -> WorldCastOutput --- + + // Get a copy of the shape's sphere. Asserts the type is correct. + Shape_GetSphere :: proc(shapeId: ShapeId) -> Sphere --- + + // Get a copy of the shape's capsule. Asserts the type is correct. + Shape_GetCapsule :: proc(shapeId: ShapeId) -> Capsule --- + + // Get the shape's convex hull. Asserts the type is correct. + Shape_GetHull :: proc(shapeId: ShapeId) -> ^HullData --- + + // Get the shape's mesh. Asserts the type is correct. + Shape_GetMesh :: proc(shapeId: ShapeId) -> Mesh --- + + // Get the shape's height field. Asserts the type is correct. + Shape_GetHeightField :: proc(shapeId: ShapeId) -> ^HeightFieldData --- + + // Allows you to change a shape to be a sphere or update the current sphere. + // This does not modify the mass properties. + // @see Body_ApplyMassFromShapes + Shape_SetSphere :: proc(shapeId: ShapeId, #by_ptr sphere: Sphere) --- + + // Allows you to change a shape to be a capsule or update the current capsule. + // This does not modify the mass properties. + // @see Body_ApplyMassFromShapes + Shape_SetCapsule :: proc(shapeId: ShapeId, #by_ptr capsule: Capsule) --- + + // Allows you to change a shape to be a hull or update the current hull. + // This does not modify the mass properties. + // @see Body_ApplyMassFromShapes + Shape_SetHull :: proc(shapeId: ShapeId, #by_ptr hull: HullData) --- + + // Allows you to change a shape to be a mesh or update the current mesh. + // This does not modify the mass properties. + // @see Body_ApplyMassFromShapes + Shape_SetMesh :: proc(shapeId: ShapeId, #by_ptr meshData: MeshData, scale: Vec3) --- + + // Get the maximum capacity required for retrieving all the touching contacts on a shape + Shape_GetContactCapacity :: proc(shapeId: ShapeId) -> c.int --- + + // Get the touching contact data for a shape. The provided shapeId will be either shapeIdA or shapeIdB on the contact data. + // @note Box3D uses speculative collision so some contact points may be separated. + // @returns the number of elements filled in the provided array + // @warning do not ignore the return value, it specifies the valid number of elements + Shape_GetContactData :: proc(shapeId: ShapeId, contactData: [^]ContactData, capacity: c.int) -> c.int --- + + // Get the maximum capacity required for retrieving all the overlapped shapes on a sensor shape. + // This returns 0 if the provided shape is not a sensor. + // @param shapeId the id of a sensor shape + // @returns the required capacity to get all the overlaps in Shape_GetSensorOverlaps + Shape_GetSensorCapacity :: proc(shapeId: ShapeId) -> c.int --- + + // Get the overlap data for a sensor shape. + // @param shapeId the id of a sensor shape + // @param visitorIds a user allocated array that is filled with the overlapping shapes (visitors) + // @param capacity the capacity of overlappedShapes + // @returns the number of elements filled in the provided array + // @warning do not ignore the return value, it specifies the valid number of elements + // @warning overlaps may contain destroyed shapes so use Shape_IsValid to confirm each overlap + Shape_GetSensorData :: proc(shapeId: ShapeId, visitorIds: [^]ShapeId, capacity: c.int) -> c.int --- + + // Get the current world AABB + Shape_GetAABB :: proc(shapeId: ShapeId) -> AABB --- + + // Compute the mass data for a shape + Shape_ComputeMassData :: proc(shapeId: ShapeId) -> MassData --- + + // Get the closest point on a shape to a target point. Target and result are in world space. + Shape_GetClosestPoint :: proc(shapeId: ShapeId, target: Vec3) -> Vec3 --- + + // Apply a wind force to the body for this shape using the density of air. This considers + // the projected area of the shape in the wind direction. This also considers + // the relative velocity of the shape. + // @param shapeId the shape id + // @param wind the wind velocity in world space + // @param drag the drag coefficient, the force that opposes the relative velocity + // @param lift the lift coefficient, the force that is perpendicular to the relative velocity + // @param maxSpeed the maximum relative speed. Speed cap is necessary for stability. Typically 10m/s or less. + // @param wake should this wake the body + Shape_ApplyWind :: proc(shapeId: ShapeId, wind: Vec3 , drag, lift: f32, maxSpeed: f32, wake: bool) --- + + /** @} */ // shape + + /** + * @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, wakeAttached: bool) --- + + // 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 world that owns this joint + Joint_GetWorld :: proc(jointId: JointId) -> WorldId --- + + // Set the local frame on bodyA + Joint_SetLocalFrameA :: proc(jointId: JointId, localFrame: Transform) --- + + // Get the local frame on bodyA + Joint_GetLocalFrameA :: proc(jointId: JointId) -> Transform --- + + // Set the local frame on bodyB + Joint_SetLocalFrameB :: proc(jointId: JointId, localFrame: Transform) --- + + // Get the local frame on bodyB + Joint_GetLocalFrameB :: proc(jointId: JointId) -> Transform --- + + // 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) --- + + // 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) -> Vec3 --- + + // Get the current constraint torque for this joint + Joint_GetConstraintTorque :: proc(jointId: JointId) -> Vec3 --- + + // Get the current linear separation error for this joint. Does not consider admissible movement. Usually in meters. + Joint_GetLinearSeparation :: proc(jointId: JointId) -> f32 --- + + // Get the current angular separation error for this joint. Does not consider admissible movement. Usually in radians. + Joint_GetAngularSeparation :: proc(jointId: JointId) -> f32 --- + + // Set the joint constraint tuning. Advanced feature. + // @param jointId the joint + // @param hertz the stiffness in Hertz (cycles per second) + // @param dampingRatio the non-dimensional damping ratio (one for critical damping) + Joint_SetConstraintTuning :: proc(jointId: JointId, hertz: f32, dampingRatio: f32) --- + + // Get the joint constraint tuning. Advanced feature. + Joint_GetConstraintTuning :: proc(jointId: JointId, hertz: ^f32, dampingRatio: ^f32) --- + + // Set the force threshold for joint events (Newtons) + Joint_SetForceThreshold :: proc(jointId: JointId, threshold: f32) --- + + // Get the force threshold for joint events (Newtons) + Joint_GetForceThreshold :: proc(jointId: JointId) -> f32 --- + + // Set the torque threshold for joint events (N-m) + Joint_SetTorqueThreshold :: proc(jointId: JointId, threshold: f32) --- + + // Get the torque threshold for joint events (N-m) + Joint_GetTorqueThreshold :: proc(jointId: JointId) -> f32 --- + + /** + * @defgroup parallel_joint Parallel Joint + * @brief Functions for the parallel joint. + * @{ + */ + + // Create a parallel joint + // @see ParallelJointDef for details + CreateParallelJoint :: proc(worldId: WorldId, #by_ptr def: ParallelJointDef) -> JointId --- + + // Set the spring stiffness in Hertz + ParallelJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) --- + + // Set the spring damping ratio, non-dimensional + ParallelJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- + + // Get the spring Hertz + ParallelJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 --- + + // Get the spring damping ratio + ParallelJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the maximum spring torque, usually in newton-meters + ParallelJoint_SetMaxTorque :: proc(jointId: JointId, force: f32) --- + + // Get the maximum spring torque, usually in newton-meters + ParallelJoint_GetMaxTorque :: proc(jointId: JointId) -> f32 --- + + /** @} */ // parallel_joint + + /** + * @defgroup distance_joint Distance Joint + * @brief Functions for the distance joint. + * @{ + */ + + // Create a distance joint + // @see DistanceJointDef 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 force range for the spring. + DistanceJoint_SetSpringForceRange :: proc(jointId: JointId, lowerForce, upperForce: f32) --- + + // Get the force range for the spring. + DistanceJoint_GetSpringForceRange :: proc(jointId: JointId, lowerForce, upperForce: ^f32) --- + + // 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_GetSpringHertz :: proc(jointId: JointId) -> f32 --- + + // Get the spring damping ratio + DistanceJoint_GetSpringDampingRatio :: 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, usually in meters per second + DistanceJoint_SetMotorSpeed :: proc(jointId: JointId, motorSpeed: f32) --- + + // Get the distance joint motor speed, usually in meters per second + DistanceJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- + + // Set the distance joint maximum motor force, usually in newtons + DistanceJoint_SetMaxMotorForce :: proc(jointId: JointId, force: f32) --- + + // Get the distance joint maximum motor force, usually in newtons + DistanceJoint_GetMaxMotorForce :: proc(jointId: JointId) -> f32 --- + + // Get the distance joint current motor force, usually in newtons + DistanceJoint_GetMotorForce :: proc(jointId: JointId) -> f32 --- + + /** @} */ // distance_joint + + /** + * @defgroup motor_joint Motor Joint + * @brief Functions for the motor joint. + * + * The motor joint is designed to control the movement of a body while still being + * responsive to collisions. A spring controls the position and rotation. A velocity motor + * can be used to control velocity and allows for friction in top-down games. Both types + * of control can be combined. For example, you can have a spring with friction. + * Position and velocity control have force and torque limits. + * @{ + */ + + // Create a motor joint + // @see MotorJointDef for details + CreateMotorJoint :: proc(worldId: WorldId, #by_ptr def: MotorJointDef) -> JointId --- + + // Set the desired relative linear velocity in meters per second + MotorJoint_SetLinearVelocity :: proc(jointId: JointId, velocity: Vec3) --- + + // Get the desired relative linear velocity in meters per second + MotorJoint_GetLinearVelocity :: proc(jointId: JointId) -> Vec3 --- + + // Set the desired relative angular velocity in radians per second + MotorJoint_SetAngularVelocity :: proc(jointId: JointId, velocity: Vec3) --- + + // Get the desired relative angular velocity in radians per second + MotorJoint_GetAngularVelocity :: proc(jointId: JointId) -> Vec3 --- + + // Set the motor joint maximum force, usually in newtons + MotorJoint_SetMaxVelocityForce :: proc(jointId: JointId, maxForce: f32) --- + + // Get the motor joint maximum force, usually in newtons + MotorJoint_GetMaxVelocityForce :: proc(jointId: JointId) -> f32 --- + + // Set the motor joint maximum torque, usually in newton-meters + MotorJoint_SetMaxVelocityTorque :: proc(jointId: JointId, maxTorque: f32) --- + + // Get the motor joint maximum torque, usually in newton-meters + MotorJoint_GetMaxVelocityTorque :: proc(jointId: JointId) -> f32 --- + + // Set the spring linear hertz stiffness + MotorJoint_SetLinearHertz :: proc(jointId: JointId, hertz: f32) --- + + // Get the spring linear hertz stiffness + MotorJoint_GetLinearHertz :: proc(jointId: JointId) -> f32 --- + + // Set the spring linear damping ratio. Use 1.0 for critical damping. + MotorJoint_SetLinearDampingRatio :: proc(jointId: JointId, damping: f32) --- + + // Get the spring linear damping ratio. + MotorJoint_GetLinearDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the spring angular hertz stiffness + MotorJoint_SetAngularHertz :: proc(jointId: JointId, hertz: f32) --- + + // Get the spring angular hertz stiffness + MotorJoint_GetAngularHertz :: proc(jointId: JointId) -> f32 --- + + // Set the spring angular damping ratio. Use 1.0 for critical damping. + MotorJoint_SetAngularDampingRatio :: proc(jointId: JointId, damping: f32) --- + + // Get the spring angular damping ratio. + MotorJoint_GetAngularDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the maximum spring force in newtons. + MotorJoint_SetMaxSpringForce :: proc(jointId: JointId, maxForce: f32) --- + + // Get the maximum spring force in newtons. + MotorJoint_GetMaxSpringForce :: proc(jointId: JointId) -> f32 --- + + // Set the maximum spring torque in newtons * meters + MotorJoint_SetMaxSpringTorque :: proc(jointId: JointId, maxTorque: f32) --- + + // Get the maximum spring torque in newtons * meters + MotorJoint_GetMaxSpringTorque :: proc(jointId: JointId) -> f32 --- + + /**@}*/ // motor_joint + + /** + * @defgroup filter_joint Filter Joint + * @brief Functions for the filter joint. + * + * The filter joint is used to disable collision between two bodies. As a side effect of being a joint, it also + * keeps the two bodies in the same simulation island. + * @{ + */ + + // Create a filter joint. + // @see FilterJointDef for details + CreateFilterJoint :: proc(worldId: WorldId, #by_ptr def: FilterJointDef) -> JointId --- + + /**@}*/ // filter_joint + + /** + * @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 PrismaticJointDef 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 --- + + // Set the prismatic joint target translation. Usually in meters. + PrismaticJoint_SetTargetTranslation :: proc(jointId: JointId, targetTranslation: f32) --- + + // Get the prismatic joint target translation. Usually in meters. + PrismaticJoint_GetTargetTranslation :: 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, usually in meters per second + PrismaticJoint_SetMotorSpeed :: proc(jointId: JointId, motorSpeed: f32) --- + + // Get the prismatic joint motor speed, usually in meters per second + PrismaticJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- + + // Set the prismatic joint maximum motor force, usually in newtons + PrismaticJoint_SetMaxMotorForce :: proc(jointId: JointId, force: f32) --- + + // Get the prismatic joint maximum motor force, usually in newtons + PrismaticJoint_GetMaxMotorForce :: proc(jointId: JointId) -> f32 --- + + // Get the prismatic joint current motor force, usually in newtons + PrismaticJoint_GetMotorForce :: proc(jointId: JointId) -> f32 --- + + // Get the current joint translation, usually in meters. + PrismaticJoint_GetTranslation :: proc(jointId: JointId) -> f32 --- + + // Get the current joint translation speed, usually in meters per second. + PrismaticJoint_GetSpeed :: proc(jointId: JointId) -> f32 --- + + /**@}*/ // prismatic_joint + + /** + * @defgroup revolute_joint Revolute Joint + * @brief A revolute joint allows for relative rotation about a single axis with no relative translation. + * + * Also called a *hinge* or *pin* joint. + * @{ + */ + + // Create a revolute joint + // @see RevoluteJointDef for details + CreateRevoluteJoint :: proc(worldId: WorldId, #by_ptr def: RevoluteJointDef) -> JointId --- + + // Enable/disable the revolute joint spring + RevoluteJoint_EnableSpring :: proc(jointId: JointId, enableSpring: bool) --- + + // Is the revolute angular spring enabled? + RevoluteJoint_IsSpringEnabled :: proc(jointId: JointId) -> 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 --- + + // Set the revolute joint target angle in radians + RevoluteJoint_SetTargetAngle :: proc(jointId: JointId, targetRadians: f32) --- + + // Get the revolute joint target angle in radians + RevoluteJoint_GetTargetAngle :: proc(jointId: JointId) -> f32 --- + + // Get the revolute joint current angle in radians relative to the reference angle + // @see RevoluteJointDef::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, lowerLimitRadians, upperLimitRadians: 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, usually in newton-meters + RevoluteJoint_GetMotorTorque :: proc(jointId: JointId) -> f32 --- + + // Set the revolute joint maximum motor torque, usually in newton-meters + RevoluteJoint_SetMaxMotorTorque :: proc(jointId: JointId, torque: f32) --- + + // Get the revolute joint maximum motor torque, usually in newton-meters + RevoluteJoint_GetMaxMotorTorque :: proc(jointId: JointId) -> f32 --- + + /**@}*/ // revolute_joint + + /** + * @defgroup spherical_joint Spherical Joint + * @brief A spherical joint allows for relative rotation in the 3D space with no relative translation. + * + * Also called a *ball-in-socket* or *point-to-point* joint. + * @{ + */ + + // Create a spherical joint + // @see SphericalJointDef for details + CreateSphericalJoint :: proc(worldId: WorldId, #by_ptr def: SphericalJointDef) -> JointId --- + + // Enable/disable the spherical joint cone limit + SphericalJoint_EnableConeLimit :: proc(jointId: JointId, enableLimit: bool) --- + + // Is the spherical joint cone limit enabled? + SphericalJoint_IsConeLimitEnabled :: proc(jointId: JointId) -> bool --- + + // Get the spherical joint cone limit in radians + SphericalJoint_GetConeLimit :: proc(jointId: JointId) -> f32 --- + + // Set the spherical joint limits in radians + SphericalJoint_SetConeLimit :: proc(jointId: JointId, angleRadians: f32) --- + + // Get the spherical joint current cone angle in radians. + SphericalJoint_GetConeAngle :: proc(jointId: JointId) -> f32 --- + + // Enable/disable the spherical joint limit + SphericalJoint_EnableTwistLimit :: proc(jointId: JointId, enableLimit: bool) --- + + // Is the spherical joint limit enabled? + SphericalJoint_IsTwistLimitEnabled :: proc(jointId: JointId) -> bool --- + + // Get the spherical joint lower limit in radians + SphericalJoint_GetLowerTwistLimit :: proc(jointId: JointId) -> f32 --- + + // Get the spherical joint upper limit in radians + SphericalJoint_GetUpperTwistLimit :: proc(jointId: JointId) -> f32 --- + + // Set the spherical joint limits in radians + SphericalJoint_SetTwistLimits :: proc(jointId: JointId, lowerLimitRadians, upperLimitRadians: f32) --- + + // Get the spherical joint current twist angle in radians. + SphericalJoint_GetTwistAngle :: proc(jointId: JointId) -> f32 --- + + // Enable/disable the spherical joint spring + SphericalJoint_EnableSpring :: proc(jointId: JointId, enableSpring: bool) --- + + // Is the spherical angular spring enabled? + SphericalJoint_IsSpringEnabled :: proc(jointId: JointId) -> bool --- + + // Set the spherical joint spring stiffness in Hertz + SphericalJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) --- + + // Get the spherical joint spring stiffness in Hertz + SphericalJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 --- + + // Set the spherical joint spring damping ratio, non-dimensional + SphericalJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- + + // Get the spherical joint spring damping ratio, non-dimensional + SphericalJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the spherical joint spring target rotation + SphericalJoint_SetTargetRotation :: proc(jointId: JointId, targetRotation: Quat) --- + + // Get the spherical joint spring target rotation + SphericalJoint_GetTargetRotation :: proc(jointId: JointId) -> Quat --- + + // Enable/disable a spherical joint motor + SphericalJoint_EnableMotor :: proc(jointId: JointId, enableMotor: bool) --- + + // Is the spherical joint motor enabled? + SphericalJoint_IsMotorEnabled :: proc(jointId: JointId) -> bool --- + + // Set the spherical joint motor velocity in radians per second + SphericalJoint_SetMotorVelocity :: proc(jointId: JointId, motorVelocity: Vec3) --- + + // Get the spherical joint motor velocity in radians per second + SphericalJoint_GetMotorVelocity :: proc(jointId: JointId) -> Vec3 --- + + // Get the spherical joint current motor torque, usually in newton-meters + SphericalJoint_GetMotorTorque :: proc(jointId: JointId) -> Vec3 --- + + // Set the spherical joint maximum motor torque, usually in newton-meters + SphericalJoint_SetMaxMotorTorque :: proc(jointId: JointId, torque: f32) --- + + // Get the spherical joint maximum motor torque, usually in newton-meters + SphericalJoint_GetMaxMotorTorque :: proc(jointId: JointId) -> f32 --- + + /**@}*/ // spherical_joint + + /** + * @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 WeldJointDef 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 --- + + /**@}*/ // weld_joint + + /** + * @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 WheelJointDef for details. + CreateWheelJoint :: proc(worldId: WorldId, #by_ptr def: WheelJointDef) -> JointId --- + + // Enable/disable the wheel joint spring. + WheelJoint_EnableSuspension :: proc(jointId: JointId, flag: bool) --- + + // Is the wheel joint spring enabled? + WheelJoint_IsSuspensionEnabled :: proc(jointId: JointId) -> bool --- + + // Set the wheel joint stiffness in Hertz. + WheelJoint_SetSuspensionHertz :: proc(jointId: JointId, hertz: f32) --- + + // Get the wheel joint stiffness in Hertz. + WheelJoint_GetSuspensionHertz :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint damping ratio, non-dimensional. + WheelJoint_SetSuspensionDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- + + // Get the wheel joint damping ratio, non-dimensional. + WheelJoint_GetSuspensionDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Enable/disable the wheel joint limit. + WheelJoint_EnableSuspensionLimit :: proc(jointId: JointId, flag: bool) --- + + // Is the wheel joint limit enabled? + WheelJoint_IsSuspensionLimitEnabled :: proc(jointId: JointId) -> bool --- + + // Get the wheel joint lower limit. + WheelJoint_GetLowerSuspensionLimit :: proc(jointId: JointId) -> f32 --- + + // Get the wheel joint upper limit. + WheelJoint_GetUpperSuspensionLimit :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint limits. + WheelJoint_SetSuspensionLimits :: proc(jointId: JointId, lower, upper: f32) --- + + // Enable/disable the wheel joint motor. + WheelJoint_EnableSpinMotor :: proc(jointId: JointId, flag: bool) --- + + // Is the wheel joint motor enabled? + WheelJoint_IsSpinMotorEnabled :: proc(jointId: JointId) -> bool --- + + // Set the wheel joint motor speed in radians per second. + WheelJoint_SetSpinMotorSpeed :: proc(jointId: JointId, speed: f32) --- + + // Get the wheel joint motor speed in radians per second. + WheelJoint_GetSpinMotorSpeed :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint maximum motor torque, usually in newton-meters. + WheelJoint_SetMaxSpinTorque :: proc(jointId: JointId, torque: f32) --- + + // Get the wheel joint maximum motor torque, usually in newton-meters. + WheelJoint_GetMaxSpinTorque :: proc(jointId: JointId) -> f32 --- + + // Get the current spin speed in radians per second. + WheelJoint_GetSpinSpeed :: proc(jointId: JointId) -> f32 --- + + // Get the wheel joint current motor torque, usually in newton-meters. + WheelJoint_GetSpinTorque :: proc(jointId: JointId) -> f32 --- + + // Enable/disable wheel steering. Steering allows the wheel to rotate about the suspension axis. + WheelJoint_EnableSteering :: proc(jointId: JointId, flag: bool) --- + + // Can the wheel steer? + WheelJoint_IsSteeringEnabled :: proc(jointId: JointId) -> bool --- + + // Set the wheel joint steering stiffness in Hertz. + WheelJoint_SetSteeringHertz :: proc(jointId: JointId, hertz: f32) --- + + // Get the wheel joint steering stiffness in Hertz. + WheelJoint_GetSteeringHertz :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint steering damping ratio, non-dimensional. + WheelJoint_SetSteeringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- + + // Get the wheel joint steering damping ratio, non-dimensional. + WheelJoint_GetSteeringDampingRatio :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint maximum steering torque in N*m. + WheelJoint_SetMaxSteeringTorque :: proc(jointId: JointId, torque: f32) --- + + // Get the wheel joint maximum steering torque in N*m. + WheelJoint_GetMaxSteeringTorque :: proc(jointId: JointId) -> f32 --- + + // Enable/disable the wheel joint steering limit. + WheelJoint_EnableSteeringLimit :: proc(jointId: JointId, flag: bool) --- + + // Is the wheel joint steering limit enabled? + WheelJoint_IsSteeringLimitEnabled :: proc(jointId: JointId) -> bool --- + + // Get the wheel joint lower steering limit in radians. + WheelJoint_GetLowerSteeringLimit :: proc(jointId: JointId) -> f32 --- + + // Get the wheel joint upper steering limit in radians. + WheelJoint_GetUpperSteeringLimit :: proc(jointId: JointId) -> f32 --- + + // Set the wheel joint steering limits in radians. + WheelJoint_SetSteeringLimits :: proc(jointId: JointId, lowerRadians, upperRadians: f32) --- + + // Set the wheel joint target steering angle in radians. + WheelJoint_SetTargetSteeringAngle :: proc(jointId: JointId, radians: f32) --- + + // Get the wheel joint target steering angle in radians. + WheelJoint_GetTargetSteeringAngle :: proc(jointId: JointId) -> f32 --- + + // Get the current steering angle in radians. + WheelJoint_GetSteeringAngle :: proc(jointId: JointId) -> f32 --- + + // Get the current steering torque in N*m. + WheelJoint_GetSteeringTorque :: proc(jointId: JointId) -> f32 --- + + /**@}*/ // wheel_joint + + /**@}*/ // joint + + /** + * @defgroup contact Contact + * Access to contacts + * @{ + */ + + // Contact identifier validation. Provides validation for up to 2^32 allocations. + Contact_IsValid :: proc(id: ContactId) -> bool --- + + // Get the manifolds for a contact. The manifold may have no points if the contact is not touching. + Contact_GetData :: proc(contactId: ContactId) -> ContactData --- + + /**@}*/ // contact +} \ No newline at end of file diff --git a/vendor/box3d/box3d_collision.odin b/vendor/box3d/box3d_collision.odin new file mode 100644 index 000000000..26435fe6f --- /dev/null +++ b/vendor/box3d/box3d_collision.odin @@ -0,0 +1,615 @@ +package vendor_box3d + +import "core:c" + +// Query callback. +MeshQueryFcn :: proc "c" (x, y, z: Vec3, triangleIndex: c.int, ctx: rawptr) -> bool + + +@(link_prefix="b3", default_calling_convention="c", require_results) +foreign lib { + /** + * @addtogroup tree + * @{ + */ + + // Constructing the tree initializes the node pool. + DynamicTree_Create :: proc(proxyCapacity: c.int) -> 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: u64, userData: u64) -> c.int --- + + // Destroy a proxy. This asserts if the id is invalid. + DynamicTree_DestroyProxy :: proc(tree: ^DynamicTree, proxyId: c.int) --- + + // Move a proxy to a new AABB by removing and reinserting into the tree. + DynamicTree_MoveProxy :: proc(tree: ^DynamicTree, proxyId: c.int, aabb: AABB) --- + + // Enlarge a proxy and enlarge ancestors as necessary. + DynamicTree_EnlargeProxy :: proc(tree: ^DynamicTree, proxyId: c.int, aabb: AABB) --- + + // Modify the category bits on a proxy. This is an expensive operation. + DynamicTree_SetCategoryBits :: proc(tree: ^DynamicTree, proxyId: c.int, categoryBits: u64) --- + + // Get the category bits on a proxy. + DynamicTree_GetCategoryBits :: proc(tree: ^DynamicTree, proxyId: c.int) -> u64 --- + + // Query an AABB for overlapping proxies. The callback function is called for each proxy that overlaps the supplied AABB. + // @return performance data + DynamicTree_Query :: proc(#by_ptr tree: DynamicTree, aabb: AABB, maskBits: u64, requireAllBits: bool, callback: TreeQueryCallbackFcn, ctx: rawptr) -> TreeStats --- + + // Query an AABB for the closest object. The callback function is called for each proxy that might be closest to the supplied point. + // @param tree the dynamic tree to query + // @param point the query point + // @param maskBits nodes are skipped if the bit-wise AND with the node category bits is zero + // @param requireAllBits nodes are skipped if the bit-wise AND with the node category bits does not equal the maskBits + // @param callback a user provided instance of TreeQueryClosestCallbackFcn + // @param context a user context object that is provided to the callback + // @param minDistanceSqr the initial and final minimum squared distance. Provide a small initial to restrict the search and + // improve performance. If the value is large this query has performance that scales linearly with the number of proxies and + // would be slower than a brute force search. + // @return performance data + DynamicTree_QueryClosest :: proc(#by_ptr tree: DynamicTree, point: Vec3, maskBits: u64, requireAllBits: bool, callback: TreeQueryClosestCallbackFcn, ctx: rawptr, minDistanceSqr: ^f32) -> TreeStats --- + + // Ray cast against the proxies in the tree. This relies on the callback + // to perform an exact ray cast in the case where the proxy contains a shape. + // The callback also performs 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. + // However, this filtering may be approximate, so the user should still apply filtering to results. + // @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 bit mask test: `bool accept = (maskBits & node->categoryBits) != 0;` + // @param requireAllBits modifies bit mask test: `bool accept = (maskBits & node->categoryBits) == maskBits;` + // @param callback a callback function that is called for each proxy that is hit by the ray + // @param context user context that is passed to the callback + // @return performance data + DynamicTree_RayCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: RayCastInput, maskBits: u64, requireAllBits: bool, callback: TreeRayCastCallbackFcn, ctx: rawptr) -> TreeStats --- + + // Sweep an AABB through the tree. The box is in the tree's world float frame and the callback + // re-differences each shape at full precision against the query origin. Used by the large world + // spatial queries so the tree traversal stays float while the narrow phase stays precise. + DynamicTree_BoxCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: BoxCastInput, maskBits: u64, requireAllBits: bool, callback: TreeBoxCastCallbackFcn, ctx: rawptr) -> TreeStats --- + + // Validate this tree. For testing. + DynamicTree_Validate :: proc(#by_ptr tree: DynamicTree) --- + + // Get the height of the binary tree. + DynamicTree_GetHeight :: 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 --- + + // Get the bounding box that contains the entire tree + DynamicTree_GetRootBounds :: proc(#by_ptr tree: DynamicTree) -> AABB --- + + // 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 --- + + // Get the number of bytes used by this tree + DynamicTree_GetByteCount :: proc(#by_ptr tree: DynamicTree) -> c.int --- + + // Validate this tree has no enlarged AABBs. For testing. + DynamicTree_ValidateNoEnlarged :: proc(#by_ptr tree: DynamicTree) --- + + // Save this tree to a file for debugging + DynamicTree_Save :: proc(#by_ptr tree: DynamicTree, fileName: cstring) --- + + // Load a file for debugging + DynamicTree_Load :: proc(fileName: cstring, scale: f32) -> DynamicTree --- + + + /**@}*/ // tree + + /** + * @addtogroup hull + * @{ + */ + + // Create a tessellated cylinder as a hull. + CreateCylinder :: proc(height: f32, radius: f32, yOffset: f32, sides: c.int) -> ^HullData --- + + // Create a tessellated cone as a hull. + CreateCone :: proc(height: f32, radius1: f32, radius2: f32, slices: c.int) -> ^HullData --- + + // Create a rock shaped hull. + CreateRock :: proc(radius: f32) -> ^HullData --- + + // Create a generic convex hull. + CreateHull :: proc(points: [^]Vec3, pointCount: c.int, maxVertexCount: c.int) -> ^HullData --- + + // Deep clone a hull. + CloneHull :: proc(#by_ptr hull: HullData) -> ^HullData --- + + // Clone and transform a hull. Supports non-uniform and mirroring scale. + CloneAndTransformHull :: proc(#by_ptr original: HullData, transform: Transform, scale: Vec3) -> ^HullData --- + + // Destroy a hull. + DestroyHull :: proc(hull: ^HullData) --- + + // Make a cube as a hull. Do not call DestroyHull on this. + MakeCubeHull :: proc(halfWidth: f32) -> BoxHull --- + + // Make a box as a hull. Do not call DestroyHull on this. + MakeBoxHull :: proc(hx, hy, hz: f32) -> BoxHull --- + + // Make an offset box as a hull. Do not call DestroyHull on this. + MakeOffsetBoxHull :: proc(hx, hy, hz: f32, offset: Vec3) -> BoxHull --- + + // Make a transformed box as a hull. Do not call DestroyHull on this. + // @param hx, hy, hz positive half widths + // @param transform local transform of box + MakeTransformedBoxHull :: proc(hx, hy, hz: f32, transform: Transform) -> BoxHull --- + + // This makes a transformed box hull with post scaling. This is useful for boxes that are scaled in + // a level editor. Such scaling can have reflection and shear. In the case of shear the result + // may be approximate. If you need to support shear consider using CreateHull. + // Do not call DestroyHull on this. + // @param halfWidths positive half widths + // @param transform local transform of box + // @param postScale scale applied after the transform, may be negative + MakeScaledBoxHull :: proc(halfWidths: Vec3, transform: Transform, postScale: Vec3) -> BoxHull --- + + // This takes a box with a transform and post scale and converts it into a box with the post scale + // resolved with new half-widths and transform. This accepts non-uniform and negative scale. + // This is approximate if there is shear. + // @param halfWidths [in/out] the box half widths + // @param transform [in/out] the box transform with rotation and translation + // @param postScale the post scale being applied to the box after the transform + // @param minHalfWidth the minimum half width after scale is applied + ScaleBox :: proc(halfWidths: ^Vec3, transform: ^Transform, postScale: Vec3, minHalfWidth: f32) --- + + /**@}*/ // hull + + /** + * @addtogroup mesh + * @{ + */ + + + // Create a grid mesh along the x and z axes. + // @param xCount the number of rows in the x direction + // @param zCount the number of rows in the z direction + // @param cellWidth the width of each cell + // @param materialCount the number of materials to generate + // @param identifyEdges compute adjacency information + CreateGridMesh :: proc(xCount: c.int, zCount: c.int, cellWidth: f32, materialCount: c.int, identifyEdges: bool) -> ^MeshData --- + + // Create a wave mesh along the x and z axes. + CreateWaveMesh :: proc(xCount: c.int, zCount: c.int, cellWidth: f32, amplitude: f32, rowFrequency: f32, columnFrequency: f32) -> ^MeshData --- + + // Create a torus mesh. + CreateTorusMesh :: proc(radialResolution: c.int, tubularResolution: c.int, radius: f32, thickness: f32) -> ^MeshData --- + + // Create a box mesh. + CreateBoxMesh :: proc(center: Vec3, extent: Vec3, identifyEdges: bool) -> ^MeshData --- + + // Create a hollow box mesh. + CreateHollowBoxMesh :: proc(center: Vec3, extent: Vec3) -> ^MeshData --- + + // Create a platform mesh. A truncated pyramid. + CreatePlatformMesh :: proc(center: Vec3, height, topWidth, bottomWidth: f32) -> ^MeshData --- + + // Create a generic mesh. + CreateMesh :: proc(#by_ptr def: MeshDef, degenerateTriangleIndices: [^]c.int, degenerateCapacity: c.int) -> ^MeshData --- + + // Destroy a mesh. + DestroyMesh :: proc(mesh: ^MeshData) --- + + // Get the height of the mesh BVH. + GetHeight :: proc(#by_ptr mesh: MeshData) -> c.int --- + + /**@}*/ // mesh + + /** + * @addtogroup height_field + * @{ + */ + + // Create a generic height field. + CreateHeightField :: proc(#by_ptr data: HeightFieldDef) -> ^HeightFieldData --- + + // Create a grid as a height field. + CreateGrid :: proc(rowCount, columnCount: c.int, scale: Vec3, makeHoles: bool) -> ^HeightFieldData --- + + // Create a wave grid as a height field. + CreateWave :: proc(rowCount, columnCount: c.int, scale: Vec3, rowFrequency: f32, columnFrequency: f32, makeHoles: bool) -> ^HeightFieldData --- + + // Destroy a height field. + DestroyHeightField :: proc(heightField: ^HeightFieldData) --- + + // Save input height data to a file + DumpHeightData :: proc(#by_ptr data: HeightFieldDef, fileName: cstring) --- + + // Create a height field by loading a previously saved height data + LoadHeightField :: proc(fileName: cstring) -> ^HeightFieldData --- + + /**@}*/ // height_field + + /** + * @addtogroup compound + * @{ + */ + + // Get a child shape of a compound. + GetCompoundChild :: proc(#by_ptr compound: CompoundData, childIndex: c.int) -> ChildShape --- + + // Query a compound shape for children that overlap an AABB. + QueryCompound :: proc(#by_ptr compound: CompoundData, aabb: AABB, fcn: CompoundQueryFcn, ctx: rawptr) --- + + // Access a child capsule by index. + GetCompoundCapsule :: proc(#by_ptr compound: CompoundData, index: c.int) -> CompoundCapsule --- + + // Access a child hull by index. + GetCompoundHull :: proc(#by_ptr compound: CompoundData, index: c.int) -> CompoundHull --- + + // Access a child mesh by index. + GetCompoundMesh :: proc(#by_ptr compound: CompoundData, index: c.int) -> CompoundMesh --- + + // Access a child sphere by index. + GetCompoundSphere :: proc(#by_ptr compound: CompoundData, index: c.int) -> CompoundSphere --- + + // Access the compound material array. + GetCompoundMaterials :: proc(#by_ptr compound: CompoundData) -> ^SurfaceMaterial --- + + // Create a compound shape. All input data in the definition is cloned into the resulting compound. + CreateCompound :: proc(#by_ptr def: CompoundDef) -> ^CompoundData --- + + // Destroy a compound shape. + DestroyCompound :: proc(compound: ^CompoundData) --- + + // If bytes is null then this returns the number of required bytes. This clones all the + // data into the bytes buffer. This is expected to run offline or asynchronously. + // This mutates the compound to nullify pointers, leaving the compound in an unusable state. + ConvertCompoundToBytes :: proc(compound: ^CompoundData) -> [^]u8 --- + + // Convert bytes to compound. This does not clone. The bytes must remain in scope while the + // compound is used. This is done to improve run-time performance and allow for instancing. + // The bytes are mutated to fixup pointers. + ConvertBytesToCompound :: proc(bytes: [^]u8, byteCount: c.int) -> ^CompoundData --- + + /**@}*/ // compound + + /** + * @addtogroup geometry + * @{ + */ + + // Compute mass properties of a sphere + ComputeSphereMass :: proc(#by_ptr shape: Sphere, density: f32) -> MassData --- + + // Compute mass properties of a capsule + ComputeCapsuleMass :: proc(#by_ptr shape: Capsule, density: f32) -> MassData --- + + // Compute mass properties of a hull + ComputeHullMass :: proc(#by_ptr shape: HullData, density: f32) -> MassData --- + + // Compute the bounding box of a transformed sphere + ComputeSphereAABB :: proc(#by_ptr shape: Sphere, 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 hull + ComputeHullAABB :: proc(#by_ptr shape: HullData, transform: Transform) -> AABB --- + + // Compute the bounding box of a transformed mesh. Scale may be non-uniform and have negative components. + ComputeMeshAABB :: proc(#by_ptr shape: MeshData, transform: Transform, scale: Vec3) -> AABB --- + + // Compute the bounding box of a transformed height-field + ComputeHeightFieldAABB :: proc(#by_ptr shape: HeightFieldData, transform: Transform) -> AABB --- + + // Compute the bounding box of a compound + ComputeCompoundAABB :: proc(#by_ptr shape: CompoundData, transform: Transform) -> AABB --- + + /**@}*/ // geometry + + /** + * @addtogroup query + * @{ + */ + + // Use this to ensure your ray cast input is valid and avoid internal assertions. + IsValidRay :: proc(#by_ptr input: RayCastInput) -> bool --- + + // Overlap shape versus capsule + OverlapCapsule :: proc(#by_ptr shape: Capsule, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Overlap shape versus compound + OverlapCompound :: proc(#by_ptr shape: CompoundData, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Overlap shape versus height field + OverlapHeightField :: proc(#by_ptr shape: HeightFieldData, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Overlap shape versus hull + OverlapHull :: proc(#by_ptr shape: HullData, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Overlap shape versus mesh + OverlapMesh :: proc(#by_ptr shape: Mesh, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Overlap shape versus sphere + OverlapSphere :: proc(#by_ptr shape: Sphere, shapeTransform: Transform, #by_ptr proxy: ShapeProxy) -> bool --- + + // Ray cast versus sphere in local space. A zero length ray is a point query. Initial overlap + // reports a hit at the ray origin with zero fraction and zero normal. + RayCastSphere :: proc(#by_ptr shape: Sphere, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus a hollow sphere shell in local space. Unlike the solid sphere a ray starting + // inside is not an overlap: it passes through and hits the far wall. + RayCastHollowSphere :: proc(#by_ptr shape: Sphere, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus capsule in local space. A zero length ray is a point query. Initial overlap + // reports a hit at the ray origin with zero fraction and zero normal. + RayCastCapsule :: proc(#by_ptr shape: Capsule, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus compound in local space. A zero length ray is a point query. Initial overlap + // with a child reports a hit at the ray origin with zero fraction and zero normal. + RayCastCompound :: proc(#by_ptr shape: CompoundData, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus hull shape in local space. A zero length ray is a point query. Initial overlap + // reports a hit at the ray origin with zero fraction and zero normal. + RayCastHull :: proc(#by_ptr shape: HullData, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus mesh in local space. A thin surface with no interior, so there is no overlap case. + RayCastMesh :: proc(#by_ptr shape: Mesh, #by_ptr input: RayCastInput) -> CastOutput --- + + // Ray cast versus height field in local space. A thin surface with no interior, so there is no overlap case. + RayCastHeightField :: proc(#by_ptr shape: HeightFieldData, #by_ptr input: RayCastInput) -> CastOutput --- + + // Shape cast versus a sphere. Initial overlap is treated as a miss. + ShapeCastSphere :: proc(#by_ptr shape: Sphere, #by_ptr input: ShapeCastInput) -> CastOutput --- + + // Shape cast versus a capsule. Initial overlap is treated as a miss. + ShapeCastCapsule :: proc(#by_ptr shape: Capsule, #by_ptr input: ShapeCastInput) -> CastOutput --- + + // Shape cast versus compound. Initial overlap is treated as a miss. + ShapeCastCompound :: proc(#by_ptr shape: CompoundData, #by_ptr input: ShapeCastInput) -> CastOutput --- + + // Shape cast versus a hull. Initial overlap is treated as a miss. + ShapeCastHull :: proc(#by_ptr shape: HullData, #by_ptr input: ShapeCastInput) -> CastOutput --- + + // Shape cast versus a mesh. Initial overlap is treated as a miss. + ShapeCastMesh :: proc(#by_ptr shape: Mesh, #by_ptr input: ShapeCastInput) -> CastOutput --- + + // Shape cast versus a height field. Initial overlap is treated as a miss. + ShapeCastHeightField :: proc(#by_ptr shape: HeightFieldData, #by_ptr input: ShapeCastInput) -> CastOutput --- + + + // Query a mesh for triangles overlapping a bounding box in local space. May have false positives. Useful for debug draw. + // @param mesh the mesh to query, includes scale + // @param bounds the bounding box in local space + // @param fcn a user function to collect triangles + // @param context the context sent to the user function. + QueryMesh :: proc(#by_ptr mesh: Mesh, bounds: AABB, fcn: MeshQueryFcn, ctx: rawptr) --- + + // Query a height field for triangles overlapping a bounding box in local space. May have false positives. Useful for debug draw. + // @param heightField the height field to query + // @param bounds the bounding box in local space + // @param fcn a user function to collect triangles + // @param context the context sent to the user function. + QueryHeightField :: proc(#by_ptr heightField: HeightFieldData, bounds: AABB, fcn: MeshQueryFcn, ctx: rawptr) --- + + // Compute the closest points between two shapes represented as point clouds. + // SimplexCache cache is input/output. On the first call set SimplexCache.count to zero. + // The query runs in frame A, so the witness points and normal are returned in frame A. + // 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(#by_ptr input: DistanceInput, cache: ^SimplexCache, simplexes: [^]Simplex, simplexCapacity: c.int) -> DistanceOutput --- + + // Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction. + // The query runs in frame A, so the hit point and normal are returned in frame A. Initially touching shapes are a miss. + 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 --- + + /**@}*/ // query + + /** + * @addtogroup collision + * @{ + */ + + // Collide two spheres. + CollideSpheres :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr sphereA, sphereB: Sphere, transformBtoA: Transform) --- + + // Collide a capsule and a sphere. + CollideCapsuleAndSphere :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr capsuleA: Capsule, #by_ptr sphereB: Sphere, transformBtoA: Transform) --- + + // Collide a hull and a sphere. + CollideHullAndSphere :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr hullA: HullData, #by_ptr sphereB: Sphere, transformBtoA: Transform, cache: ^SimplexCache) --- + + // Collide two capsules. + CollideCapsules :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr capsuleA, capsuleB: Capsule, transformBtoA: Transform) --- + + // Collide a hull and a capsule. + CollideHullAndCapsule :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr hullA: HullData, #by_ptr capsuleB: Capsule, transformBtoA: Transform, cache: ^SimplexCache) --- + + // Collide two hulls. + CollideHulls :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr hullA: HullData, #by_ptr hullB: HullData, transformBtoA: Transform, cache: ^SATCache) --- + + // Collide a capsule and a triangle. + CollideCapsuleAndTriangle :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr capsuleA: Capsule, #by_ptr triangleB: [3]Vec3, cache: ^SimplexCache) --- + + // Collide a hull and a triangle. + CollideHullAndTriangle :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr hullA: HullData, v1, v2, v3: Vec3, triangleFlags: c.int, cache: ^SATCache) --- + + // Collide a sphere and a triangle. + CollideSphereAndTriangle :: proc(manifold: ^LocalManifold, capacity: c.int, #by_ptr sphereA: Sphere, #by_ptr triangleB: [3]Vec3) --- + + /**@}*/ // collision + + /** + * @addtogroup character + * @{ + */ + + // Solves the position of a mover that satisfies the given collision planes. + // @param targetDelta the desired translation from the position used to generate the collision planes + // @param planes the collision planes + // @param count the number of collision planes + SolvePlanes :: proc(targetDelta: Vec3, planes: [^]CollisionPlane, count: c.int) -> PlaneSolverResult --- + + // Clips the velocity against the given collision planes. Planes with zero push or clipVelocity + // set to false are skipped. + ClipVector :: proc(vector: Vec3, planes: [^]CollisionPlane, count: c.int) -> Vec3 --- + + /**@}*/ // character +} + +// Get proxy user data +@(require_results) +DynamicTree_GetUserData :: proc "c" (#by_ptr tree: DynamicTree, proxyId: c.int) -> u64 { + return tree.nodes[proxyId].userData +} + +// Get the AABB of a proxy +@(require_results) +DynamicTree_GetAABB :: proc "c" (#by_ptr tree: DynamicTree, proxyId: c.int) -> AABB { + return tree.nodes[proxyId].aabb +} + + +// Get read only hull vertices. +@(require_results) +GetHullVertices :: proc "c" (hull: ^HullData) -> Maybe(^HullVertex) { + if hull.vertexOffset == 0 { + return nil + } + + return (^HullVertex)(uintptr(hull) + uintptr(hull.vertexOffset)) +} + +// Get read only hull points. +@(require_results) +GetHullPoints :: proc "c" (hull: ^HullData) -> Maybe(^Vec3) { + if hull.pointOffset == 0 { + return nil + } + + return (^Vec3)(uintptr(hull) + uintptr(hull.pointOffset)) +} + +// Get read only hull half edges. +@(require_results) +GetHullEdges :: proc "c" (hull: ^HullData) -> Maybe(^HullHalfEdge) { + if hull.edgeOffset == 0 { + return nil + } + + return (^HullHalfEdge)(uintptr(hull) + uintptr(hull.edgeOffset)) +} + +// Get read only hull faces. +@(require_results) +GetHullFaces :: proc "c" (hull: ^HullData) -> Maybe(^HullFace) { + if hull.faceOffset == 0 { + return nil + } + + return (^HullFace)(uintptr(hull) + uintptr(hull.faceOffset)) +} + +// Get read only hull planes. +@(require_results) +GetHullPlanes :: proc "c" (hull: ^HullData) -> Maybe(^Plane) { + if hull.planeOffset == 0 { + return nil + } + + return (^Plane)(uintptr(hull) + uintptr(hull.planeOffset)) +} + + +// Get read only mesh BVH nodes. +@(require_results) +GetMeshNodes :: proc "c" (mesh: ^MeshData) -> Maybe(^MeshNode) { + if mesh.nodeOffset == 0 { + return nil + } + + return (^MeshNode)(uintptr(mesh) + uintptr(mesh.nodeOffset)) +} + +// Get read only mesh vertices. +@(require_results) +GetMeshVertices :: proc "c" (mesh: ^MeshData) -> Maybe(^Vec3) { + if mesh.vertexOffset == 0 { + return nil + } + + return (^Vec3)(uintptr(mesh) + uintptr(mesh.vertexOffset)) +} + +// Get read only mesh triangles. +@(require_results) +GetMeshTriangles :: proc "c" (mesh: ^MeshData) -> Maybe(^MeshTriangle) { + if mesh.triangleOffset == 0 { + return nil + } + + return (^MeshTriangle)(uintptr(mesh) + uintptr(mesh.triangleOffset)) +} + +// Get read only mesh materials. The count is equal to the triangle count. +@(require_results) +GetMeshMaterialIndices :: proc "c" (mesh: ^MeshData) -> Maybe([^]u8) { + if mesh.materialOffset == 0 { + return nil + } + + return ([^]u8)(uintptr(mesh) + uintptr(mesh.materialOffset)) +} + +// Get read only mesh flags. The count is equal to the triangle count. +@(require_results) +GetMeshFlags :: proc "c" (mesh: ^MeshData) -> [^]u8 { + if mesh.flagsOffset == 0 { + return nil + } + + return ([^]u8)(uintptr(mesh) + uintptr(mesh.flagsOffset)) +} + + +// Get read only compressed heights. One u16 per grid point. +@(require_results) +GetHeightFieldCompressedHeights :: proc "c" (hf: ^HeightFieldData) -> [^]u16 { + if hf.heightsOffset == 0 { + return nil + } + + return ([^]u16)(uintptr(hf) + uintptr(hf.heightsOffset)) +} + +// Get read only material indices. One u8 per cell. +@(require_results) +GetHeightFieldMaterialIndices :: proc "c" (hf: ^HeightFieldData) -> [^]u8 { + if hf.materialOffset == 0 { + return nil + } + + return ([^]u8)(uintptr(hf) + uintptr(hf.materialOffset)) +} + +// Get read only triangle flags. One u8 per triangle. +@(require_results) +GetHeightFieldFlags :: proc "c" (hf: ^HeightFieldData) -> [^]u8 { + if hf.flagsOffset == 0 { + return nil + } + + return ([^]u8)(uintptr(hf) + uintptr(hf.flagsOffset)) +} diff --git a/vendor/box3d/box3d_constants.odin b/vendor/box3d/box3d_constants.odin new file mode 100644 index 000000000..3cc8233ab --- /dev/null +++ b/vendor/box3d/box3d_constants.odin @@ -0,0 +1,140 @@ +package vendor_box3d + + +@(link_prefix="b3", default_calling_convention="c") +foreign lib { + // Box3D 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 Box3D + SetLengthUnitsPerMeter :: proc(lengthUnits: f32) --- + + // Get the current length units per meter. + GetLengthUnitsPerMeter :: proc() -> f32 --- + + // Set the threshold for logging stalls. + SetStallThreshold :: proc(seconds: f32) --- + + // Get the threshold for logging stalls. + GetStallThreshold :: proc() -> f32 --- +} + +// Used to detect bad values. In float mode positions greater than about 16km have precision +// problems, so 100km is a safe limit. Large world mode keeps coordinates accurate much farther +// from the origin, so the sanity limit widens to keep valid far-field positions from tripping it. +@(require_results) +HUGE :: #force_inline proc "c" () -> f32 { + when DOUBLE_PRECISION { + return 1.0e9 * GetLengthUnitsPerMeter() + } else { + return 1.0e5 * GetLengthUnitsPerMeter() + } +} + +// Maximum parallel workers. Used for some fixed size arrays. +MAX_WORKERS :: 32 + +// Maximum number of tasks queued per world step. b3EnqueueTaskCallback will never be called +// more than this per world step. This is related to B3_MAX_WORKERS. With 32 workers, +// the maximum observed task count is 130. This allows an external task system to use a fixed +// size array for Box3D task, which may help with creating stable user task pointers. +MAX_TASKS :: 256 + +// Maximum number of colors in the constraint graph. Constraints that cannot +// find a color are added to the overflow set which are solved single-threaded. +// The compound barrel benchmark has minor overflow with 24 colors +GRAPH_COLOR_COUNT :: 24 + +// Number of contact point buckets for counting the number of contact points per +// shape contact pair. This is just for reporting and doesn't affect simulation. +CONTACT_MANIFOLD_COUNT_BUCKETS :: 8 + +// A small length used as a collision and constraint tolerance. Usually it is +// chosen to be numerically significant, but visually insignificant. In meters. +// @warning modifying this can have a significant impact on stability +@(require_results) +LINEAR_SLOP :: #force_inline proc "c" () -> f32 { + return 0.005 * GetLengthUnitsPerMeter() +} + +@(require_results) +MIN_CAPSULE_LENGTH :: #force_inline proc "c" () -> f32 { + return LINEAR_SLOP() +} + +// The distance between shapes where they are considered overlapped. This is needed +// because GJK may return small positive values for overlapped shapes in degenerate +// configurations. +@(require_results) +OVERLAP_SLOP :: #force_inline proc "c" () -> f32 { + return 0.1 * LINEAR_SLOP() +} + +// Maximum number of simultaneous worlds that can be allocated +MAX_WORLDS :: 128 + +// The maximum rotation of a body per time step. This limit is very large and is used +// to prevent numerical problems. You shouldn't need to adjust this. +// @warning increasing this to 0.5f * B3_PI or greater will break continuous collision. +MAX_ROTATION :: 0.25 * PI + +// @warning modifying this can have a significant impact on performance and stability +@(require_results) +SPECULATIVE_DISTANCE :: #force_inline proc "c" () -> f32 { + return 4.0 * LINEAR_SLOP() +} + +// The rest offset is used for mesh contact to reduce ghost collisions and assist with CCD. +// The rest offset adjusts the contact point separation value, making the solver push the shapes +// apart by this distance. +// Must be at least B3_LINEAR_SLOP and less than B3_SPECULATIVE_DISTANCE. +@(require_results) +MESH_REST_OFFSET :: #force_inline proc "c" () -> f32 { + return 1.0 * LINEAR_SLOP() +} + +// The default contact recycling distance. +@(require_results) +CONTACT_RECYCLE_DISTANCE :: #force_inline proc "c" () -> f32 { + return 10.0 * LINEAR_SLOP() +} + +// The default contact recycling world angle threshold. For performance this value +// is cos(angle/2)^2. This value corresponds to 10 degrees. +CONTACT_RECYCLE_ANGULAR_DISTANCE :: 0.99240388 + +// This is used to fatten AABBs in the dynamic tree. This allows proxies +// to move by a small amount without triggering a tree adjustment. This is in meters. +// @warning modifying this can have a significant impact on performance +@(require_results) +MAX_AABB_MARGIN :: #force_inline proc "c" () -> f32 { + return 0.05 * GetLengthUnitsPerMeter() +} + +// Per-shape AABB margin is a fraction of the shape extent (capped by B3_MAX_AABB_MARGIN). +// Small shapes get small margins; large shapes are clamped to the cap. +AABB_MARGIN_FRACTION :: 0.125 + +// The time that a body must be still before it will go to sleep. In seconds. +TIME_TO_SLEEP :: 0.5 + +// Maximum length of the body name. Can be 0 if you don't need names. +// Note: this gates recording capability. +BODY_NAME_LENGTH :: 18 + +// Maximum length of the shape name. Can be 0 if you don't need names. +// Note: this gates recording capability. +// todo waiting on this because it breaks existing recordings +SHAPE_NAME_LENGTH :: 18 + +// The maximum number of contact points between two touching shapes. +MAX_MANIFOLD_POINTS :: 4 + +// The maximum number points to use for shape cast proxies (swept point cloud). +MAX_SHAPE_CAST_POINTS :: 64 + +// These generous limits allow for easy hashing. See b3ShapePairKey. +SHAPE_POWER :: 22 +CHILD_POWER :: 64 - 2 * SHAPE_POWER +MAX_SHAPES :: 1 << SHAPE_POWER +MAX_CHILD_SHAPES :: 1 << CHILD_POWER \ No newline at end of file diff --git a/vendor/box3d/box3d_id.odin b/vendor/box3d/box3d_id.odin new file mode 100644 index 000000000..69453c4ba --- /dev/null +++ b/vendor/box3d/box3d_id.odin @@ -0,0 +1,129 @@ +package vendor_box3d + +/// World id references a world instance. This should be treated as an opaque handle. +WorldId :: struct { + index1: u16, + generation: u16, +} + +/// Body id references a body instance. This should be treated as an opaque handle. +BodyId :: struct { + index1: i32, + world0: u16, + generation: u16, +} + +/// Shape id references a shape instance. This should be treated as an opaque handle. +ShapeId :: struct { + index1: i32, + world0: u16, + generation: u16, +} + +/// Joint id references a joint instance. This should be treated as an opaque handle. +JointId :: struct { + index1: i32, + world0: u16, + generation: u16, +} + +/// Contact id references a contact instance. This should be treated as an opaque handle. +ContactId :: struct { + index1: i32, + world0: u16, + _: i16, + generation: u32, +} + + +/// Use these to make your identifiers null. +/// You may also use zero initialization to get null. +nullWorldId :: WorldId{} +nullBodyId :: BodyId{} +nullShapeId :: ShapeId{} +nullJointId :: JointId{} +nullContactId :: ContactId{} + +/// Macro to determine if any id is null. +@(require_results) +IS_NULL :: #force_inline proc "c" (id: $T) -> bool { + return id.index1 == 0 +} + +/// Macro to determine if any id is non-null. +@(require_results) +IS_NON_NULL :: #force_inline proc "c" (id: $T) -> bool { + return id.index1 != 0 +} + +/// Compare two ids for equality. Doesn't work for b3WorldId. Don't mix types. +@(require_results) +ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool { + return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation +} + +/// Store a world id into a u32. +@(require_results) +StoreWorldId :: #force_inline proc "c" (id: WorldId) -> u32 { + return u32(id.index1) << 16 | u32(id.generation) +} + +/// Load a u32 into a world id. +@(require_results) +LoadWorldId :: #force_inline proc "c" (x: u32) -> WorldId { + return WorldId{u16(x >> 16), u16(x)} +} + +/// Store a body id into a u64. +@(require_results) +StoreBodyId :: #force_inline proc "c" (id: BodyId) -> u64 { + return (u64(id.index1) << 32) | u64(id.world0) << 16 | u64(id.generation) +} + +/// Load a u64 into a body id. +@(require_results) +LoadBodyId :: #force_inline proc "c" (x: u64) -> BodyId { + return BodyId{i32(x >> 32), u16(x >> 16), u16(x)} +} + +/// Store a shape id into a u64. +@(require_results) +StoreShapeId :: #force_inline proc "c" (id: ShapeId) -> u64 { + return (u64(id.index1) << 32) | u64(id.world0) << 16 | u64(id.generation) +} + +/// Load a u64 into a shape id. +@(require_results) +LoadShapeId :: #force_inline proc "c" (x: u64) -> ShapeId { + return ShapeId{i32(x >> 32), u16(x >> 16), u16(x)} +} + +/// Store a joint id into a u64. +@(require_results) +StoreJointId :: #force_inline proc "c" (id: JointId) -> u64 { + return (u64(id.index1) << 32) | u64(id.world0) << 16 | u64(id.generation) +} + +/// Load a u64 into a joint id. +@(require_results) +LoadJointId :: #force_inline proc "c" (x: u64) -> JointId { + return JointId{i32(x >> 32), u16(x >> 16), u16(x)} +} + +/// Store a contact id into three uint32 values +@(require_results) +StoreContactId :: #force_inline proc "c" (id: ContactId) -> (values: [3]u32) { + values[0] = u32(id.index1) + values[1] = u32(id.world0) + values[2] = u32(id.generation) + return +} + +/// Load a contact id from three uint32 values. +@(require_results) +LoadContactId :: #force_inline proc "c" (values: [3]u32) -> (id: ContactId) { + id.index1 = i32(values[0]) + id.world0 = u16(values[1]) + id.generation = u32(values[2]) + return +} \ No newline at end of file diff --git a/vendor/box3d/box3d_math.odin b/vendor/box3d/box3d_math.odin new file mode 100644 index 000000000..ee7ac4528 --- /dev/null +++ b/vendor/box3d/box3d_math.odin @@ -0,0 +1,747 @@ +package vendor_box3d + +import "base:builtin" +import "core:math" +import "core:math/linalg" + +DOUBLE_PRECISION :: false + +// https://en.wikipedia.org/wiki/Pi +PI :: math.PI + +// Convenience constant to convert from degrees to radians. +DEG_TO_RAD :: math.RAD_PER_DEG +// Convenience constant to convert from radians to degrees. +RAD_TO_DEG :: math.DEG_PER_RAD + + +// Minimum scale used for scaling collision meshes, etc. +MIN_SCALE :: 0.01 + +Vec2 :: [2]f32 +Vec3 :: [3]f32 + +// Cosine and sine pair. +// This uses a custom implementation designed for cross-platform determinism. +CosSin :: struct { + cosine: f32, + sine: f32, +} + +Quat :: quaternion128 + +Transform :: struct { + p: Vec3, + q: Quat, +} + +Pos :: [3]f64 when DOUBLE_PRECISION else [3]f32 + +WorldTransform :: struct { + p: Pos, + q: Quat, +} + +Matrix3 :: matrix[3, 3]f32 + +// Axis aligned bounding box. +AABB :: struct { + lowerBound: Vec3, + upperBound: Vec3, +} + +// A plane. +// separation = dot(normal, point) - offset +Plane :: struct { + normal: Vec3, + offset: f32, +} + +Vec3_zero :: Vec3{0.0, 0.0, 0.0} +Vec3_one :: Vec3{1.0, 1.0, 1.0} +Vec3_axisX :: Vec3{1.0, 0.0, 0.0} +Vec3_axisY :: Vec3{0.0, 1.0, 0.0} +Vec3_axisZ :: Vec3{0.0, 0.0, 1.0} +Quat_identity :: Quat(1) +Transform_identity :: Transform{p={0, 0, 0}, q=1} +Mat3_zero :: Matrix3(0) +Mat3_identity :: Matrix3(1) + +Pos_zero :: Pos{0.0, 0.0, 0.0} +WorldTransform_identity :: WorldTransform{p={0, 0, 0}, q=1} + + + +// @return the minimum of two integers. + +MinInt :: builtin.min +MaxInt :: builtin.max +ClampInt :: builtin.clamp + +// The closest points between to segments or infinite lines. +SegmentDistanceResult :: struct { + point1: Vec3, + fraction1: f32, + point2: Vec3, + fraction2: f32, +} + + +@(link_prefix="b3", default_calling_convention="c", require_results) +foreign lib { + // @return is this float valid (finite and not NaN). + IsValidFloat :: proc(a: f32) -> bool --- + + + // Compute an approximate arctangent in the range [-pi, pi] + // This is hand coded for cross-platform determinism. The atan2f + // function in the standard library is not cross-platform deterministic. + // Accurate to around 0.0023 degrees. + Atan2 :: proc(y, x: f32) -> f32 --- + + // Compute the cosine and sine of an angle in radians. Implemented + // for cross-platform determinism. + ComputeCosSin :: proc(radians: f32) -> CosSin --- + + // Compute the closest point on the segment a-b to the target q. + PointToSegmentDistance :: proc(a, b: Vec3, q: Vec3) -> Vec3 --- + + // Compute the closest points on two infinite lines. + LineDistance :: proc(p1, d1: Vec3, p2, d2: Vec3) -> SegmentDistanceResult --- + + // Compute the closest points on two line segments. + SegmentDistance :: proc(p1, q1: Vec3, p2, q2: Vec3) -> SegmentDistanceResult --- + + // Is this a valid vector? Not NaN or infinity. + IsValidVec3 :: proc(a: Vec3) -> bool --- + + // Is this a valid quaternion? Not NaN or infinity. Is normalized. + IsValidQuat :: proc(q: Quat) -> bool --- + + // Is this a valid transform? Not NaN or infinity. Is normalized. + IsValidTransform :: proc(a: Transform) -> bool --- + + // Is this a valid matrix? Not NaN or infinity. + IsValidMatrix3 :: proc(a: Matrix3) -> bool --- + + // Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound. + IsValidAABB :: proc(a: AABB) -> bool --- + + // Is this AABB reasonably close to the origin? See B3_HUGE. + IsBoundedAABB :: proc(a: AABB) -> bool --- + + // Is this AABB valid and reasonable? + IsSaneAABB :: proc(a: AABB) -> bool --- + + // Is this a valid plane? Normal is a unit vector. Not Nan or infinity. + IsValidPlane :: proc(a: Plane) -> bool --- + + // Is this a valid world position? Not NaN or infinity. + IsValidPosition :: proc(p: Pos) -> bool --- + + // Is this a valid world transform? Not NaN or infinity. Rotation is normalized. + IsValidWorldTransform :: proc(t: WorldTransform) -> bool --- + + // Get the inertia tensor of an offset point. + // https://en.wikipedia.org/wiki/Parallel_axis_theorem + Steiner :: proc(mass: f32, origin: Vec3) -> Matrix3 --- + + // Extract a quaternion from a rotation matrix. + MakeQuatFromMatrix :: proc(#by_ptr m: Matrix3) -> Quat --- + + // Find a quaternion that rotates one vector to another. + ComputeQuatBetweenUnitVectors :: proc(v1, v2: Vec3) -> Quat --- + + + +} + +AbsFloat :: builtin.abs +MinFloat :: builtin.min +MaxFloat :: builtin.max +ClampFloat :: builtin.clamp +LerpFloat :: math.lerp + +// Convert any angle into the range [-pi, pi]. +@(require_results) +UnwindAngle :: #force_inline proc "c" (radians: f32) -> f32 { + // Assuming this is deterministic + return math.remainder(radians, 2.0 * PI) +} + +// Vector dot product. +Dot :: linalg.dot +Length :: linalg.length +LengthSquared :: linalg.length2 + + +// Distance between two points. +@(require_results) +Distance :: #force_inline proc "c" (a, b: Vec3) -> f32 { + dv := b - a + return Length(dv) +} + +// Squared distance between two points. +@(require_results) +DistanceSquared :: #force_inline proc "c" (a, b: Vec3) -> f32 { + dv := b - a + return LengthSquared(dv) +} + +FLT_EPSILON :: 1.1920928955078125e-07 /* 0x0.000002p0 */ + + +// Normalize a vector. Returns a zero vector if the input vector is very small. +@(require_results) +Normalize :: proc "c" (a: Vec3) -> Vec3 { + lengthSquared := a.x * a.x + a.y * a.y + a.z * a.z + + if lengthSquared > 1000.0 * min(f32) { + s := 1.0 / math.sqrt(lengthSquared) + return Vec3{ s * a.x, s * a.y, s * a.z } + } + + return Vec3{0.0, 0.0, 0.0} +} + +// Normalize a vector and return the length. Returns a zero vector +// if the input is very small. +@(require_results) +GetLengthAndNormalize :: proc "c" (a: Vec3) -> (length: f32, n: Vec3) { + length = Length(a) + if length < FLT_EPSILON { + return + } + + invLength := 1.0 / length + n = {invLength * a.x, invLength * a.y, invLength * a.z} + return +} + +// Get a unit vector that is perpendicular to the supplied vector. +@(require_results) +Perp :: proc "c" (a: Vec3) -> Vec3 { + // Suppose vector a has all equal components and is a unit vector: a = (s, s, s) + // Then 3*s*s = 1, s = sqrt(1/3) = 0.57735. This means that at least one component + // of a unit vector must be greater or equal to 0.57735. + p: Vec3 + if a.x < -0.5 || 0.5 < a.x { + p = {a.y, -a.x, 0.0} + } else { + p = {0.0, a.z, -a.y} + } + + return Normalize(p) +} + +// Is a vector normalized? In other words, does it have unit length? +@(require_results) +IsNormalized :: proc "c" (a: Vec3) -> bool { + aa := Dot(a, a) + return AbsFloat(1.0 - aa) < 100.0 * FLT_EPSILON +} +// https://en.wikipedia.org/wiki/Cross_product +Cross :: linalg.cross + +// Linearly interpolate between two vectors. +Lerp :: linalg.lerp + +// Blend two vectors: s * a + t * b +@(require_results) +Blend2 :: proc "c" (s: f32, a: Vec3, t: f32, b: Vec3) -> Vec3 { + return { + s * a.x + t * b.x, + s * a.y + t * b.y, + s * a.z + t * b.z, + } +} + +// Component-wise absolute value. +Abs :: linalg.abs + +// Component-wise -1 or 1 (1 if zero). +Sign :: linalg.sign + +// Component-wise minimum value. +Min :: linalg.min + +// Component-wise maximum value. +Max :: linalg.max + +// Component-wise clamped value. +Clamp :: linalg.clamp + +// Create a safe scaling value for scaling collision. This allows +// negative scale, but keeps scale sufficiently far from zero. +@(require_results) +SafeScale :: proc "c" (a: Vec3) -> Vec3 { + absScale := Abs(a) + minScale := Vec3{MIN_SCALE, MIN_SCALE, MIN_SCALE} + safeScale := Sign(a) * Max(absScale, minScale) + return safeScale +} + +// Does the supplied quaternion have unit length? +@(require_results) +IsNormalizedQuat :: proc "c" (q: Quat) -> bool { + qq := q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w + return 1.0 - 20.0 * FLT_EPSILON < qq && qq < 1.0 + 20.0 * FLT_EPSILON +} + +// Rotate a vector. +@(require_results) +RotateVector :: proc "c" (q: Quat, v: Vec3) -> Vec3 { + // v + 2 * cross(q.xyz, cross(q.xyz, v) + q.w * v) + // B3_ASSERT(IsNormalizedQuat(q)); + t1 := Cross(q.xyz, v) + t2 := t1 * q.w + v + t3 := Cross(q.xyz, t2) + return v * 2.0 + t3 +} + +// Inverse rotate a vector. +@(require_results) +InvRotateVector :: proc "c" (q: Quat, v: Vec3) -> Vec3 { + // v + 2 * cross(q.xyz, cross(q.xyz, v) - q.w * v) + // B3_ASSERT(IsNormalizedQuat(q)); + t1 := Cross(q.xyz, v) + t2 := t1 * q.w - v + t3 := Cross(q.xyz, t2) + return v * 2.0 + t3 +} + +// Compute dot product of two quaternions. Useful for polarity tests. +@(require_results) +DotQuat :: linalg.dot + +// Multiply two quaternions. +@(require_results) +MulQuat :: proc "c" (q1, q2: Quat) -> Quat { + return q1 * q2 +} + +// Compute a relative quaternion. +// inv(q1) * q2 +@(require_results) +InvMulQuat :: proc "c" (q1, q2: Quat) -> Quat { + t1 := Cross(q2.xyz, q1.xyz) + t2 := t1 * q1.w + q2.xyz + t3 := t2 * q2.w - q1.xyz + return quaternion(x=t3.x, y=t3.y, z=t3.z, w=q1.w * q2.w + Dot(q1.xyz, q2.xyz)) +} + +// Quaternion conjugate (cheap inverse). +Conjugate :: builtin.conj + +// Component-wise quaternion negation. +@(require_results) +NegateQuat :: proc "c" (q: Quat) -> Quat { + return -q +} + +// Normalize a quaternion. +@(require_results) +NormalizeQuat :: proc "c" (q: Quat) -> Quat { + lengthSq := DotQuat(q, q) + if lengthSq > 1000.0 * min(f32) { + s := 1.0 / math.sqrt(lengthSq) + return Quat(s) * q + } + + return Quat_identity +} + +// Make a quaternion that is equivalent to rotating around an axis by a specified angle. +@(require_results) +MakeQuatFromAxisAngle :: proc "c" (axis: Vec3, radians: f32) -> Quat { + ASSERT(IsNormalized(axis)) + cs := ComputeCosSin(0.5 * radians) + return quaternion(x=cs.sine * axis.x, y=cs.sine * axis.y, z=cs.sine * axis.z, w=cs.cosine) +} + +// Get the axis and angle from a quaternion. Assumes the quaternion is normalized. +@(require_results) +GetAxisAngle :: proc "c" (q: Quat) -> (radians: f32, axis: Vec3) { + length := math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z) + radians = 2.0 * Atan2(length, q.w) + if length > 0.0 { + invLength := 1.0 / length + axis = {invLength * q.x, invLength * q.y, invLength * q.z} + } + return +} + +// Get the angle for a quaternion in radians +@(require_results) +GetQuatAngle :: proc "c" (q: Quat) -> f32 { + length := math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z) + return 2.0 * Atan2(length, q.w) +} + +// Twist angle around the z-axis, used for twist limit and revolute angle limit +@(require_results) +GetTwistAngle :: proc "c" (q: Quat) -> f32 { + // Account for polarity to keep the twist angle in range. + // This is simpler than asking the user to check polarity or unwinding. + twist := q.w < 0.0 ? Atan2(-q.z, -q.w) : Atan2(q.z, q.w) + twist *= 2.0 + ASSERT(-PI <= twist && twist <= PI) + return twist +} + +// Swing angle used for cone limit +@(require_results) +GetSwingAngle :: proc "c" (q: Quat) -> f32 { + // Polarity should not matter because all terms are squared. + x := math.sqrt(q.z * q.z + q.w * q.w) + y := math.sqrt(q.x * q.x + q.y * q.y) + swing := 2.0 * Atan2(y, x) + ASSERT(0.0 <= swing && swing <= PI) + return swing +} + +// Linearly interpolate and normalize between two quaternions +@(require_results) +NLerp :: proc "c" (q1, q2: Quat, alpha: f32) -> Quat { + VALIDATE(0.0 <= alpha && alpha <= 1.0) + q1 := q1 + if DotQuat(q1, q2) < 0.0 { + q1 = -q1 + } + + q: Quat + q.xyz = Lerp(q1.xyz, q2.xyz, alpha) + q.w = (1.0 - alpha) * q1.w + alpha * q2.w + + return NormalizeQuat(q) +} + +// Multiply two transforms. If the result is applied to a point p local to frame B, +// the transform would first convert p to a point local to frame A, then into a point +// in the world frame. This is useful if frame B is a child of frame A. +@(require_results) +MulTransforms :: proc "c" (a, b: Transform) -> (out: Transform) { + out.p = RotateVector(a.q, b.p) + a.p + out.q = a.q * b.q + return +} + +// Creates a transform that converts a local point in frame B to a local point in frame A. +// This is useful for transforming points between the local spaces of two frames that are +// in world space. +@(require_results) +InvMulTransforms :: #force_inline proc "c" (a, b: Transform) -> (out: Transform) { + out.p = InvRotateVector(a.q, b.p - a.p) + out.q = InvMulQuat(a.q, b.q) + return +} + +// Get the inverse of a transform. +@(require_results) +InvertTransform :: proc "c" (t: Transform) -> (out: Transform) { + out.p = InvRotateVector(t.q, -t.p) + out.q = Conjugate(t.q) + return +} + +// Transform a point. +@(require_results) +TransformPoint :: proc "c" (t: Transform, v: Vec3) -> Vec3 { + rv := RotateVector(t.q, v) + return rv + t.p +} + +// Inverse transform a point. +@(require_results) +InvTransformPoint :: proc "c" (t: Transform, v: Vec3) -> Vec3 { + return InvRotateVector(t.q, v - t.p) +} + +// World position boundary. These cross between the double precision world space at the public +// boundary and the float interior. One set of bodies serves both modes: the typedefs collapse +// the types in float mode and the explicit float casts become no-ops. + +// Convert a vector to a world position. +@(require_results) +ToPos :: proc "c" (v: Vec3) -> Pos { + T :: type_of(Pos{}.x) + return {T(v.x), T(v.y), T(v.z)} +} + +// Lossy conversion of a world position to a float vector. +@(require_results) +ToVec3 :: proc "c" (p: Pos) -> Vec3 { + return {f32(p.x), f32(p.y), f32(p.z)} +} + +// Narrow a world coordinate to float, rounding toward negative infinity. Use with +// RoundUpFloat to build a conservative float box that always contains the double bounds, +// where plain rounding far from the origin could clip. nextafterf is an exact IEEE operation, +// so this is cross-platform deterministic. With large world mode off this is a plain conversion. +@(require_results) +RoundDownFloat :: proc "c" (x: f64) -> f32 { + when DOUBLE_PRECISION { + f := f32(x) + return f64(f) > f64(x) ? math.nextafter(f, -max(f32)) : f + } else { + return f32(x) + } +} + +// Narrow a world coordinate to float, rounding toward positive infinity. +@(require_results) +RoundUpFloat :: proc "c" (x: f32) -> f32 { + when DOUBLE_PRECISION { + f := f32(x) + return f64(f) < f64(x) ? math.nextafter(f, max(f32)) : f + } else { + return f32(x) + } +} + +// p + d +@(require_results) +OffsetPos :: proc "c" (p: Pos, d: Vec3) -> Pos { + T :: type_of(Pos{}.x) + return {p.x + T(d.x), p.y + T(d.y), p.z + T(d.z)} +} + +// World position interpolation for sweeps and sampling. +LerpPosition :: linalg.lerp + +// Transform a local point to a world position. Rotation in float, translation in double. +@(require_results) +TransformWorldPoint :: proc "c" (t: WorldTransform, p: Vec3) -> Pos { + T :: type_of(Pos{}.x) + r := RotateVector(t.q, p) + return {T(t.p.x + r.x), T(t.p.y + r.y), T(t.p.z + r.z)} +} + +// Transform a world position to a local point. One double subtraction, then float. +@(require_results) +InvTransformWorldPoint :: proc "c" (t: WorldTransform, p: Pos) -> Vec3 { + d := Vec3{f32(p.x - t.p.x), f32(p.y - t.p.y), f32(p.z - t.p.z)} + return InvRotateVector(t.q, d) +} + +// Relative transform of frame B in frame A. The narrow phase boundary. +@(require_results) +InvMulWorldTransforms :: proc "c" (A, B: WorldTransform) -> (C: Transform) { + C.q = InvMulQuat(A.q, B.q) + d := Vec3{f32(B.p.x - A.p.x), f32(B.p.y - A.p.y), f32(B.p.z - A.p.z)} + C.p = InvRotateVector(A.q, d) + return +} + +// Compose a world transform with a local transform. +@(require_results) +MulWorldTransforms :: proc "c" (A: WorldTransform, B: Transform) -> (C: WorldTransform) { + T :: type_of(Pos{}.x) + C.q = A.q * B.q + r := RotateVector(A.q, B.p) + C.p = Pos{T(A.p.x + r.x), T(A.p.y + r.y), T(A.p.z + r.z)} + return +} + +// Shift a world transform into the frame of a base position. +@(require_results) +ToRelativeTransform :: proc "c" (t: WorldTransform, base: Pos) -> (r: Transform) { + r.q = t.q + r.p = {f32(t.p.x - base.x), f32(t.p.y - base.y), f32(t.p.z - base.z)} + return +} + +// Promote a float transform to a world transform. Lossless. +@(require_results) +MakeWorldTransform :: proc "c" (t: Transform) -> (w: WorldTransform) { + w.p = ToPos(t.p) + w.q = t.q + return +} + +// Translate a local AABB by a world origin, rounding outward so the float box always contains +// the double box. Far from the origin a plain conversion could clip a shape out of its own box. +// In float mode the origin is float and the rounding is a no-op. +@(require_results) +OffsetAABB :: proc "c" (localBox: AABB, origin: Pos) -> (out: AABB) { + out.lowerBound.x = RoundDownFloat(f64(origin.x + localBox.lowerBound.x)) + out.lowerBound.y = RoundDownFloat(f64(origin.y + localBox.lowerBound.y)) + out.lowerBound.z = RoundDownFloat(f64(origin.z + localBox.lowerBound.z)) + out.upperBound.x = RoundUpFloat(f32(origin.x + localBox.upperBound.x)) + out.upperBound.y = RoundUpFloat(f32(origin.y + localBox.upperBound.y)) + out.upperBound.z = RoundUpFloat(f32(origin.z + localBox.upperBound.z)) + return +} + +// Compute the determinant of a 3-by-3 matrix. +Det :: linalg.determinant + +// Matrix transpose. +Transpose :: linalg.transpose + +// General matrix inverse. +@(require_results) +InvertMatrix :: proc "c" (m: Matrix3) -> Matrix3 { + det := Det(m) + if AbsFloat(det) > 1000.0 * min(f32) { + invDet := 1.0 / det + out: Matrix3 + out[0] = invDet * Cross(m[1], m[2]) + out[1] = invDet * Cross(m[2], m[0]) + out[2] = invDet * Cross(m[0], m[1]) + return Transpose(out) + } + return Mat3_zero +} + +// Solve a matrix equation. +// @return inv(m) * a +@(require_results) +Solve3 :: proc "c" (m: Matrix3, a: Vec3) -> Vec3 { + return InvertMatrix(m) * a +} + +// Invert a matrix. +@(require_results) +InvertT :: proc "c" (m: Matrix3) -> Matrix3 { + det := Det(m) + if AbsFloat(det) > 1000.0 * min(f32) { + invDet := 1.0 / det + out: Matrix3 + out[0] = invDet * Cross(m[1], m[2]) + out[1] = invDet * Cross(m[2], m[0]) + out[2] = invDet * Cross(m[0], m[1]) + return out + } + return Mat3_zero +} + +// Get the component-wise absolute value of a matrix. +@(require_results) +AbsMatrix3 :: proc "c" (m: Matrix3) -> (out: Matrix3) { + out[0] = Abs(m[0]) + out[1] = Abs(m[1]) + out[2] = Abs(m[2]) + return +} + +// Make a matrix from a quaternion. This is useful if you need to +// rotate many vectors. +// The force inline improves the performance of ShapeDistance. +@(require_results) +MakeMatrixFromQuat :: proc "c" (q: Quat) -> (out: Matrix3) { + xx := q.x * q.x + yy := q.y * q.y + zz := q.z * q.z + xy := q.x * q.y + xz := q.x * q.z + xw := q.x * q.w + yz := q.y * q.z + yw := q.y * q.w + zw := q.z * q.w + + out[0] = { 1.0 - 2.0 * (yy + zz), 2.0 * (xy + zw), 2.0 * (xz - yw) } + out[1] = { 2.0 * (xy - zw), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + xw) } + out[2] = { 2.0 * (xz + yw), 2.0 * (yz - xw), 1.0 - 2.0 * (xx + yy) } + return +} + +// Get the AABB of a point cloud. +@(require_results) +MakeAABB :: proc "c" (points: []Vec3, radius: f32) -> (a: AABB) #no_bounds_check { + ASSERT(len(points) > 0) + a = AABB{points[0], points[0]} + for i in 1.. bool { + switch { + case a.lowerBound.x > b.lowerBound.x || b.upperBound.x > a.upperBound.x: + return false + case a.lowerBound.y > b.lowerBound.y || b.upperBound.y > a.upperBound.y: + return false + case a.lowerBound.z > b.lowerBound.z || b.upperBound.z > a.upperBound.z: + return false + } + return true +} + +// Get the surface area of an axis-aligned bounding box. +@(require_results) +AABB_Area :: proc "c" (a: AABB) -> f32 { + delta := a.upperBound - a.lowerBound + return 2.0 * (delta.x * delta.y + delta.y * delta.z + delta.z * delta.x) +} + +// Get the center of an axis-aligned bounding box. +@(require_results) +AABB_Center :: proc "c" (a: AABB) -> Vec3 { + return 0.5 * (a.upperBound + a.lowerBound) +} + +// Get the extents (half-widths) of an axis-aligned bounding box. +@(require_results) +AABB_Extents :: proc "c" (a: AABB) -> Vec3 { + return 0.5 * (a.upperBound - a.lowerBound) +} + +// Get the union of two axis-aligned bounding boxes. +@(require_results) +AABB_Union :: proc "c" (a, b: AABB) -> (out: AABB) { + out.lowerBound = Min(a.lowerBound, b.lowerBound) + out.upperBound = Max(a.upperBound, b.upperBound) + return +} + +// Add uniform padding to an axis-aligned bounding box. +@(require_results) +AABB_Inflate :: proc "c" (a: AABB, extension: f32) -> (out: AABB) { + radius := Vec3{extension, extension, extension} + + out.lowerBound = a.lowerBound - radius + out.upperBound = a.upperBound + radius + return +} + +// Do two axis-aligned boxes overlap? +@(require_results) +AABB_Overlaps :: proc "c" (a, b: AABB) -> bool { + // No intersection if separated along one axis + switch { + case a.upperBound.x < b.lowerBound.x || a.lowerBound.x > b.upperBound.x: + return false + case a.upperBound.y < b.lowerBound.y || a.lowerBound.y > b.upperBound.y: + return false + case a.upperBound.z < b.lowerBound.z || a.lowerBound.z > b.upperBound.z: + return false + } + + // Overlapping on all axis means bounds are intersecting + return true +} + +// Transform an axis-aligned bounding box. This can create a larger box +// than if you recomputed the AABB of the original shape with the transform +// applied. +@(require_results) +AABB_Transform :: proc "c" (transform: Transform, a: AABB) -> AABB { + center := TransformPoint(transform, AABB_Center(a)) + m := MakeMatrixFromQuat(transform.q) + extent := AbsMatrix3(m) * AABB_Extents(a) + return AABB{center - extent, center + extent} +} + +// Get the closest point on an axis-aligned bounding box. +@(require_results) +ClosestPointToAABB :: proc "c" (point: Vec3, a: AABB) -> Vec3 { + return Clamp(point, a.lowerBound, a.upperBound) +} diff --git a/vendor/box3d/box3d_types.odin b/vendor/box3d/box3d_types.odin new file mode 100644 index 000000000..895261696 --- /dev/null +++ b/vendor/box3d/box3d_types.odin @@ -0,0 +1,2923 @@ +package vendor_box3d + +import "core:c" + +DEFAULT_CATEGORY_BITS :: max(u64) +DEFAULT_MASK_BITS :: max(u64) + + +// Task interface +// This is the prototype for a Box3D task. Your task system is expected to run this callback on a worker thread, +// exactly once per enqueue, passing back the same taskContext pointer supplied to EnqueueTaskCallback. +// @ingroup world +TaskCallback :: proc "c" (taskContext: rawptr) + +// These functions can be provided to Box3D to invoke a task system. +// Returns a pointer to the user's task object. May be nullptr. A nullptr indicates to Box3D that the work was executed +// serially within the callback and there is no need to call b3FinishTaskCallback. Otherwise the returned +// value must be non-null will be passed to b3FinishTaskCallback as the userTask. +// @param task the Box3D task to be called by the scheduler +// @param taskContext the Box3D context object that the scheduler must pass to the task +// @param userContext the scheduler context object that is opaque to Box3D +// @param taskName the Box3D task name that the scheduler can use for diagnostics +// @ingroup world +EnqueueTaskCallback :: proc "c" (task: rawptr, taskContext: rawptr, userContext: rawptr, taskName: cstring) -> rawptr + +// Finishes a user task object that wraps a Box3D task. This must block until the task has completed. +// The step blocks here on the tasks it spawned, so b3World_Step holds its stack across every +// fork/join. Drive it from a thread you can dedicate to the step, or from a fiber this callback can +// park to free the underlying thread. In a job system that cannot park a job's stack, do not call +// b3World_Step from inside a job: a job that blocks on its own sub-jobs without yielding its thread +// can deadlock. The in-tree scheduler instead runs other pending tasks on the waiting thread. +// @ingroup world +FinishTaskCallback :: proc "c" (userTask: rawptr, userContext: rawptr) + + +// The user needs to be able to create debug draw shapes for multi-pass rendering to work efficiently. +// These user shapes are created and destroyed via callback so they can be bound to shape lifetime and scaling updates. +// @ingroup debug_draw +CreateDebugShapeCallback :: proc "c" (debugShape: ^DebugShape, userContext: rawptr) -> rawptr +DestroyDebugShapeCallback :: proc "c" (userShape: rawptr, userContext: rawptr) + +// Optional friction mixing callback. This intentionally provides no context objects because this is called +// from a worker thread. +// @warning This function should not attempt to modify Box3D state or user application state. +// @ingroup world +FrictionCallback :: proc "c" (frictionA: f32, userMaterialIdA: u64, frictionB: f32, userMaterialIdB: u64) -> f32 + +// Optional restitution mixing callback. This intentionally provides no context objects because this is called +// from a worker thread. +// @warning This function should not attempt to modify Box3D state or user application state. +// @ingroup world +RestitutionCallback :: proc "c" (restitutionA: f32, userMaterialIdA: u64, restitutionB: f32, userMaterialIdB: u64) -> f32 + +// 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 b3ShapeDef. +// 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 :: proc "c" (shapeIdA: ShapeId, 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 +// collision before it goes to the solver. +// Notes: +// - this function must be thread-safe +// - this is only called if the shape has enabled pre-solve events +// - this may be called for awake dynamic bodies and sensors +// - this is not called for sensors +// Return false if you want to disable the contact this step +// This has limited information because it is used during CCD which does not have the +// full contact manifold. +// @warning Do not attempt to modify the world inside this callback +// @ingroup world +PreSolveFcn :: proc "c" (shapeIdA: ShapeId, shapeIdB: ShapeId, point: Pos, normal: Vec3, ctx: rawptr) -> bool + +// Prototype callback for overlap queries. +// Called for each shape found in the query. +// @see b3World_OverlapAABB +// @return false to terminate the query. +// @ingroup world +OverlapResultFcn :: 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 float: +// 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 userMaterialId the shape or triangle surface type +// @param triangleIndex the triangle index for mesh or height field shapes or -1 for other shape types +// @param childIndex the child shape index for compound shapes +// @param context the user context +// @return -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue +// @see b3World_CastRay +// @ingroup world +CastResultFcn :: proc "c" (shapeId: ShapeId, point: Pos, normal: Vec3, fraction: f32, userMateriald: u64, triangleIndex: c.int, childIndex: c.int, ctx: rawptr) -> f32 + +@(link_prefix="b3", default_calling_convention="c", require_results) +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 surface material + // @ingroup shape + DefaultSurfaceMaterial :: proc() -> SurfaceMaterial --- + + // Use this to initialize your shape definition + // @ingroup shape + DefaultShapeDef :: proc() -> ShapeDef --- + + // 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 filter_joint + DefaultFilterJointDef :: proc() -> FilterJointDef --- + + + // Use this to initialize your joint definition + // @ingroup parallel_joint + DefaultParallelJointDef :: proc() -> ParallelJointDef --- + + + // Use this to initialize your joint definition + // @ingroup 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 spherical_joint + DefaultSphericalJointDef :: proc() -> SphericalJointDef --- + + + // 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 --- + + // Use this to initialize your explosion definition + // @ingroup world + DefaultExplosionDef :: proc() -> ExplosionDef --- + + // Use this to initialize your query filter + DefaultQueryFilter :: proc() -> QueryFilter --- + + // Get the visualization color assigned to a constraint graph color slot. The last index + // (B3_GRAPH_COLOR_COUNT - 1) is the overflow color. + GetGraphColor :: proc(index: c.int) -> HexColor --- + + // Create a debug draw struct with default values. + DefaultDebugDraw :: proc() -> DebugDraw --- +} + +// Pack an RGB color with a material preset for debug draw. The preset rides in +// the high byte where the color converters ignore it. +@(require_results) +MakeDebugColor :: #force_inline proc "c" (rgb: HexColor, material: DebugMaterial) -> u32 { + return (u32(rgb)&0x00FFFFFF) | (u32(material)<<24) +} + + + + +// Optional world capacities that can be use to avoid run-time allocations +// @ingroup world +Capacity :: struct { + // Number of expected static shapes. + staticShapeCount: c.int, + + // Number of expected dynamic and kinematic shapes. + dynamicShapeCount: c.int, + + // Number of expected static bodies. + staticBodyCount: c.int, + + // Number of expected dynamic and kinematic bodies. + dynamicBodyCount: c.int, + + // Number of expected contacts. + contactCount: c.int, +} + + +// World definition used to create a simulation world. Must be initialized using b3DefaultWorldDef. +// @ingroup world +WorldDef :: struct { + // Gravity vector. Box3D has no up-vector defined. + gravity: Vec3, + + // Restitution speed threshold, usually in m/s. Collisions above this + // speed have restitution applied (will bounce). + restitutionThreshold: f32, + + // Hit event speed threshold, usually in m/s. Collisions above this + // speed can generate hit events if the shape also enables hit events. + hitEventThreshold: f32, + + // Contact stiffness. Cycles per second. Increasing this increases the speed of overlap recovery, but can introduce jitter. + contactHertz: f32, + + // Contact bounciness. Non-dimensional. You can speed up overlap recovery by decreasing this with + // the trade-off that overlap resolution becomes more energetic. + contactDampingRatio: f32, + + // This parameter controls how fast overlap is resolved and usually has units of meters per second. This only + // puts a cap on the resolution speed. The resolution speed is increased by increasing the hertz and/or + // decreasing the damping ratio. + contactSpeed: f32, + + // Maximum linear speed. Usually meters per second. + maximumLinearSpeed: f32, + + // Optional mixing callback for friction. The default uses sqrt(frictionA * frictionB). + frictionCallback: FrictionCallback, + + // Optional mixing callback for restitution. The default uses max(restitutionA, restitutionB). + restitutionCallback: RestitutionCallback, + + // Can bodies go to sleep to improve performance + enableSleep: bool, + + // Enable continuous collision + enableContinuous: bool, + + // Number of workers to use with the provided task system. Box3D 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. + // This is clamped to the range [1, B3_MAX_WORKERS]. Using a value above 1 will turn on multithreading. + // If task callbacks are provided then Box3D will use the user provided task system. Otherwise Box3D + // will create threads and use an internal scheduler. + workerCount: u32, + + // function to spawn task + enqueueTask: EnqueueTaskCallback, + + // function to finish a task + finishTask: FinishTaskCallback, + + // User context that is provided to enqueueTask and finishTask + userTaskContext: rawptr, + + // User data associated with a world + userData: rawptr, + + // Used to create debug draw shapes. This is called when a shape is + // first drawn using b3DebugDraw. + createDebugShape: CreateDebugShapeCallback, + + // Used to destroy debug draw shapes. This is called when a shape is modified or destroyed. + destroyDebugShape: DestroyDebugShapeCallback, + + // This is passed to the debug shape callbacks to provide a user context. + userDebugShapeContext: rawptr, + + // Optional initial capacities + capacity: Capacity, + + // Used internally to detect a valid definition. DO NOT SET. + internalValue: c.int, +} + + +// 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, +} + +// Motion locks to restrict the body movement +// @ingroup body +MotionLocks :: struct { + // Prevent translation along the x-axis + linearX: bool, + + // Prevent translation along the y-axis + linearY: bool, + + // Prevent translation along the z-axis + linearZ: bool, + + // Prevent rotation around the x-axis + angularX: bool, + + // Prevent rotation around the y-axis + angularY: bool, + + // Prevent rotation around the z-axis + angularZ: bool, +} + +// 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 b3DefaultBodyDef(). +// @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: Pos, + + // The initial world rotation of the body. + rotation: Quat, + + // The initial linear velocity of the body's origin. Usually in meters per second. + linearVelocity: Vec3, + + // The initial angular velocity of the body. Radians per second. + angularVelocity: Vec3, + + // Linear damping is used to reduce the linear velocity. The damping parameter + // can be larger than 1 but the damping effect becomes sensitive to the + // time step when the damping parameter is large. + // Generally linear damping is undesirable because it makes objects move slowly + // as if they are floating. + linearDamping: f32, + + // Angular damping is used to reduce the angular velocity. The damping parameter + // can be larger than 1.0f but the damping effect becomes sensitive to the + // time step when the damping parameter is large. + // Angular damping can be used to slow down rotating bodies. + angularDamping: f32, + + // Scale the gravity applied to this body. Non-dimensional. + gravityScale: f32, + + // Sleep speed threshold, default is 0.05 meters per second + sleepThreshold: f32, + + // Optional body name for debugging. Up to B3_BODY_NAME_LENGTH characters (including null termination) + name: cstring, + + // Use this to store application specific body data. + userData: rawptr, + + // Motions locks to restrict linear and angular movement + motionLocks: MotionLocks, + + // Set this flag to false if this body should never fall asleep. + enableSleep: bool, + + // Is this body initially awake or sleeping? + isAwake: bool, + + // Treat this body as a 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 do not guarantee accurate collision if both bodies are fast moving because + // the bullet does a continuous check after all non-bullet bodies have moved. You could get unlucky and have + // the bullet body end a time step very close to a non-bullet body and the non-bullet body then moves over + // the bullet body. In continuous collision, initial overlap is ignored to avoid freezing bodies in place. + // I do not recommend using them for game projectiles if precise collision timing is needed. Instead consider + // using a ray or shape cast. You can use a marching ray or shape cast for projectile that moves over time. + // If you want a fast moving projectile to collide with a fast moving target, you need to consider the relative + // movement in your ray or shape cast. This is out of the scope of Box3D. + // So what are good use cases for bullets? Pinball games or games with dynamic containers that hold other objects. + // It should be a use case where it doesn't break the game if there is a collision missed, but having them + // captured improves the quality of the game. + isBullet: bool, + + // Used to disable a body. A disabled body does not move or collide. + isEnabled: bool, + + // This allows this body to bypass rotational speed limits. Should only be used + // for circular objects, like wheels. + allowFastRotation: bool, + + // Enable contact recycling. True by default. Leaving this enabled improves performance + // but may lead to ghost collision that should be avoided on characters. + enableContactRecycling: bool, + + // Used internally to detect a valid definition. DO NOT SET. + internalValue: c.int, +} + + +// This is used to filter collision on shapes. It affects shape-vs-shape collision +// and shape-versus-query collision (such as b3World_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} + // MyCategories :: bit_set[MyCategory; u64] + // MyCategory :: enum { + // Static = 0, + // Dynamic = 1, + // Debris = 2, + // Player = 3, + // // etc + // }; + // @endcode + categoryBits: u64, + + // The collision mask bits. This states the categories that this + // shape would accept for collision. + // For example, you may want your player to only collide with static objects + // and other players. + // @code{.odin} + // maskBits = {/Static, .Player}; + // @endcode + maskBits: u64, + + // Collision groups allow a certain group of objects to never collide (negative) + // or always collide (positive). A group index of zero has no effect. Non-zero group filtering + // 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: c.int, +} + + +// Material properties supported per triangle on meshes and height fields +// @ingroup shape +SurfaceMaterial :: struct { + // The Coulomb (dry) friction coefficient, usually in the range [0,1]. + friction: f32, + + // The coefficient of restitution (bounce) usually in the range [0,1]. + // https://en.wikipedia.org/wiki/Coefficient_of_restitution + restitution: f32, + + // The rolling resistance usually in the range [0,1]. This is only used for spheres and capsules. + rollingResistance: f32, + + // The tangent velocity for conveyor belts. This is local to the shape and will be projected + // onto the contact surface. + tangentVelocity: Vec3, + + // User material identifier. This is passed with query results and to friction and restitution + // combining functions. It is not used internally. + userMaterialId: u64, + + // Custom debug draw color. Ignored if 0. The low 24 bits are RGB. The high byte may + // carry a b3DebugMaterial preset, see b3MakeDebugColor. + // @see b3HexColor + customColor: u32, +} + + +// Shape type +// @ingroup shape +ShapeType :: enum c.int { + // A capsule is an extruded sphere + capsuleShape, + + // A compound shape composed of up to 64K spheres, capsules, hulls, and meshes + compoundShape, + + // A height field useful for terrain + heightShape, + + // A convex hull + hullShape, + + // A triangle soup + meshShape, + + // A sphere with an offset + sphereShape, +} + +// Used to create a shape +// @ingroup shape +ShapeDef :: struct { + // Use this to store application specific shape data. + userData: rawptr, + + // Surface material used on mesh shapes per triangle. Ignored for convex shapes. Ignored for compound shapes. + materials: [^]SurfaceMaterial `fmt:"v,materialCount"`, + + // Surface material count. + materialCount: c.int, + + // The base surface material. Ignored for compound shapes. + baseMaterial: SurfaceMaterial, + + // The density, usually in kg/m^3. + density: f32, + + // Explosion scale for b3World_Explode. non-dimensional + explosionScale: f32, + + // Contact filtering data. + filter: Filter, + + // Enable custom filtering. Only one of the two shapes needs to enable custom filtering. See b3WorldDef. + enableCustomFiltering: bool, + + // A sensor shape generates overlap events but never generates a collision response. + // Sensors do not have continuous collision. Instead, use a ray or shape cast for those scenarios. + // Sensors still contribute to the body mass if they have non-zero density. + // @note Sensor events are disabled by default. + // @see enableSensorEvents + isSensor: bool, + + // Enable sensor events for this shape. This applies to sensors and non-sensors. False by default, even for sensors. + enableSensorEvents: bool, + + // Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. + enableContactEvents: bool, + + // Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. + enableHitEvents: bool, + + // Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive + // and must be carefully handled due to multithreading. Ignored for sensors. + enablePreSolveEvents: bool, + + // When shapes are created they will scan the environment for collision the next time step. This can significantly slow down + // static body creation when there are many static shapes. + // This is flag is ignored for dynamic and kinematic shapes which always invoke contact creation. + invokeContactCreation: bool, + + // Should the body update the mass properties when this shape is created. Default is true. + updateBodyMass: bool, + + // Used internally to detect a valid definition. DO NOT SET. + internalValue: c.int, +} + +//! @cond +// Profiling data. Times are in milliseconds. +// @ingroup world +Profile :: struct { + step: f32, + pairs: f32, + collide: f32, + solve: f32, + solverSetup: f32, + constraints: f32, + prepareConstraints: f32, + integrateVelocities: f32, + warmStart: f32, + solveImpulses: f32, + integratePositions: f32, + relaxImpulses: f32, + applyRestitution: f32, + storeImpulses: f32, + splitIslands: f32, + transforms: f32, + sensorHits: f32, + jointEvents: f32, + hitEvents: f32, + refit: f32, + bullets: f32, + sleepIslands: f32, + sensors: f32, +} + +// Counters that give details of the simulation size. +// @ingroup world +Counters :: struct { + bodyCount: c.int, + shapeCount: c.int, + contactCount: c.int, + jointCount: c.int, + islandCount: c.int, + stackUsed: c.int, + arenaCapacity: c.int, + staticTreeHeight: c.int, + treeHeight: c.int, + satCallCount: c.int, + satCacheHitCount: c.int, + byteCount: c.int, + taskCount: c.int, + colorCounts: [24]c.int, + manifoldCounts: [CONTACT_MANIFOLD_COUNT_BUCKETS]c.int, + + // Number of contacts touched by the collide pass + // graph contacts + awake-set non-touching + awakeContactCount: c.int, + + // Number of contacts recycled in the most recent step. + recycledContactCount: c.int, + + // Maximum number of time of impact iterations + distanceIterations: c.int, + pushBackIterations: c.int, + rootIterations: c.int, +} +//! @endcond + +// Joint type enumeration. This is useful because all joint types use b3JointId and sometimes you +// want to get the type of a joint. +// @ingroup joint +JointType :: enum c.int { + parallelJoint, + distanceJoint, + filterJoint, + motorJoint, + prismaticJoint, + revoluteJoint, + sphericalJoint, + weldJoint, + wheelJoint, +} + +// Base joint definition used by all joint types. The local frames 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 joint +JointDef :: struct { + // User data pointer + userData: rawptr, + + // The first attached body + bodyIdA: BodyId, + + // The second attached body + bodyIdB: BodyId, + + // The first local joint frame + localFrameA: Transform, + + // The second local joint frame + localFrameB: Transform, + + // Force threshold for joint events + forceThreshold: f32, + + // Torque threshold for joint events + torqueThreshold: f32, + + // Constraint hertz (advanced feature) + constraintHertz: f32, + + // Constraint damping ratio (advanced feature) + constraintDampingRatio: f32, + + // Debug draw scale + drawScale: f32, + + // Set this flag to true if the attached bodies should collide + collideConnected: bool, + + // Used internally to detect a valid definition. DO NOT SET. + internalValue: c.int, +} + +// Distance joint definition. +// Connects a point on body A with a point on body B by a segment. +// Useful for ropes and springs. +// @ingroup distance_joint +DistanceJointDef :: struct { + // Base joint definition + using base: JointDef, + + // 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 lower spring force controls how much tension it can sustain + lowerSpringForce: f32, + + // The upper spring force controls how much compression it can sustain + upperSpringForce: f32, + + // 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, +} + + +// A motor joint is used to control the relative position and velocity between two bodies. +// @ingroup motor_joint +MotorJointDef :: struct { + // Base joint definition + using base: JointDef, + + // The desired linear velocity + linearVelocity: Vec3, + + // The maximum motor force in newtons + maxVelocityForce: f32, + + // The desired angular velocity + angularVelocity: Vec3, + + // The maximum motor torque in newton-meters + maxVelocityTorque: f32, + + // Linear spring hertz for position control + linearHertz: f32, + + // Linear spring damping ratio + linearDampingRatio: f32, + + // Maximum spring force in newtons + maxSpringForce: f32, + + // Angular spring hertz for position control + angularHertz: f32, + + // Angular spring damping ratio + angularDampingRatio: f32, + + // Maximum spring torque in newton-meters + maxSpringTorque: f32, +} + +// A filter joint is used to disable collision between two specific bodies. +// @ingroup filter_joint +FilterJointDef :: struct { + // Base joint definition + using base: JointDef, +} + + +// Parallel joint definition. Constrains the angle between axis z in body A and axis z in body B +// using a spring. Useful to keep a body upright. +// @ingroup parallel_joint +ParallelJointDef :: struct { + // Base joint definition + using base: JointDef, + + // The spring stiffness Hertz, cycles per second + hertz: f32, + + // The spring damping ratio, non-dimensional + dampingRatio: f32, + + // The maximum spring torque, typically in newton-meters. + maxTorque: f32, +} + +// Prismatic joint definition. Body B may slide along the x-axis in local frame A. +// Body B cannot rotate relative to body A. The joint translation is zero when the +// local frame origins coincide in world space. +// @ingroup prismatic_joint +PrismaticJointDef :: struct { + // Base joint definition + using base: JointDef, + + // 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, + + // The target translation for the joint in meters. The spring-damper will drive + // to this translation. + targetTranslation: 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, +} + +// Revolute joint definition. A point on body B is fixed to a point on body A. +// Allows relative rotation about the z-axis. +// @ingroup revolute_joint +RevoluteJointDef :: struct { + // Base joint definition. + using base: JointDef, + + // The bodyB angle minus bodyA angle in the reference state (radians). + // This defines the zero angle for the joint limit. + targetAngle: 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. Minimum of -0.99*pi radians. + lowerAngle: f32, + + // The upper angle for the joint limit in radians. Maximum of 0.99*pi 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, +} + +// Spherical joint definition. A point on body B is fixed to a point on body A. +// Allows rotation about the shared point. +// @ingroup spherical_joint +SphericalJointDef :: struct { + // Base joint definition + using base: JointDef, + + // Enable a rotational spring that attempts to align the two joint frames. + enableSpring: bool, + + // The spring stiffness Hertz, cycles per second. This may be clamped internally + // according to the time step to maintain stability. Non-negative number. + hertz: f32, + + // The spring damping ratio, non-dimensional. Non-negative number. + dampingRatio: f32, + + // Target spring rotation, joint frame B relative to joint frame A. + targetRotation: Quat, + + // A flag to enable the cone limit. The cone is centered on the frameA z-axis. + enableConeLimit: bool, + + // The angle for the cone limit in radians. Valid range is [0, pi] + coneAngle: f32, + + // A flag to enable the twist limit. The twist is centered on the frameB z-axis. + enableTwistLimit: bool, + + // The angle for the lower twist limit in radians. Minimum of -0.99*pi radians. + lowerTwistAngle: f32, + + // The angle for the upper twist limit in radians. Maximum of 0.99*pi radians. + upperTwistAngle: f32, + + // A flag to enable the joint motor + enableMotor: bool, + + // The maximum motor torque, typically in newton-meters. Non-negative number. + maxMotorTorque: f32, + + // The desired motor angular velocity in radians per second. + motorVelocity: Vec3, +} + + +// Weld joint definition +// Connects two bodies together rigidly. This constraint provides springs to mimic +// soft-body simulation. +// @note The approximate solver in Box3D cannot hold many bodies together rigidly +// @ingroup weld_joint +WeldJointDef :: struct { + // Base joint definition + using base: JointDef, + + // 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, +} + +// Wheel joint definition +// Body A is the chassis and body B is the wheel. +// The wheel rotates around the local z-axis in frame B. +// The wheel translates along the local x-axis in frame A. +// The wheel can optionally steer along the x-axis in frame A. +// @ingroup wheel_joint +WheelJointDef :: struct { + // Base joint definition + using base: JointDef, + + // Enable a linear spring along the local axis + enableSuspensionSpring: bool, + + // Spring stiffness in Hertz + suspensionHertz: f32, + + // Spring damping ratio, non-dimensional + suspensionDampingRatio: f32, + + // Enable/disable the joint linear limit + enableSuspensionLimit: bool, + + // The lower suspension translation limit + lowerSuspensionLimit: f32, + + // The upper translation limit + upperSuspensionLimit: f32, + + // Enable/disable the joint rotational motor + enableSpinMotor: bool, + + // The maximum motor torque, typically in newton-meters + maxSpinTorque: f32, + + // The desired motor speed in radians per second + spinSpeed: f32, + + // Enable steering, otherwise the steering is fixed forward + enableSteering: bool, + + // Steering stiffness in Hertz + steeringHertz: f32, + + // Spring damping ratio, non-dimensional + steeringDampingRatio: f32, + + // The target steering angle in radians + targetSteeringAngle: f32, + + // The maximum steering torque in N*m + maxSteeringTorque: f32, + + // Enable/disable the steering angular limit + enableSteeringLimit: bool, + + // The lower steering angle in radians + lowerSteeringLimit: f32, + + // The upper steering angle in radians + upperSteeringLimit: f32, +} + + +// The explosion definition is used to configure options for explosions. Explosions +// consider shape geometry when computing the impulse. +// @ingroup world +ExplosionDef :: struct { + // Mask bits to filter shapes + maskBits: u64, + + // The center of the explosion in world space + position: Pos, + + // The radius of the explosion + radius: f32, + + // The falloff distance beyond the radius. Impulse is reduced to zero at this distance. + falloff: f32, + + // Impulse per unit area. This applies an impulse according to the shape area that + // is facing the explosion. Explosions only apply to spheres, capsules, and hulls. This + // may be negative for implosions. + impulsePerArea: f32, +} + +/** + * @defgroup event 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 Box3D 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 shape that began touching the sensor shape + visitorShapeId: ShapeId, +} + +// An end touch event is generated when a shape stops overlapping a sensor shape. +// These include things like setting the transform, destroying a body or shape, or changing +// a filter. You will also get an end event if the sensor or visitor are destroyed. +// Therefore you should always confirm the shape id is valid using b3Shape_IsValid. +SensorEndTouchEvent :: struct { + // The id of the sensor shape + // @warning this shape may have been destroyed + // @see b3Shape_IsValid + sensorShapeId: ShapeId, + + // The id of the shape that stopped touching the sensor shape + // @warning this shape may have been destroyed + // @see b3Shape_IsValid + visitorShapeId: ShapeId, +} + +// Sensor events are buffered in the 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: c.int, + + // The number of end touch events + endCount: c.int, +} + +// 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, + + // The transient contact id. This contact may be destroyed automatically when the world is modified or simulated. + // Use b3Contact_IsValid before using this id. + contactId: ContactId, +} + +// An end touch event is generated when two shapes stop touching. +// You will get an end event if you do anything that destroys contacts previous to the last +// world step. These include things like setting the transform, destroying a body +// or shape, or changing a filter or body type. +ContactEndTouchEvent :: struct { + // Id of the first shape + // @warning this shape may have been destroyed + // @see b3Shape_IsValid + shapeIdA: ShapeId, + + // Id of the first shape + // @warning this shape may have been destroyed + // @see b3Shape_IsValid + shapeIdB: ShapeId, + + // Id of the contact. + // @warning this contact may have been destroyed + // @see b3Contact_IsValid + contactId: ContactId, +} + +// A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold. +// This may be reported for speculative contacts that have a confirmed impulse. +ContactHitEvent :: struct { + // Id of the first shape + shapeIdA: ShapeId, + + // Id of the second shape + shapeIdB: ShapeId, + + // Id of the contact. + // @warning this contact may have been destroyed + // @see b3Contact_IsValid + contactId: ContactId, + + // Point where the shapes hit at the beginning of the time step. + // This is a mid-point between the two surfaces. It could be at speculative + // point where the two shapes were not touching at the beginning of the time step. + point: Pos, + + // Normal vector pointing from shape A to shape B + normal: Vec3, + + // The speed the shapes are approaching. Always positive. Typically in meters per second. + approachSpeed: f32, + + // User material on shape A + userMaterialIdA: u64, + + // User material on shape B + userMaterialIdB: u64, +} + +// Contact events are buffered in the 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: c.int, + + // Number of end touch events + endCount: c.int, + + // Number of hit events + hitCount: c.int, +} + +// 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 b3Body_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 { + // The body user data. + userData: rawptr, + + // The body transform. + transform: WorldTransform, + + // The body id. + bodyId: BodyId, + + // Did the body fall asleep this time step? + fellAsleep: bool, +} + +// Body events are buffered in the world and are available +// as event arrays after the time step is complete. +// Note: this data becomes invalid if bodies are destroyed +BodyEvents :: struct { + // Array of move events + moveEvents: [^]BodyMoveEvent `fmt:"v,moveCount"`, + + // Number of move events + moveCount: c.int, +} + +// Joint events report joints that are awake and have a force and/or torque exceeding the threshold +// The observed forces and torques are not returned for efficiency reasons. +JointEvent :: struct { + // The joint id + jointId: JointId, + + // The user data from the joint for convenience + userData: rawptr, +} + +// Joint events are buffered in the world and are available +// as event arrays after the time step is complete. +// Note: this data becomes invalid if joints are destroyed +JointEvents :: struct { + // Array of events + jointEvents: [^]JointEvent `fmt:"v,count"`, + + // Number of events + count: c.int, +} + +// The contact data for two shapes. By convention the manifold normal points +// from shape A to shape B. +// @see b3Shape_GetContactData() and b3Body_GetContactData() +ContactData :: struct { + // The contact id. You may hold onto this to track a contact across time steps. + // This id may become orphaned. Use b3Contact_IsValid before using it for other functions. + contactId: ContactId, + + // The first shape id. + shapeIdA: ShapeId, + + // The second shape id. + shapeIdB: ShapeId, + + // The contact manifold. This points to internal data and may become invalid. Do not store + // this pointer. + manifolds: [^]Manifold `fmt:"v,manifoldCount"`, + + // The number of contact manifolds. For mesh and height-field collision there can be multiple manifolds. + manifoldCount: c.int, +} + +/**@}*/ // event + +/** + * @defgroup query Query + * @brief Query types and functions + * + * Queries include ray casts, shapes casts, overlap, distance, and time of impact. + * @{ + */ + +// 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. +QueryFilter :: struct { + // The collision category bits of this query. Normally you would just set one bit. + categoryBits: u64, + + // The collision mask bits. This states the shape categories that this + // query would accept for collision. + maskBits: u64, + + // Optional id combined with @ref name to identify this query in a recording, e.g. an entity id. + // Need not be unique on its own. 0 with a null name means untagged. Ignored when not recording. + id: u64, + + // Optional label combined with @ref id to identify this query, e.g. "bullet". Need not be unique + // on its own. The recorder hashes (id, name) into one stable key the viewer tracks the query by, + // so the same id and name pair identifies the same query across frames. NULL means none. Ignored + // when not recording. + name: cstring, +} + + +// Low level ray cast input data. +RayCastInput :: struct { + // Start point of the ray cast. + origin: Vec3, + + // Translation of the ray cast. + // end = start + translation. + translation: Vec3, + + // The maximum fraction of the translation to consider, typically 1 + maxFraction: f32, +} + +// Result from b3World_RayCastClosest. +RayResult :: struct { + // The shape hit. + shapeId: ShapeId, + + // The world point of the hit. + point: Pos, + + // The world normal of the shape surface at the hit point. + normal: Vec3, + + // The user material id at the hit point. This can be per triangle + // if the shape is a mesh, height-field, or compound with child mesh. + userMaterialId: u64, + + // The fraction of the input ray. + fraction: f32, + + // The triangle index if the shape is a mesh, height-field, or compound with + // child mesh. + triangleIndex: c.int, + + // The child index if the shape is a compound. + childIndex: c.int, + + // The number of BVH nodes visited. Diagnostic. + nodeVisits: c.int, + + // The number of BVH leaves visited. Diagnostic. + leafVisits: c.int, + + // Did the ray hit? If false, all other data is invalid. + hit: bool, +} + +// A shape proxy is used by the GJK algorithm. It can represent a convex shape. +ShapeProxy :: struct { + // The point cloud. + points: [^]Vec3 `fmt:"v,count"`, + + // The number of points. Do not exceed B3_MAX_SHAPE_CAST_POINTS. + count: c.int, + + // The external radius of the point cloud. + radius: f32, +} + +// Low level shape cast input in generic form. This allows casting an arbitrary point +// cloud wrap with a radius. For example, a sphere is a single point with a non-zero radius. +// A capsule is two points with a non-zero radius. A box is four points with a zero radius. +ShapeCastInput :: struct { + // A generic query shape. + proxy: ShapeProxy, + + // The translation of the shape cast. + translation: Vec3, + + // The maximum fraction of the translation to consider, typically 1. + maxFraction: f32, + + // Allow shape cast to encroach when initially touching. This only works if the radius is greater than zero. + canEncroach: bool, +} + +// Input for sweeping an AABB through a dynamic tree. The box is in the tree's world float frame. +// The caller folds the cast shape radius and any world origin into the box, so the tree traversal +// stays a conservative box sweep and the precise narrow phase happens per shape in the callback. +BoxCastInput :: struct { + // The AABB to cast, in the tree's frame. + box: AABB, + + // The sweep translation. + translation: Vec3, + + // 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: Vec3, + + // The surface hit point. + point: Vec3, + + // The fraction of the input translation at collision. + fraction: f32, + + // The number of iterations used. + iterations: c.int, + + // The index of the mesh or height field triangle hit. + triangleIndex: c.int, + + // The index of the compound child shape. + childIndex: c.int, + + // The material index. May be -1 for null. + materialIndex: c.int, + + // Did the cast hit? + hit: bool, +} + + +// Ray cast or shape-cast output in world space. The hit point is a world position so the result +// stays precise far from the world origin. Mirrors b3CastOutput with a double precision point. +WorldCastOutput :: struct { + // The surface normal at the hit point. + normal: Vec3, + + // The surface hit point in world space. + point: Pos, + + // The fraction of the input translation at collision. + fraction: f32, + + // The number of iterations used. + iterations: c.int, + + // The index of the mesh or height field triangle hit. + triangleIndex: c.int, + + // The index of the compound child shape. + childIndex: c.int, + + // The material index. May be -1 for null. + materialIndex: c.int, + + // Did the cast hit? + hit: bool, +} + + +// Body cast result for ray and shape casts. +BodyCastResult :: struct { + // The shape hit. + shapeId: ShapeId, + + // The world point on the shape surface. + point: Pos, + + // The world normal vector on the shape surface. + normal: Vec3, + + // The fraction along the ray hit. + // hit point = origin + fraction * translation + fraction: f32, + + // The triangle index if the shape is a mesh or height-field. + triangleIndex: c.int, + + // The user material id at the hit point. This can be per triangle + // if the shape is a mesh, height-field, or compound with child mesh. + userMaterialId: u64, + + // The number of iterations used. Diagnostic. + iterations: c.int, + + // Did the cast hit? If false, all other fields are invalid. + hit: bool, +} + +// Used to warm start the GJK simplex. If you call this function multiple times with nearby +// transforms this might improve performance. Otherwise you can zero initialize this. +// The distance cache must be initialized to zero on the first call. +// Users should generally just zero initialize this structure for each call. +SimplexCache :: struct { + // Value use to compare length, area, volume of two simplexes. + metric: f32, + + // todo use an index of 0xFF as a sentinel and remove the count + // The number of stored simplex points + count: u16, + + // The cached simplex indices on shape A + indexA: [4]u8, + + // The cached simplex indices on shape B + indexB: [4]u8, +} + +emptyDistanceCache :: SimplexCache{} + +// Input parameters for b3ShapeCast +ShapeCastPairInput :: struct { + proxyA: ShapeProxy, //< The proxy for shape A + proxyB: ShapeProxy, //< The proxy for shape B + transform: Transform, //< Transform of shape B in shape A's frame, the relative pose B in A + translationB: Vec3, //< The translation of shape B, in A's frame + maxFraction: f32, //< The fraction of the translation to consider, typically 1 + canEncroach: bool, //< Allows shapes with a radius to move slightly closer if already touching +} + +// Input for ShapeDistance +DistanceInput :: struct { + // The proxy for shape A + proxyA: ShapeProxy, + + // The proxy for shape B + proxyB: ShapeProxy, + + // Transform of shape B in shape A's frame, the relative pose B in A + // (b3InvMulWorldTransforms( worldA, worldB )). The query is origin independent and runs in frame A. + transform: Transform, + + // Should the proxy radius be considered? + useRadii: bool, +} + +// Output for b3ShapeDistance +DistanceOutput :: struct { + pointA: Vec3, //< Closest point on shapeA, in shape A's frame + pointB: Vec3, //< Closest point on shapeB, in shape A's frame + normal: Vec3, //< A to B normal in shape A's frame. Invalid if distance is zero. + distance: f32, //< The final distance, zero if overlapped + iterations: c.int, //< Number of GJK iterations used + simplexCount: c.int, //< The number of simplexes stored in the simplex array +} + +// Simplex vertex for debugging the GJK algorithm +SimplexVertex :: struct { + wA: Vec3, //< support point in proxyA + wB: Vec3, //< support point in proxyB + w: Vec3, //< wB - wA + a: f32, //< barycentric coordinates + indexA: c.int, //< wA index + indexB: c.int, //< wB index +} + +// Simplex from the GJK algorithm +Simplex :: struct { + vertices: [4]SimplexVertex `fmt:"v,count"`, //< vertices + count: c.int, //< number of valid vertices +} + +// 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: Vec3, //< Local center of mass position + c1: Vec3, //< Starting center of mass world position + c2: Vec3, //< Ending center of mass world position + q1: Quat, //< Starting world rotation + q2: Quat, //< Ending world rotation +} + +// Time of impact input +TOIInput :: struct { + proxyA: ShapeProxy, //< The proxy for shape A + proxyB: ShapeProxy, //< The proxy for shape B + sweepA: Sweep, //< The movement of shape A + sweepB: Sweep, //< The movement of shape B + maxFraction: f32, //< Defines the sweep interval [0, tMax] +} + +// Describes the TOI output +TOIState :: enum c.int { + Unknown, + Failed, + Overlapped, + Hit, + Separated, +} + +// Time of impact output +TOIOutput :: struct { + // The type of result + state: TOIState, + + // The hit point + point: Vec3, + + // The hit normal + normal: Vec3, + + // The sweep time of the collision + fraction: f32, + + // The final distance + distance: f32, + + // Number of outer iterations + distanceIterations: c.int, + + // Total number of push back iterations + pushBackIterations: c.int, + + // Total number of root iterations + rootIterations: c.int, + + // Indicates that the time of impact detected initial + // overlap and used a fallback sphere as a last ditch effort + // to prevent tunneling. + usedFallback: bool, +} + +/**@}*/ // query + +/** + * @defgroup tree Dynamic Tree + * The dynamic tree is a binary AABB tree to organize and query large numbers of geometric objects + * + * Box3D 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 Box3D 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. + * 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. + * @{ + */ + +// Flags for tree nodes. For internal usage. +TreeNodeFlags :: distinct bit_set[TreeNodeFlag; u16] + +TreeNodeFlag :: enum u16 { + allocatedNode = 0, + enlargedNode = 1, + leafNode = 2, +} + +// Tree node child indices. For internal usage. +TreeNodeChildren :: struct { + child1: c.int, //< child node index 1 + child2: c.int, //< child node index 2 +} + +// A node in the dynamic tree. This is private data placed here for performance reasons. +// todo test padding to 64 bytes to avoid straddling cache lines +TreeNode :: struct { + // The node bounding box + aabb: AABB, // 24 + + // Category bits for collision filtering + categoryBits: u64, // 8 + + using _: struct #raw_union { + // Children (internal node) + children: TreeNodeChildren, + + // User data (leaf node) + userData: u64, + }, // 8 + + using _: struct #raw_union { + // The node parent index (allocated node) + parent: c.int, + + // The node freelist next index (free node) + next: c.int, + }, // 4 + + // Height of the node. Leaves have a height of 0. + height: u16, // 2 + + // @see TreeNodeFlags + flags: TreeNodeFlags, // 2 +} + +// Dynamic tree version for compatibility testing. +DYNAMIC_TREE_VERSION :: 0x93EDAF889FD30B4A + +// The dynamic tree structure. This should be considered private data. +// It is placed here for performance reasons. +DynamicTree :: struct { + // The dynamic tree version. Always the first field. Useful + // if the tree is serialized. + version: u64, + + // The tree nodes + nodes: [^]TreeNode `fmt:"v,nodeCapacity"`, + + // The root index + root: c.int, + + // The number of nodes + nodeCount: c.int, + + // The allocated node space + nodeCapacity: c.int, + + // Number of proxies created + proxyCount: c.int, + + // Node free list + freeList: c.int, + + // Leaf indices for rebuild + leafIndices: [^]int, + + // Leaf bounding boxes for rebuild + leafBoxes: [^]AABB, + + // Leaf bounding box centers for rebuild + leafCenters: [^]Vec3, + + // Bins for sorting during rebuild + binIndices: [^]c.int, + + // Allocated space for rebuilding + rebuildCapacity: c.int, +} + +// These are performance results returned by dynamic tree queries. +TreeStats :: struct { + // Number of internal nodes visited during the query + nodeVisits: c.int, + + // Number of leaf nodes visited during the query + leafVisits: c.int, +} + +// This function receives proxies found in the AABB query. +// @return true if the query should continue +TreeQueryCallbackFcn :: proc "c" (proxyId: c.int, userData: u64, ctx: rawptr) -> bool + +// This function receives the minimum distance squared so far and proxy to check in the closest query. +// @return minimum distance squared to user objects in the proxy +TreeQueryClosestCallbackFcn :: proc "c" (distanceSqrMin: f32, proxyId: c.int, userData: u64, ctx: rawptr) -> f32 + +// This function receives clipped AABB cast input for a proxy. The function returns the new cast +// fraction. +// - return a value of 0 to terminate the cast +// - return a value less than input->maxFraction to clip the cast +// - return a value of input->maxFraction to continue the cast without clipping +TreeBoxCastCallbackFcn :: proc "c" (#by_ptr input: BoxCastInput, proxyId: c.int, userData: u64, ctx: rawptr) -> f32 + +// 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 +TreeRayCastCallbackFcn :: proc "c" (#by_ptr input: RayCastInput, proxyId: c.int, userData: u64, ctx: rawptr) -> f32 + +/**@}*/ // tree + +/** + * @defgroup character Character Mover + * Character movement solver + * @{ + */ + +// The plane between a character mover and a shape +PlaneResult :: struct { + // Outward pointing plane. + plane: Plane, + + // Closest point on the shape. May not be unique. + point: Vec3, +} + +// These are collision planes that can be fed to b3SolvePlanes. Normally +// this is assembled by the user from plane results in b3PlaneResult. +CollisionPlane :: struct { + // The collision plane between the mover and some shape. + plane: Plane, + + // Setting this to FLT_MAX makes the plane as rigid as possible. Lower values can + // make the plane collision soft. Usually in meters. + pushLimit: f32, + + // The push on the mover determined by b3SolvePlanes. Usually in meters. + push: f32, + + // Indicates if b3ClipVector should clip against this plane. Should be false for soft collision. + clipVelocity: bool, +} + +// Result returned by b3SolvePlanes. +PlaneSolverResult :: struct { + // The final relative translation. + delta: Vec3, + + // The number of iterations used by the plane solver. For diagnostics. + iterationCount: c.int, +} + +// Body plane result for movers. +BodyPlaneResult :: struct { + // The shape id on the body. + shapeId: ShapeId, + + // The plane result. + result: PlaneResult, +} + +// Used to collect collision planes for character movers. +// Return true to continue gathering planes. +PlaneResultFcn :: proc "c" (shapeId: ShapeId, plane: [^]PlaneResult, planeCount: c.int, ctx: rawptr) -> bool + +// Used to filter shapes for shape casting character movers. +// Return true to accept the collision +MoverFilterFcn :: proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool + +/**@}*/ // mover + +/** + * @defgroup geometry Geometry + * @brief Geometry types and algorithms + * + * Definitions of spheres, capsules, hulls, meshes, height fields, and compounds. + * @{ + */ + +// This holds the mass data computed for a shape. +MassData :: struct { + // The shape mass + mass: f32, + + // The local center of mass position. + center: Vec3, + + // The inertia tensor about the shape center of mass. + inertia: Matrix3, +} + +/** + * @defgroup sphere Sphere + * @brief Sphere primitive + * @{ + */ + +// A solid sphere +Sphere :: struct { + // The local center + center: Vec3, + + // The radius + radius: f32, +} + +/**@}*/ // sphere + +/** + * @defgroup capsule Capsule + * @brief Capsule primitive + * @{ + */ + +// A solid capsule can be viewed as two hemispheres connected +// by a rectangle. +Capsule :: struct { + // Local center of the first hemisphere + center1: Vec3, + + // Local center of the second hemisphere + center2: Vec3, + + // The radius of the hemispheres + radius: f32, +} + +/**@}*/ // capsule + +/** + * @defgroup hull Convex Hull + * @brief Convex hull primitive + * @{ + */ + +// A hull vertex. Identified by a half-edge with this +// vertex as its tail. +HullVertex :: struct { + // A half-edge that has this vertex as the origin + // Can be used along with edge twins and winding order + // to traverse all the edges connected to this vertex. + edge: u8, +} + +// Half-edge for hull data structure +HullHalfEdge :: struct { + // Next edge index CCW + next: u8, + + // Twin edge index + twin: u8, + + // index of origin vertex and point + origin: u8, + + // Face to the left of this edge + face: u8, +} + +// A hull face. Hulls use a half-edge data structure, so a face +// can be determined from a single half-edge index. +HullFace :: struct { + // An arbitrary half-edge on this face + edge: u8, +} + +// 64-bit hull version. Useful for validating serialized data. +HULL_VERSION :: 0x9D4716CE3793900E + +// A convex hull. +// @note This data structure has data hanging off the end and cannot be directly copied. +HullData :: struct { + // Version must be first and match B3_HULL_VERSION + version: u64, + + // The total number of bytes for this hull. + byteCount: c.int, + + // Hash of this hull (this field is zero when the hash is computed). + hash: u32, + + // Axis-aligned box in local space. + aabb: AABB, + + // Surface area, typically in squared meters. + surfaceArea: f32, + + // Volume, typically in m^3. + volume: f32, + + // The radius of the largest sphere at the center. + innerRadius: f32, + + // The local centroid + center: Vec3, + + // The inertia tensor about the centroid. + centralInertia: Matrix3, + + // The vertex count. + vertexCount: c.int, + + // Offset of the vertex array in bytes from the struct address. + vertexOffset: c.int, + + // Offset of the point array in bytes from the struct address. + pointOffset: c.int, + + // This is the half-edge count (double the edge count) + edgeCount: c.int, + + // Offset of the edge array in bytes from the struct address. + edgeOffset: c.int, + + // The face count. Hulls faces are convex polygons. + faceCount: c.int, + + // Offset of the face array in bytes from the struct address. + faceOffset: c.int, + + // Offset of the face plane array in bytes from the struct address. + planeOffset: c.int, + + // Explicit padding. Hull identity is a content hash and memcmp over raw bytes, + // so there must be no unnamed padding for struct copies to scramble. + padding: c.int, +} + +// Efficient box hull +BoxHull :: struct { + // The embedded hull. So the offsets index into the arrays that follow. + base: HullData, + boxVertices: [8]HullVertex, //< Box vertices. + boxPoints: [8]Vec3, //< Box points. + boxEdges: [24]HullHalfEdge, //< Box half-edges. + boxFaces: [6]HullFace, //< Box faces. + padding: [2]u8, //< Explicit padding, see b3HullData::padding. + boxPlanes: [6]Plane, //< Box face planes. +} + +/**@}*/ // hull + +/** + * @defgroup mesh Triangle Mesh + * @brief Triangle mesh collision shape + * @{ + */ + +// This is used to create a re-usable collision mesh +MeshDef :: struct { + // Triangle vertices + vertices: [^]Vec3 `fmt:"v,vertexCount"`, + + // Triangle vertex indices. 3 for each triangle. + indices: [^]i32, + + // Triangle material index. 1 per triangle. Indexes into b3ShapeDef::materials. + // This allows different run-time material data to be associated with different + // instances of this mesh. + materialIndices: [^]u8, + + // Tolerance for vertex welding in length units. + weldTolerance: f32, + + // The vertex count. Must be 3 or more. + vertexCount: c.int, + + // The triangle count. Must be 1 or more. + triangleCount: c.int, + + // Optionally weld nearby vertices. + weldVertices: bool, + + // Use the median split instead of SAH to speed up mesh creation. Good + // for meshes that are structured like a grid. + useMedianSplit: bool, + + // Compute triangle adjacency information using shared edges + identifyEdges: bool, +} + +// 64-bit mesh version. Useful for validating serialized data. +MESH_VERSION :: 0xABD11AB62A6E886D + +// Triangle mesh edge flags. + +MeshEdgeFlags :: distinct bit_set[MeshEdgeFlag; c.uint] +MeshEdgeFlag :: enum c.uint { + concaveEdge1 = 0, + concaveEdge2 = 1, + concaveEdge3 = 2, + + inverseConcaveEdge1 = 4, + inverseConcaveEdge2 = 5, + inverseConcaveEdge3 = 6, +} + +concaveEdge1 :: MeshEdgeFlags{.concaveEdge1} +concaveEdge2 :: MeshEdgeFlags{.concaveEdge2} +concaveEdge3 :: MeshEdgeFlags{.concaveEdge3} +inverseConcaveEdge1 :: MeshEdgeFlags{.inverseConcaveEdge1} +inverseConcaveEdge2 :: MeshEdgeFlags{.inverseConcaveEdge2} +inverseConcaveEdge3 :: MeshEdgeFlags{.inverseConcaveEdge3} +allConcaveEdges :: concaveEdge1 + concaveEdge2 + concaveEdge3 +flatEdge1 :: concaveEdge1 + inverseConcaveEdge1 +flatEdge2 :: concaveEdge2 + inverseConcaveEdge2 +flatEdge3 :: concaveEdge3 + inverseConcaveEdge3 +allFlatEdges :: flatEdge1 + flatEdge2 + flatEdge3 + +// A mesh triangle. +MeshTriangle :: struct { + index1: i32, //< Index of vertex 1. + index2: i32, //< Index of vertex 2. + index3: i32, //< Index of vertex 3. +} + +// A mesh BVH node. +MeshNode :: struct { + // The lower bound of the node AABB. Strategic placement for SIMD. + lowerBound: Vec3, + + // Anonymous union. + data: struct #raw_union { + // Internal node + asNode: bit_field u32 { + // Split axis. 0, 1, or 2. + axis: u32 | 2, + // Offset of the second child node. + childOffset: u32 | 30, + }, + + // Leaf node + asLeaf: bit_field u32 { + // Aligned with axis above and has value of 3 if this is a leaf. + type: u32 | 2, + + // The number of triangles for this leaf node. + triangleCount: u32 | 30, + }, + }, + + // The upper bound of the node AABB. Strategic placement for SIMD. + upperBound: Vec3, + + // The index of the leaf triangles. + triangleOffset: u32, +} + +// This is a sorted triangle collision bounding volume hierarchy. +// @note This struct has data hanging off the end and cannot be directly copied. +MeshData :: struct { + // Version must be first. + version: u64, + + // The total number of bytes for this mesh. + byteCount: c.int, + + // Hash of this mesh (this field is zero when the hash is computed) + hash: u32, + + // Local axis-aligned box. + bounds: AABB, + + // Combined surface area of all triangles. Single-sided. + surfaceArea: f32, + + // The height of the bounding volume hierarchy. + treeHeight: c.int, + + // The number of degenerate triangles. Diagnostic. + degenerateCount: c.int, + + // Offset of the node array in bytes from the struct address. + nodeOffset: c.int, + + // The number of BVH nodes. + nodeCount: c.int, + + // Offset of the vertex array in bytes from the struct address. + vertexOffset: c.int, + + // The number of vertices. + vertexCount: c.int, + + // Offset of the triangle array in bytes from the struct address. + triangleOffset: c.int, + + // The number of triangles. + triangleCount: c.int, + + // Offset of the material array in bytes from the struct address. + materialOffset: c.int, + + // The number of materials. + materialCount: c.int, + + // Offset of the triangle flag array in bytes from the struct address. + flagsOffset: c.int, +} + +// This allows mesh data to be re-used with different scales. +Mesh :: struct { + // Immutable pointer to the mesh data. + data: ^MeshData, + + // This scale may be non-uniform and have negative components. However, + // no component may be very small in magnitude. + scale: Vec3, +} + +/**@}*/ // mesh + +/** + * @defgroup height_field Height Field + * @brief Height field collision shape + * @{ + */ + +// Data used to create a height field +HeightFieldDef :: struct { + // Grid point heights + // count = countX * countZ + heights: [^]f32, + + // Grid cell material + // A value of 0xFF is reserved for holes + // count = (countX - 1) * (countZ - 1) + materialIndices: [^]u8, + + // The height field scale. All components must be positive values. + scale: Vec3, + + // The number of grid lines along the x-axis. + countX: c.int, + + // The number of grid lines along the z-axis. + countZ: c.int, + + // Global minimum and maximum heights used for quantization. This is important + // if you want height fields to be placed next to each other and line up exactly. + // In that case, both height fields should use the same minimum and maximum heights. + // All height values are clamped to this range. + // These values are in unscaled space. + globalMinimumHeight: f32, + + // The maximum. + globalMaximumHeight: f32, + + // Use clock-wise winding. This effectively inverts the height-field along the y-axis. + clockwiseWinding: bool, +} + +// This material index is used to designate holes in a height field. +HEIGHT_FIELD_HOLE :: 0xFF + +// 64-bit height-field version. Useful for validating serialized data. +HEIGHT_FIELD_VERSION :: 0x8B18CBD138A6BC84 + +// A height field with compressed storage. +// @note This data structure has data hanging off the end and cannot be directly copied. +HeightFieldData :: struct { + // Version must be first and match B3_HEIGHT_FIELD_VERSION + version: i64, + + // The total number of bytes for this height field. + byteCount: c.int, + + // Hash of this height field (this field is zero when the hash is computed). + hash: u32, + + // The local axis-aligned bounding box. + aabb: AABB, + + // The minimum y value. + minHeight: f32, + + // The maximum y value + maxHeight: f32, + + // The quantization scale. + heightScale: f32, + + // The overall scale. + scale: Vec3, + + // The number of grid columns along the local x-axis. + columnCount: c.int, + + // The number of grid rows along the local z-axis. + rowCount: c.int, + + // Offset of the compressed height array in bytes from the struct address. + // uint16_t, one per grid point. + heightsOffset: c.int, + + // Offset of the material index array in bytes from the struct address. + // uint8_t, one per cell. + materialOffset: c.int, + + // Offset of the flag array in bytes from the struct address. + // uint8_t, one per triangle. + flagsOffset: c.int, + + // Triangle winding. + clockwise: bool, + + // Explicit padding. Identity is a content hash over raw bytes, so there must + // be no unnamed padding for struct copies to scramble. + padding: [3]u8, +} + +/**@}*/ // height_field + +/** + * @defgroup compound Compound + * @brief Compound collision shape + * @{ + */ + +// Definition for a capsule in a compound shape. +CompoundCapsuleDef :: struct { + // Local capsule. + capsule: Capsule, + + // Material properties. + material: SurfaceMaterial, +} + +// Definition for a convex hull in a compound shape. +CompoundHullDef :: struct { + // Shared hull. + hull: ^HullData, + + // Transform of the shared hull into compound local space. + transform: Transform, + + // Material properties. + material: SurfaceMaterial, +} + +// Definition for a triangle mesh in a compound shape. +CompoundMeshDef :: struct { + // Shared mesh. + meshData: ^MeshData, + + // Transform of the shared mesh into compound local space. + transform: Transform, + + // Local space non-uniform mesh scale. May have negative components. + scale: Vec3, + + // Material properties. + // This array must line up with the material indices on the triangles. + materials: [^]SurfaceMaterial `fmt:"v,materialCount"`, + + // Number of materials. + materialCount: c.int, +} + +// Definition for a sphere in a compound shape. +CompoundSphereDef :: struct { + // Local sphere. + sphere: Sphere, + + // Material properties. + material: SurfaceMaterial, +} + +// Definition for creating a compound shape. All this data is fully cloned +// into the run-time compound shape. +CompoundDef :: struct { + // Capsule instances. + capsules: [^]CompoundCapsuleDef `fmt:"v,capsuleCount"`, + + // Number of capsules. + capsuleCount: int, + + // Hulls instances. + hulls: [^]CompoundHullDef `fmt:"v,hullCount"`, + + // Number of hull instances. + hullCount: int, + + // Mesh instances. + meshes: [^]CompoundMeshDef `fmt:"v,meshCount"`, + + // Number of mesh instances. + meshCount: int, + + // Sphere instances. + spheres: [^]CompoundSphereDef `fmt:"v,sphereCount"`, + + // Number of spheres. + sphereCount: int, +} + +// The compound version depends on the tree, mesh, and hull versions. +COMPOUND_VERSION :: 0x830778DB07086EB4 ~ DYNAMIC_TREE_VERSION ~ MESH_VERSION ~ HULL_VERSION + +// Meshes used in compounds have limited space for materials. If you have +// a mesh with many materials, you can use it outside of the compound. +MAX_COMPOUND_MESH_MATERIALS :: 4 + +// The runtime data for a compound shape. This is a potentially large yet highly optimized +// data structure. It can contain thousands of child shapes, yet at runtime it populates +// into the world as a single shape in the runtime broad-phase. +// This data structure has data living off the end and must be accessed using offsets. +// Accessors are provided for user relevant data. +CompoundData :: struct { + // The compound version is always first. + version: u64, + + // The total number of bytes for this compound. + byteCount: c.int, + + // Offset of the tree node array in bytes from the struct address. + nodeOffset: c.int, + + // Immutable dynamic tree. The tree node pointer must be fixed up using the node offset + tree: DynamicTree, + + // Offset of the material array in bytes from the struct address. + materialOffset: c.int, + + // The number of materials. + materialCount: c.int, + + // Offset of the capsule array in bytes from the struct address. + capsuleOffset: c.int, + + // The number of capsules. + capsuleCount: c.int, + + // Offset of the hull instance array in bytes from the struct address. + hullOffset: c.int, + + // The number of hull instances. + hullCount: c.int, + + // The number of unique hulls. Diagnostic. + sharedHullCount: c.int, + + // Offset of the mesh instance array in bytes from the struct address. + meshOffset: c.int, + + // The number of mesh instances. + meshCount: c.int, + + // The number of unique meshes. Diagnostic. + sharedMeshCount: c.int, + + // Offset of the sphere array in bytes from the struct address. + sphereOffset: c.int, + + // The number of spheres. + sphereCount: c.int, +} + +// A capsule that lives in a compound. +CompoundCapsule :: struct { + // Local capsule. + capsule: Capsule, + + // Index to a shared material. + materialIndex: c.int, +} + +// A hull that lives in a compound. +CompoundHull :: struct { + // Pointer to the unique shared hull. + hull: ^HullData, + + // The transform of this hull instance. + transform: Transform, + + // Index to a shared material. + materialIndex: c.int, +} + +// A mesh with non-uniform scale that lives in a compound. +CompoundMesh :: struct { + // Pointer to the unique shared mesh. + meshData: [^]MeshData, + + // The transform of this mesh instance. + transform: Transform, + + // Non-uniform scale of this mesh instance. + scale: Vec3, + + // This is used to access the surface material from b3GetCompoundMaterials. + // Requires an extra level of indirection. The triangle material index + // is clamped to B3_MAX_COMPOUND_MESH_MATERIALS. + // materialIndex = materialIndices[triangle->materialIndex] + materialIndices: [MAX_COMPOUND_MESH_MATERIALS]c.int, +} + +// A sphere that lives in a compound. +CompoundSphere :: struct { + // Local sphere. + sphere: Sphere, + + // Index to a shared material. + materialIndex: c.int, +} + +// Child shape of a compound +ChildShape :: struct { + // Tagged union. + using _: struct #raw_union { + capsule: Capsule, //< Capsule. + hull: ^HullData, //< Hull. + mesh: Mesh, //< Mesh. + sphere: Sphere, //< Sphere. + }, + + // Transform of the shape into compound local space. + transform: Transform, + + // Material indices. Index 0 is used for convex shapes. + // todo limit to 64K? + materialIndices: [MAX_COMPOUND_MESH_MATERIALS]c.int, + + // The shape type (union tag). + type: ShapeType, +} + +// Callback for compound overlap queries. +CompoundQueryFcn :: proc "c" (#by_ptr compound: CompoundData, childIndex: c.int, ctx: rawptr) -> bool + +/**@}*/ // compound + +/**@}*/ // geometry + +/** + * @defgroup collision Shape Collision + * Collide 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. +// Box3D uses speculative collision so some contact points may be separated. +// You may use the maxNormalImpulse to determine if there was an interaction during +// the time step. +ManifoldPoint :: struct { + // Location of the contact point relative to the bodyA center of mass in world space. + anchorA: Vec3, + + // Location of the contact point relative to the bodyB center of mass in world space. + anchorB: Vec3, + + // The separation of the contact point, negative if penetrating + separation: f32, + + // Cached separation used for contact recycling + baseSeparation: f32, + + // The impulse along the manifold normal vector. Since Box3D uses sub-stepping, this is + // result from the final sub-step. + normalImpulse: f32, + + // The total normal impulse applied during sub-stepping. This is important + // to identify speculative contact points that had an interaction in the time step. + totalNormalImpulse: 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, + + // Local point for matching + // Uniquely identifies a contact point between two shapes + featureId: u32, + + // Triangle index if one of the shapes is a mesh or height field + triangleIndex: c.int, + + // Did this contact point exist in the previous step? + persisted: bool, +} + +// A contact manifold describes the contact points between colliding shapes. +// @note Box3D uses speculative collision so some contact points may be separated. +Manifold :: struct { + // The manifold points. There may be 1 to 4 valid points. + points: [MAX_MANIFOLD_POINTS]ManifoldPoint, + + // The unit normal vector in world space, points from shape A to shape B + normal: Vec3, + + // Central friction angular impulse (applied about the normal) + twistImpulse: f32, + + // Central friction linear impulse + frictionImpulse: Vec3, + + // Rolling resistance angular impulse + rollingImpulse: Vec3, + + // The number of contact points, will be 0 to 4 + pointCount: c.int, +} + +// Cached separating axis feature. +SeparatingFeature :: enum c.int { + invalidAxis = 0, + backsideAxis, + faceAxisA, + faceAxisB, + edgePairAxis, + closestPointsAxis, + + // These are for testing + manualFaceAxisA, + manualFaceAxisB, + manualEdgePairAxis, +} + +// Cached triangle feature. +TriangleFeature :: enum c.int { + featureNone = 0, + featureTriangleFace, + featureHullFace, + // v1-v2 + featureEdge1, + // v2-v3 + featureEdge2, + // v3-v1 + featureEdge3, + featureVertex1, + featureVertex2, + featureVertex3, +} + +// Separating axis test cache. Provides temporal acceleration of collision routines. +SATCache :: struct { + // The separation when the cache is populated. Negative for overlap. + separation: f32, + + // b3SeparatingFeature. + type: u8, + + // Index of the feature on shape A. + indexA: u8, + + // Index of the feature on shape B. + indexB: u8, + + // Was the cache re-used? + hit: u8, +} + +// Contact points are always the result of two edges intersecting. +// It can be two edges of the same shape, which is just a shape vertex. +// Or a contact point can be the result of two edges crossing from different shapes. +// This is designed to support hull versus hull, but it is adapted to work +// with all shape types. The feature pair is used to identify contact points +// for temporal coherence and warm starting. +FeaturePair :: struct { + // Incoming type (either edge on shape A or shape B) + owner1: u8, + // Incoming edge index (into associated shape array) + index1: u8, + // Outgoing type (either edge on shape A or shape B) + owner2: u8, + // Outgoing edge index (into associated shape array) + index2: u8, +} + +// A local manifold point and normal in frame A. +LocalManifoldPoint :: struct { + // Local point in frame A. + point: Vec3, + + // The contact point separation. Negative for overlap. + separation: f32, + + // The feature pair for this point. + pair: FeaturePair, + + // The triangle index when collide with a mesh or height-field. + triangleIndex: c.int, +} + +// A local manifold with no dynamic information. Used by b3Collide functions. +LocalManifold :: struct { + // Local normal in frame A. + normal: Vec3, + + // The triangle normal. + triangleNormal: Vec3, + + // The manifold points. From a point buffer. + points: LocalManifoldPoint, + + // The number of manifold points. Only bounded by the buffer capacity. + pointCount: c.int, + + // The index of the triangle. + triangleIndex: c.int, + + i1: c.int, //< Vertex 1 index. + i2: c.int, //< Vertex 2 index. + i3: c.int, //< Vertex 3 index. + + // The squared distance of a sphere from a triangle. For ghost collision reduction. + squaredDistance: f32, + + // The triangle feature involved. + feature: TriangleFeature, + + // MeshEdgeFlags. + triangleFlags: MeshEdgeFlags, +} + +/**@}*/ // collision + +/** + * @defgroup debug_draw Debug Draw + * @{ + */ + +// These colors are used for debug draw and mostly match the named SVG colors. +// See https://www.rapidtables.com/web/color/index.html +// https://johndecember.com/html/spec/colorsvg.html +// https://upload.wikimedia.org/wikipedia/commons/2/2b/SVG_Recognized_color_keyword_names.svg +HexColor :: enum c.uint { + 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 = 0x808080, + Green = 0x008000, + GreenYellow = 0xADFF2F, + HoneyDew = 0xF0FFF0, + HotPink = 0xFF69B4, + IndianRed = 0xCD5C5C, + Indigo = 0x4B0082, + Ivory = 0xFFFFF0, + Khaki = 0xF0E68C, + Lavender = 0xE6E6FA, + LavenderBlush = 0xFFF0F5, + LawnGreen = 0x7CFC00, + LemonChiffon = 0xFFFACD, + LightBlue = 0xADD8E6, + LightCoral = 0xF08080, + LightCyan = 0xE0FFFF, + LightGoldenRodYellow = 0xFAFAD2, + LightGray = 0xD3D3D3, + LightGreen = 0x90EE90, + LightPink = 0xFFB6C1, + LightSalmon = 0xFFA07A, + LightSeaGreen = 0x20B2AA, + LightSkyBlue = 0x87CEFA, + LightSlateGray = 0x778899, + LightSteelBlue = 0xB0C4DE, + LightYellow = 0xFFFFE0, + Lime = 0x00FF00, + LimeGreen = 0x32CD32, + Linen = 0xFAF0E6, + Magenta = 0xFF00FF, + Maroon = 0x800000, + MediumAquaMarine = 0x66CDAA, + MediumBlue = 0x0000CD, + MediumOrchid = 0xBA55D3, + MediumPurple = 0x9370DB, + MediumSeaGreen = 0x3CB371, + MediumSlateBlue = 0x7B68EE, + MediumSpringGreen = 0x00FA9A, + MediumTurquoise = 0x48D1CC, + MediumVioletRed = 0xC71585, + MidnightBlue = 0x191970, + MintCream = 0xF5FFFA, + MistyRose = 0xFFE4E1, + Moccasin = 0xFFE4B5, + NavajoWhite = 0xFFDEAD, + Navy = 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 = 0x800080, + RebeccaPurple = 0x663399, + Red = 0xFF0000, + RosyBrown = 0xBC8F8F, + RoyalBlue = 0x4169E1, + SaddleBrown = 0x8B4513, + Salmon = 0xFA8072, + SandyBrown = 0xF4A460, + SeaGreen = 0x2E8B57, + SeaShell = 0xFFF5EE, + Sienna = 0xA0522D, + Silver = 0xC0C0C0, + SkyBlue = 0x87CEEB, + SlateBlue = 0x6A5ACD, + SlateGray = 0x708090, + Snow = 0xFFFAFA, + SpringGreen = 0x00FF7F, + SteelBlue = 0x4682B4, + Tan = 0xD2B48C, + Teal = 0x008080, + Thistle = 0xD8BFD8, + Tomato = 0xFF6347, + Turquoise = 0x40E0D0, + Violet = 0xEE82EE, + Wheat = 0xF5DEB3, + White = 0xFFFFFF, + WhiteSmoke = 0xF5F5F5, + Yellow = 0xFFFF00, + YellowGreen = 0x9ACD32, + + Box2DRed = 0xDC3132, + Box2DBlue = 0x30AEBF, + Box2DGreen = 0x8CC924, + Box2DYellow = 0xFFEE8C, +} + +// Debug draw material preset. Optionally packed into the unused high byte of a +// b3HexColor (or b3SurfaceMaterial::customColor) to drive the renderer's PBR +// roughness and metalness. The low 24 bits stay RGB, so a plain 0xRRGGBB color +// reads as b3_debugMaterialDefault and keeps the renderer's per-body-type look. +DebugMaterial :: enum c.uint { + Default = 0, + Matte, + Soft, + Dead, + Glossy, + Metallic, +} + + +// This is sent to the user for debug shape creation. The user should know the type in case they have +// custom sphere or capsule rendering. +DebugShape :: struct { + // Shape id. + shapeId: ShapeId, + + // Shape type. + type: ShapeType, + + // Tagged union. + using _: struct #raw_union { + capsule: ^Capsule `raw_union_tag:"type=.capsuleShape"`, //< Capsule shape. + compound: ^CompoundData `raw_union_tag:"type=.compoundShape"`, //< Compound shape. + heightField: ^HeightFieldData `raw_union_tag:"type=.heightShape"`, //< Height-field shape. + hull: ^HullData `raw_union_tag:"type=.hullShape"`, //< Convex hull shape. + mesh: ^Mesh `raw_union_tag:"type=.meshShape"`, //< Mesh shape with scale. + sphere: ^Sphere `raw_union_tag:"type=.sphereShape"`, //< Sphere shape. + }, +} + +// This struct is passed to b3World_Draw to draw a debug view of the simulation world. +// Callbacks receive world coordinates. In large world mode the translation is double precision so +// it stays accurate far from the origin. Shift into your own camera frame inside the callbacks. +DebugDraw :: struct { + // Draws a shape and returns true if drawing should continue + DrawShapeFcn: proc "c" (userShape: rawptr, transform: WorldTransform, color: HexColor, ctx: rawptr) -> bool, + + // Draw a line segment. + DrawSegmentFcn: proc "c" (p1, p2: Pos, color: HexColor, ctx: rawptr), + + // Draw a transform. Choose your own length scale. + DrawTransformFcn: proc "c" (transform: WorldTransform, ctx: rawptr), + + // Draw a point. + DrawPointFcn: proc "c" (p: Pos, size: f32, color: HexColor, ctx: rawptr), + + // Draw a sphere. + DrawSphereFcn: proc "c" (p: Pos, radius: f32, color: HexColor, alpha: f32, ctx: rawptr), + + // Draw a capsule. + DrawCapsuleFcn: proc "c" (p1, p2: Pos, radius: f32, color: HexColor, alpha: f32, ctx: rawptr), + + // Draw a bounding box. + DrawBoundsFcn: proc "c" (aabb: AABB, color: HexColor, ctx: rawptr), + + // Draw an oriented box. + DrawBoxFcn: proc "c" (extents: Vec3, transform: WorldTransform, color: HexColor, ctx: rawptr), + + // Draw a string in world space + DrawStringFcn: proc "c" (p: Pos, s: cstring, color: HexColor, ctx: rawptr), + + // World bounds to use for debug draw + drawingBounds: AABB, + + // Scale to use when drawing forces + forceScale: f32, + + // Global scaling for joint drawing + jointScale: f32, + + // 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 + drawBounds: bool, + + // Option to draw the mass and center of mass of dynamic bodies + drawMass: bool, + + // Option to draw body names + drawBodyNames: bool, + + // Option to draw contact points + drawContacts: bool, + + // Draw contact anchor A or B + drawAnchorA: c.int, + + // Option to visualize the graph coloring used for contacts and joints + drawGraphColors: bool, + + // Option to draw contact features + drawContactFeatures: bool, + + // Option to draw contact normals + drawContactNormals: bool, + + // Option to draw contact normal forces + drawContactForces: bool, + + // Option to draw contact friction forces + drawFrictionForces: bool, + + // Option to draw islands as bounding boxes + drawIslands: bool, + + // User context that is passed as an argument to drawing callback functions + ctx: rawptr, +}