Lucien Greathouse 1 éve
commit
b6c1bede17
8 módosított fájl, 6421 hozzáadás és 0 törlés
  1. 3 0
      .gitmodules
  2. 3101 0
      JoltC/JoltPhysicsC.cpp
  3. 2113 0
      JoltC/JoltPhysicsC.h
  4. 301 0
      JoltC/JoltPhysicsC_Extensions.cpp
  5. 856 0
      JoltC/JoltPhysicsC_Tests.c
  6. 1 0
      JoltPhysics
  7. 22 0
      LICENSE
  8. 24 0
      README.md

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "JoltPhysics"]
+	path = JoltPhysics
+	url = https://github.com/jrouwe/JoltPhysics

+ 3101 - 0
JoltC/JoltPhysicsC.cpp

@@ -0,0 +1,3101 @@
+#include "JoltPhysicsC.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <Jolt/Jolt.h>
+#include <Jolt/RegisterTypes.h>
+#include <Jolt/Core/Factory.h>
+#include <Jolt/Core/TempAllocator.h>
+#include <Jolt/Core/Memory.h>
+#include <Jolt/Core/JobSystemThreadPool.h>
+#include <Jolt/Physics/PhysicsSettings.h>
+#include <Jolt/Physics/PhysicsSystem.h>
+#include <Jolt/Physics/EPhysicsUpdateError.h>
+#include <Jolt/Physics/Collision/NarrowPhaseQuery.h>
+#include <Jolt/Physics/Collision/CollideShape.h>
+#include <Jolt/Physics/Collision/Shape/BoxShape.h>
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
+#include <Jolt/Physics/Collision/Shape/TriangleShape.h>
+#include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
+#include <Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h>
+#include <Jolt/Physics/Collision/Shape/CylinderShape.h>
+#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
+#include <Jolt/Physics/Collision/Shape/HeightFieldShape.h>
+#include <Jolt/Physics/Collision/Shape/MeshShape.h>
+#include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
+#include <Jolt/Physics/Collision/Shape/ScaledShape.h>
+#include <Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h>
+#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
+#include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
+#include <Jolt/Physics/Collision/PhysicsMaterial.h>
+#include <Jolt/Physics/Constraints/FixedConstraint.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
+#include <Jolt/Physics/Body/BodyActivationListener.h>
+#include <Jolt/Physics/Body/BodyLock.h>
+#include <Jolt/Physics/Body/BodyManager.h>
+#include <Jolt/Physics/Body/BodyFilter.h>
+#include <Jolt/Physics/Character/Character.h>
+#include <Jolt/Physics/Character/CharacterVirtual.h>
+
+#if JPC_DEBUG_RENDERER == 1
+#include <string_view>
+#include <Jolt/Renderer/DebugRenderer.h>
+#endif //JPC_DEBUG_RENDERER
+
+JPH_SUPPRESS_WARNINGS
+
+#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
+#error Currently JoltPhysicsC does not support profiling. Please undef JPH_EXTERNAL_PROFILE and JPH_PROFILE_ENABLED.
+#endif
+
+#if defined(JPH_TRACK_BROADPHASE_STATS)
+#error JPH_TRACK_BROADPHASE_STATS is not supported.
+#endif
+
+#define ENSURE_TYPE(o, t) \
+    assert(o != nullptr); \
+    assert(reinterpret_cast<const JPH::SerializableObject *>(o)->CastTo(JPH_RTTI(t)) != nullptr)
+
+#define FN(name) static auto name
+
+FN(toJph)(JPC_BodyID in) { return JPH::BodyID(in); }
+FN(toJpc)(JPH::BodyID in) { return in.GetIndexAndSequenceNumber(); }
+
+FN(toJpc)(const JPH::Body *in) { assert(in); return reinterpret_cast<const JPC_Body *>(in); }
+FN(toJph)(const JPC_Body *in) { assert(in); return reinterpret_cast<const JPH::Body *>(in); }
+FN(toJpc)(JPH::Body *in) { assert(in); return reinterpret_cast<JPC_Body *>(in); }
+FN(toJph)(JPC_Body *in) { assert(in); return reinterpret_cast<JPH::Body *>(in); }
+
+FN(toJph)(const JPC_PhysicsMaterial *in) { return reinterpret_cast<const JPH::PhysicsMaterial *>(in); }
+FN(toJpc)(const JPH::PhysicsMaterial *in) { return reinterpret_cast<const JPC_PhysicsMaterial *>(in); }
+
+FN(toJph)(const JPC_ShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ShapeSettings);
+    return reinterpret_cast<const JPH::ShapeSettings *>(in);
+}
+FN(toJph)(JPC_ShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ShapeSettings);
+    return reinterpret_cast<JPH::ShapeSettings *>(in);
+}
+FN(toJpc)(const JPH::ShapeSettings *in) { assert(in); return reinterpret_cast<const JPC_ShapeSettings *>(in); }
+FN(toJpc)(JPH::ShapeSettings *in) { assert(in); return reinterpret_cast<JPC_ShapeSettings *>(in); }
+
+FN(toJph)(const JPC_BoxShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::BoxShapeSettings);
+    return reinterpret_cast<const JPH::BoxShapeSettings *>(in);
+}
+FN(toJph)(JPC_BoxShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::BoxShapeSettings);
+    return reinterpret_cast<JPH::BoxShapeSettings *>(in);
+}
+FN(toJpc)(JPH::BoxShapeSettings *in) { assert(in); return reinterpret_cast<JPC_BoxShapeSettings *>(in); }
+
+FN(toJph)(const JPC_SphereShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::SphereShapeSettings);
+    return reinterpret_cast<const JPH::SphereShapeSettings *>(in);
+}
+FN(toJph)(JPC_SphereShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::SphereShapeSettings);
+    return reinterpret_cast<JPH::SphereShapeSettings *>(in);
+}
+FN(toJpc)(JPH::SphereShapeSettings *in) { assert(in); return reinterpret_cast<JPC_SphereShapeSettings *>(in); }
+
+FN(toJph)(const JPC_TriangleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::TriangleShapeSettings);
+    return reinterpret_cast<const JPH::TriangleShapeSettings *>(in);
+}
+FN(toJph)(JPC_TriangleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::TriangleShapeSettings);
+    return reinterpret_cast<JPH::TriangleShapeSettings *>(in);
+}
+FN(toJpc)(JPH::TriangleShapeSettings *in) { assert(in); return reinterpret_cast<JPC_TriangleShapeSettings *>(in); }
+
+FN(toJph)(const JPC_CapsuleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::CapsuleShapeSettings);
+    return reinterpret_cast<const JPH::CapsuleShapeSettings *>(in);
+}
+FN(toJph)(JPC_CapsuleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::CapsuleShapeSettings);
+    return reinterpret_cast<JPH::CapsuleShapeSettings *>(in);
+}
+FN(toJpc)(JPH::CapsuleShapeSettings *in) { assert(in); return reinterpret_cast<JPC_CapsuleShapeSettings *>(in); }
+
+FN(toJph)(const JPC_TaperedCapsuleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::TaperedCapsuleShapeSettings);
+    return reinterpret_cast<const JPH::TaperedCapsuleShapeSettings *>(in);
+}
+FN(toJph)(JPC_TaperedCapsuleShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::TaperedCapsuleShapeSettings);
+    return reinterpret_cast<JPH::TaperedCapsuleShapeSettings *>(in);
+}
+FN(toJpc)(JPH::TaperedCapsuleShapeSettings *in) {
+    assert(in); return reinterpret_cast<JPC_TaperedCapsuleShapeSettings *>(in);
+}
+
+FN(toJph)(const JPC_CylinderShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::CylinderShapeSettings);
+    return reinterpret_cast<const JPH::CylinderShapeSettings *>(in);
+}
+FN(toJph)(JPC_CylinderShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::CylinderShapeSettings);
+    return reinterpret_cast<JPH::CylinderShapeSettings *>(in);
+}
+FN(toJpc)(JPH::CylinderShapeSettings *in) { assert(in); return reinterpret_cast<JPC_CylinderShapeSettings *>(in); }
+
+FN(toJph)(const JPC_ConvexHullShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ConvexHullShapeSettings);
+    return reinterpret_cast<const JPH::ConvexHullShapeSettings *>(in);
+}
+FN(toJph)(JPC_ConvexHullShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ConvexHullShapeSettings);
+    return reinterpret_cast<JPH::ConvexHullShapeSettings *>(in);
+}
+FN(toJpc)(JPH::ConvexHullShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_ConvexHullShapeSettings *>(in);
+}
+
+FN(toJph)(const JPC_HeightFieldShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::HeightFieldShapeSettings);
+    return reinterpret_cast<const JPH::HeightFieldShapeSettings *>(in);
+}
+FN(toJph)(JPC_HeightFieldShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::HeightFieldShapeSettings);
+    return reinterpret_cast<JPH::HeightFieldShapeSettings *>(in);
+}
+FN(toJpc)(JPH::HeightFieldShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_HeightFieldShapeSettings *>(in);
+}
+
+FN(toJph)(const JPC_MeshShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::MeshShapeSettings);
+    return reinterpret_cast<const JPH::MeshShapeSettings *>(in);
+}
+FN(toJph)(JPC_MeshShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::MeshShapeSettings);
+    return reinterpret_cast<JPH::MeshShapeSettings *>(in);
+}
+FN(toJpc)(JPH::MeshShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_MeshShapeSettings *>(in);
+}
+
+FN(toJph)(const JPC_ConvexShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ConvexShapeSettings);
+    return reinterpret_cast<const JPH::ConvexShapeSettings *>(in);
+}
+FN(toJph)(JPC_ConvexShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::ConvexShapeSettings);
+    return reinterpret_cast<JPH::ConvexShapeSettings *>(in);
+}
+
+FN(toJpc)(JPH::RotatedTranslatedShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_DecoratedShapeSettings *>(in);
+}
+FN(toJpc)(JPH::ScaledShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_DecoratedShapeSettings *>(in);
+}
+FN(toJpc)(JPH::OffsetCenterOfMassShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_DecoratedShapeSettings *>(in);
+}
+FN(toJph)(JPC_DecoratedShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::DecoratedShapeSettings);
+    return reinterpret_cast<JPH::DecoratedShapeSettings *>(in);
+}
+
+FN(toJpc)(JPH::StaticCompoundShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_CompoundShapeSettings *>(in);
+}
+FN(toJpc)(JPH::MutableCompoundShapeSettings *in) {
+    assert(in);
+    return reinterpret_cast<JPC_CompoundShapeSettings *>(in);
+}
+FN(toJph)(JPC_CompoundShapeSettings *in) {
+    ENSURE_TYPE(in, JPH::CompoundShapeSettings);
+    return reinterpret_cast<JPH::CompoundShapeSettings *>(in);
+}
+
+FN(toJph)(const JPC_ConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::ConstraintSettings);
+    return reinterpret_cast<const JPH::ConstraintSettings *>(in);
+}
+FN(toJph)(JPC_ConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::ConstraintSettings);
+    return reinterpret_cast<JPH::ConstraintSettings *>(in);
+}
+FN(toJpc)(const JPH::ConstraintSettings *in) { assert(in); return reinterpret_cast<const JPC_ConstraintSettings *>(in); }
+FN(toJpc)(JPH::ConstraintSettings *in) { assert(in); return reinterpret_cast<JPC_ConstraintSettings *>(in); }
+
+FN(toJph)(const JPC_TwoBodyConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::TwoBodyConstraintSettings);
+    return reinterpret_cast<const JPH::TwoBodyConstraintSettings *>(in);
+}
+FN(toJph)(JPC_TwoBodyConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::TwoBodyConstraintSettings);
+    return reinterpret_cast<JPH::TwoBodyConstraintSettings *>(in);
+}
+FN(toJpc)(const JPH::TwoBodyConstraintSettings *in) { assert(in); return reinterpret_cast<const JPC_TwoBodyConstraintSettings *>(in); }
+FN(toJpc)(JPH::TwoBodyConstraintSettings *in) { assert(in); return reinterpret_cast<JPC_TwoBodyConstraintSettings *>(in); }
+
+FN(toJph)(const JPC_FixedConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::FixedConstraintSettings);
+    return reinterpret_cast<const JPH::FixedConstraintSettings *>(in);
+}
+FN(toJph)(JPC_FixedConstraintSettings *in) {
+    ENSURE_TYPE(in, JPH::FixedConstraintSettings);
+    return reinterpret_cast<JPH::FixedConstraintSettings *>(in);
+}
+FN(toJpc)(JPH::FixedConstraintSettings *in) { assert(in); return reinterpret_cast<JPC_FixedConstraintSettings *>(in); }
+
+FN(toJph)(const JPC_CollisionGroup *in) { assert(in); return reinterpret_cast<const JPH::CollisionGroup *>(in); }
+FN(toJpc)(const JPH::CollisionGroup *in) { assert(in); return reinterpret_cast<const JPC_CollisionGroup *>(in); }
+FN(toJpc)(JPH::CollisionGroup *in) { assert(in); return reinterpret_cast<JPC_CollisionGroup *>(in); }
+
+FN(toJph)(const JPC_SubShapeID *in) { assert(in); return reinterpret_cast<const JPH::SubShapeID *>(in); }
+
+FN(toJph)(const JPC_BodyLockInterface *in) {
+    assert(in); return reinterpret_cast<const JPH::BodyLockInterface *>(in);
+}
+FN(toJpc)(const JPH::BodyLockInterface *in) {
+    assert(in); return reinterpret_cast<const JPC_BodyLockInterface *>(in);
+}
+
+FN(toJpc)(const JPH::NarrowPhaseQuery *in) {
+    assert(in); return reinterpret_cast<const JPC_NarrowPhaseQuery *>(in);
+}
+
+FN(toJph)(const JPC_PhysicsSystem *in) { assert(in); return reinterpret_cast<const JPH::PhysicsSystem *>(in); }
+FN(toJph)(JPC_PhysicsSystem *in) { assert(in); return reinterpret_cast<JPH::PhysicsSystem *>(in); }
+FN(toJpc)(JPH::PhysicsSystem *in) { assert(in); return reinterpret_cast<JPC_PhysicsSystem *>(in); }
+
+FN(toJpc)(const JPH::Shape *in) { assert(in); return reinterpret_cast<const JPC_Shape *>(in); }
+FN(toJph)(const JPC_Shape *in) { assert(in); return reinterpret_cast<const JPH::Shape *>(in); }
+FN(toJpc)(JPH::Shape *in) { assert(in); return reinterpret_cast<JPC_Shape *>(in); }
+FN(toJph)(JPC_Shape *in) { assert(in); return reinterpret_cast<JPH::Shape *>(in); }
+
+FN(toJpc)(const JPH::Constraint *in) { assert(in); return reinterpret_cast<const JPC_Constraint *>(in); }
+FN(toJph)(const JPC_Constraint *in) { assert(in); return reinterpret_cast<const JPH::Constraint *>(in); }
+FN(toJpc)(JPH::Constraint *in) { assert(in); return reinterpret_cast<JPC_Constraint *>(in); }
+FN(toJph)(JPC_Constraint *in) { assert(in); return reinterpret_cast<JPH::Constraint *>(in); }
+
+FN(toJpc)(const JPH::BodyInterface *in) { assert(in); return reinterpret_cast<const JPC_BodyInterface *>(in); }
+FN(toJph)(const JPC_BodyInterface *in) { assert(in); return reinterpret_cast<const JPH::BodyInterface *>(in); }
+FN(toJpc)(JPH::BodyInterface *in) { assert(in); return reinterpret_cast<JPC_BodyInterface *>(in); }
+FN(toJph)(JPC_BodyInterface *in) { assert(in); return reinterpret_cast<JPH::BodyInterface *>(in); }
+
+FN(toJpc)(const JPH::TransformedShape *in) { assert(in); return reinterpret_cast<const JPC_TransformedShape *>(in); }
+
+FN(toJph)(const JPC_MassProperties *in) { assert(in); return reinterpret_cast<const JPH::MassProperties *>(in); }
+
+FN(toJph)(JPC_BodyLockRead *in) { assert(in); return reinterpret_cast<const JPH::BodyLockRead *>(in); }
+FN(toJph)(JPC_BodyLockWrite *in) { assert(in); return reinterpret_cast<const JPH::BodyLockWrite *>(in); }
+
+FN(toJpc)(const JPH::BodyCreationSettings *in) {
+    assert(in); return reinterpret_cast<const JPC_BodyCreationSettings *>(in);
+}
+FN(toJph)(const JPC_BodyCreationSettings *in) {
+    assert(in); return reinterpret_cast<const JPH::BodyCreationSettings *>(in);
+}
+
+FN(toJpc)(const JPH::MotionProperties *in) { assert(in); return reinterpret_cast<const JPC_MotionProperties *>(in); }
+FN(toJph)(const JPC_MotionProperties *in) { assert(in); return reinterpret_cast<const JPH::MotionProperties *>(in); }
+FN(toJpc)(JPH::MotionProperties *in) { assert(in); return reinterpret_cast<JPC_MotionProperties *>(in); }
+FN(toJph)(JPC_MotionProperties *in) { assert(in); return reinterpret_cast<JPH::MotionProperties *>(in); }
+
+FN(toJpc)(const JPH::SubShapeIDPair *in) {
+    assert(in); return reinterpret_cast<const JPC_SubShapeIDPair *>(in);
+}
+
+FN(toJpc)(const JPH::ContactManifold *in) {
+    assert(in); return reinterpret_cast<const JPC_ContactManifold *>(in);
+}
+
+FN(toJpc)(const JPH::CollideShapeResult *in) {
+    assert(in); return reinterpret_cast<const JPC_CollideShapeResult *>(in);
+}
+
+FN(toJpc)(JPH::ContactSettings *in) {
+    assert(in); return reinterpret_cast<JPC_ContactSettings *>(in);
+}
+
+FN(toJpc)(JPH::BroadPhaseLayer in) { return static_cast<JPC_BroadPhaseLayer>(in); }
+FN(toJpc)(JPH::ObjectLayer in) { return static_cast<JPC_ObjectLayer>(in); }
+FN(toJpc)(JPH::EShapeType in) { return static_cast<JPC_ShapeType>(in); }
+FN(toJpc)(JPH::EShapeSubType in) { return static_cast<JPC_ShapeSubType>(in); }
+FN(toJpc)(JPH::EConstraintType in) { return static_cast<JPC_ConstraintType>(in); }
+FN(toJpc)(JPH::EConstraintSubType in) { return static_cast<JPC_ConstraintSubType>(in); }
+FN(toJpc)(JPH::EConstraintSpace in) { return static_cast<JPC_ConstraintSpace>(in); }
+FN(toJpc)(JPH::EMotionType in) { return static_cast<JPC_MotionType>(in); }
+FN(toJpc)(JPH::EActivation in) { return static_cast<JPC_Activation>(in); }
+FN(toJpc)(JPH::EMotionQuality in) { return static_cast<JPC_MotionQuality>(in); }
+FN(toJpc)(JPH::CharacterBase::EGroundState in) { return static_cast<JPC_CharacterGroundState>(in); }
+
+FN(toJph)(JPC_ConstraintSpace in) { return static_cast<JPH::EConstraintSpace>(in); }
+
+FN(toJph)(const JPC_Character *in) { assert(in); return reinterpret_cast<const JPH::Character *>(in); }
+FN(toJph)(JPC_Character *in) { assert(in); return reinterpret_cast<JPH::Character *>(in); }
+FN(toJpc)(const JPH::Character *in) { assert(in); return reinterpret_cast<const JPC_Character *>(in); }
+FN(toJpc)(JPH::Character *in) { assert(in); return reinterpret_cast<JPC_Character *>(in); }
+
+FN(toJph)(const JPC_CharacterSettings *in) { assert(in); return reinterpret_cast<const JPH::CharacterSettings *>(in); }
+FN(toJph)(JPC_CharacterSettings *in) { assert(in); return reinterpret_cast<JPH::CharacterSettings *>(in); }
+FN(toJpc)(const JPH::CharacterSettings *in) { assert(in); return reinterpret_cast<const JPC_CharacterSettings *>(in); }
+FN(toJpc)(JPH::CharacterSettings *in) { assert(in); return reinterpret_cast<JPC_CharacterSettings *>(in); }
+
+FN(toJph)(const JPC_CharacterVirtual *in) { assert(in); return reinterpret_cast<const JPH::CharacterVirtual *>(in); }
+FN(toJph)(JPC_CharacterVirtual *in) { assert(in); return reinterpret_cast<JPH::CharacterVirtual *>(in); }
+FN(toJpc)(const JPH::CharacterVirtual *in) { assert(in); return reinterpret_cast<const JPC_CharacterVirtual *>(in); }
+FN(toJpc)(JPH::CharacterVirtual *in) { assert(in); return reinterpret_cast<JPC_CharacterVirtual *>(in); }
+
+FN(toJph)(const JPC_CharacterVirtualSettings *in) { assert(in); return reinterpret_cast<const JPH::CharacterVirtualSettings *>(in); }
+FN(toJph)(JPC_CharacterVirtualSettings *in) { assert(in); return reinterpret_cast<JPH::CharacterVirtualSettings *>(in); }
+FN(toJpc)(const JPH::CharacterVirtualSettings *in) { assert(in); return reinterpret_cast<const JPC_CharacterVirtualSettings *>(in); }
+FN(toJpc)(JPH::CharacterVirtualSettings *in) { assert(in); return reinterpret_cast<JPC_CharacterVirtualSettings *>(in); }
+
+#if JPC_DEBUG_RENDERER == 1
+FN(toJpc)(const JPH::BodyManager::DrawSettings *in) { assert(in); return reinterpret_cast<const JPC_BodyManager_DrawSettings *>(in); }
+FN(toJph)(const JPC_BodyManager_DrawSettings *in) { assert(in); return reinterpret_cast<const JPH::BodyManager::DrawSettings *>(in); }
+FN(toJpc)(JPH::BodyManager::DrawSettings *in) { assert(in); return reinterpret_cast<JPC_BodyManager_DrawSettings *>(in); }
+FN(toJph)(JPC_BodyManager_DrawSettings *in) { assert(in); return reinterpret_cast<JPH::BodyManager::DrawSettings *>(in); }
+
+FN(toJpc)(const JPH::BodyDrawFilter *in) { assert(in); return reinterpret_cast<const JPC_BodyDrawFilter *>(in); }
+FN(toJph)(const JPC_BodyDrawFilter *in) { assert(in); return reinterpret_cast<const JPH::BodyDrawFilter *>(in); }
+FN(toJpc)(JPH::BodyDrawFilter *in) { assert(in); return reinterpret_cast<JPC_BodyDrawFilter *>(in); }
+FN(toJph)(JPC_BodyDrawFilter *in) { assert(in); return reinterpret_cast<JPH::BodyDrawFilter *>(in); }
+
+FN(toJpc)(const JPH::ColorArg *in) { assert(in); return reinterpret_cast<const JPC_Color *>(in); }
+FN(toJph)(const JPC_Color *in) { assert(in); return reinterpret_cast<const JPH::ColorArg *>(in); }
+FN(toJpc)(JPH::ColorArg *in) { assert(in); return reinterpret_cast<JPC_Color *>(in); }
+FN(toJph)(JPC_Color *in) { assert(in); return reinterpret_cast<JPH::ColorArg *>(in); }
+
+FN(toJpc)(const JPH::AABox *in) { assert(in); return reinterpret_cast<const JPC_AABox *>(in); }
+FN(toJph)(const JPC_AABox *in) { assert(in); return reinterpret_cast<const JPH::AABox *>(in); }
+FN(toJpc)(JPH::AABox *in) { assert(in); return reinterpret_cast<JPC_AABox *>(in); }
+FN(toJph)(JPC_AABox *in) { assert(in); return reinterpret_cast<JPH::AABox *>(in); }
+
+FN(toJpc)(const JPH::DebugRenderer::Vertex *in) { assert(in); return reinterpret_cast<const JPC_DebugRenderer_Vertex *>(in); }
+FN(toJph)(const JPC_DebugRenderer_Vertex *in) { assert(in); return reinterpret_cast<const JPH::DebugRenderer::Vertex *>(in); }
+FN(toJpc)(JPH::DebugRenderer::Vertex *in) { assert(in); return reinterpret_cast<JPC_DebugRenderer_Vertex *>(in); }
+FN(toJph)(JPC_DebugRenderer_Vertex *in) { assert(in); return reinterpret_cast<JPH::DebugRenderer::Vertex *>(in); }
+
+FN(toJpc)(const JPH::DebugRenderer::Triangle *in) { assert(in); return reinterpret_cast<const JPC_DebugRenderer_Triangle *>(in); }
+FN(toJph)(const JPC_DebugRenderer_Triangle *in) { assert(in); return reinterpret_cast<const JPH::DebugRenderer::Triangle *>(in); }
+FN(toJpc)(JPH::DebugRenderer::Triangle *in) { assert(in); return reinterpret_cast<JPC_DebugRenderer_Triangle *>(in); }
+FN(toJph)(JPC_DebugRenderer_Triangle *in) { assert(in); return reinterpret_cast<JPH::DebugRenderer::Triangle *>(in); }
+
+FN(toJpc)(const JPH::DebugRenderer::LOD *in) { assert(in); return reinterpret_cast<const JPC_DebugRenderer_LOD *>(in); }
+FN(toJph)(const JPC_DebugRenderer_LOD *in) { assert(in); return reinterpret_cast<const JPH::DebugRenderer::LOD *>(in); }
+FN(toJpc)(JPH::DebugRenderer::LOD *in) { assert(in); return reinterpret_cast<JPC_DebugRenderer_LOD *>(in); }
+FN(toJph)(JPC_DebugRenderer_LOD *in) { assert(in); return reinterpret_cast<JPH::DebugRenderer::LOD *>(in); }
+#endif //JPC_DEBUG_RENDERER
+
+#undef FN
+
+static inline JPH::Vec3 loadVec3(const float in[3]) {
+    assert(in != nullptr);
+    return JPH::Vec3(*reinterpret_cast<const JPH::Float3 *>(in));
+}
+
+static inline JPH::Vec4 loadVec4(const float in[4]) {
+    assert(in != nullptr);
+    return JPH::Vec4::sLoadFloat4(reinterpret_cast<const JPH::Float4 *>(in));
+}
+
+static inline JPH::Mat44 loadMat44(const float in[16]) {
+    assert(in != nullptr);
+    return JPH::Mat44::sLoadFloat4x4(reinterpret_cast<const JPH::Float4 *>(in));
+}
+
+static inline JPH::RVec3 loadRVec3(const JPC_Real in[3]) {
+    assert(in != nullptr);
+#if JPC_DOUBLE_PRECISION == 0
+    return JPH::Vec3(*reinterpret_cast<const JPH::Float3 *>(in));
+#else
+    return JPH::DVec3(in[0], in[1], in[2]);
+#endif
+}
+
+static inline void storeRVec3(JPC_Real out[3], JPH::RVec3Arg in) {
+    assert(out != nullptr);
+#if JPC_DOUBLE_PRECISION == 0
+    in.StoreFloat3(reinterpret_cast<JPH::Float3 *>(out));
+#else
+    in.StoreDouble3(reinterpret_cast<JPH::Double3 *>(out));
+#endif
+}
+
+static inline void storeVec3(float out[3], JPH::Vec3Arg in) {
+    assert(out != nullptr);
+    in.StoreFloat3(reinterpret_cast<JPH::Float3 *>(out));
+}
+
+static inline void storeVec4(float out[4], JPH::Vec4Arg in) {
+    assert(out != nullptr);
+    in.StoreFloat4(reinterpret_cast<JPH::Float4 *>(out));
+}
+
+static inline void storeMat44(float out[16], JPH::Mat44Arg in) {
+    assert(out != nullptr);
+    in.StoreFloat4x4(reinterpret_cast<JPH::Float4 *>(out));
+}
+
+#ifdef JPH_ENABLE_ASSERTS
+
+static bool
+AssertFailedImpl(const char *in_expression,
+                 const char *in_message,
+                 const char *in_file,
+                 uint32_t in_line)
+{
+	return true;
+}
+
+#endif
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_RegisterDefaultAllocator(void)
+{
+    JPH::RegisterDefaultAllocator();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_RegisterCustomAllocator(JPC_AllocateFunction in_alloc,
+                            JPC_FreeFunction in_free,
+                            JPC_AlignedAllocateFunction in_aligned_alloc,
+                            JPC_AlignedFreeFunction in_aligned_free)
+{
+#ifndef JPH_DISABLE_CUSTOM_ALLOCATOR
+    JPH::Allocate = in_alloc;
+    JPH::Free = in_free;
+    JPH::AlignedAllocate = in_aligned_alloc;
+    JPH::AlignedFree = in_aligned_free;
+#endif
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CreateFactory(void)
+{
+    assert(JPH::Factory::sInstance == nullptr);
+    JPH::Factory::sInstance = new JPH::Factory();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_DestroyFactory(void)
+{
+    assert(JPH::Factory::sInstance != nullptr);
+    JPH::PhysicsMaterial::sDefault = nullptr;
+    delete JPH::Factory::sInstance;
+    JPH::Factory::sInstance = nullptr;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_RegisterTypes(void)
+{
+    JPH::RegisterTypes();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyCreationSettings_SetDefault(JPC_BodyCreationSettings *out_settings)
+{
+    assert(out_settings != nullptr);
+    const JPH::BodyCreationSettings settings;
+    *out_settings = *toJpc(&settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyCreationSettings_Set(JPC_BodyCreationSettings *out_settings,
+                             const JPC_Shape *in_shape,
+                             const JPC_Real in_position[3],
+                             const float in_rotation[4],
+                             JPC_MotionType in_motion_type,
+                             JPC_ObjectLayer in_layer)
+{
+    assert(out_settings != nullptr && in_shape != nullptr && in_position != nullptr && in_rotation != nullptr);
+
+    JPC_BodyCreationSettings settings;
+    JPC_BodyCreationSettings_SetDefault(&settings);
+
+    settings.position[0] = in_position[0];
+    settings.position[1] = in_position[1];
+    settings.position[2] = in_position[2];
+    settings.rotation[0] = in_rotation[0];
+    settings.rotation[1] = in_rotation[1];
+    settings.rotation[2] = in_rotation[2];
+    settings.rotation[3] = in_rotation[3];
+    settings.object_layer = in_layer;
+    settings.motion_type = in_motion_type;
+    settings.shape = in_shape;
+
+    *out_settings = settings;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TempAllocator
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TempAllocator *
+JPC_TempAllocator_Create(uint32_t in_size)
+{
+    auto impl = new JPH::TempAllocatorImpl(in_size);
+    return reinterpret_cast<JPC_TempAllocator *>(impl);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TempAllocator_Destroy(JPC_TempAllocator *in_allocator)
+{
+    assert(in_allocator != nullptr);
+    delete reinterpret_cast<JPH::TempAllocator *>(in_allocator);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_JobSystem
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_JobSystem *
+JPC_JobSystem_Create(uint32_t in_max_jobs, uint32_t in_max_barriers, int in_num_threads)
+{
+    auto job_system = new JPH::JobSystemThreadPool(in_max_jobs, in_max_barriers, in_num_threads);
+    return reinterpret_cast<JPC_JobSystem *>(job_system);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_JobSystem_Destroy(JPC_JobSystem *in_job_system)
+{
+    assert(in_job_system != nullptr);
+    delete reinterpret_cast<JPH::JobSystemThreadPool *>(in_job_system);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_PhysicsSystem
+//
+//--------------------------------------------------------------------------------------------------
+class ContactListener : public JPH::ContactListener
+{
+public:
+    JPH::ValidateResult OnContactValidate(
+        const JPH::Body &inBody1,
+        const JPH::Body &inBody2,
+        JPH::RVec3Arg inBaseOffset,
+        const JPH::CollideShapeResult &inCollisionResult) override
+    {
+        if (c_listener->vtbl->OnContactValidate)
+        {
+            JPC_Real base_offset[3];
+            storeRVec3(base_offset, inBaseOffset);
+
+            const JPC_ValidateResult res = c_listener->vtbl->OnContactValidate(
+                    c_listener, toJpc(&inBody1), toJpc(&inBody2), base_offset, toJpc(&inCollisionResult));
+
+            return static_cast<JPH::ValidateResult>(res);
+        }
+        return JPH::ContactListener::OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
+    }
+
+    void OnContactAdded(
+        const JPH::Body &inBody1,
+        const JPH::Body &inBody2,
+        const JPH::ContactManifold &inManifold,
+        JPH::ContactSettings &ioSettings) override
+    {
+        if (c_listener->vtbl->OnContactAdded)
+        {
+            c_listener->vtbl->OnContactAdded(
+                c_listener, toJpc(&inBody1), toJpc(&inBody2), toJpc(&inManifold), toJpc(&ioSettings));
+        }
+    }
+
+    void OnContactPersisted(
+        const JPH::Body &inBody1,
+        const JPH::Body &inBody2,
+        const JPH::ContactManifold &inManifold,
+        JPH::ContactSettings &ioSettings) override
+    {
+        if (c_listener->vtbl->OnContactPersisted)
+        {
+            c_listener->vtbl->OnContactPersisted(
+                c_listener, toJpc(&inBody1), toJpc(&inBody2), toJpc(&inManifold), toJpc(&ioSettings));
+        }
+    }
+
+    void OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) override
+    {
+        if (c_listener->vtbl->OnContactRemoved)
+            c_listener->vtbl->OnContactRemoved(c_listener, toJpc(&inSubShapePair));
+    }
+
+    struct CListener
+    {
+        JPC_ContactListenerVTable *vtbl;
+    };
+    CListener *c_listener;
+};
+
+#if JPC_DEBUG_RENDERER == 1
+
+class DebugRendererImpl final : public JPH::DebugRenderer
+{
+public:
+
+    class RenderPrimitive : public JPH::RefTarget<RenderPrimitive>
+    {
+    protected:
+        RenderPrimitive(const JPC_DebugRenderer_Primitive *prim) : c_primitive(prim) { }
+        const JPC_DebugRenderer_Primitive *c_primitive;
+    };
+
+    class BatchImpl : public JPH::RefTargetVirtual, public RenderPrimitive
+    {
+    public:
+        JPH_OVERRIDE_NEW_DELETE
+        BatchImpl(const JPC_DebugRenderer_Primitive *prim) : RenderPrimitive(prim) { }
+
+        virtual void AddRef() override
+        {
+            RenderPrimitive::AddRef();
+        }
+        virtual void Release() override
+        {
+            if (--mRefCount == 0) delete this;
+        }
+        const JPC_DebugRenderer_Primitive *GetPrimitive() const
+        {
+            return c_primitive;
+        }
+    };
+
+    class BodyDrawFilter : public JPH::BodyDrawFilter
+    {
+        JPC_BodyDrawFilterFunc func = nullptr;
+    public:
+        JPH_OVERRIDE_NEW_DELETE
+        BodyDrawFilter(const JPC_BodyDrawFilterFunc func) : func(func) {}
+        virtual bool ShouldDraw(const JPH::Body& inBody) const override
+        {
+            return func(toJpc(&inBody));
+        }
+    };
+
+    struct CRenderer
+    {
+        JPC_DebugRendererVTable *vtbl;
+    };
+    CRenderer *c_renderer;
+    static DebugRendererImpl *sInstance;
+
+    JPH_OVERRIDE_NEW_DELETE
+    DebugRendererImpl(CRenderer *in_renderer) : c_renderer(in_renderer)
+    {
+        DebugRenderer::Initialize();
+    }
+    JPC_DebugRendererResult ValidateCallbacks()
+    {
+        bool valid = true;
+        valid &= (c_renderer->vtbl->DrawLine                   != nullptr);
+        valid &= (c_renderer->vtbl->DrawTriangle               != nullptr);
+        valid &= (c_renderer->vtbl->CreateTriangleBatch        != nullptr);
+        valid &= (c_renderer->vtbl->CreateTriangleBatchIndexed != nullptr);
+        valid &= (c_renderer->vtbl->DrawGeometry               != nullptr);
+        valid &= (c_renderer->vtbl->DrawText3D                 != nullptr);
+        return valid ? JPC_DEBUGRENDERER_SUCCESS : JPC_DEBUGRENDERER_INCOMPLETE_IMPL;
+    }
+    virtual void DrawLine(JPH::RVec3Arg inFrom, JPH::RVec3Arg inTo, JPH::ColorArg inColor) override
+    {
+        JPC_Real in_from[3];
+        storeRVec3(in_from, inFrom);
+        JPC_Real in_to[3];
+        storeRVec3(in_to, inTo);
+        c_renderer->vtbl->DrawLine(c_renderer, in_from, in_to, *toJpc(&inColor));
+    }
+    virtual void DrawTriangle(
+        JPH::RVec3Arg inV1,
+        JPH::RVec3Arg inV2,
+        JPH::RVec3Arg inV3,
+        JPH::ColorArg inColor) override
+    {
+        JPC_Real in_v1[3];
+        storeRVec3(in_v1, inV1);
+        JPC_Real in_v2[3];
+        storeRVec3(in_v2, inV2);
+        JPC_Real in_v3[3];
+        storeRVec3(in_v3, inV3);
+        c_renderer->vtbl->DrawTriangle(c_renderer, in_v1, in_v2, in_v3, *toJpc(&inColor));
+    }
+    virtual JPH::DebugRenderer::Batch CreateTriangleBatch(
+        const JPH::DebugRenderer::Triangle *inTriangles,
+        int inTriangleCount) override
+    {
+        JPC_DebugRenderer_TriangleBatch *c_batch = c_renderer->vtbl->CreateTriangleBatch(
+            c_renderer,
+            toJpc(inTriangles),
+            inTriangleCount);
+        auto jph_batch = reinterpret_cast<BatchImpl *>(c_batch);
+        return jph_batch;
+    }
+    virtual JPH::DebugRenderer::Batch CreateTriangleBatch(
+        const JPH::DebugRenderer::Vertex *inVertices,
+        int inVertexCount,
+        const uint32_t *inIndices,
+        int inIndexCount) override
+    {
+        JPC_DebugRenderer_TriangleBatch *c_batch = c_renderer->vtbl->CreateTriangleBatchIndexed(
+            c_renderer,
+            toJpc(inVertices),
+            inVertexCount,
+            inIndices,
+            inIndexCount);
+        auto jph_batch = reinterpret_cast<BatchImpl *>(c_batch);
+        return jph_batch;
+    }
+    virtual void DrawGeometry(
+        JPH::RMat44Arg inModelMatrix,
+        const JPH::AABox &inWorldSpaceBounds,
+        float inLODScaleSq,
+        JPH::ColorArg inModelColor,
+        const JPH::DebugRenderer::GeometryRef &inGeometry,
+        JPH::DebugRenderer::ECullMode inCullMode,
+        JPH::DebugRenderer::ECastShadow inCastShadow,
+        JPH::DebugRenderer::EDrawMode inDrawMode) override
+    {
+        float in_model_matrix[16]; // Model matrix will always be rounded to floats (JPH samples assume the same).
+        storeMat44(in_model_matrix, inModelMatrix.ToMat44());
+        JPC_DebugRenderer_Geometry in_geometry {
+            toJpc(&inGeometry.GetPtr()->mLODs[0]),
+            static_cast<uint64_t>(inGeometry.GetPtr()->mLODs.size()),
+            toJpc(&inGeometry.GetPtr()->mBounds)
+        };
+        c_renderer->vtbl->DrawGeometry(
+            c_renderer,
+            in_model_matrix,
+            toJpc(&inWorldSpaceBounds),
+            inLODScaleSq,
+            *toJpc(&inModelColor),
+            &in_geometry,
+            static_cast<JPC_CullMode>(inCullMode),
+            static_cast<JPC_CastShadow>(inCastShadow),
+            static_cast<JPC_DrawMode>(inDrawMode));
+    }
+    virtual void DrawText3D(
+        JPH::RVec3Arg inPosition,
+        const std::string_view &inString,
+        JPH::ColorArg inColor,
+        float inHeight) override
+    {
+        JPC_Real in_position[3];
+        storeRVec3(in_position, inPosition);
+        c_renderer->vtbl->DrawText3D(
+            c_renderer,
+            in_position,
+            std::string(inString).c_str(),
+            *toJpc(&inColor),
+            inHeight);
+    }
+};
+DebugRendererImpl *DebugRendererImpl::sInstance = nullptr;
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_DebugRendererResult
+JPC_CreateDebugRendererSingleton(void *in_debug_renderer)
+{
+    assert(JPH::DebugRenderer::sInstance == nullptr); //Only one instance of JPH::DebugRenderer may ever be made
+    if (JPH::DebugRenderer::sInstance != nullptr) return JPC_DEBUGRENDERER_DUPLICATE_SINGLETON; //No assert in release
+    DebugRendererImpl::sInstance =
+        new DebugRendererImpl(reinterpret_cast<DebugRendererImpl::CRenderer *>(in_debug_renderer));
+    // At this point, a pointer to the created instance is also kept in JPH::DebugRenderer::sInstance.
+    return DebugRendererImpl::sInstance->ValidateCallbacks();
+}
+
+JPC_API JPC_DebugRendererResult
+JPC_DestroyDebugRendererSingleton()
+{
+    assert(JPH::DebugRenderer::sInstance != nullptr); //The singleton must have already been instantiated
+    if (JPH::DebugRenderer::sInstance == nullptr) return JPC_DEBUGRENDERER_MISSING_SINGLETON; //No assert in release
+    delete DebugRendererImpl::sInstance;
+    return JPC_DEBUGRENDERER_SUCCESS;
+}
+
+JPC_API JPC_DebugRenderer_TriangleBatch *
+JPC_DebugRenderer_TriangleBatch_Create(const void *in_c_primitive)
+{
+    auto batch = static_cast<DebugRendererImpl::BatchImpl *>(JPH::Allocate(sizeof(DebugRendererImpl::BatchImpl)));
+    ::new (batch) DebugRendererImpl::BatchImpl(reinterpret_cast<const JPC_DebugRenderer_Primitive *>(in_c_primitive));
+    return reinterpret_cast<JPC_DebugRenderer_TriangleBatch *>(batch);
+}
+
+JPC_API const JPC_DebugRenderer_Primitive *
+JPC_DebugRenderer_TriangleBatch_GetPrimitive(const JPC_DebugRenderer_TriangleBatch * in_batch)
+{
+    auto fat_batch = reinterpret_cast<const DebugRendererImpl::BatchImpl *>(in_batch);
+    return fat_batch->GetPrimitive();
+}
+
+JPC_API void
+JPC_DebugRenderer_TriangleBatch_AddRef(JPC_DebugRenderer_TriangleBatch *in_batch)
+{
+    assert(in_batch);
+    reinterpret_cast<DebugRendererImpl::BatchImpl *>(in_batch)->AddRef();
+}
+
+JPC_API void
+JPC_DebugRenderer_TriangleBatch_Release(JPC_DebugRenderer_TriangleBatch *in_batch)
+{
+    assert(in_batch);
+    reinterpret_cast<DebugRendererImpl::BatchImpl *>(in_batch)->Release();
+}
+
+JPC_API uint32_t
+JPC_DebugRenderer_TriangleBatch_GetRefCount(const JPC_DebugRenderer_TriangleBatch *in_batch)
+{
+    assert(in_batch);
+    return reinterpret_cast<const DebugRendererImpl::BatchImpl *>(in_batch)->GetRefCount();
+}
+#endif //JPC_DEBUG_RENDERER
+
+struct PhysicsSystemData
+{
+    uint64_t safety_token = 0xC0DEC0DEC0DEC0DE;
+    ContactListener *contact_listener = nullptr;
+};
+
+JPC_API JPC_PhysicsSystem *
+JPC_PhysicsSystem_Create(uint32_t in_max_bodies,
+                         uint32_t in_num_body_mutexes,
+                         uint32_t in_max_body_pairs,
+                         uint32_t in_max_contact_constraints,
+                         const void *in_broad_phase_layer_interface,
+                         const void *in_object_vs_broad_phase_layer_filter,
+                         const void *in_object_layer_pair_filter)
+{
+    assert(in_broad_phase_layer_interface != nullptr);
+    assert(in_object_vs_broad_phase_layer_filter != nullptr);
+    assert(in_object_layer_pair_filter != nullptr);
+
+    auto physics_system =
+        static_cast<JPH::PhysicsSystem *>(
+            JPH::Allocate(sizeof(JPH::PhysicsSystem) + sizeof(PhysicsSystemData)));
+    ::new (physics_system) JPH::PhysicsSystem();
+
+    PhysicsSystemData* data =
+        ::new (reinterpret_cast<uint8_t *>(physics_system) + sizeof(JPH::PhysicsSystem)) PhysicsSystemData();
+    assert(data->safety_token == 0xC0DEC0DEC0DEC0DE);
+
+    physics_system->Init(
+        in_max_bodies,
+        in_num_body_mutexes,
+        in_max_body_pairs,
+        in_max_contact_constraints,
+        *static_cast<const JPH::BroadPhaseLayerInterface *>(in_broad_phase_layer_interface),
+        *static_cast<const JPH::ObjectVsBroadPhaseLayerFilter *>(in_object_vs_broad_phase_layer_filter),
+        *static_cast<const JPH::ObjectLayerPairFilter *>(in_object_layer_pair_filter));
+
+    return toJpc(physics_system);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_Destroy(JPC_PhysicsSystem *in_physics_system)
+{
+    auto data = reinterpret_cast<PhysicsSystemData *>(
+        reinterpret_cast<uint8_t *>(in_physics_system) + sizeof(JPH::PhysicsSystem));
+    assert(data->safety_token == 0xC0DEC0DEC0DEC0DE);
+
+    if (data->contact_listener)
+    {
+        data->contact_listener->~ContactListener();
+        JPH::Free(data->contact_listener);
+    }
+
+    toJph(in_physics_system)->~PhysicsSystem();
+    JPH::Free(in_physics_system);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_SetBodyActivationListener(JPC_PhysicsSystem *in_physics_system, void *in_listener)
+{
+    toJph(in_physics_system)->SetBodyActivationListener(static_cast<JPH::BodyActivationListener *>(in_listener));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void *
+JPC_PhysicsSystem_GetBodyActivationListener(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJph(in_physics_system)->GetBodyActivationListener();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_SetContactListener(JPC_PhysicsSystem *in_physics_system, void *in_listener)
+{
+    if (in_listener == nullptr)
+    {
+        toJph(in_physics_system)->SetContactListener(nullptr);
+        return;
+    }
+
+    auto data = reinterpret_cast<PhysicsSystemData *>(
+        reinterpret_cast<uint8_t *>(in_physics_system) + sizeof(JPH::PhysicsSystem));
+    assert(data->safety_token == 0xC0DEC0DEC0DEC0DE);
+
+    if (data->contact_listener == nullptr)
+    {
+        data->contact_listener = static_cast<ContactListener *>(JPH::Allocate(sizeof(ContactListener)));
+        ::new (data->contact_listener) ContactListener();
+    }
+
+    toJph(in_physics_system)->SetContactListener(data->contact_listener);
+
+    data->contact_listener->c_listener = static_cast<ContactListener::CListener *>(in_listener);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void *
+JPC_PhysicsSystem_GetContactListener(const JPC_PhysicsSystem *in_physics_system)
+{
+    auto listener = static_cast<ContactListener *>(toJph(in_physics_system)->GetContactListener());
+    if (listener == nullptr)
+        return nullptr;
+    return listener->c_listener;
+}
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+JPC_API void
+JPC_PhysicsSystem_DrawBodies(JPC_PhysicsSystem *in_physics_system,
+                             const JPC_BodyManager_DrawSettings *in_draw_settings,
+                             const JPC_BodyDrawFilter *in_draw_filter = nullptr)
+{
+    // It's weird that JPH has both a singleton DebugRenderer and a DebugRenderer pointer passed into
+    // some of the draw functions. The pointer should always be the singleton instance, right?
+    assert(JPH::DebugRenderer::sInstance != nullptr);
+    const JPH::BodyManager::DrawSettings *settings = toJph(in_draw_settings);
+    const JPH::BodyDrawFilter *filter = (in_draw_filter != nullptr) ? toJph(in_draw_filter) : nullptr;
+    toJph(in_physics_system)->DrawBodies(*settings, JPH::DebugRenderer::sInstance, filter);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_DrawConstraints(JPC_PhysicsSystem *in_physics_system)
+{
+    assert(JPH::DebugRenderer::sInstance != nullptr);
+    toJph(in_physics_system)->DrawConstraints(JPH::DebugRenderer::sInstance);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_DrawConstraintLimits(JPC_PhysicsSystem *in_physics_system)
+{
+    assert(JPH::DebugRenderer::sInstance != nullptr);
+    toJph(in_physics_system)->DrawConstraintLimits(JPH::DebugRenderer::sInstance);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_DrawConstraintReferenceFrame(JPC_PhysicsSystem *in_physics_system)
+{
+    assert(JPH::DebugRenderer::sInstance != nullptr);
+    toJph(in_physics_system)->DrawConstraintReferenceFrame(JPH::DebugRenderer::sInstance);
+}
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_PhysicsSystem_GetNumBodies(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJph(in_physics_system)->GetNumBodies();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_PhysicsSystem_GetNumActiveBodies(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJph(in_physics_system)->GetNumActiveBodies();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_PhysicsSystem_GetMaxBodies(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJph(in_physics_system)->GetMaxBodies();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_GetGravity(const JPC_PhysicsSystem *in_physics_system, float out_gravity[3])
+{
+    storeVec3(out_gravity, toJph(in_physics_system)->GetGravity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_SetGravity(JPC_PhysicsSystem *in_physics_system, const float in_gravity[3])
+{
+    toJph(in_physics_system)->SetGravity(loadVec3(in_gravity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BodyInterface *
+JPC_PhysicsSystem_GetBodyInterface(JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetBodyInterface());
+}
+JPC_API JPC_BodyInterface *
+JPC_PhysicsSystem_GetBodyInterfaceNoLock(JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetBodyInterfaceNoLock());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_OptimizeBroadPhase(JPC_PhysicsSystem *in_physics_system)
+{
+    toJph(in_physics_system)->OptimizeBroadPhase();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_AddStepListener(JPC_PhysicsSystem *in_physics_system, void *in_listener)
+{
+    assert(in_listener != nullptr);
+    toJph(in_physics_system)->AddStepListener(static_cast<JPH::PhysicsStepListener *>(in_listener));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_RemoveStepListener(JPC_PhysicsSystem *in_physics_system, void *in_listener)
+{
+    assert(in_listener != nullptr);
+    toJph(in_physics_system)->RemoveStepListener(static_cast<JPH::PhysicsStepListener *>(in_listener));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_AddConstraint(JPC_PhysicsSystem *in_physics_system, void *in_two_body_constraint)
+{
+    assert(in_two_body_constraint != nullptr);
+    toJph(in_physics_system)->AddConstraint(static_cast<JPH::TwoBodyConstraint *>(in_two_body_constraint));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_RemoveConstraint(JPC_PhysicsSystem *in_physics_system, void *in_two_body_constraint)
+{
+    assert(in_two_body_constraint != nullptr);
+    toJph(in_physics_system)->RemoveConstraint(static_cast<JPH::TwoBodyConstraint *>(in_two_body_constraint));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_PhysicsUpdateError
+JPC_PhysicsSystem_Update(JPC_PhysicsSystem *in_physics_system,
+                         float in_delta_time,
+                         int in_collision_steps,
+                         int in_integration_sub_steps,
+                         JPC_TempAllocator *in_temp_allocator,
+                         JPC_JobSystem *in_job_system)
+{
+    assert(in_temp_allocator != nullptr && in_job_system != nullptr);
+    JPC_PhysicsUpdateError error = (JPC_PhysicsUpdateError)toJph(in_physics_system)->Update(
+        in_delta_time,
+        in_collision_steps,
+        in_integration_sub_steps,
+        reinterpret_cast<JPH::TempAllocator *>(in_temp_allocator),
+        reinterpret_cast<JPH::JobSystem *>(in_job_system));
+    return error;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API const JPC_BodyLockInterface *
+JPC_PhysicsSystem_GetBodyLockInterface(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetBodyLockInterface());
+}
+JPC_API const JPC_BodyLockInterface *
+JPC_PhysicsSystem_GetBodyLockInterfaceNoLock(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetBodyLockInterfaceNoLock());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API const JPC_NarrowPhaseQuery *
+JPC_PhysicsSystem_GetNarrowPhaseQuery(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetNarrowPhaseQuery());
+}
+JPC_API const JPC_NarrowPhaseQuery *
+JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(const JPC_PhysicsSystem *in_physics_system)
+{
+    return toJpc(&toJph(in_physics_system)->GetNarrowPhaseQueryNoLock());
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyLockInterface
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyLockInterface_LockRead(const JPC_BodyLockInterface *in_lock_interface,
+                               JPC_BodyID in_body_id,
+                               JPC_BodyLockRead *out_lock)
+{
+    assert(out_lock != nullptr);
+    ::new (out_lock) JPH::BodyLockRead(*toJph(in_lock_interface), toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyLockInterface_UnlockRead(const JPC_BodyLockInterface *in_lock_interface,
+                                 JPC_BodyLockRead *io_lock)
+{
+    assert(io_lock != nullptr);
+    assert(in_lock_interface != nullptr && in_lock_interface == io_lock->lock_interface);
+    toJph(io_lock)->~BodyLockRead();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyLockInterface_LockWrite(const JPC_BodyLockInterface *in_lock_interface,
+                                JPC_BodyID in_body_id,
+                                JPC_BodyLockWrite *out_lock)
+{
+    assert(out_lock != nullptr);
+    ::new (out_lock) JPH::BodyLockWrite(*toJph(in_lock_interface), toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyLockInterface_UnlockWrite(const JPC_BodyLockInterface *in_lock_interface,
+                                  JPC_BodyLockWrite *io_lock)
+{
+    assert(io_lock != nullptr);
+    assert(in_lock_interface != nullptr && in_lock_interface == io_lock->lock_interface);
+    toJph(io_lock)->~BodyLockWrite();
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_NarrowPhaseQuery
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_NarrowPhaseQuery_CastRay(const JPC_NarrowPhaseQuery *in_query,
+                             const JPC_RRayCast *in_ray,
+                             JPC_RayCastResult *io_hit,
+                             const void *in_broad_phase_layer_filter,
+                             const void *in_object_layer_filter,
+                             const void *in_body_filter)
+{
+    assert(in_query && in_ray && io_hit);
+
+    const JPH::BroadPhaseLayerFilter broad_phase_layer_filter{};
+    const JPH::ObjectLayerFilter object_layer_filter{};
+    const JPH::BodyFilter body_filter{};
+
+    auto query = reinterpret_cast<const JPH::NarrowPhaseQuery *>(in_query);
+    return query->CastRay(
+        *reinterpret_cast<const JPH::RRayCast *>(in_ray),
+        *reinterpret_cast<JPH::RayCastResult *>(io_hit),
+        in_broad_phase_layer_filter ?
+            *static_cast<const JPH::BroadPhaseLayerFilter *>(in_broad_phase_layer_filter) :
+            broad_phase_layer_filter,
+        in_object_layer_filter ?
+            *static_cast<const JPH::ObjectLayerFilter *>(in_object_layer_filter) : object_layer_filter,
+        in_body_filter ?
+            *static_cast<const JPH::BodyFilter *>(in_body_filter) : body_filter);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ShapeSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ShapeSettings_AddRef(JPC_ShapeSettings *in_settings)
+{
+    toJph(in_settings)->AddRef();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ShapeSettings_Release(JPC_ShapeSettings *in_settings)
+{
+    toJph(in_settings)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_ShapeSettings_GetRefCount(const JPC_ShapeSettings *in_settings)
+{
+    return toJph(in_settings)->GetRefCount();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Shape *
+JPC_ShapeSettings_CreateShape(const JPC_ShapeSettings *in_settings)
+{
+    const JPH::Result result = toJph(in_settings)->Create();
+    if (result.HasError()) return nullptr;
+    JPH::Shape *shape = const_cast<JPH::Shape *>(result.Get().GetPtr());
+    shape->AddRef();
+    return toJpc(shape);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint64_t
+JPC_ShapeSettings_GetUserData(const JPC_ShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mUserData;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ShapeSettings_SetUserData(JPC_ShapeSettings *in_settings, uint64_t in_user_data)
+{
+    toJph(in_settings)->mUserData = in_user_data;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConvexShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API const JPC_PhysicsMaterial *
+JPC_ConvexShapeSettings_GetMaterial(const JPC_ConvexShapeSettings *in_settings)
+{
+    // TODO: Increment ref count?
+    return toJpc(toJph(in_settings)->mMaterial.GetPtr());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConvexShapeSettings_SetMaterial(JPC_ConvexShapeSettings *in_settings,
+                                    const JPC_PhysicsMaterial *in_material)
+{
+    toJph(in_settings)->mMaterial = toJph(in_material);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_ConvexShapeSettings_GetDensity(const JPC_ConvexShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mDensity;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConvexShapeSettings_SetDensity(JPC_ConvexShapeSettings *in_settings, float in_density)
+{
+    toJph(in_settings)->SetDensity(in_density);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BoxShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BoxShapeSettings *
+JPC_BoxShapeSettings_Create(const float in_half_extent[3])
+{
+    auto settings = new JPH::BoxShapeSettings(loadVec3(in_half_extent));
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BoxShapeSettings_GetHalfExtent(const JPC_BoxShapeSettings *in_settings, float out_half_extent[3])
+{
+    storeVec3(out_half_extent, toJph(in_settings)->mHalfExtent);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BoxShapeSettings_SetHalfExtent(JPC_BoxShapeSettings *in_settings, const float in_half_extent[3])
+{
+    toJph(in_settings)->mHalfExtent = loadVec3(in_half_extent);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_BoxShapeSettings_GetConvexRadius(const JPC_BoxShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mConvexRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BoxShapeSettings_SetConvexRadius(JPC_BoxShapeSettings *in_settings, float in_convex_radius)
+{
+    toJph(in_settings)->mConvexRadius = in_convex_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_SphereShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_SphereShapeSettings *
+JPC_SphereShapeSettings_Create(float in_radius)
+{
+    auto settings = new JPH::SphereShapeSettings(in_radius);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_SphereShapeSettings_GetRadius(const JPC_SphereShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_SphereShapeSettings_SetRadius(JPC_SphereShapeSettings *in_settings, float in_radius)
+{
+    toJph(in_settings)->mRadius = in_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TriangleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TriangleShapeSettings *
+JPC_TriangleShapeSettings_Create(const float in_v1[3], const float in_v2[3], const float in_v3[3])
+{
+    auto settings = new JPH::TriangleShapeSettings(loadVec3(in_v1), loadVec3(in_v2), loadVec3(in_v3));
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TriangleShapeSettings_SetVertices(JPC_TriangleShapeSettings *in_settings,
+                                      const float in_v1[3],
+                                      const float in_v2[3],
+                                      const float in_v3[3])
+{
+    JPH::TriangleShapeSettings *settings = toJph(in_settings);
+    settings->mV1 = loadVec3(in_v1);
+    settings->mV2 = loadVec3(in_v2);
+    settings->mV3 = loadVec3(in_v3);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TriangleShapeSettings_GetVertices(const JPC_TriangleShapeSettings *in_settings,
+                                      float out_v1[3],
+                                      float out_v2[3],
+                                      float out_v3[3])
+{
+    const JPH::TriangleShapeSettings *settings = toJph(in_settings);
+    storeVec3(out_v1, settings->mV1);
+    storeVec3(out_v2, settings->mV2);
+    storeVec3(out_v3, settings->mV3);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_TriangleShapeSettings_GetConvexRadius(const JPC_TriangleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mConvexRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TriangleShapeSettings_SetConvexRadius(JPC_TriangleShapeSettings *in_settings, float in_convex_radius)
+{
+    toJph(in_settings)->mConvexRadius = in_convex_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CapsuleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CapsuleShapeSettings *
+JPC_CapsuleShapeSettings_Create(float in_half_height_of_cylinder, float in_radius)
+{
+    auto settings = new JPH::CapsuleShapeSettings(in_half_height_of_cylinder, in_radius);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_CapsuleShapeSettings_GetHalfHeight(const JPC_CapsuleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mHalfHeightOfCylinder;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CapsuleShapeSettings_SetHalfHeight(JPC_CapsuleShapeSettings *in_settings,
+                                       float in_half_height_of_cylinder)
+{
+    toJph(in_settings)->mHalfHeightOfCylinder = in_half_height_of_cylinder;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_CapsuleShapeSettings_GetRadius(const JPC_CapsuleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CapsuleShapeSettings_SetRadius(JPC_CapsuleShapeSettings *in_settings, float in_radius)
+{
+    toJph(in_settings)->mRadius = in_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TaperedCapsuleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TaperedCapsuleShapeSettings *
+JPC_TaperedCapsuleShapeSettings_Create(float in_half_height, float in_top_radius, float in_bottom_radius)
+{
+    auto settings = new JPH::TaperedCapsuleShapeSettings(in_half_height, in_top_radius, in_bottom_radius);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetHalfHeight(const JPC_TaperedCapsuleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mHalfHeightOfTaperedCylinder;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetHalfHeight(JPC_TaperedCapsuleShapeSettings *in_settings,
+                                              float in_half_height)
+{
+    toJph(in_settings)->mHalfHeightOfTaperedCylinder = in_half_height;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetTopRadius(const JPC_TaperedCapsuleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mTopRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetTopRadius(JPC_TaperedCapsuleShapeSettings *in_settings, float in_top_radius)
+{
+    toJph(in_settings)->mTopRadius = in_top_radius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetBottomRadius(const JPC_TaperedCapsuleShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mBottomRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetBottomRadius(JPC_TaperedCapsuleShapeSettings *in_settings,
+                                                float in_bottom_radius)
+{
+    toJph(in_settings)->mBottomRadius = in_bottom_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CylinderShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CylinderShapeSettings *
+JPC_CylinderShapeSettings_Create(float in_half_height, float in_radius)
+{
+    auto settings = new JPH::CylinderShapeSettings(in_half_height, in_radius);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_CylinderShapeSettings_GetConvexRadius(const JPC_CylinderShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mConvexRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CylinderShapeSettings_SetConvexRadius(JPC_CylinderShapeSettings *in_settings, float in_convex_radius)
+{
+    toJph(in_settings)->mConvexRadius = in_convex_radius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_CylinderShapeSettings_GetHalfHeight(const JPC_CylinderShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mHalfHeight;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CylinderShapeSettings_SetHalfHeight(JPC_CylinderShapeSettings *in_settings, float in_half_height)
+{
+    toJph(in_settings)->mHalfHeight = in_half_height;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_CylinderShapeSettings_GetRadius(const JPC_CylinderShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CylinderShapeSettings_SetRadius(JPC_CylinderShapeSettings *in_settings, float in_radius)
+{
+    toJph(in_settings)->mRadius = in_radius;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConvexHullShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ConvexHullShapeSettings *
+JPC_ConvexHullShapeSettings_Create(const void *in_vertices, uint32_t in_num_vertices, uint32_t in_vertex_size)
+{
+    assert(in_vertices && in_num_vertices >= 3);
+    assert(in_vertex_size >= 3 * sizeof(float));
+
+    JPH::Array<JPH::Vec3> points;
+    points.reserve(in_num_vertices);
+
+    for (uint32_t i = 0; i < in_num_vertices; ++i)
+    {
+        const uint8_t *base = static_cast<const uint8_t *>(in_vertices) + i * in_vertex_size;
+        points.push_back(loadVec3(reinterpret_cast<const float *>(base)));
+    }
+
+    auto settings = new JPH::ConvexHullShapeSettings(points);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_ConvexHullShapeSettings_GetMaxConvexRadius(const JPC_ConvexHullShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mMaxConvexRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConvexHullShapeSettings_SetMaxConvexRadius(JPC_ConvexHullShapeSettings *in_settings,
+                                               float in_max_convex_radius)
+{
+    toJph(in_settings)->mMaxConvexRadius = in_max_convex_radius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_ConvexHullShapeSettings_GetMaxErrorConvexRadius(const JPC_ConvexHullShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mMaxErrorConvexRadius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConvexHullShapeSettings_SetMaxErrorConvexRadius(JPC_ConvexHullShapeSettings *in_settings,
+                                                    float in_max_err_convex_radius)
+{
+    toJph(in_settings)->mMaxErrorConvexRadius = in_max_err_convex_radius;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_ConvexHullShapeSettings_GetHullTolerance(const JPC_ConvexHullShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mHullTolerance;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConvexHullShapeSettings_SetHullTolerance(JPC_ConvexHullShapeSettings *in_settings,
+                                             float in_hull_tolerance)
+{
+    toJph(in_settings)->mHullTolerance = in_hull_tolerance;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_HeightFieldShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_HeightFieldShapeSettings *
+JPC_HeightFieldShapeSettings_Create(const float *in_samples, uint32_t in_height_field_size)
+{
+    assert(in_samples != nullptr && in_height_field_size >= 2);
+    auto settings = new JPH::HeightFieldShapeSettings(
+        in_samples, JPH::Vec3(0,0,0), JPH::Vec3(1,1,1), in_height_field_size);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_GetOffset(const JPC_HeightFieldShapeSettings *in_settings, float out_offset[3])
+{
+    storeVec3(out_offset, toJph(in_settings)->mOffset);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_SetOffset(JPC_HeightFieldShapeSettings *in_settings, const float in_offset[3])
+{
+    toJph(in_settings)->mOffset = loadVec3(in_offset);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_GetScale(const JPC_HeightFieldShapeSettings *in_settings, float out_scale[3])
+{
+    storeVec3(out_scale, toJph(in_settings)->mScale);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_SetScale(JPC_HeightFieldShapeSettings *in_settings, const float in_scale[3])
+{
+    toJph(in_settings)->mScale = loadVec3(in_scale);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_HeightFieldShapeSettings_GetBlockSize(const JPC_HeightFieldShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mBlockSize;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_SetBlockSize(JPC_HeightFieldShapeSettings *in_settings, uint32_t in_block_size)
+{
+    toJph(in_settings)->mBlockSize = in_block_size;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_HeightFieldShapeSettings_GetBitsPerSample(const JPC_HeightFieldShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mBitsPerSample;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_HeightFieldShapeSettings_SetBitsPerSample(JPC_HeightFieldShapeSettings *in_settings, uint32_t in_num_bits)
+{
+    toJph(in_settings)->mBitsPerSample = in_num_bits;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_MeshShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MeshShapeSettings *
+JPC_MeshShapeSettings_Create(const void *in_vertices,
+                             uint32_t in_num_vertices,
+                             uint32_t in_vertex_size,
+                             const uint32_t *in_indices,
+                             uint32_t in_num_indices)
+{
+    assert(in_vertices && in_indices);
+    assert(in_num_vertices >= 3);
+    assert(in_vertex_size >= 3 * sizeof(float));
+    assert(in_num_indices >= 3 && in_num_indices % 3 == 0);
+
+    JPH::VertexList vertices;
+    vertices.reserve(in_num_vertices);
+
+    for (uint32_t i = 0; i < in_num_vertices; ++i)
+    {
+        const float *base = reinterpret_cast<const float *>(
+            static_cast<const uint8_t *>(in_vertices) + i * in_vertex_size);
+        vertices.push_back(JPH::Float3(base[0], base[1], base[2]));
+    }
+
+    JPH::IndexedTriangleList triangles;
+    triangles.reserve(in_num_indices / 3);
+
+    for (uint32_t i = 0; i < in_num_indices / 3; ++i)
+    {
+        triangles.push_back(
+            JPH::IndexedTriangle(in_indices[i * 3], in_indices[i * 3 + 1], in_indices[i * 3 + 2], 0));
+    }
+
+    auto settings = new JPH::MeshShapeSettings(vertices, triangles);
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_MeshShapeSettings_GetMaxTrianglesPerLeaf(const JPC_MeshShapeSettings *in_settings)
+{
+    return toJph(in_settings)->mMaxTrianglesPerLeaf;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MeshShapeSettings_SetMaxTrianglesPerLeaf(JPC_MeshShapeSettings *in_settings, uint32_t in_max_triangles)
+{
+    toJph(in_settings)->mMaxTrianglesPerLeaf = in_max_triangles;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MeshShapeSettings_Sanitize(JPC_MeshShapeSettings *in_settings)
+{
+    toJph(in_settings)->Sanitize();
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_DecoratedShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_DecoratedShapeSettings *
+JPC_RotatedTranslatedShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                                          const JPC_Real in_rotated[4],
+                                          const JPC_Real in_translated[3])
+{
+    auto settings = new JPH::RotatedTranslatedShapeSettings(loadRVec3(in_translated),
+                                                            JPH::Quat(loadVec4(in_rotated)),
+                                                            toJph(in_inner_shape_settings));
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_DecoratedShapeSettings *
+JPC_ScaledShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                               const JPC_Real in_scale[3])
+{
+    auto settings = new JPH::ScaledShapeSettings(toJph(in_inner_shape_settings), loadRVec3(in_scale));
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_DecoratedShapeSettings *
+JPC_OffsetCenterOfMassShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                                           const JPC_Real in_center_of_mass[3])
+{
+    auto settings = new JPH::OffsetCenterOfMassShapeSettings(loadRVec3(in_center_of_mass),
+                                                             toJph(in_inner_shape_settings));
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CompoundShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CompoundShapeSettings *
+JPC_StaticCompoundShapeSettings_Create()
+{
+    auto settings = new JPH::StaticCompoundShapeSettings();
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CompoundShapeSettings *
+JPC_MutableCompoundShapeSettings_Create()
+{
+    auto settings = new JPH::MutableCompoundShapeSettings();
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CompoundShapeSettings_AddShape(JPC_CompoundShapeSettings *in_settings,
+                                   const JPC_Real in_position[3],
+                                   const JPC_Real in_rotation[4],
+                                   const JPC_ShapeSettings *in_shape,
+                                   const uint32_t in_user_data)
+{
+    toJph(in_settings)->AddShape(loadRVec3(in_position),
+                                 JPH::Quat(loadVec4(in_rotation)),
+                                 toJph(in_shape),
+                                 in_user_data);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyManager_DrawSettings
+//
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+JPC_API JPC_BodyManager_DrawSettings *
+JPC_BodyManager_DrawSettings_Create()
+{
+    auto settings =
+        static_cast<JPH::BodyManager::DrawSettings *>
+            (JPH::Allocate(sizeof(JPH::BodyManager::DrawSettings)));
+    ::new (settings) JPH::BodyManager::DrawSettings();
+    return toJpc(reinterpret_cast<JPH::BodyManager::DrawSettings *>(settings));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyManager_DrawSettings_Destroy(JPC_BodyManager_DrawSettings *settings)
+{
+    JPH::Free(reinterpret_cast<JPH::BodyManager::DrawSettings *>(settings));
+}
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyDrawFilter
+//
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+JPC_API JPC_BodyDrawFilter *
+JPC_BodyDrawFilter_Create(const JPC_BodyDrawFilterFunc func)
+{
+    return toJpc(new DebugRendererImpl::BodyDrawFilter(func));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyDrawFilter_Destroy(JPC_BodyDrawFilter *filter)
+{
+    JPH::Free(reinterpret_cast<DebugRendererImpl::BodyDrawFilter *>(filter));
+}
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Shape
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Shape_AddRef(JPC_Shape *in_shape)
+{
+    toJph(in_shape)->AddRef();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Shape_Release(JPC_Shape *in_shape)
+{
+    toJph(in_shape)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_Shape_GetRefCount(const JPC_Shape *in_shape)
+{
+    return toJph(in_shape)->GetRefCount();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ShapeType
+JPC_Shape_GetType(const JPC_Shape *in_shape)
+{
+    return toJpc(toJph(in_shape)->GetType());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ShapeSubType
+JPC_Shape_GetSubType(const JPC_Shape *in_shape)
+{
+    return toJpc(toJph(in_shape)->GetSubType());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint64_t
+JPC_Shape_GetUserData(const JPC_Shape *in_shape)
+{
+    return toJph(in_shape)->GetUserData();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Shape_SetUserData(JPC_Shape *in_shape, uint64_t in_user_data)
+{
+    return toJph(in_shape)->SetUserData(in_user_data);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Shape_GetCenterOfMass(const JPC_Shape *in_shape, JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_shape)->GetCenterOfMass());
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConstraintSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConstraintSettings_AddRef(JPC_ConstraintSettings *in_settings)
+{
+    toJph(in_settings)->AddRef();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConstraintSettings_Release(JPC_ConstraintSettings *in_settings)
+{
+    toJph(in_settings)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_ConstraintSettings_GetRefCount(const JPC_ConstraintSettings *in_settings)
+{
+    return toJph(in_settings)->GetRefCount();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint64_t
+JPC_ConstraintSettings_GetUserData(const JPC_ConstraintSettings *in_settings)
+{
+    return toJph(in_settings)->mUserData;
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConstraintSettings_SetUserData(JPC_ConstraintSettings *in_settings, uint64_t in_user_data)
+{
+    toJph(in_settings)->mUserData = in_user_data;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TwoBodyConstraintSettings (-> JPC_ConstraintSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Constraint *
+JPC_TwoBodyConstraintSettings_CreateConstraint(const JPC_TwoBodyConstraintSettings *in_settings,
+                                               JPC_Body *in_body1,
+                                               JPC_Body *in_body2)
+{
+    auto constraint = toJph(in_settings)->Create(*toJph(in_body1), *toJph(in_body2));
+    if (constraint != nullptr) constraint->AddRef();
+    return toJpc(constraint);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_FixedConstraintSettings (-> JPC_TwoBodyConstraintSettings -> JPC_ConstraintSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_FixedConstraintSettings *
+JPC_FixedConstraintSettings_Create()
+{
+    auto settings = new JPH::FixedConstraintSettings();
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_FixedConstraintSettings_SetSpace(JPC_FixedConstraintSettings *in_settings, JPC_ConstraintSpace in_space)
+{
+    toJph(in_settings)->mSpace = toJph(in_space);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_FixedConstraintSettings_SetAutoDetectPoint(JPC_FixedConstraintSettings *in_settings, bool in_enabled)
+{
+    toJph(in_settings)->mAutoDetectPoint = in_enabled;
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Constraint
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Constraint_AddRef(JPC_Constraint *in_shape)
+{
+    toJph(in_shape)->AddRef();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Constraint_Release(JPC_Constraint *in_shape)
+{
+    toJph(in_shape)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_Constraint_GetRefCount(const JPC_Constraint *in_shape)
+{
+    return toJph(in_shape)->GetRefCount();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ConstraintType
+JPC_Constraint_GetType(const JPC_Constraint *in_shape)
+{
+    return toJpc(toJph(in_shape)->GetType());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ConstraintSubType
+JPC_Constraint_GetSubType(const JPC_Constraint *in_shape)
+{
+    return toJpc(toJph(in_shape)->GetSubType());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint64_t
+JPC_Constraint_GetUserData(const JPC_Constraint *in_shape)
+{
+    return toJph(in_shape)->GetUserData();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Constraint_SetUserData(JPC_Constraint *in_shape, uint64_t in_user_data)
+{
+    return toJph(in_shape)->SetUserData(in_user_data);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyInterface
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Body *
+JPC_BodyInterface_CreateBody(JPC_BodyInterface *in_iface, const JPC_BodyCreationSettings *in_settings)
+{
+    return toJpc(toJph(in_iface)->CreateBody(*toJph(in_settings)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Body *
+JPC_BodyInterface_CreateBodyWithID(JPC_BodyInterface *in_iface,
+                                   JPC_BodyID in_body_id,
+                                   const JPC_BodyCreationSettings *in_settings)
+{
+    return toJpc(toJph(in_iface)->CreateBodyWithID(toJph(in_body_id), *toJph(in_settings)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_DestroyBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    toJph(in_iface)->DestroyBody(toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_Activation in_mode)
+{
+    toJph(in_iface)->AddBody(toJph(in_body_id), static_cast<JPH::EActivation>(in_mode));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_RemoveBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    toJph(in_iface)->RemoveBody(toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BodyID
+JPC_BodyInterface_CreateAndAddBody(JPC_BodyInterface *in_iface,
+                                   const JPC_BodyCreationSettings *in_settings,
+                                   JPC_Activation in_mode)
+{
+    return toJpc(toJph(in_iface)->CreateAndAddBody(*toJph(in_settings),
+        static_cast<JPH::EActivation>(in_mode)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_BodyInterface_IsAdded(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    return toJph(in_iface)->IsAdded(toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetLinearAndAngularVelocity(JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              const float in_linear_velocity[3],
+                                              const float in_angular_velocity[3])
+{
+    toJph(in_iface)->SetLinearAndAngularVelocity(
+        toJph(in_body_id), loadVec3(in_linear_velocity), loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetLinearAndAngularVelocity(const JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              float out_linear_velocity[3],
+                                              float out_angular_velocity[3])
+{
+    JPH::Vec3 linear, angular;
+    toJph(in_iface)->GetLinearAndAngularVelocity(toJph(in_body_id), linear, angular);
+    storeVec3(out_linear_velocity, linear);
+    storeVec3(out_angular_velocity, angular);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetLinearVelocity(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_velocity[3])
+{
+    toJph(in_iface)->SetLinearVelocity(toJph(in_body_id), loadVec3(in_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetLinearVelocity(const JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    float out_velocity[3])
+{
+    storeVec3(out_velocity, toJph(in_iface)->GetLinearVelocity(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddLinearVelocity(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_velocity[3])
+{
+    toJph(in_iface)->AddLinearVelocity(toJph(in_body_id), loadVec3(in_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddLinearAndAngularVelocity(JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              const float in_linear_velocity[3],
+                                              const float in_angular_velocity[3])
+{
+    toJph(in_iface)->AddLinearAndAngularVelocity(
+        toJph(in_body_id), loadVec3(in_linear_velocity), loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetAngularVelocity(JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     const float in_velocity[3])
+{
+    toJph(in_iface)->SetAngularVelocity(toJph(in_body_id), loadVec3(in_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetAngularVelocity(const JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     float out_velocity[3])
+{
+    storeVec3(out_velocity, toJph(in_iface)->GetAngularVelocity(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetPointVelocity(const JPC_BodyInterface *in_iface,
+                                   JPC_BodyID in_body_id,
+                                   const JPC_Real in_point[3],
+                                   float out_velocity[3])
+{
+    storeVec3(out_velocity, toJph(in_iface)->GetPointVelocity(toJph(in_body_id), loadRVec3(in_point)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetPosition(const JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_iface)->GetPosition(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetPosition(JPC_BodyInterface *in_iface,
+                                          JPC_BodyID in_body_id,
+                                          const JPC_Real in_position[3],
+                                          JPC_Activation in_activation)
+{
+    toJph(in_iface)->SetPosition(toJph(in_body_id), loadRVec3(in_position), static_cast<JPH::EActivation>(in_activation));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetCenterOfMassPosition(const JPC_BodyInterface *in_iface,
+                                          JPC_BodyID in_body_id,
+                                          JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_iface)->GetCenterOfMassPosition(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetRotation(JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              const JPC_Real in_rotation[4],
+                              JPC_Activation in_activation)
+{
+    toJph(in_iface)->SetRotation(toJph(in_body_id), JPH::Quat(loadVec4(in_rotation)), static_cast<JPH::EActivation>(in_activation));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_GetRotation(const JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              float out_rotation[4])
+{
+    storeVec4(out_rotation, toJph(in_iface)->GetRotation(toJph(in_body_id)).GetXYZW());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_ActivateBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    toJph(in_iface)->ActivateBody(toJph(in_body_id));
+}
+
+JPC_API void
+JPC_BodyInterface_DeactivateBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    toJph(in_iface)->DeactivateBody(toJph(in_body_id));
+}
+
+JPC_API bool
+JPC_BodyInterface_IsActive(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    return toJph(in_iface)->IsActive(toJph(in_body_id));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetPositionRotationAndVelocity(JPC_BodyInterface *in_iface,
+                                                 JPC_BodyID in_body_id,
+                                                 const JPC_Real in_position[3],
+                                                 const float in_rotation[4],
+                                                 const float in_linear_velocity[3],
+                                                 const float in_angular_velocity[3])
+{
+    toJph(in_iface)->SetPositionRotationAndVelocity(
+        toJph(in_body_id),
+        loadRVec3(in_position),
+        JPH::Quat(loadVec4(in_rotation)),
+        loadVec3(in_linear_velocity),
+        loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddForce(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_force[3])
+{
+    toJph(in_iface)->AddForce(toJph(in_body_id), loadVec3(in_force));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddForceAtPosition(JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     const float in_force[3],
+                                     const JPC_Real in_position[3])
+{
+    toJph(in_iface)->AddForce(toJph(in_body_id), loadVec3(in_force), loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddTorque(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_torque[3])
+{
+    toJph(in_iface)->AddTorque(toJph(in_body_id), loadVec3(in_torque));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddForceAndTorque(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_force[3],
+                                    const float in_torque[3])
+{
+    toJph(in_iface)->AddForceAndTorque(toJph(in_body_id), loadVec3(in_force), loadVec3(in_torque));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddImpulse(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_impulse[3])
+{
+    toJph(in_iface)->AddImpulse(toJph(in_body_id), loadVec3(in_impulse));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddImpulseAtPosition(JPC_BodyInterface *in_iface,
+                                       JPC_BodyID in_body_id,
+                                       const float in_impulse[3],
+                                       const JPC_Real in_position[3])
+{
+    toJph(in_iface)->AddImpulse(toJph(in_body_id), loadVec3(in_impulse), loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_AddAngularImpulse(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_impulse[3])
+{
+    toJph(in_iface)->AddAngularImpulse(toJph(in_body_id), loadVec3(in_impulse));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MotionType 
+JPC_BodyInterface_GetMotionType(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    return toJpc(toJph(in_iface)->GetMotionType(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetMotionType(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_MotionType in_motion_type, JPC_Activation in_activation)
+{
+    toJph(in_iface)->SetMotionType(toJph(in_body_id), static_cast<JPH::EMotionType>(in_motion_type), static_cast<JPH::EActivation>(in_activation));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ObjectLayer
+JPC_BodyInterface_GetObjectLayer(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id)
+{
+    return toJpc(toJph(in_iface)->GetObjectLayer(toJph(in_body_id)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyInterface_SetObjectLayer(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_ObjectLayer in_layer)
+{
+    toJph(in_iface)->SetObjectLayer(toJph(in_body_id), static_cast<JPH::ObjectLayer>(in_layer));
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Body
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BodyID
+JPC_Body_GetID(const JPC_Body *in_body)
+{
+    return toJph(in_body)->GetID().GetIndexAndSequenceNumber();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsActive(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsActive();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsStatic(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsStatic();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsKinematic(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsKinematic();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsDynamic(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsDynamic();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_CanBeKinematicOrDynamic(const JPC_Body *in_body)
+{
+    return toJph(in_body)->CanBeKinematicOrDynamic();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetIsSensor(JPC_Body *in_body, bool in_is_sensor)
+{
+    toJph(in_body)->SetIsSensor(in_is_sensor);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsSensor(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsSensor();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MotionType
+JPC_Body_GetMotionType(const JPC_Body *in_body)
+{
+    return toJpc(toJph(in_body)->GetMotionType());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetMotionType(JPC_Body *in_body, JPC_MotionType in_motion_type)
+{
+    toJph(in_body)->SetMotionType(static_cast<JPH::EMotionType>(in_motion_type));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BroadPhaseLayer
+JPC_Body_GetBroadPhaseLayer(const JPC_Body *in_body)
+{
+    return toJpc(toJph(in_body)->GetBroadPhaseLayer());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ObjectLayer
+JPC_Body_GetObjectLayer(const JPC_Body *in_body)
+{
+    return toJpc(toJph(in_body)->GetObjectLayer());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CollisionGroup *
+JPC_Body_GetCollisionGroup(JPC_Body *in_body)
+{
+    return toJpc(&toJph(in_body)->GetCollisionGroup());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetCollisionGroup(JPC_Body *in_body, const JPC_CollisionGroup *in_group)
+{
+    toJph(in_body)->SetCollisionGroup(*toJph(in_group));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_GetAllowSleeping(const JPC_Body *in_body)
+{
+    return toJph(in_body)->GetAllowSleeping();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetAllowSleeping(JPC_Body *in_body, bool in_allow)
+{
+    toJph(in_body)->SetAllowSleeping(in_allow);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_Body_GetFriction(const JPC_Body *in_body)
+{
+    return toJph(in_body)->GetFriction();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetFriction(JPC_Body *in_body, float in_friction)
+{
+    toJph(in_body)->SetFriction(in_friction);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_Body_GetRestitution(const JPC_Body *in_body)
+{
+    return toJph(in_body)->GetRestitution();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetRestitution(JPC_Body *in_body, float in_restitution)
+{
+    toJph(in_body)->SetRestitution(in_restitution);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetLinearVelocity(const JPC_Body *in_body, float out_linear_velocity[3])
+{
+    storeVec3(out_linear_velocity, toJph(in_body)->GetLinearVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetLinearVelocity(JPC_Body *in_body, const float in_linear_velocity[3])
+{
+    toJph(in_body)->SetLinearVelocity(loadVec3(in_linear_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetLinearVelocityClamped(JPC_Body *in_body, const float in_linear_velocity[3])
+{
+    toJph(in_body)->SetLinearVelocityClamped(loadVec3(in_linear_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetAngularVelocity(const JPC_Body *in_body, float out_angular_velocity[3])
+{
+    storeVec3(out_angular_velocity, toJph(in_body)->GetAngularVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetAnglularVelocity(JPC_Body *in_body, const float in_angular_velocity[3])
+{
+    toJph(in_body)->SetAngularVelocity(loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetAnglularVelocityClamped(JPC_Body *in_body, const float in_angular_velocity[3])
+{
+    toJph(in_body)->SetAngularVelocityClamped(loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetPointVelocityCOM(const JPC_Body *in_body,
+                             const float in_point_relative_to_com[3],
+                             float out_velocity[3])
+{
+    storeVec3(out_velocity, toJph(in_body)->GetPointVelocityCOM(loadVec3(in_point_relative_to_com)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetPointVelocity(const JPC_Body *in_body, const JPC_Real in_point[3], float out_velocity[3])
+{
+    storeVec3(out_velocity, toJph(in_body)->GetPointVelocity(loadRVec3(in_point)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddForce(JPC_Body *in_body, const float in_force[3])
+{
+    toJph(in_body)->AddForce(loadVec3(in_force));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddForceAtPosition(JPC_Body *in_body, const float in_force[3], const JPC_Real in_position[3])
+{
+    toJph(in_body)->AddForce(loadVec3(in_force), loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddTorque(JPC_Body *in_body, const float in_torque[3])
+{
+    toJph(in_body)->AddTorque(loadVec3(in_torque));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetInverseInertia(const JPC_Body *in_body, float out_inverse_inertia[16])
+{
+    storeMat44(out_inverse_inertia, toJph(in_body)->GetInverseInertia());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddImpulse(JPC_Body *in_body, const float in_impulse[3])
+{
+    toJph(in_body)->AddImpulse(loadVec3(in_impulse));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddImpulseAtPosition(JPC_Body *in_body, const float in_impulse[3], const JPC_Real in_position[3])
+{
+    toJph(in_body)->AddImpulse(loadVec3(in_impulse), loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_AddAngularImpulse(JPC_Body *in_body, const float in_angular_impulse[3])
+{
+    toJph(in_body)->AddAngularImpulse(loadVec3(in_angular_impulse));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_MoveKinematic(JPC_Body *in_body,
+                       const JPC_Real in_target_position[3],
+                       const float in_target_rotation[4],
+                       float in_delta_time)
+{
+    toJph(in_body)->MoveKinematic(
+        loadRVec3(in_target_position), JPH::Quat(loadVec4(in_target_rotation)), in_delta_time);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_ApplyBuoyancyImpulse(JPC_Body *in_body,
+                              const JPC_Real in_surface_position[3],
+                              const float in_surface_normal[3],
+                              float in_buoyancy,
+                              float in_linear_drag,
+                              float in_angular_drag,
+                              const float in_fluid_velocity[3],
+                              const float in_gravity[3],
+                              float in_delta_time)
+{
+    toJph(in_body)->ApplyBuoyancyImpulse(
+        loadRVec3(in_surface_position),
+        loadVec3(in_surface_normal),
+        in_buoyancy,
+        in_linear_drag,
+        in_angular_drag,
+        loadVec3(in_fluid_velocity),
+        loadVec3(in_gravity),
+        in_delta_time);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsInBroadPhase(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsInBroadPhase();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_Body_IsCollisionCacheInvalid(const JPC_Body *in_body)
+{
+    return toJph(in_body)->IsCollisionCacheInvalid();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API const JPC_Shape *
+JPC_Body_GetShape(const JPC_Body *in_body)
+{
+    return toJpc(toJph(in_body)->GetShape());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetPosition(const JPC_Body *in_body, JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_body)->GetPosition());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetRotation(const JPC_Body *in_body, float out_rotation[4])
+{
+    storeVec4(out_rotation, toJph(in_body)->GetRotation().GetXYZW());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetWorldTransform(const JPC_Body *in_body, float out_rotation[9], JPC_Real out_translation[3])
+{
+    const JPH::RMat44 m = toJph(in_body)->GetWorldTransform();
+    storeVec3(&out_rotation[0], m.GetColumn3(0));
+    storeVec3(&out_rotation[3], m.GetColumn3(1));
+    storeVec3(&out_rotation[6], m.GetColumn3(2));
+    storeRVec3(&out_translation[0], m.GetTranslation());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetCenterOfMassPosition(const JPC_Body *in_body, JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_body)->GetCenterOfMassPosition());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetCenterOfMassTransform(const JPC_Body *in_body,
+                                  float out_rotation[9],
+                                  JPC_Real out_translation[3])
+{
+    const JPH::RMat44 m = toJph(in_body)->GetCenterOfMassTransform();
+    storeVec3(&out_rotation[0], m.GetColumn3(0));
+    storeVec3(&out_rotation[3], m.GetColumn3(1));
+    storeVec3(&out_rotation[6], m.GetColumn3(2));
+    storeRVec3(&out_translation[0], m.GetTranslation());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetInverseCenterOfMassTransform(const JPC_Body *in_body,
+                                         float out_rotation[9],
+                                         JPC_Real out_translation[3])
+{
+    const JPH::RMat44 m = toJph(in_body)->GetInverseCenterOfMassTransform();
+    storeVec3(&out_rotation[0], m.GetColumn3(0));
+    storeVec3(&out_rotation[3], m.GetColumn3(1));
+    storeVec3(&out_rotation[6], m.GetColumn3(2));
+    storeRVec3(&out_translation[0], m.GetTranslation());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetWorldSpaceBounds(const JPC_Body *in_body, float out_min[3], float out_max[3])
+{
+    const JPH::AABox& aabb = toJph(in_body)->GetWorldSpaceBounds();
+    storeVec3(out_min, aabb.mMin);
+    storeVec3(out_max, aabb.mMax);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MotionProperties *
+JPC_Body_GetMotionProperties(JPC_Body *in_body)
+{
+    return toJpc(toJph(in_body)->GetMotionProperties());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint64_t
+JPC_Body_GetUserData(const JPC_Body *in_body)
+{
+    return toJph(in_body)->GetUserData();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_SetUserData(JPC_Body *in_body, uint64_t in_user_data)
+{
+    toJph(in_body)->SetUserData(in_user_data);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Body_GetWorldSpaceSurfaceNormal(const JPC_Body *in_body,
+                                    JPC_SubShapeID in_sub_shape_id,
+                                    const JPC_Real in_position[3],
+                                    float out_normal_vector[3])
+{
+    const JPH::Vec3 v = toJph(in_body)->GetWorldSpaceSurfaceNormal(
+        *toJph(&in_sub_shape_id), loadRVec3(in_position));
+    storeVec3(out_normal_vector, v);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_MotionProperties
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MotionQuality
+JPC_MotionProperties_GetMotionQuality(const JPC_MotionProperties *in_properties)
+{
+    return toJpc(toJph(in_properties)->GetMotionQuality());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetLinearVelocity(const JPC_MotionProperties *in_properties,
+                                       float out_linear_velocity[3])
+{
+    storeVec3(out_linear_velocity, toJph(in_properties)->GetLinearVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetLinearVelocity(JPC_MotionProperties *in_properties,
+                                       const float in_linear_velocity[3])
+{
+    toJph(in_properties)->SetLinearVelocity(loadVec3(in_linear_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetLinearVelocityClamped(JPC_MotionProperties *in_properties,
+                                              const float in_linear_velocity[3])
+{
+    toJph(in_properties)->SetLinearVelocityClamped(loadVec3(in_linear_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetAngularVelocity(const JPC_MotionProperties *in_properties,
+                                        float out_angular_velocity[3])
+{
+    storeVec3(out_angular_velocity, toJph(in_properties)->GetAngularVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetAngularVelocity(JPC_MotionProperties *in_properties,
+                                        const float in_angular_velocity[3])
+{
+    toJph(in_properties)->SetAngularVelocity(loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetAngularVelocityClamped(JPC_MotionProperties *in_properties,
+                                               const float in_angular_velocity[3])
+{
+    toJph(in_properties)->SetAngularVelocityClamped(loadVec3(in_angular_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_MoveKinematic(JPC_MotionProperties *in_properties,
+                                   const float in_delta_position[3],
+                                   const float in_delta_rotation[4],
+                                   float in_delta_time)
+{
+    toJph(in_properties)->MoveKinematic(
+        loadVec3(in_delta_position), JPH::Quat(loadVec4(in_delta_rotation)), in_delta_time);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_ClampLinearVelocity(JPC_MotionProperties *in_properties)
+{
+    toJph(in_properties)->ClampLinearVelocity();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_ClampAngularVelocity(JPC_MotionProperties *in_properties)
+{
+    toJph(in_properties)->ClampAngularVelocity();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetLinearDamping(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetLinearDamping();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetLinearDamping(JPC_MotionProperties *in_properties,
+                                      float in_linear_damping)
+{
+    toJph(in_properties)->SetLinearDamping(in_linear_damping);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetAngularDamping(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetAngularDamping();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetAngularDamping(JPC_MotionProperties *in_properties,
+                                       float in_angular_damping)
+{
+    toJph(in_properties)->SetAngularDamping(in_angular_damping);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetGravityFactor(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetGravityFactor();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetGravityFactor(JPC_MotionProperties *in_properties,
+                                      float in_gravity_factor)
+{
+    toJph(in_properties)->SetGravityFactor(in_gravity_factor);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetMassProperties(JPC_MotionProperties *in_properties,
+                                       const JPC_MassProperties *in_mass_properties)
+{
+    toJph(in_properties)->SetMassProperties(*toJph(in_mass_properties));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetInverseMass(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetInverseMass();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetInverseMass(JPC_MotionProperties *in_properties, float in_inv_mass)
+{
+    toJph(in_properties)->SetInverseMass(in_inv_mass);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetInverseInertiaDiagonal(const JPC_MotionProperties *in_properties,
+                                               float out_inverse_inertia_diagonal[3])
+{
+    storeVec3(out_inverse_inertia_diagonal, toJph(in_properties)->GetInverseInertiaDiagonal());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetInertiaRotation(const JPC_MotionProperties *in_properties,
+                                        float out_inertia_rotation[4])
+{
+    storeVec4(out_inertia_rotation, toJph(in_properties)->GetInertiaRotation().GetXYZW());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetInverseInertia(JPC_MotionProperties *in_properties,
+                                       const float in_diagonal[3],
+                                       const float in_rotation[4])
+{
+    toJph(in_properties)->SetInverseInertia(
+        loadVec3(in_diagonal),
+        JPH::Quat(loadVec4(in_rotation)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetLocalSpaceInverseInertia(const JPC_MotionProperties *in_properties,
+                                                 float out_matrix[16])
+{
+    storeMat44(out_matrix, toJph(in_properties)->GetLocalSpaceInverseInertia());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetInverseInertiaForRotation(const JPC_MotionProperties *in_properties,
+                                                  const float in_rotation_matrix[16],
+                                                  float out_matrix[16])
+{
+    storeMat44(out_matrix, toJph(in_properties)->GetInverseInertiaForRotation(loadMat44(in_rotation_matrix)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_MultiplyWorldSpaceInverseInertiaByVector(const JPC_MotionProperties *in_properties,
+                                                              const float in_body_rotation[4],
+                                                              const float in_vector[3],
+                                                              float out_vector[3])
+{
+    const JPH::Vec3 v = toJph(in_properties)->MultiplyWorldSpaceInverseInertiaByVector(
+        JPH::Quat(loadVec4(in_body_rotation)), loadVec3(in_vector));
+    storeVec3(out_vector, v);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_GetPointVelocityCOM(const JPC_MotionProperties *in_properties,
+                                         const float in_point_relative_to_com[3],
+                                         float out_point[3])
+{
+    storeVec3(out_point, toJph(in_properties)->GetPointVelocityCOM(loadVec3(in_point_relative_to_com)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetMaxLinearVelocity(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetMaxLinearVelocity();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetMaxLinearVelocity(JPC_MotionProperties *in_properties,
+                                          float in_max_linear_velocity)
+{
+    toJph(in_properties)->SetMaxLinearVelocity(in_max_linear_velocity);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API float
+JPC_MotionProperties_GetMaxAngularVelocity(const JPC_MotionProperties *in_properties)
+{
+    return toJph(in_properties)->GetMaxAngularVelocity();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_MotionProperties_SetMaxAngularVelocity(JPC_MotionProperties *in_properties,
+                                           float in_max_angular_velocity)
+{
+    toJph(in_properties)->SetMaxAngularVelocity(in_max_angular_velocity);
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyID
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_BodyID_GetIndex(JPC_BodyID in_body_id)
+{
+    return JPH::BodyID(in_body_id).GetIndex();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API uint8_t
+JPC_BodyID_GetSequenceNumber(JPC_BodyID in_body_id)
+{
+    return JPH::BodyID(in_body_id).GetSequenceNumber();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_BodyID_IsInvalid(JPC_BodyID in_body_id)
+{
+    return JPH::BodyID(in_body_id).IsInvalid();
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterSettings *
+JPC_CharacterSettings_Create()
+{
+    auto settings = new JPH::CharacterSettings();
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterSettings_Release(JPC_CharacterSettings *in_settings)
+{
+    toJph(in_settings)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterSettings_AddRef(JPC_CharacterSettings *in_settings)
+{
+    toJph(in_settings)->AddRef();
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Character
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Character *
+JPC_Character_Create(const JPC_CharacterSettings *in_settings,
+                     const JPC_Real in_position[3],
+                     const float in_rotation[4],
+                     uint64_t in_user_data,
+                     JPC_PhysicsSystem *in_physics_system)
+{
+    auto character = new JPH::Character(toJph(in_settings),
+                                        loadVec3(in_position),
+                                        JPH::Quat(loadVec4(in_rotation)),
+                                        in_user_data,
+                                        toJph(in_physics_system));
+    return toJpc(character);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_Destroy(JPC_Character *in_character)
+{
+    delete toJph(in_character);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_AddToPhysicsSystem(JPC_Character *in_character, JPC_Activation in_activation, bool in_lock_bodies)
+{
+    toJph(in_character)->AddToPhysicsSystem(static_cast<JPH::EActivation>(in_activation), in_lock_bodies);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_RemoveFromPhysicsSystem(JPC_Character *in_character, bool in_lock_bodies)
+{
+    toJph(in_character)->RemoveFromPhysicsSystem(in_lock_bodies);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_GetPosition(const JPC_Character *in_character, JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_character)->GetPosition());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_SetPosition(JPC_Character *in_character, const JPC_Real in_position[3])
+{
+    toJph(in_character)->SetPosition(loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_GetLinearVelocity(const JPC_Character *in_character, float out_linear_velocity[3])
+{
+    storeVec3(out_linear_velocity, toJph(in_character)->GetLinearVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Character_SetLinearVelocity(JPC_Character *in_character, const float in_linear_velocity[3])
+{
+    toJph(in_character)->SetLinearVelocity(loadVec3(in_linear_velocity));
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterVirtualSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterVirtualSettings *
+JPC_CharacterVirtualSettings_Create()
+{
+    auto settings = new JPH::CharacterVirtualSettings();
+    settings->AddRef();
+    return toJpc(settings);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtualSettings_Release(JPC_CharacterVirtualSettings *in_settings)
+{
+    toJph(in_settings)->Release();
+}
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterVirtual
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterVirtual *
+JPC_CharacterVirtual_Create(const JPC_CharacterVirtualSettings *in_settings,
+                            const JPC_Real in_position[3],
+                            const float in_rotation[4],
+                            JPC_PhysicsSystem *in_physics_system)
+{
+    auto character = new JPH::CharacterVirtual(
+        toJph(in_settings), loadVec3(in_position), JPH::Quat(loadVec4(in_rotation)), toJph(in_physics_system));
+    return toJpc(character);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_Destroy(JPC_CharacterVirtual *in_character)
+{
+    delete toJph(in_character);
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_Update(JPC_CharacterVirtual *in_character,
+                            float in_delta_time,
+                            const float in_gravity[3],
+                            const void *in_broad_phase_layer_filter,
+                            const void *in_object_layer_filter,
+                            const void *in_body_filter,
+                            const void *in_shape_filter,
+                            JPC_TempAllocator *in_temp_allocator)
+{
+    const JPH::BroadPhaseLayerFilter broad_phase_layer_filter{};
+    const JPH::ObjectLayerFilter object_layer_filter{};
+    const JPH::BodyFilter body_filter{};
+    const JPH::ShapeFilter shape_filter{};
+    toJph(in_character)->Update(
+        in_delta_time,
+        loadVec3(in_gravity),
+        in_broad_phase_layer_filter ?
+        *static_cast<const JPH::BroadPhaseLayerFilter *>(in_broad_phase_layer_filter) : broad_phase_layer_filter,
+        in_object_layer_filter ?
+        *static_cast<const JPH::ObjectLayerFilter *>(in_object_layer_filter) : object_layer_filter,
+        in_body_filter ? *static_cast<const JPH::BodyFilter *>(in_body_filter) : body_filter,
+        in_shape_filter ? *static_cast<const JPH::ShapeFilter *>(in_shape_filter) : shape_filter,
+        *reinterpret_cast<JPH::TempAllocator *>(in_temp_allocator));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterGroundState
+JPC_CharacterVirtual_GetGroundState(JPC_CharacterVirtual *in_character)
+{
+    return toJpc(toJph(in_character)->GetGroundState());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_SetListener(JPC_CharacterVirtual *in_character, void *in_listener)
+{
+    if (in_listener == nullptr)
+    {
+        toJph(in_character)->SetListener(nullptr);
+        return;
+    }
+    toJph(in_character)->SetListener(static_cast<JPH::CharacterContactListener *>(in_listener));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_UpdateGroundVelocity(JPC_CharacterVirtual *in_character)
+{
+    toJph(in_character)->UpdateGroundVelocity();
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_GetGroundVelocity(const JPC_CharacterVirtual *in_character, float out_ground_velocity[3])
+{
+    storeVec3(out_ground_velocity, toJph(in_character)->GetGroundVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_GetPosition(const JPC_CharacterVirtual *in_character, JPC_Real out_position[3])
+{
+    storeRVec3(out_position, toJph(in_character)->GetPosition());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_SetPosition(JPC_CharacterVirtual *in_character, const JPC_Real in_position[3])
+{
+    toJph(in_character)->SetPosition(loadRVec3(in_position));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_GetRotation(const JPC_CharacterVirtual *in_character, float out_rotation[4])
+{
+    storeVec4(out_rotation, toJph(in_character)->GetRotation().GetXYZW());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_SetRotation(JPC_CharacterVirtual *in_character, const float in_rotation[4])
+{
+    toJph(in_character)->SetRotation(JPH::Quat(loadVec4(in_rotation)));
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_GetLinearVelocity(const JPC_CharacterVirtual *in_character, float out_linear_velocity[3])
+{
+    storeVec3(out_linear_velocity, toJph(in_character)->GetLinearVelocity());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_CharacterVirtual_SetLinearVelocity(JPC_CharacterVirtual *in_character, const float in_linear_velocity[3])
+{
+    toJph(in_character)->SetLinearVelocity(loadVec3(in_linear_velocity));
+}
+
+JPC_API JPC_Features JPC_GetFeatures()
+{
+    JPC_Features features{};
+
+	features |= JPH_IF_SINGLE_PRECISION_ELSE(0, 1) << 0;
+
+#ifdef JPH_USE_NEON
+		features |= 1 << 1;
+#endif
+#ifdef JPH_USE_SSE
+		features |= 1 << 2;
+#endif
+#ifdef JPH_USE_SSE4_1
+		features |= 1 << 3;
+#endif
+#ifdef JPH_USE_SSE4_2
+		features |= 1 << 4;
+#endif
+#ifdef JPH_USE_AVX
+		features |= 1 << 5;
+#endif
+#ifdef JPH_USE_AVX2
+		features |= 1 << 6;
+#endif
+#ifdef JPH_USE_AVX512
+		features |= 1 << 7;
+#endif
+#ifdef JPH_USE_F16C
+		features |= 1 << 8;
+#endif
+#ifdef JPH_USE_LZCNT
+		features |= 1 << 9;
+#endif
+#ifdef JPH_USE_TZCNT
+		features |= 1 << 10;
+#endif
+#ifdef JPH_USE_FMADD
+		features |= 1 << 11;
+#endif
+#ifdef JPH_CROSS_PLATFORM_DETERMINISTIC
+		features |= 1 << 12;
+#endif
+#ifdef JPH_FLOATING_POINT_EXCEPTIONS_ENABLED
+		features |= 1 << 13;
+#endif
+#ifdef _DEBUG
+		features |= 1 << 14;
+#endif
+
+    return features;
+}

+ 2113 - 0
JoltC/JoltPhysicsC.h

@@ -0,0 +1,2113 @@
+// JoltPhysicsC v0.0.6 - C API for Jolt Physics C++ library
+
+#pragma once
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdalign.h>
+#include <float.h>
+//--------------------------------------------------------------------------------------------------
+//
+// Const
+//
+//--------------------------------------------------------------------------------------------------
+#define JPC_API extern __declspec(dllexport) // TODO: Define this properly
+
+// Always turn on asserts in Debug mode
+#if defined(_DEBUG) || defined(JPH_ENABLE_ASSERTS)
+    #define JPC_ENABLE_ASSERTS 1
+#else
+    #define JPC_ENABLE_ASSERTS 0
+#endif
+
+#if defined(JPH_DOUBLE_PRECISION)
+    #define JPC_DOUBLE_PRECISION 1
+#else
+    #define JPC_DOUBLE_PRECISION 0
+#endif
+
+#if JPC_DOUBLE_PRECISION == 1
+typedef double JPC_Real;
+#define JPC_RVEC_ALIGN alignas(32)
+#else
+typedef float JPC_Real;
+#define JPC_RVEC_ALIGN alignas(16)
+#endif
+
+#if defined(JPH_DEBUG_RENDERER)
+    #define JPC_DEBUG_RENDERER 1
+#else
+    #define JPC_DEBUG_RENDERER 0
+#endif
+
+#define JPC_PI 3.14159265358979323846f
+
+#define JPC_COLLISION_GROUP_INVALID_GROUP 0xffffffff
+#define JPC_COLLISION_GROUP_INVALID_SUB_GROUP 0xffffffff
+
+#define JPC_BODY_ID_INVALID 0xffffffff
+#define JPC_BODY_ID_INDEX_BITS 0x007fffff
+#define JPC_BODY_ID_SEQUENCE_BITS 0xff000000
+#define JPC_BODY_ID_SEQUENCE_SHIFT 24
+
+#define JPC_SUB_SHAPE_ID_EMPTY 0xffffffff
+
+#define JPC_FLT_EPSILON FLT_EPSILON
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// JPC_JobSystem_Create()
+enum JPC_JobSystemConstants
+{
+    JPC_MAX_PHYSICS_JOBS     = 2048,
+    JPC_MAX_PHYSICS_BARRIERS = 8
+};
+
+typedef uint8_t JPC_PhysicsUpdateError;
+typedef enum JPC_EPhysicsUpdateError
+{
+    JPC_PHYSICS_UPDATE_NO_ERROR                 = 0,
+    JPC_PHYSICS_UPDATE_MANIFOLD_CACHE_FULL      = 1 << 0,
+    JPC_PHYSICS_UPDATE_BODY_PAIR_CACHE_FULL     = 1 << 1,
+    JPC_PHYSICS_UPDATE_CONTACT_CONSTRAINTS_FULL = 1 << 2,
+} JPC_EPhysicsUpdateError;
+
+typedef uint8_t JPC_ShapeType;
+typedef enum JPC_EShapeType
+{
+    JPC_SHAPE_TYPE_CONVEX       = 0,
+    JPC_SHAPE_TYPE_COMPOUND     = 1,
+    JPC_SHAPE_TYPE_DECORATED    = 2,
+    JPC_SHAPE_TYPE_MESH         = 3,
+    JPC_SHAPE_TYPE_HEIGHT_FIELD = 4,
+    JPC_SHAPE_TYPE_USER1        = 5,
+    JPC_SHAPE_TYPE_USER2        = 6,
+    JPC_SHAPE_TYPE_USER3        = 7,
+    JPC_SHAPE_TYPE_USER4        = 8
+} JPC_EShapeType;
+
+typedef uint8_t JPC_ShapeSubType;
+typedef enum JPC_EShapeSubType
+{
+    JPC_SHAPE_SUB_TYPE_SPHERE                = 0,
+    JPC_SHAPE_SUB_TYPE_BOX                   = 1,
+    JPC_SHAPE_SUB_TYPE_TRIANGLE              = 2,
+    JPC_SHAPE_SUB_TYPE_CAPSULE               = 3,
+    JPC_SHAPE_SUB_TYPE_TAPERED_CAPSULE       = 4,
+    JPC_SHAPE_SUB_TYPE_CYLINDER              = 5,
+    JPC_SHAPE_SUB_TYPE_CONVEX_HULL           = 6,
+    JPC_SHAPE_SUB_TYPE_STATIC_COMPOUND       = 7,
+    JPC_SHAPE_SUB_TYPE_MUTABLE_COMPOUND      = 8,
+    JPC_SHAPE_SUB_TYPE_ROTATED_TRANSLATED    = 9,
+    JPC_SHAPE_SUB_TYPE_SCALED                = 10,
+    JPC_SHAPE_SUB_TYPE_OFFSET_CENTER_OF_MASS = 11,
+    JPC_SHAPE_SUB_TYPE_MESH                  = 12,
+    JPC_SHAPE_SUB_TYPE_HEIGHT_FIELD          = 13,
+    JPC_SHAPE_SUB_TYPE_USER1                 = 14,
+    JPC_SHAPE_SUB_TYPE_USER2                 = 15,
+    JPC_SHAPE_SUB_TYPE_USER3                 = 16,
+    JPC_SHAPE_SUB_TYPE_USER4                 = 17,
+    JPC_SHAPE_SUB_TYPE_USER5                 = 18,
+    JPC_SHAPE_SUB_TYPE_USER6                 = 19,
+    JPC_SHAPE_SUB_TYPE_USER7                 = 20,
+    JPC_SHAPE_SUB_TYPE_USER8                 = 21,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX1          = 22,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX2          = 23,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX3          = 24,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX4          = 25,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX5          = 26,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX6          = 27,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX7          = 28,
+    JPC_SHAPE_SUB_TYPE_USER_CONVEX8          = 29,
+} JPC_EShapeSubType;
+
+typedef enum JPC_ConstraintType
+{
+    JPC_CONSTRAINT_TYPE_CONSTRAINT          = 0,
+    JPC_CONSTRAINT_TYPE_TWO_BODY_CONSTRAINT = 1,
+    _JPC_CONSTRAINT_TYPE_FORCEU32           = 0x7fffffff
+} JPC_ConstraintType;
+
+typedef enum JPC_ConstraintSubType
+{
+    JPC_CONSTRAINT_SUB_TYPE_FIXED           = 0,
+    JPC_CONSTRAINT_SUB_TYPE_POINT           = 1,
+    JPC_CONSTRAINT_SUB_TYPE_HINGE           = 2,
+    JPC_CONSTRAINT_SUB_TYPE_SLIDER          = 3,
+    JPC_CONSTRAINT_SUB_TYPE_DISTANCE        = 4,
+    JPC_CONSTRAINT_SUB_TYPE_CONE            = 5,
+    JPC_CONSTRAINT_SUB_TYPE_SWING_TWIST     = 6,
+    JPC_CONSTRAINT_SUB_TYPE_SIX_DOF         = 7,
+    JPC_CONSTRAINT_SUB_TYPE_PATH            = 8,
+    JPC_CONSTRAINT_SUB_TYPE_VEHICLE         = 9,
+    JPC_CONSTRAINT_SUB_TYPE_RACK_AND_PINION = 10,
+    JPC_CONSTRAINT_SUB_TYPE_GEAR            = 11,
+    JPC_CONSTRAINT_SUB_TYPE_PULLEY          = 12,
+    JPC_CONSTRAINT_SUB_TYPE_USER1           = 13,
+    JPC_CONSTRAINT_SUB_TYPE_USER2           = 14,
+    JPC_CONSTRAINT_SUB_TYPE_USER3           = 15,
+    JPC_CONSTRAINT_SUB_TYPE_USER4           = 16,
+    _JPC_CONSTRAINT_SUB_TYPE_FORCEU32       = 0x7fffffff
+} JPC_ConstraintSubType;
+
+typedef enum JPC_ConstraintSpace
+{
+    JPC_CONSTRAINT_SPACE_LOCAL_TO_BODY_COM = 0,
+    JPC_CONSTRAINT_SPACE_WORLD_SPACE       = 1,
+    _JPC_CONSTRAINT_SPACE_FORCEU32         = 0x7fffffff
+} JPC_ConstraintSpace;
+
+typedef uint8_t JPC_MotionType;
+typedef enum JPC_EMotionType
+{
+    JPC_MOTION_TYPE_STATIC    = 0,
+    JPC_MOTION_TYPE_KINEMATIC = 1,
+    JPC_MOTION_TYPE_DYNAMIC   = 2
+} JPC_EMotionType;
+
+typedef uint8_t JPC_MotionQuality;
+typedef enum JPC_EMotionQuality
+{
+    JPC_MOTION_QUALITY_DISCRETE    = 0,
+    JPC_MOTION_QUALITY_LINEAR_CAST = 1
+} JPC_EMotionQuality;
+
+typedef uint8_t JPC_OverrideMassProperties;
+typedef enum JPC_EOverrideMassProperties
+{
+    JPC_OVERRIDE_MASS_PROPS_CALC_MASS_INERTIA     = 0,
+    JPC_OVERRIDE_MASS_PROPS_CALC_INERTIA          = 1,
+    JPC_OVERRIDE_MASS_PROPS_MASS_INERTIA_PROVIDED = 2
+} JPC_EOverrideMassProperties;
+
+typedef enum JPC_CharacterGroundState
+{
+    JPC_CHARACTER_GROUND_STATE_ON_GROUND       = 0,
+    JPC_CHARACTER_GROUND_STATE_ON_STEEP_GROUND = 1,
+    JPC_CHARACTER_GROUND_STATE_NOT_SUPPORTED   = 2,
+    JPC_CHARACTER_GROUND_STATE_IN_AIR          = 3,
+    _JPC_CHARACTER_GROUND_FORCEU32             = 0x7fffffff
+} JPC_CharacterGroundState;
+
+typedef enum JPC_Activation
+{
+    JPC_ACTIVATION_ACTIVATE      = 0,
+    JPC_ACTIVATION_DONT_ACTIVATE = 1,
+    _JPC_ACTIVATION_FORCEU32     = 0x7fffffff
+} JPC_Activation;
+
+typedef enum JPC_ValidateResult
+{
+    JPC_VALIDATE_RESULT_ACCEPT_ALL_CONTACTS = 0,
+    JPC_VALIDATE_RESULT_ACCEPT_CONTACT      = 1,
+    JPC_VALIDATE_RESULT_REJECT_CONTACT      = 2,
+    JPC_VALIDATE_RESULT_REJECT_ALL_CONTACTS = 3,
+    _JPC_VALIDATE_RESULT_FORCEU32           = 0x7fffffff
+} JPC_ValidateResult;
+
+typedef uint8_t JPC_BackFaceMode;
+typedef enum JPC_EBackFaceMode
+{
+    JPC_BACK_FACE_IGNORE  = 0,
+    JPC_BACK_FACE_COLLIDE = 1
+} JPC_EBackFaceMode;
+
+typedef uint32_t JPC_Features;
+typedef enum JPC_EFeatures {
+    JPC_FEATURE_DOUBLE_PRECISION = (1 << 0),
+    JPC_FEATURE_NEON = (1 << 1),
+    JPC_FEATURE_SSE = (1 << 2),
+    JPC_FEATURE_SSE4_1 = (1 << 3),
+    JPC_FEATURE_SSE4_2 = (1 << 4),
+    JPC_FEATURE_AVX = (1 << 5),
+    JPC_FEATURE_AVX2 = (1 << 6),
+    JPC_FEATURE_AVX512 = (1 << 7),
+    JPC_FEATURE_F16C = (1 << 8),
+    JPC_FEATURE_LZCNT = (1 << 9),
+    JPC_FEATURE_TZCNT = (1 << 10),
+    JPC_FEATURE_FMADD = (1 << 11),
+    JPC_FEATURE_PLATFORM_DETERMINISTIC = (1 << 12),
+    JPC_FEATURE_FLOATING_POINT_EXCEPTIONS = (1 << 13),
+    JPC_FEATURE_DEBUG = (1 << 14),
+} JPC_EFeatures;
+
+#if JPC_DEBUG_RENDERER == 1
+typedef enum JPC_DebugRendererResult {
+    JPC_DEBUGRENDERER_SUCCESS,
+    JPC_DEBUGRENDERER_DUPLICATE_SINGLETON,
+    JPC_DEBUGRENDERER_MISSING_SINGLETON,
+    JPC_DEBUGRENDERER_INCOMPLETE_IMPL
+} JPC_DebugRendererResult;
+
+typedef enum JPC_CullMode {
+    JPC_CULL_BACK_FACE    = 0,
+    JPC_CULL_FRONT_FACE   = 1,
+    JPC_CULLING_OFF       = 2,
+    _JPC_CULLING_FORCEU32 = 0x7fffffff
+} JPC_CullMode;
+
+typedef enum JPC_CastShadow {
+    JPC_CAST_SHADOW_ON        = 0,
+    JPC_CAST_SHADOW_OFF       = 1,
+    _JPC_CAST_SHADOW_FORCEU32 = 0x7fffffff
+} JPC_CastShadow;
+
+typedef enum JPC_DrawMode {
+    JPC_DRAW_MODE_SOLID     = 0,
+    JPC_DRAW_MODE_WIREFRAME = 1,
+    _JPC_DRAW_MODE_FORCEU32 = 0x7fffffff
+} JPC_DrawMode;
+
+typedef enum JPC_ShapeColor {
+    JPC_INSTANCE_COLOR,     // Random color per instance
+    JPC_SHAPE_TYPE_COLOR,   // Convex = green, scaled = yellow, compound = orange, mesh = red
+    JPC_MOTION_TYPE_COLOR,  // Static = grey, keyframed = green, dynamic = random color per instance
+    JPC_SLEEP_COLOR,        // Static = grey, keyframed = green, dynamic = yellow, sleeping = red
+    JPC_ISLAND_COLOR,       // Static = grey, active = random color per island, sleeping = light grey
+    JPC_MATERIAL_COLOR,     // Color as defined by the PhysicsMaterial of the shape
+} JPC_ShapeColor;
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// Types
+//
+//--------------------------------------------------------------------------------------------------
+typedef uint16_t JPC_ObjectLayer;
+typedef uint8_t  JPC_BroadPhaseLayer;
+
+// TODO: Consider using structures for IDs
+typedef uint32_t JPC_BodyID;
+typedef uint32_t JPC_SubShapeID;
+typedef uint32_t JPC_CollisionGroupID;
+typedef uint32_t JPC_CollisionSubGroupID;
+
+// Must be 16 byte aligned
+typedef void *(*JPC_AllocateFunction)(size_t in_size);
+typedef void (*JPC_FreeFunction)(void *in_block);
+
+typedef void *(*JPC_AlignedAllocateFunction)(size_t in_size, size_t in_alignment);
+typedef void (*JPC_AlignedFreeFunction)(void *in_block);
+//--------------------------------------------------------------------------------------------------
+//
+// Opaque Types
+//
+//--------------------------------------------------------------------------------------------------
+typedef struct JPC_TempAllocator     JPC_TempAllocator;
+typedef struct JPC_JobSystem         JPC_JobSystem;
+typedef struct JPC_BodyInterface     JPC_BodyInterface;
+typedef struct JPC_BodyLockInterface JPC_BodyLockInterface;
+typedef struct JPC_NarrowPhaseQuery  JPC_NarrowPhaseQuery;
+
+typedef struct JPC_ShapeSettings               JPC_ShapeSettings;
+typedef struct JPC_ConvexShapeSettings         JPC_ConvexShapeSettings;
+typedef struct JPC_BoxShapeSettings            JPC_BoxShapeSettings;
+typedef struct JPC_SphereShapeSettings         JPC_SphereShapeSettings;
+typedef struct JPC_TriangleShapeSettings       JPC_TriangleShapeSettings;
+typedef struct JPC_CapsuleShapeSettings        JPC_CapsuleShapeSettings;
+typedef struct JPC_TaperedCapsuleShapeSettings JPC_TaperedCapsuleShapeSettings;
+typedef struct JPC_CylinderShapeSettings       JPC_CylinderShapeSettings;
+typedef struct JPC_ConvexHullShapeSettings     JPC_ConvexHullShapeSettings;
+typedef struct JPC_HeightFieldShapeSettings    JPC_HeightFieldShapeSettings;
+typedef struct JPC_MeshShapeSettings           JPC_MeshShapeSettings;
+typedef struct JPC_DecoratedShapeSettings      JPC_DecoratedShapeSettings;
+typedef struct JPC_CompoundShapeSettings       JPC_CompoundShapeSettings;
+typedef struct JPC_CharacterContactSettings    JPC_CharacterContactSettings;
+
+typedef struct JPC_ConstraintSettings        JPC_ConstraintSettings;
+typedef struct JPC_TwoBodyConstraintSettings JPC_TwoBodyConstraintSettings;
+typedef struct JPC_FixedConstraintSettings   JPC_FixedConstraintSettings;
+
+typedef struct JPC_PhysicsSystem JPC_PhysicsSystem;
+typedef struct JPC_SharedMutex   JPC_SharedMutex;
+
+typedef struct JPC_Shape            JPC_Shape;
+typedef struct JPC_Constraint       JPC_Constraint;
+typedef struct JPC_PhysicsMaterial  JPC_PhysicsMaterial;
+typedef struct JPC_GroupFilter      JPC_GroupFilter;
+typedef struct JPC_Character        JPC_Character;
+typedef struct JPC_CharacterVirtual JPC_CharacterVirtual;
+
+#if JPC_DEBUG_RENDERER == 1
+typedef struct JPC_BodyDrawFilter              JPC_BodyDrawFilter;
+typedef struct JPC_DebugRenderer_TriangleBatch JPC_DebugRenderer_TriangleBatch;
+typedef struct JPC_DebugRenderer_Primitive     JPC_DebugRenderer_Primitive;
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// Structures
+//
+//--------------------------------------------------------------------------------------------------
+// NOTE: Needs to be kept in sync with JPH::MassProperties
+typedef struct JPC_MassProperties
+{
+    float             mass;
+    alignas(16) float inertia[16];
+} JPC_MassProperties;
+
+// NOTE: Needs to be kept in sync with JPH::MotionProperties
+typedef struct JPC_MotionProperties
+{
+    alignas(16) float  linear_velocity[4]; // 4th element is ignored
+    alignas(16) float  angular_velocity[4]; // 4th element is ignored
+    alignas(16) float  inv_inertia_diagnonal[4]; // 4th element is ignored
+    alignas(16) float  inertia_rotation[4];
+
+    float              force[3];
+    float              torque[3];
+    float              inv_mass;
+    float              linear_damping;
+    float              angular_daming;
+    float              max_linear_velocity;
+    float              max_angular_velocity;
+    float              gravity_factor;
+    uint32_t           index_in_active_bodies;
+    uint32_t           island_index;
+
+    JPC_MotionQuality  motion_quality;
+    bool               allow_sleeping;
+
+#if JPC_DOUBLE_PRECISION == 1
+    alignas(8) uint8_t reserved[76];
+#else
+    alignas(4) uint8_t reserved[52];
+#endif
+
+#if JPC_ENABLE_ASSERTS == 1
+    JPC_MotionType     cached_motion_type;
+#endif
+} JPC_MotionProperties;
+
+// NOTE: Needs to be kept in sync with JPH::CollisionGroup
+typedef struct JPC_CollisionGroup
+{
+    const JPC_GroupFilter * filter;
+    JPC_CollisionGroupID    group_id;
+    JPC_CollisionSubGroupID sub_group_id;
+} JPC_CollisionGroup;
+
+// NOTE: Needs to be kept in sync with JPH::BodyCreationSettings
+typedef struct JPC_BodyCreationSettings
+{
+    JPC_RVEC_ALIGN JPC_Real    position[4]; // 4th element is ignored
+    alignas(16) float          rotation[4];
+    alignas(16) float          linear_velocity[4]; // 4th element is ignored
+    alignas(16) float          angular_velocity[4]; // 4th element is ignored
+    uint64_t                   user_data;
+    JPC_ObjectLayer            object_layer;
+    JPC_CollisionGroup         collision_group;
+    JPC_MotionType             motion_type;
+    bool                       allow_dynamic_or_kinematic;
+    bool                       is_sensor;
+    bool                       use_manifold_reduction;
+    JPC_MotionQuality          motion_quality;
+    bool                       allow_sleeping;
+    float                      friction;
+    float                      restitution;
+    float                      linear_damping;
+    float                      angular_damping;
+    float                      max_linear_velocity;
+    float                      max_angular_velocity;
+    float                      gravity_factor;
+    JPC_OverrideMassProperties override_mass_properties;
+    float                      inertia_multiplier;
+    JPC_MassProperties         mass_properties_override;
+    const void *               reserved;
+    const JPC_Shape *          shape;
+} JPC_BodyCreationSettings;
+
+// NOTE: Needs to be kept in sync with JPH::Body
+typedef struct JPC_Body
+{
+    JPC_RVEC_ALIGN JPC_Real position[4]; // 4th element is ignored
+    alignas(16) float       rotation[4];
+    alignas(16) float       bounds_min[4]; // 4th element is ignored
+    alignas(16) float       bounds_max[4]; // 4th element is ignored
+
+    const JPC_Shape *       shape;
+    JPC_MotionProperties *  motion_properties; // will be NULL for static bodies
+    uint64_t                user_data;
+    JPC_CollisionGroup      collision_group;
+
+    float                   friction;
+    float                   restitution;
+    JPC_BodyID              id;
+
+    JPC_ObjectLayer         object_layer;
+
+    JPC_BroadPhaseLayer     broad_phase_layer;
+    JPC_MotionType          motion_type;
+    uint8_t                 flags;
+} JPC_Body;
+
+// NOTE: Needs to be kept in sync
+typedef struct JPC_CharacterBaseSettings
+{
+#   if defined(_MSC_VER)
+        const void* __vtable_header[1];
+#   else
+        const void* __vtable_header[2];
+#   endif
+    alignas(16) float   up[4]; // 4th element is ignored
+    alignas(16) float   supporting_volume[4];
+    float               max_slope_angle;
+    const JPC_Shape *   shape;
+} JPC_CharacterBaseSettings;
+
+// NOTE: Needs to be kept in sync
+typedef struct JPC_CharacterSettings
+{
+    JPC_CharacterBaseSettings base;
+    JPC_ObjectLayer layer;
+    float mass;
+    float friction;
+    float gravity_factor;
+} JPC_CharacterSettings;
+
+// NOTE: Needs to be kept in sync
+typedef struct JPC_CharacterVirtualSettings
+{
+    JPC_CharacterBaseSettings base;
+    float               mass;
+    float               max_strength;
+    alignas(16) float   shape_offset[4];
+    JPC_BackFaceMode    back_face_mode;
+    float               predictive_contact_distance;
+    uint32_t            max_collision_iterations;
+    uint32_t            max_constraint_iterations;
+    float               min_time_remaining;
+    float               collision_tolerance;
+    float               character_padding;
+    uint32_t            max_num_hits;
+    float               hit_reduction_cos_max_angle;
+    float               penetration_recovery_speed;
+} JPC_CharacterVirtualSettings;
+
+// NOTE: Needs to be kept in sync with JPH::SubShapeIDCreator
+typedef struct JPC_SubShapeIDCreator
+{
+    JPC_SubShapeID id;
+    uint32_t       current_bit;
+} JPC_SubShapeIDCreator;
+
+// NOTE: Needs to be kept in sync with JPH::SubShapeIDPair
+typedef struct JPC_SubShapeIDPair
+{
+    struct {
+        JPC_BodyID     body_id;
+        JPC_SubShapeID sub_shape_id;
+    }                  first;
+    struct {
+        JPC_BodyID     body_id;
+        JPC_SubShapeID sub_shape_id;
+    }                  second;
+} JPC_SubShapeIDPair;
+
+// NOTE: Needs to be kept in sync with JPH::ContactManifold
+typedef struct JPC_ContactManifold
+{
+    JPC_RVEC_ALIGN JPC_Real  base_offset[4]; // 4th element is ignored
+    alignas(16) float        normal[4]; // 4th element is ignored; world space
+    float                    penetration_depth;
+    JPC_SubShapeID           shape1_sub_shape_id;
+    JPC_SubShapeID           shape2_sub_shape_id;
+    struct {
+        alignas(16) uint32_t num_points;
+        alignas(16) float    points[64][4]; // 4th element is ignored; world space
+    }                        shape1_relative_contact;
+    struct {
+        alignas(16) uint32_t num_points;
+        alignas(16) float    points[64][4]; // 4th element is ignored; world space
+    }                        shape2_relative_contact;
+} JPC_ContactManifold;
+
+// NOTE: Needs to be kept in sync with JPH::ContactSettings
+typedef struct JPC_ContactSettings
+{
+    float combined_friction;
+    float combined_restitution;
+    bool  is_sensor;
+} JPC_ContactSettings;
+
+// NOTE: Needs to be kept in sync with JPH::CollideShapeResult
+typedef struct JPC_CollideShapeResult
+{
+    alignas(16) float        shape1_contact_point[4]; // 4th element is ignored; world space
+    alignas(16) float        shape2_contact_point[4]; // 4th element is ignored; world space
+    alignas(16) float        penetration_axis[4]; // 4th element is ignored; world space
+    float                    penetration_depth;
+    JPC_SubShapeID           shape1_sub_shape_id;
+    JPC_SubShapeID           shape2_sub_shape_id;
+    JPC_BodyID               body2_id;
+    struct {
+        alignas(16) uint32_t num_points;
+        alignas(16) float    points[32][4]; // 4th element is ignored; world space
+    }                        shape1_face;
+    struct {
+        alignas(16) uint32_t num_points;
+        alignas(16) float    points[32][4]; // 4th element is ignored; world space
+    }                        shape2_face;
+} JPC_CollideShapeResult;
+
+// NOTE: Needs to be kept in sync with JPH::TransformedShape
+typedef struct JPC_TransformedShape
+{
+    JPC_RVEC_ALIGN JPC_Real shape_position_com[4]; // 4th element is ignored
+    alignas(16) float       shape_rotation[4];
+    const JPC_Shape *       shape;
+    float                   shape_scale[3];
+    JPC_BodyID              body_id;
+    JPC_SubShapeIDCreator   sub_shape_id_creator;
+} JPC_TransformedShape;
+
+// NOTE: Needs to be kept in sync with JPH::BodyLockRead
+typedef struct JPC_BodyLockRead
+{
+    const JPC_BodyLockInterface *lock_interface;
+    JPC_SharedMutex *            mutex;
+    const JPC_Body *             body;
+} JPC_BodyLockRead;
+
+// NOTE: Needs to be kept in sync with JPH::BodyLockWrite
+typedef struct JPC_BodyLockWrite
+{
+    const JPC_BodyLockInterface *lock_interface;
+    JPC_SharedMutex *            mutex;
+    JPC_Body *                   body;
+} JPC_BodyLockWrite;
+
+// NOTE: Needs to be kept in sync with JPH::RRayCast
+typedef struct JPC_RRayCast
+{
+    JPC_RVEC_ALIGN JPC_Real origin[4]; // 4th element is ignored
+    alignas(16) float       direction[4]; // length of the vector is important; 4th element is ignored
+} JPC_RRayCast;
+
+// NOTE: Needs to be kept in sync with JPH::RayCastResult
+typedef struct JPC_RayCastResult
+{
+    JPC_BodyID     body_id; // JPC_BODY_ID_INVALID
+    float          fraction; // 1.0 + JPC_FLT_EPSILON
+    JPC_SubShapeID sub_shape_id;
+} JPC_RayCastResult;
+
+// NOTE: Needs to be kept in sync with JPH::RayCastSettings
+typedef struct JPC_RayCastSettings
+{
+    JPC_BackFaceMode back_face_mode;
+    bool             treat_convex_as_solid;
+} JPC_RayCastSettings;
+
+#if JPC_DEBUG_RENDERER == 1
+// NOTE: Needs to be kept in sync with JPH::AABox
+typedef struct JPC_AABox
+{
+    float min[3];
+    float max[3];
+} JPC_AABox;
+
+// NOTE: Needs to be kept in sync with JPH::Color
+typedef union JPC_Color
+{
+    uint32_t u32;
+    struct
+    {
+        uint8_t r;
+        uint8_t g;
+        uint8_t b;
+        uint8_t a;
+    };
+} JPC_Color;
+
+// NOTE: Needs to be kept in sync with JPH::DebugRenderer::Vertex
+typedef struct JPC_DebugRenderer_Vertex
+{
+    float position[3];
+    float normal[3];
+    float uv[2];
+    JPC_Color color;
+} JPC_DebugRenderer_Vertex;
+
+// NOTE: Needs to be kept in sync with JPH::DebugRenderer::Triangle
+typedef struct JPC_DebugRenderer_Triangle
+{
+    JPC_DebugRenderer_Vertex v[3];
+} JPC_DebugRenderer_Triangle;
+
+// NOTE: Needs to be kept in sync with JPH::DebugRenderer::LOD
+typedef struct JPC_DebugRenderer_LOD
+{
+    JPC_DebugRenderer_TriangleBatch *batch;
+    float distance;
+} JPC_DebugRenderer_LOD;
+
+// NOTE: NOT kept in sync - some translation required due to JPH::DebugRenderer::Geometry using std::vector.
+typedef struct JPC_DebugRenderer_Geometry
+{
+    JPC_DebugRenderer_LOD *LODs;
+    uint64_t num_LODs;
+    JPC_AABox *bounds;
+} JPC_DebugRenderer_Geometry;
+
+// NOTE: Needs to be kept in sync with JPH::BodyManager::DrawSettings
+// For each boolean field, if it's true, that thing will be drawn.
+typedef struct JPC_BodyManager_DrawSettings
+{
+    bool get_support_func;         // = false | Draw the GetSupport() function, used for convex collision detection
+    bool get_support_dir;          // = false | If above true, also draw direction mapped to a specific support point
+    bool get_supporting_face;      // = false | Draw the faces that were found colliding during collision detection
+    bool shape;                    // = true  | Draw the shapes of all bodies
+    bool shape_wireframe;          // = false | If 'shape' true, the shapes will be drawn in wireframe instead of solid.
+    JPC_ShapeColor shape_color;    // = JPC_MOTION_TYPE_COLOR | Coloring scheme to use for shapes
+    bool bounding_box;             // = false | Draw a bounding box per body
+    bool center_of_mass_transform; // = false | Draw the center of mass for each body
+    bool world_transform;          // = false | Draw the world transform (which can be different than CoM) for each body
+    bool velocity;                 // = false | Draw the velocity vector for each body
+    bool mass_and_inertia;         // = false | Draw the mass and inertia (as the box equivalent) for each body
+    bool sleep_stats;              // = false | Draw stats regarding the sleeping algorithm of each body
+} JPC_BodyManager_DrawSettings;
+
+typedef bool (*JPC_BodyDrawFilterFunc)(const JPC_Body *);
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// Interfaces (virtual tables)
+//
+//--------------------------------------------------------------------------------------------------
+#if defined(_MSC_VER)
+#define _JPC_VTABLE_HEADER const void* __vtable_header[1]
+#else
+#define _JPC_VTABLE_HEADER const void* __vtable_header[2]
+#endif
+
+typedef struct JPC_BroadPhaseLayerInterfaceVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    uint32_t
+    (*GetNumBroadPhaseLayers)(const void *in_self);
+
+#ifdef _MSC_VER
+    // Required, *cannot* be NULL.
+    const JPC_BroadPhaseLayer *
+    (*GetBroadPhaseLayer)(const void *in_self, JPC_BroadPhaseLayer *out_layer, JPC_ObjectLayer in_layer);
+#else
+    // Required, *cannot* be NULL.
+    JPC_BroadPhaseLayer
+    (*GetBroadPhaseLayer)(const void *in_self, JPC_ObjectLayer in_layer);
+#endif
+} JPC_BroadPhaseLayerInterfaceVTable;
+
+typedef struct JPC_ObjectVsBroadPhaseLayerFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, JPC_ObjectLayer in_layer1, JPC_BroadPhaseLayer in_layer2);
+} JPC_ObjectVsBroadPhaseLayerFilterVTable;
+
+typedef struct JPC_BroadPhaseLayerFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, JPC_BroadPhaseLayer in_layer);
+} JPC_BroadPhaseLayerFilterVTable;
+
+typedef struct JPC_ObjectLayerPairFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, JPC_ObjectLayer in_layer1, JPC_ObjectLayer in_layer2);
+} JPC_ObjectLayerPairFilterVTable;
+
+typedef struct JPC_ObjectLayerFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, JPC_ObjectLayer in_layer);
+} JPC_ObjectLayerFilterVTable;
+
+typedef struct JPC_BodyActivationListenerVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnBodyActivated)(void *in_self, const JPC_BodyID *in_body_id, uint64_t in_user_data);
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnBodyDeactivated)(void *in_self, const JPC_BodyID *in_body_id, uint64_t in_user_data);
+} JPC_BodyActivationListenerVTable;
+
+typedef struct JPC_BodyFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, const JPC_BodyID *in_body_id);
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollideLocked)(const void *in_self, const JPC_Body *in_body);
+} JPC_BodyFilterVTable;
+
+typedef struct JPC_ShapeFilterVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    bool
+    (*ShouldCollide)(const void *in_self, const JPC_Shape *in_shape, const JPC_SubShapeID *in_sub_shape_id);
+
+    // Required, *cannot* be NULL.
+    bool
+    (*PairShouldCollide)(const void *in_self,
+                         const JPC_Shape *in_shape1,
+                         const JPC_SubShapeID *in_sub_shape_id1,
+                         const JPC_Shape *in_shape2,
+                         const JPC_SubShapeID *in_sub_shape_id2);
+
+    // Set by the collision detection functions to the body ID of the "receiving" body before ShouldCollide is called.
+    uint32_t bodyId2;
+} JPC_ShapeFilterVTable;
+
+typedef struct JPC_PhysicsStepListenerVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnStep)(float in_delta_time, JPC_PhysicsSystem *in_physics_system);
+} JPC_PhysicsStepListener;
+
+// Made all callbacks required for this one for simplicity's sake, but can be modified to imitate ContactListener later.
+typedef struct JPC_CharacterContactListenerVTable
+{
+    _JPC_VTABLE_HEADER;
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnAdjustBodyVelocity)(void *in_self,
+                            const JPC_CharacterVirtual *in_character,
+                            const JPC_Body *in_body2,
+                            const float io_linear_velocity[3],
+                            const float io_angular_velocity[3]);
+
+    // Required, *cannot* be NULL.
+    bool
+    (*OnContactValidate)(void *in_self,
+                         const JPC_CharacterVirtual *in_character,
+                         const JPC_Body *in_body2,
+                         const JPC_SubShapeID *sub_shape_id);
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnContactAdded)(void *in_self,
+                      const JPC_CharacterVirtual *in_character,
+                      const JPC_Body *in_body2,
+                      const JPC_SubShapeID *sub_shape_id,
+                      const JPC_Real contact_position[3],
+                      const float contact_normal[3],
+                      JPC_CharacterContactSettings *io_settings);
+
+    // Required, *cannot* be NULL.
+    void
+    (*OnContactSolve)(void *in_self,
+                      const JPC_CharacterVirtual *in_character,
+                      const JPC_Body *in_body2,
+                      const JPC_SubShapeID *sub_shape_id,
+                      const JPC_Real contact_position[3],
+                      const float contact_normal[3],
+                      const float contact_velocity[3],
+                      const JPC_PhysicsMaterial *contact_material,
+                      const float character_velocity_in[3],
+                      float character_velocity_out[3]);
+} JPC_CharacterContactListenerVTable;
+
+typedef struct JPC_ContactListenerVTable
+{
+    // Optional, can be NULL.
+    JPC_ValidateResult
+    (*OnContactValidate)(void *in_self,
+                         const JPC_Body *in_body1,
+                         const JPC_Body *in_body2,
+                         const JPC_Real in_base_offset[3],
+                         const JPC_CollideShapeResult *in_collision_result);
+
+    // Optional, can be NULL.
+    void
+    (*OnContactAdded)(void *in_self,
+                      const JPC_Body *in_body1,
+                      const JPC_Body *in_body2,
+                      const JPC_ContactManifold *in_manifold,
+                      JPC_ContactSettings *io_settings);
+
+    // Optional, can be NULL.
+    void
+    (*OnContactPersisted)(void *in_self,
+                          const JPC_Body *in_body1,
+                          const JPC_Body *in_body2,
+                          const JPC_ContactManifold *in_manifold,
+                          JPC_ContactSettings *io_settings);
+
+    // Optional, can be NULL.
+    void
+    (*OnContactRemoved)(void *in_self, const JPC_SubShapeIDPair *in_sub_shape_pair);
+} JPC_ContactListenerVTable;
+
+#if JPC_DEBUG_RENDERER == 1
+/// Although used similarly to the VTables above, this struct is not pointer-compatible with JPH::DebugRenderer
+/// Instead, it's wrapped by the DebugRendererImpl inheritor class (as seen in JoltPhysicsC.cpp), because
+/// of the design of JPH::DebugRenderer not playing as nicely with C as the other structures in Jolt.
+/// Since debug rendering should never be used in production code, a wrapper seems ok in this case.
+typedef struct JPC_DebugRendererVTable
+{
+    // Required, *cannot* be NULL.
+    void
+    (*DrawLine)(void *in_self, JPC_Real in_from[3], JPC_Real in_to[3], JPC_Color in_color);
+
+    // Required, *cannot* be NULL.
+    void
+    (*DrawTriangle)(void *in_self, JPC_Real in_v1[3], JPC_Real in_v2[3], JPC_Real in_v3[3], JPC_Color in_color);
+
+    // Required, *cannot* be NULL.
+    JPC_DebugRenderer_TriangleBatch *
+    (*CreateTriangleBatch)(void *in_self, const JPC_DebugRenderer_Triangle *in_triangles, uint32_t in_triangle_count);
+
+    // Required, *cannot* be NULL.
+    JPC_DebugRenderer_TriangleBatch *
+    (*CreateTriangleBatchIndexed)(void *in_self,
+                                  const JPC_DebugRenderer_Vertex *in_vertices,
+                                  uint32_t in_vertex_count,
+                                  const uint32_t *in_indices,
+                                  uint32_t in_index_count);
+
+    // Required, *cannot* be NULL.
+    void
+    (*DrawGeometry)(void *in_self,
+                    const float inModelMatrix[16],
+                    const JPC_AABox *inWorldSpaceBounds,
+                    float inLODScaleSq,
+                    JPC_Color in_color,
+                    const JPC_DebugRenderer_Geometry *in_geometry,
+                    JPC_CullMode in_cull_mode,
+                    JPC_CastShadow in_cast_shadow,
+                    JPC_DrawMode in_draw_mode);
+
+    // Required, *cannot* be NULL.
+    void
+    (*DrawText3D)(void *in_self, JPC_Real in_position[3], const char *in_string, JPC_Color in_color, float in_height);
+} JPC_DebugRendererVTable;
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// Misc functions
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_RegisterDefaultAllocator(void);
+
+JPC_API void
+JPC_RegisterCustomAllocator(JPC_AllocateFunction in_alloc,
+                            JPC_FreeFunction in_free,
+                            JPC_AlignedAllocateFunction in_aligned_alloc,
+                            JPC_AlignedFreeFunction in_aligned_free);
+JPC_API void
+JPC_CreateFactory(void);
+
+JPC_API void
+JPC_DestroyFactory(void);
+
+JPC_API void
+JPC_RegisterTypes(void);
+
+JPC_API void
+JPC_BodyCreationSettings_SetDefault(JPC_BodyCreationSettings *out_settings);
+
+JPC_API void
+JPC_BodyCreationSettings_Set(JPC_BodyCreationSettings *out_settings,
+                             const JPC_Shape *in_shape,
+                             const JPC_Real in_position[3],
+                             const float in_rotation[4],
+                             JPC_MotionType in_motion_type,
+                             JPC_ObjectLayer in_layer);
+
+#if JPC_DEBUG_RENDERER == 1
+/// Provide an instantiated VTable to get wrapped by the singleton implementation of JPH::DebugRenderer. This should be
+/// called only once, at program initialization, as when instantiating a DebugRenderer implementation in Jolt proper.
+/// You may pass a pointer to any struct, as long as its first member is a pointer to your JPC_DebugRendererVTable.
+JPC_API enum JPC_DebugRendererResult
+JPC_CreateDebugRendererSingleton(void *in_debug_renderer);
+/// Iff there is a debug renderer currently instantiated, destroy it. This may allow another call to CreateDebugRenderer
+/// to be made without breaking things, but this isn't sufficiently tested to be a guarantee. This is used, for example,
+/// in the unit tests when more than one test needs to instantiate a debug renderer. Shouldn't be necessary for a game.
+JPC_API enum JPC_DebugRendererResult
+JPC_DestroyDebugRendererSingleton();
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_DebugRenderer_TriangleBatch
+//
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+/// Within the user's DebugRendererVTable callbacks to create triangle batches, the user creates whatever
+/// structure their rendering engine requires to represent the triangle batch Jolt requests. The user passes a
+/// pointer to that structure into this function to be stored as one of Jolt's reference-counted objects internally.
+///
+/// \return An opaque JPC_DebugRenderer_TriangleBatch* for the user to keep as a handle to their primitive
+JPC_API JPC_DebugRenderer_TriangleBatch *
+JPC_DebugRenderer_TriangleBatch_Create(const void *in_c_primitive);
+
+/// When Jolt calls the user's DrawGeometry, it passes the user a JPC_DebugRenderer_Geometry *. This structure
+/// contains, among other things, at least one JPC_DebugRenderer_TriangleBatch * (inside LOD levels). The user
+/// may retrieve the pointer to the corresponding primitive they made by passing the batch pointer to this function.
+///
+/// \return An opaque JPC_DebugRenderer_Primitive * wherein the user is keeping rendering data for that batch
+JPC_API const JPC_DebugRenderer_Primitive *
+JPC_DebugRenderer_TriangleBatch_GetPrimitive(const JPC_DebugRenderer_TriangleBatch *in_batch);
+
+JPC_API void
+JPC_DebugRenderer_TriangleBatch_AddRef(JPC_DebugRenderer_TriangleBatch *in_batch);
+
+JPC_API void
+JPC_DebugRenderer_TriangleBatch_Release(JPC_DebugRenderer_TriangleBatch *in_batch);
+
+JPC_API uint32_t
+JPC_DebugRenderer_TriangleBatch_GetRefCount(const JPC_DebugRenderer_TriangleBatch *in_batch);
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_MotionProperties
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MotionQuality
+JPC_MotionProperties_GetMotionQuality(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_GetLinearVelocity(const JPC_MotionProperties *in_properties,
+                                       float out_linear_velocity[3]);
+JPC_API void
+JPC_MotionProperties_SetLinearVelocity(JPC_MotionProperties *in_properties,
+                                       const float in_linear_velocity[3]);
+JPC_API void
+JPC_MotionProperties_SetLinearVelocityClamped(JPC_MotionProperties *in_properties,
+                                              const float in_linear_velocity[3]);
+JPC_API void
+JPC_MotionProperties_GetAngularVelocity(const JPC_MotionProperties *in_properties,
+                                        float out_angular_velocity[3]);
+JPC_API void
+JPC_MotionProperties_SetAngularVelocity(JPC_MotionProperties *in_properties,
+                                        const float in_angular_velocity[3]);
+JPC_API void
+JPC_MotionProperties_SetAngularVelocityClamped(JPC_MotionProperties *in_properties,
+                                               const float in_angular_velocity[3]);
+JPC_API void
+JPC_MotionProperties_MoveKinematic(JPC_MotionProperties *in_properties,
+                                   const float in_delta_position[3],
+                                   const float in_delta_rotation[4],
+                                   float in_delta_time);
+JPC_API void
+JPC_MotionProperties_ClampLinearVelocity(JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_ClampAngularVelocity(JPC_MotionProperties *in_properties);
+
+JPC_API float
+JPC_MotionProperties_GetLinearDamping(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetLinearDamping(JPC_MotionProperties *in_properties,
+                                      float in_linear_damping);
+JPC_API float
+JPC_MotionProperties_GetAngularDamping(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetAngularDamping(JPC_MotionProperties *in_properties,
+                                       float in_angular_damping);
+JPC_API float
+JPC_MotionProperties_GetGravityFactor(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetGravityFactor(JPC_MotionProperties *in_properties,
+                                      float in_gravity_factor);
+JPC_API void
+JPC_MotionProperties_SetMassProperties(JPC_MotionProperties *in_properties,
+                                       const JPC_MassProperties *in_mass_properties);
+JPC_API float
+JPC_MotionProperties_GetInverseMass(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetInverseMass(JPC_MotionProperties *in_properties, float in_inv_mass);
+
+JPC_API void
+JPC_MotionProperties_GetInverseInertiaDiagonal(const JPC_MotionProperties *in_properties,
+                                               float out_inverse_inertia_diagonal[3]);
+JPC_API void
+JPC_MotionProperties_GetInertiaRotation(const JPC_MotionProperties *in_properties,
+                                        float out_inertia_rotation[4]);
+JPC_API void
+JPC_MotionProperties_SetInverseInertia(JPC_MotionProperties *in_properties,
+                                       const float in_diagonal[3],
+                                       const float in_rotation[4]);
+JPC_API void
+JPC_MotionProperties_GetLocalSpaceInverseInertia(const JPC_MotionProperties *in_properties,
+                                                 float out_matrix[16]);
+JPC_API void
+JPC_MotionProperties_GetInverseInertiaForRotation(const JPC_MotionProperties *in_properties,
+                                                  const float in_rotation_matrix[16],
+                                                  float out_matrix[16]);
+JPC_API void
+JPC_MotionProperties_MultiplyWorldSpaceInverseInertiaByVector(const JPC_MotionProperties *in_properties,
+                                                              const float in_body_rotation[4],
+                                                              const float in_vector[3],
+                                                              float out_vector[3]);
+JPC_API void
+JPC_MotionProperties_GetPointVelocityCOM(const JPC_MotionProperties *in_properties,
+                                         const float in_point_relative_to_com[3],
+                                         float out_point[3]);
+JPC_API float
+JPC_MotionProperties_GetMaxLinearVelocity(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetMaxLinearVelocity(JPC_MotionProperties *in_properties,
+                                          float in_max_linear_velocity);
+JPC_API float
+JPC_MotionProperties_GetMaxAngularVelocity(const JPC_MotionProperties *in_properties);
+
+JPC_API void
+JPC_MotionProperties_SetMaxAngularVelocity(JPC_MotionProperties *in_properties,
+                                           float in_max_angular_velocity);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TempAllocator
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TempAllocator *
+JPC_TempAllocator_Create(uint32_t in_size);
+
+JPC_API void
+JPC_TempAllocator_Destroy(JPC_TempAllocator *in_allocator);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_JobSystem
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_JobSystem *
+JPC_JobSystem_Create(uint32_t in_max_jobs, uint32_t in_max_barriers, int in_num_threads);
+
+JPC_API void
+JPC_JobSystem_Destroy(JPC_JobSystem *in_job_system);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_PhysicsSystem
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_PhysicsSystem *
+JPC_PhysicsSystem_Create(uint32_t in_max_bodies,
+                         uint32_t in_num_body_mutexes,
+                         uint32_t in_max_body_pairs,
+                         uint32_t in_max_contact_constraints,
+                         const void *in_broad_phase_layer_interface,
+                         const void *in_object_vs_broad_phase_layer_filter,
+                         const void *in_object_layer_pair_filter);
+JPC_API void
+JPC_PhysicsSystem_Destroy(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_SetBodyActivationListener(JPC_PhysicsSystem *in_physics_system, void *in_listener);
+
+JPC_API void *
+JPC_PhysicsSystem_GetBodyActivationListener(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_SetContactListener(JPC_PhysicsSystem *in_physics_system, void *in_listener);
+
+JPC_API void *
+JPC_PhysicsSystem_GetContactListener(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API uint32_t
+JPC_PhysicsSystem_GetNumBodies(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API uint32_t
+JPC_PhysicsSystem_GetNumActiveBodies(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API uint32_t
+JPC_PhysicsSystem_GetMaxBodies(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_GetGravity(const JPC_PhysicsSystem *in_physics_system, float out_gravity[3]);
+
+JPC_API void
+JPC_PhysicsSystem_SetGravity(JPC_PhysicsSystem *in_physics_system, const float in_gravity[3]);
+
+JPC_API JPC_BodyInterface *
+JPC_PhysicsSystem_GetBodyInterface(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API JPC_BodyInterface *
+JPC_PhysicsSystem_GetBodyInterfaceNoLock(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_OptimizeBroadPhase(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_AddStepListener(JPC_PhysicsSystem *in_physics_system, void *in_listener);
+
+JPC_API void
+JPC_PhysicsSystem_RemoveStepListener(JPC_PhysicsSystem *in_physics_system, void *in_listener);
+
+JPC_API void
+JPC_PhysicsSystem_AddConstraint(JPC_PhysicsSystem *in_physics_system, void *in_two_body_constraint);
+
+JPC_API void
+JPC_PhysicsSystem_RemoveConstraint(JPC_PhysicsSystem *in_physics_system, void *in_two_body_constraint);
+
+JPC_API JPC_PhysicsUpdateError
+JPC_PhysicsSystem_Update(JPC_PhysicsSystem *in_physics_system,
+                         float in_delta_time,
+                         int in_collision_steps,
+                         int in_integration_sub_steps,
+                         JPC_TempAllocator *in_temp_allocator,
+                         JPC_JobSystem *in_job_system);
+
+JPC_API const JPC_BodyLockInterface *
+JPC_PhysicsSystem_GetBodyLockInterface(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API const JPC_BodyLockInterface *
+JPC_PhysicsSystem_GetBodyLockInterfaceNoLock(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API const JPC_NarrowPhaseQuery *
+JPC_PhysicsSystem_GetNarrowPhaseQuery(const JPC_PhysicsSystem *in_physics_system);
+
+JPC_API const JPC_NarrowPhaseQuery *
+JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(const JPC_PhysicsSystem *in_physics_system);
+
+/// Get copy of the list of all bodies under protection of a lock.
+JPC_API void
+JPC_PhysicsSystem_GetBodyIDs(const JPC_PhysicsSystem *in_physics_system,
+                             uint32_t in_max_body_ids,
+                             uint32_t *out_num_body_ids,
+                             JPC_BodyID *out_body_ids);
+
+/// Get copy of the list of active bodies under protection of a lock.
+JPC_API void
+JPC_PhysicsSystem_GetActiveBodyIDs(const JPC_PhysicsSystem *in_physics_system,
+                                   uint32_t in_max_body_ids,
+                                   uint32_t *out_num_body_ids,
+                                   JPC_BodyID *out_body_ids);
+///
+/// Low-level access for advanced usage and zero CPU overhead (access *not* protected by a lock)
+///
+/// Check if this is a valid body pointer.
+/// When a body is freed the memory that the pointer occupies is reused to store a freelist.
+#define _JPC_IS_FREED_BODY_BIT 0x1
+
+#define JPC_IS_VALID_BODY_POINTER(body_ptr) (((uintptr_t)(body_ptr) & _JPC_IS_FREED_BODY_BIT) == 0)
+
+/// Access a body, will return NULL if the body ID is no longer valid.
+/// Use `JPC_PhysicsSystem_GetBodiesUnsafe()` to get an array of all body pointers.
+#define JPC_TRY_GET_BODY(all_body_ptrs, body_id) \
+    JPC_IS_VALID_BODY_POINTER(all_body_ptrs[body_id & JPC_BODY_ID_INDEX_BITS]) && \
+    all_body_ptrs[body_id & JPC_BODY_ID_INDEX_BITS]->id == body_id ? \
+    all_body_ptrs[body_id & JPC_BODY_ID_INDEX_BITS] : NULL
+
+/// Get direct access to all bodies. Not protected by a lock. Use with great care!
+JPC_API JPC_Body **
+JPC_PhysicsSystem_GetBodiesUnsafe(JPC_PhysicsSystem *in_physics_system);
+
+#if JPC_DEBUG_RENDERER == 1
+JPC_API void
+JPC_PhysicsSystem_DrawBodies(JPC_PhysicsSystem *in_physics_system,
+                             const JPC_BodyManager_DrawSettings *in_draw_settings,
+                             const JPC_BodyDrawFilter *in_draw_filter); // Can be NULL (no filter)
+
+JPC_API void
+JPC_PhysicsSystem_DrawConstraints(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_DrawConstraintLimits(JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_PhysicsSystem_DrawConstraintReferenceFrame(JPC_PhysicsSystem *in_physics_system);
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyLockInterface
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_BodyLockInterface_LockRead(const JPC_BodyLockInterface *in_lock_interface,
+                               JPC_BodyID in_body_id,
+                               JPC_BodyLockRead *out_lock);
+JPC_API void
+JPC_BodyLockInterface_UnlockRead(const JPC_BodyLockInterface *in_lock_interface,
+                                 JPC_BodyLockRead *io_lock);
+JPC_API void
+JPC_BodyLockInterface_LockWrite(const JPC_BodyLockInterface *in_lock_interface,
+                                JPC_BodyID in_body_id,
+                                JPC_BodyLockWrite *out_lock);
+JPC_API void
+JPC_BodyLockInterface_UnlockWrite(const JPC_BodyLockInterface *in_lock_interface,
+                                  JPC_BodyLockWrite *io_lock);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_NarrowPhaseQuery
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API bool
+JPC_NarrowPhaseQuery_CastRay(const JPC_NarrowPhaseQuery *in_query,
+                             const JPC_RRayCast *in_ray,
+                             JPC_RayCastResult *io_hit, // *Must* be default initialized (see JPC_RayCastResult)
+                             const void *in_broad_phase_layer_filter, // Can be NULL (no filter)
+                             const void *in_object_layer_filter, // Can be NULL (no filter)
+                             const void *in_body_filter); // Can be NULL (no filter)
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ShapeSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ShapeSettings_AddRef(JPC_ShapeSettings *in_settings);
+
+JPC_API void
+JPC_ShapeSettings_Release(JPC_ShapeSettings *in_settings);
+
+JPC_API uint32_t
+JPC_ShapeSettings_GetRefCount(const JPC_ShapeSettings *in_settings);
+
+/// First call creates the shape, subsequent calls return the same pointer and increments reference count.
+/// Call `JPC_Shape_Release()` when you don't need returned pointer anymore.
+JPC_API JPC_Shape *
+JPC_ShapeSettings_CreateShape(const JPC_ShapeSettings *in_settings);
+
+JPC_API uint64_t
+JPC_ShapeSettings_GetUserData(const JPC_ShapeSettings *in_settings);
+
+JPC_API void
+JPC_ShapeSettings_SetUserData(JPC_ShapeSettings *in_settings, uint64_t in_user_data);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConvexShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API const JPC_PhysicsMaterial *
+JPC_ConvexShapeSettings_GetMaterial(const JPC_ConvexShapeSettings *in_settings);
+
+JPC_API void
+JPC_ConvexShapeSettings_SetMaterial(JPC_ConvexShapeSettings *in_settings,
+                                    const JPC_PhysicsMaterial *in_material);
+
+JPC_API float
+JPC_ConvexShapeSettings_GetDensity(const JPC_ConvexShapeSettings *in_settings);
+
+JPC_API void
+JPC_ConvexShapeSettings_SetDensity(JPC_ConvexShapeSettings *in_settings, float in_density);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BoxShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BoxShapeSettings *
+JPC_BoxShapeSettings_Create(const float in_half_extent[3]);
+
+JPC_API void
+JPC_BoxShapeSettings_GetHalfExtent(const JPC_BoxShapeSettings *in_settings, float out_half_extent[3]);
+
+JPC_API void
+JPC_BoxShapeSettings_SetHalfExtent(JPC_BoxShapeSettings *in_settings, const float in_half_extent[3]);
+
+JPC_API float
+JPC_BoxShapeSettings_GetConvexRadius(const JPC_BoxShapeSettings *in_settings);
+
+JPC_API void
+JPC_BoxShapeSettings_SetConvexRadius(JPC_BoxShapeSettings *in_settings, float in_convex_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_SphereShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_SphereShapeSettings *
+JPC_SphereShapeSettings_Create(float in_radius);
+
+JPC_API float
+JPC_SphereShapeSettings_GetRadius(const JPC_SphereShapeSettings *in_settings);
+
+JPC_API void
+JPC_SphereShapeSettings_SetRadius(JPC_SphereShapeSettings *in_settings, float in_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TriangleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TriangleShapeSettings *
+JPC_TriangleShapeSettings_Create(const float in_v1[3], const float in_v2[3], const float in_v3[3]);
+
+JPC_API void
+JPC_TriangleShapeSettings_SetVertices(JPC_TriangleShapeSettings *in_settings,
+                                      const float in_v1[3],
+                                      const float in_v2[3],
+                                      const float in_v3[3]);
+JPC_API void
+JPC_TriangleShapeSettings_GetVertices(const JPC_TriangleShapeSettings *in_settings,
+                                      float out_v1[3],
+                                      float out_v2[3],
+                                      float out_v3[3]);
+JPC_API float
+JPC_TriangleShapeSettings_GetConvexRadius(const JPC_TriangleShapeSettings *in_settings);
+
+JPC_API void
+JPC_TriangleShapeSettings_SetConvexRadius(JPC_TriangleShapeSettings *in_settings,
+                                          float in_convex_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CapsuleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CapsuleShapeSettings *
+JPC_CapsuleShapeSettings_Create(float in_half_height_of_cylinder, float in_radius);
+
+JPC_API float
+JPC_CapsuleShapeSettings_GetHalfHeight(const JPC_CapsuleShapeSettings *in_settings);
+
+JPC_API void
+JPC_CapsuleShapeSettings_SetHalfHeight(JPC_CapsuleShapeSettings *in_settings,
+                                       float in_half_height_of_cylinder);
+JPC_API float
+JPC_CapsuleShapeSettings_GetRadius(const JPC_CapsuleShapeSettings *in_settings);
+
+JPC_API void
+JPC_CapsuleShapeSettings_SetRadius(JPC_CapsuleShapeSettings *in_settings, float in_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TaperedCapsuleShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_TaperedCapsuleShapeSettings *
+JPC_TaperedCapsuleShapeSettings_Create(float in_half_height, float in_top_radius, float in_bottom_radius);
+
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetHalfHeight(const JPC_TaperedCapsuleShapeSettings *in_settings);
+
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetHalfHeight(JPC_TaperedCapsuleShapeSettings *in_settings,
+                                              float in_half_height);
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetTopRadius(const JPC_TaperedCapsuleShapeSettings *in_settings);
+
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetTopRadius(JPC_TaperedCapsuleShapeSettings *in_settings, float in_top_radius);
+
+JPC_API float
+JPC_TaperedCapsuleShapeSettings_GetBottomRadius(const JPC_TaperedCapsuleShapeSettings *in_settings);
+
+JPC_API void
+JPC_TaperedCapsuleShapeSettings_SetBottomRadius(JPC_TaperedCapsuleShapeSettings *in_settings,
+                                                float in_bottom_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CylinderShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CylinderShapeSettings *
+JPC_CylinderShapeSettings_Create(float in_half_height, float in_radius);
+
+JPC_API float
+JPC_CylinderShapeSettings_GetConvexRadius(const JPC_CylinderShapeSettings *in_settings);
+
+JPC_API void
+JPC_CylinderShapeSettings_SetConvexRadius(JPC_CylinderShapeSettings *in_settings, float in_convex_radius);
+
+JPC_API float
+JPC_CylinderShapeSettings_GetHalfHeight(const JPC_CylinderShapeSettings *in_settings);
+
+JPC_API void
+JPC_CylinderShapeSettings_SetHalfHeight(JPC_CylinderShapeSettings *in_settings, float in_half_height);
+
+JPC_API float
+JPC_CylinderShapeSettings_GetRadius(const JPC_CylinderShapeSettings *in_settings);
+
+JPC_API void
+JPC_CylinderShapeSettings_SetRadius(JPC_CylinderShapeSettings *in_settings, float in_radius);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConvexHullShapeSettings (-> JPC_ConvexShapeSettings -> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_ConvexHullShapeSettings *
+JPC_ConvexHullShapeSettings_Create(const void *in_vertices, uint32_t in_num_vertices, uint32_t in_vertex_size);
+
+JPC_API float
+JPC_ConvexHullShapeSettings_GetMaxConvexRadius(const JPC_ConvexHullShapeSettings *in_settings);
+
+JPC_API void
+JPC_ConvexHullShapeSettings_SetMaxConvexRadius(JPC_ConvexHullShapeSettings *in_settings,
+                                               float in_max_convex_radius);
+JPC_API float
+JPC_ConvexHullShapeSettings_GetMaxErrorConvexRadius(const JPC_ConvexHullShapeSettings *in_settings);
+
+JPC_API void
+JPC_ConvexHullShapeSettings_SetMaxErrorConvexRadius(JPC_ConvexHullShapeSettings *in_settings,
+                                                    float in_max_err_convex_radius);
+JPC_API float
+JPC_ConvexHullShapeSettings_GetHullTolerance(const JPC_ConvexHullShapeSettings *in_settings);
+
+JPC_API void
+JPC_ConvexHullShapeSettings_SetHullTolerance(JPC_ConvexHullShapeSettings *in_settings,
+                                             float in_hull_tolerance);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_HeightFieldShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_HeightFieldShapeSettings *
+JPC_HeightFieldShapeSettings_Create(const float *in_samples, uint32_t in_height_field_size);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_GetOffset(const JPC_HeightFieldShapeSettings *in_settings, float out_offset[3]);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_SetOffset(JPC_HeightFieldShapeSettings *in_settings, const float in_offset[3]);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_GetScale(const JPC_HeightFieldShapeSettings *in_settings, float out_scale[3]);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_SetScale(JPC_HeightFieldShapeSettings *in_settings, const float in_scale[3]);
+
+JPC_API uint32_t
+JPC_HeightFieldShapeSettings_GetBlockSize(const JPC_HeightFieldShapeSettings *in_settings);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_SetBlockSize(JPC_HeightFieldShapeSettings *in_settings, uint32_t in_block_size);
+
+JPC_API uint32_t
+JPC_HeightFieldShapeSettings_GetBitsPerSample(const JPC_HeightFieldShapeSettings *in_settings);
+
+JPC_API void
+JPC_HeightFieldShapeSettings_SetBitsPerSample(JPC_HeightFieldShapeSettings *in_settings, uint32_t in_num_bits);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_MeshShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_MeshShapeSettings *
+JPC_MeshShapeSettings_Create(const void *in_vertices,
+                             uint32_t in_num_vertices,
+                             uint32_t in_vertex_size,
+                             const uint32_t *in_indices,
+                             uint32_t in_num_indices);
+JPC_API uint32_t
+JPC_MeshShapeSettings_GetMaxTrianglesPerLeaf(const JPC_MeshShapeSettings *in_settings);
+
+JPC_API void
+JPC_MeshShapeSettings_SetMaxTrianglesPerLeaf(JPC_MeshShapeSettings *in_settings, uint32_t in_max_triangles);
+
+JPC_API void
+JPC_MeshShapeSettings_Sanitize(JPC_MeshShapeSettings *in_settings);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_DecoratedShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_DecoratedShapeSettings *
+JPC_RotatedTranslatedShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                                          const JPC_Real in_rotated[4],
+                                          const JPC_Real in_translated[3]);
+
+JPC_API JPC_DecoratedShapeSettings *
+JPC_ScaledShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                               const JPC_Real in_scale[3]);
+
+JPC_API JPC_DecoratedShapeSettings *
+JPC_OffsetCenterOfMassShapeSettings_Create(const JPC_ShapeSettings *in_inner_shape_settings,
+                                           const JPC_Real in_center_of_mass[3]);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CompoundShapeSettings (-> JPC_ShapeSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CompoundShapeSettings *
+JPC_StaticCompoundShapeSettings_Create();
+
+JPC_API JPC_CompoundShapeSettings *
+JPC_MutableCompoundShapeSettings_Create();
+
+JPC_API void
+JPC_CompoundShapeSettings_AddShape(JPC_CompoundShapeSettings *in_settings,
+                                   const JPC_Real in_position[3],
+                                   const JPC_Real in_rotation[4],
+                                   const JPC_ShapeSettings *in_shape,
+                                   const uint32_t in_user_data);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyManager_DrawSettings
+//
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+JPC_API JPC_BodyManager_DrawSettings *
+JPC_BodyManager_DrawSettings_Create();
+
+JPC_API void
+JPC_BodyManager_DrawSettings_Destroy(JPC_BodyManager_DrawSettings *);
+#endif // JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyDrawFilter
+//
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+JPC_API JPC_BodyDrawFilter *
+JPC_BodyDrawFilter_Create(const JPC_BodyDrawFilterFunc);
+
+JPC_API void
+JPC_BodyDrawFilter_Destroy(JPC_BodyDrawFilter *);
+#endif // JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Shape
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Shape_AddRef(JPC_Shape *in_shape);
+
+JPC_API void
+JPC_Shape_Release(JPC_Shape *in_shape);
+
+JPC_API uint32_t
+JPC_Shape_GetRefCount(const JPC_Shape *in_shape);
+
+JPC_API JPC_ShapeType
+JPC_Shape_GetType(const JPC_Shape *in_shape);
+
+JPC_API JPC_ShapeSubType
+JPC_Shape_GetSubType(const JPC_Shape *in_shape);
+
+JPC_API uint64_t
+JPC_Shape_GetUserData(const JPC_Shape *in_shape);
+
+JPC_API void
+JPC_Shape_SetUserData(JPC_Shape *in_shape, uint64_t in_user_data);
+
+JPC_API void
+JPC_Shape_GetCenterOfMass(const JPC_Shape *in_shape, JPC_Real out_position[3]);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_ConstraintSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_ConstraintSettings_AddRef(JPC_ConstraintSettings *in_settings);
+
+JPC_API void
+JPC_ConstraintSettings_Release(JPC_ConstraintSettings *in_settings);
+
+JPC_API uint32_t
+JPC_ConstraintSettings_GetRefCount(const JPC_ConstraintSettings *in_settings);
+
+JPC_API uint64_t
+JPC_ConstraintSettings_GetUserData(const JPC_ConstraintSettings *in_settings);
+
+JPC_API void
+JPC_ConstraintSettings_SetUserData(JPC_ConstraintSettings *in_settings, uint64_t in_user_data);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_TwoBodyConstraintSettings (-> JPC_ConstraintSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Constraint *
+JPC_TwoBodyConstraintSettings_CreateConstraint(const JPC_TwoBodyConstraintSettings *in_settings,
+                                               JPC_Body *in_body1,
+                                               JPC_Body *in_body2);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_FixedConstraintSettings (-> JPC_TwoBodyConstraintSettings -> JPC_ConstraintSettings)
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_FixedConstraintSettings *
+JPC_FixedConstraintSettings_Create();
+
+JPC_API void
+JPC_FixedConstraintSettings_SetSpace(JPC_FixedConstraintSettings *in_settings, JPC_ConstraintSpace in_space);
+
+JPC_API void
+JPC_FixedConstraintSettings_SetAutoDetectPoint(JPC_FixedConstraintSettings *in_settings, bool in_enabled);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Constraint
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_Constraint_AddRef(JPC_Constraint *in_shape);
+
+JPC_API void
+JPC_Constraint_Release(JPC_Constraint *in_shape);
+
+JPC_API uint32_t
+JPC_Constraint_GetRefCount(const JPC_Constraint *in_shape);
+
+JPC_API JPC_ConstraintType
+JPC_Constraint_GetType(const JPC_Constraint *in_shape);
+
+JPC_API JPC_ConstraintSubType
+JPC_Constraint_GetSubType(const JPC_Constraint *in_shape);
+
+JPC_API uint64_t
+JPC_Constraint_GetUserData(const JPC_Constraint *in_shape);
+
+JPC_API void
+JPC_Constraint_SetUserData(JPC_Constraint *in_shape, uint64_t in_user_data);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyInterface
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Body *
+JPC_BodyInterface_CreateBody(JPC_BodyInterface *in_iface, const JPC_BodyCreationSettings *in_setting);
+
+JPC_API JPC_Body *
+JPC_BodyInterface_CreateBodyWithID(JPC_BodyInterface *in_iface,
+                                   JPC_BodyID in_body_id,
+                                   const JPC_BodyCreationSettings *in_settings);
+
+JPC_API void
+JPC_BodyInterface_DestroyBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_AddBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_Activation in_mode);
+
+JPC_API void
+JPC_BodyInterface_RemoveBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API JPC_BodyID
+JPC_BodyInterface_CreateAndAddBody(JPC_BodyInterface *in_iface,
+                                   const JPC_BodyCreationSettings *in_settings,
+                                   JPC_Activation in_mode);
+JPC_API bool
+JPC_BodyInterface_IsAdded(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_SetLinearAndAngularVelocity(JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              const float in_linear_velocity[3],
+                                              const float in_angular_velocity[3]);
+JPC_API void
+JPC_BodyInterface_GetLinearAndAngularVelocity(const JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              float out_linear_velocity[3],
+                                              float out_angular_velocity[3]);
+JPC_API void
+JPC_BodyInterface_SetLinearVelocity(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_velocity[3]);
+JPC_API void
+JPC_BodyInterface_GetLinearVelocity(const JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    float out_velocity[3]);
+JPC_API void
+JPC_BodyInterface_AddLinearVelocity(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_velocity[3]);
+JPC_API void
+JPC_BodyInterface_AddLinearAndAngularVelocity(JPC_BodyInterface *in_iface,
+                                              JPC_BodyID in_body_id,
+                                              const float in_linear_velocity[3],
+                                              const float in_angular_velocity[3]);
+JPC_API void
+JPC_BodyInterface_SetAngularVelocity(JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     const float in_velocity[3]);
+JPC_API void
+JPC_BodyInterface_GetAngularVelocity(const JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     float out_velocity[3]);
+JPC_API void
+JPC_BodyInterface_GetPointVelocity(const JPC_BodyInterface *in_iface,
+                                   JPC_BodyID in_body_id,
+                                   const JPC_Real in_point[3],
+                                   float out_velocity[3]);
+JPC_API void
+JPC_BodyInterface_GetPosition(const JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              JPC_Real out_position[3]);
+JPC_API void
+JPC_BodyInterface_SetPosition(JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              const JPC_Real in_position[3],
+                              JPC_Activation in_activation);
+JPC_API void
+JPC_BodyInterface_GetCenterOfMassPosition(const JPC_BodyInterface *in_iface,
+                                          JPC_BodyID in_body_id,
+                                          JPC_Real out_position[3]);
+JPC_API void
+JPC_BodyInterface_GetRotation(const JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              float out_rotation[4]);
+JPC_API void
+JPC_BodyInterface_SetRotation(JPC_BodyInterface *in_iface,
+                              JPC_BodyID in_body_id,
+                              const JPC_Real in_rotation[4],
+                              JPC_Activation in_activation);
+JPC_API void
+JPC_BodyInterface_ActivateBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_DeactivateBody(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API bool
+JPC_BodyInterface_IsActive(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_SetPositionRotationAndVelocity(JPC_BodyInterface *in_iface,
+                                                 JPC_BodyID in_body_id,
+                                                 const JPC_Real in_position[3],
+                                                 const float in_rotation[4],
+                                                 const float in_linear_velocity[3],
+                                                 const float in_angular_velocity[3]);
+JPC_API void
+JPC_BodyInterface_AddForce(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_force[3]);
+
+JPC_API void
+JPC_BodyInterface_AddForceAtPosition(JPC_BodyInterface *in_iface,
+                                     JPC_BodyID in_body_id,
+                                     const float in_force[3],
+                                     const JPC_Real in_position[3]);
+JPC_API void
+JPC_BodyInterface_AddTorque(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_torque[3]);
+
+JPC_API void
+JPC_BodyInterface_AddForceAndTorque(JPC_BodyInterface *in_iface,
+                                    JPC_BodyID in_body_id,
+                                    const float in_force[3],
+                                    const float in_torque[3]);
+JPC_API void
+JPC_BodyInterface_AddImpulse(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_impulse[3]);
+
+JPC_API void
+JPC_BodyInterface_AddImpulseAtPosition(JPC_BodyInterface *in_iface,
+                                       JPC_BodyID in_body_id,
+                                       const float in_impulse[3],
+                                       const JPC_Real in_position[3]);
+JPC_API void
+JPC_BodyInterface_AddAngularImpulse(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, const float in_impulse[3]);
+
+JPC_API JPC_MotionType 
+JPC_BodyInterface_GetMotionType(const JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_SetMotionType(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_MotionType motion_type, JPC_Activation activation);
+
+JPC_API JPC_ObjectLayer
+JPC_BodyInterface_GetObjectLayer(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id);
+
+JPC_API void
+JPC_BodyInterface_SetObjectLayer(JPC_BodyInterface *in_iface, JPC_BodyID in_body_id, JPC_ObjectLayer in_layer);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Body
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_BodyID
+JPC_Body_GetID(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_IsActive(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_IsStatic(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_IsKinematic(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_IsDynamic(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_CanBeKinematicOrDynamic(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetIsSensor(JPC_Body *in_body, bool in_is_sensor);
+
+JPC_API bool
+JPC_Body_IsSensor(const JPC_Body *in_body);
+
+JPC_API JPC_MotionType
+JPC_Body_GetMotionType(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetMotionType(JPC_Body *in_body, JPC_MotionType in_motion_type);
+
+JPC_API JPC_BroadPhaseLayer
+JPC_Body_GetBroadPhaseLayer(const JPC_Body *in_body);
+
+JPC_API JPC_ObjectLayer
+JPC_Body_GetObjectLayer(const JPC_Body *in_body);
+
+JPC_API JPC_CollisionGroup *
+JPC_Body_GetCollisionGroup(JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetCollisionGroup(JPC_Body *in_body, const JPC_CollisionGroup *in_group);
+
+JPC_API bool
+JPC_Body_GetAllowSleeping(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetAllowSleeping(JPC_Body *in_body, bool in_allow_sleeping);
+
+JPC_API float
+JPC_Body_GetFriction(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetFriction(JPC_Body *in_body, float in_friction);
+
+JPC_API float
+JPC_Body_GetRestitution(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetRestitution(JPC_Body *in_body, float in_restitution);
+
+JPC_API void
+JPC_Body_GetLinearVelocity(const JPC_Body *in_body, float out_linear_velocity[3]);
+
+JPC_API void
+JPC_Body_SetLinearVelocity(JPC_Body *in_body, const float in_linear_velocity[3]);
+
+JPC_API void
+JPC_Body_SetLinearVelocityClamped(JPC_Body *in_body, const float in_linear_velocity[3]);
+
+JPC_API void
+JPC_Body_GetAngularVelocity(const JPC_Body *in_body, float out_angular_velocity[3]);
+
+JPC_API void
+JPC_Body_SetAnglularVelocity(JPC_Body *in_body, const float in_angular_velocity[3]);
+
+JPC_API void
+JPC_Body_SetAnglularVelocityClamped(JPC_Body *in_body, const float in_angular_velocity[3]);
+
+JPC_API void
+JPC_Body_GetPointVelocityCOM(const JPC_Body *in_body,
+                             const float in_point_relative_to_com[3],
+                             float out_velocity[3]);
+JPC_API void
+JPC_Body_GetPointVelocity(const JPC_Body *in_body, const JPC_Real in_point[3], float out_velocity[3]);
+
+JPC_API void
+JPC_Body_AddForce(JPC_Body *in_body, const float in_force[3]);
+
+JPC_API void
+JPC_Body_AddForceAtPosition(JPC_Body *in_body, const float in_force[3], const JPC_Real in_position[3]);
+
+JPC_API void
+JPC_Body_AddTorque(JPC_Body *in_body, const float in_torque[3]);
+
+JPC_API void
+JPC_Body_GetInverseInertia(const JPC_Body *in_body, float out_inverse_inertia[16]);
+
+JPC_API void
+JPC_Body_AddImpulse(JPC_Body *in_body, const float in_impulse[3]);
+
+JPC_API void
+JPC_Body_AddImpulseAtPosition(JPC_Body *in_body, const float in_impulse[3], const JPC_Real in_position[3]);
+
+JPC_API void
+JPC_Body_AddAngularImpulse(JPC_Body *in_body, const float in_angular_impulse[3]);
+
+JPC_API void
+JPC_Body_MoveKinematic(JPC_Body *in_body,
+                       const JPC_Real in_target_position[3],
+                       const float in_target_rotation[4],
+                       float in_delta_time);
+JPC_API void
+JPC_Body_ApplyBuoyancyImpulse(JPC_Body *in_body,
+                              const JPC_Real in_surface_position[3],
+                              const float in_surface_normal[3],
+                              float in_buoyancy,
+                              float in_linear_drag,
+                              float in_angular_drag,
+                              const float in_fluid_velocity[3],
+                              const float in_gravity[3],
+                              float in_delta_time);
+JPC_API bool
+JPC_Body_IsInBroadPhase(const JPC_Body *in_body);
+
+JPC_API bool
+JPC_Body_IsCollisionCacheInvalid(const JPC_Body *in_body);
+
+JPC_API const JPC_Shape *
+JPC_Body_GetShape(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_GetPosition(const JPC_Body *in_body, JPC_Real out_position[3]);
+
+JPC_API void
+JPC_Body_GetRotation(const JPC_Body *in_body, float out_rotation[4]);
+
+JPC_API void
+JPC_Body_GetWorldTransform(const JPC_Body *in_body, float out_rotation[9], JPC_Real out_translation[3]);
+
+JPC_API void
+JPC_Body_GetCenterOfMassPosition(const JPC_Body *in_body, JPC_Real out_position[3]);
+
+JPC_API void
+JPC_Body_GetCenterOfMassTransform(const JPC_Body *in_body,
+                                  float out_rotation[9],
+                                  JPC_Real out_translation[3]);
+JPC_API void
+JPC_Body_GetInverseCenterOfMassTransform(const JPC_Body *in_body,
+                                         float out_rotation[9],
+                                         JPC_Real out_translation[3]);
+JPC_API void
+JPC_Body_GetWorldSpaceBounds(const JPC_Body *in_body, float out_min[3], float out_max[3]);
+
+JPC_API JPC_MotionProperties *
+JPC_Body_GetMotionProperties(JPC_Body *in_body);
+
+JPC_API uint64_t
+JPC_Body_GetUserData(const JPC_Body *in_body);
+
+JPC_API void
+JPC_Body_SetUserData(JPC_Body *in_body, uint64_t in_user_data);
+
+JPC_API void
+JPC_Body_GetWorldSpaceSurfaceNormal(const JPC_Body *in_body,
+                                    JPC_SubShapeID in_sub_shape_id,
+                                    const JPC_Real in_position[3], // world space
+                                    float out_normal_vector[3]);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_BodyID
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API uint32_t
+JPC_BodyID_GetIndex(JPC_BodyID in_body_id);
+
+JPC_API uint8_t
+JPC_BodyID_GetSequenceNumber(JPC_BodyID in_body_id);
+
+JPC_API bool
+JPC_BodyID_IsInvalid(JPC_BodyID in_body_id);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterSettings *
+JPC_CharacterSettings_Create();
+
+JPC_API void
+JPC_CharacterSettings_Release(JPC_CharacterSettings *in_settings);
+
+JPC_API void
+JPC_CharacterSettings_AddRef(JPC_CharacterSettings *in_settings);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_Character
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Character *
+JPC_Character_Create(const JPC_CharacterSettings *in_settings,
+                     const JPC_Real in_position[3],
+                     const float in_rotation[4],
+                     uint64_t in_user_data,
+                     JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_Character_Destroy(JPC_Character *in_character);
+
+JPC_API void
+JPC_Character_AddToPhysicsSystem(JPC_Character *in_character, JPC_Activation in_activation, bool in_lock_bodies);
+
+JPC_API void
+JPC_Character_RemoveFromPhysicsSystem(JPC_Character *in_character, bool in_lock_bodies);
+
+JPC_API void
+JPC_Character_GetPosition(const JPC_Character *in_character, JPC_Real out_position[3]);
+
+JPC_API void
+JPC_Character_SetPosition(JPC_Character *in_character, const JPC_Real in_position[3]);
+
+JPC_API void
+JPC_Character_GetLinearVelocity(const JPC_Character *in_character, float out_linear_velocity[3]);
+
+JPC_API void
+JPC_Character_SetLinearVelocity(JPC_Character *in_character, const float in_linear_velocity[3]);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterVirtualSettings
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterVirtualSettings *
+JPC_CharacterVirtualSettings_Create();
+
+JPC_API void
+JPC_CharacterVirtualSettings_Release(JPC_CharacterVirtualSettings *in_settings);
+//--------------------------------------------------------------------------------------------------
+//
+// JPC_CharacterVirtual
+//
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_CharacterVirtual *
+JPC_CharacterVirtual_Create(const JPC_CharacterVirtualSettings *in_settings,
+                            const JPC_Real in_position[3],
+                            const float in_rotation[4],
+                            JPC_PhysicsSystem *in_physics_system);
+
+JPC_API void
+JPC_CharacterVirtual_Destroy(JPC_CharacterVirtual *in_character);
+
+JPC_API void
+JPC_CharacterVirtual_Update(JPC_CharacterVirtual *in_character,
+                            float in_delta_time,
+                            const float in_gravity[3],
+                            const void *in_broad_phase_layer_filter,
+                            const void *in_object_layer_filter,
+                            const void *in_body_filter,
+                            const void *in_shape_filter,
+                            JPC_TempAllocator *in_temp_allocator);
+
+JPC_API void
+JPC_CharacterVirtual_SetListener(JPC_CharacterVirtual *in_character, void *in_listener);
+
+JPC_API void
+JPC_CharacterVirtual_UpdateGroundVelocity(JPC_CharacterVirtual *in_character);
+
+JPC_API void
+JPC_CharacterVirtual_GetGroundVelocity(const JPC_CharacterVirtual *in_character, float out_ground_velocity[3]);
+
+JPC_API JPC_CharacterGroundState
+JPC_CharacterVirtual_GetGroundState(JPC_CharacterVirtual *in_character);
+
+JPC_API void
+JPC_CharacterVirtual_GetPosition(const JPC_CharacterVirtual *in_character, JPC_Real out_position[3]);
+
+JPC_API void
+JPC_CharacterVirtual_SetPosition(JPC_CharacterVirtual *in_character, const JPC_Real in_position[3]);
+
+JPC_API void
+JPC_CharacterVirtual_GetRotation(const JPC_CharacterVirtual *in_character, float out_rotation[4]);
+
+JPC_API void
+JPC_CharacterVirtual_SetRotation(JPC_CharacterVirtual *in_character, const float in_rotation[4]);
+
+JPC_API void
+JPC_CharacterVirtual_GetLinearVelocity(const JPC_CharacterVirtual *in_character, float out_linear_velocity[3]);
+
+JPC_API void
+JPC_CharacterVirtual_SetLinearVelocity(JPC_CharacterVirtual *in_character, const float in_linear_velocity[3]);
+//--------------------------------------------------------------------------------------------------
+
+JPC_API JPC_Features JPC_GetFeatures();
+
+#ifdef __cplusplus
+}
+#endif

+ 301 - 0
JoltC/JoltPhysicsC_Extensions.cpp

@@ -0,0 +1,301 @@
+//--------------------------------------------------------------------------------------------------
+#include "JoltPhysicsC.h"
+#include <assert.h>
+
+#ifdef _MSC_VER
+#define _ALLOW_KEYWORD_MACROS
+#endif
+// We do this because we add some low-level functions which need access to private fields.
+// Also, we static assert offsets of some private fields (see bottom of this file).
+#define private public
+
+#include <Jolt/Jolt.h>
+#include <Jolt/RegisterTypes.h>
+#include <Jolt/Core/Factory.h>
+#include <Jolt/Core/Memory.h>
+#include <Jolt/Core/TempAllocator.h>
+#include <Jolt/Core/JobSystemThreadPool.h>
+#include <Jolt/Physics/PhysicsSettings.h>
+#include <Jolt/Physics/PhysicsSystem.h>
+#include <Jolt/Physics/Collision/CastResult.h>
+#include <Jolt/Physics/Collision/RayCast.h>
+#include <Jolt/Physics/Collision/CollideShape.h>
+#include <Jolt/Physics/Collision/Shape/BoxShape.h>
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
+#include <Jolt/Physics/Collision/Shape/TriangleShape.h>
+#include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
+#include <Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h>
+#include <Jolt/Physics/Collision/Shape/CylinderShape.h>
+#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
+#include <Jolt/Physics/Body/BodyActivationListener.h>
+#include <Jolt/Physics/Body/BodyLock.h>
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+#include <Jolt/Physics/PhysicsLock.cpp>
+#endif
+
+JPH_SUPPRESS_WARNINGS
+//--------------------------------------------------------------------------------------------------
+JPC_API JPC_Body **
+JPC_PhysicsSystem_GetBodiesUnsafe(JPC_PhysicsSystem *in_physics_system)
+{
+    assert(in_physics_system != nullptr);
+    auto physics_system = reinterpret_cast<JPH::PhysicsSystem *>(in_physics_system);
+    return reinterpret_cast<JPC_Body **>(physics_system->mBodyManager.mBodies.data());
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_GetBodyIDs(const JPC_PhysicsSystem *in_physics_system,
+                             uint32_t in_max_body_ids,
+                             uint32_t *out_num_body_ids,
+                             JPC_BodyID *out_body_ids)
+{
+    assert(in_physics_system != nullptr && out_body_ids != nullptr);
+    assert(in_max_body_ids > 0);
+
+    auto physics_system = reinterpret_cast<const JPH::PhysicsSystem *>(in_physics_system);
+
+    JPH::UniqueLock lock(
+        physics_system->mBodyManager.mBodiesMutex
+        JPH_IF_ENABLE_ASSERTS(, &physics_system->mBodyManager, JPH::EPhysicsLockTypes::BodiesList));
+
+    if (out_num_body_ids) *out_num_body_ids = 0;
+
+    for (const JPH::Body *b : physics_system->mBodyManager.mBodies)
+        if (JPH::BodyManager::sIsValidBodyPointer(b))
+        {
+            *out_body_ids = b->GetID().GetIndexAndSequenceNumber();
+            out_body_ids += 1;
+            if (out_num_body_ids) *out_num_body_ids += 1;
+            in_max_body_ids -= 1;
+            if (in_max_body_ids == 0)
+                break;
+        }
+}
+//--------------------------------------------------------------------------------------------------
+JPC_API void
+JPC_PhysicsSystem_GetActiveBodyIDs(const JPC_PhysicsSystem *in_physics_system,
+                                   uint32_t in_max_body_ids,
+                                   uint32_t *out_num_body_ids,
+                                   JPC_BodyID *out_body_ids)
+{
+    assert(in_physics_system != nullptr && out_body_ids != nullptr);
+    assert(in_max_body_ids > 0);
+
+    auto physics_system = reinterpret_cast<const JPH::PhysicsSystem *>(in_physics_system);
+
+    JPH::UniqueLock lock(
+        physics_system->mBodyManager.mBodiesMutex
+        JPH_IF_ENABLE_ASSERTS(, &physics_system->mBodyManager, JPH::EPhysicsLockTypes::BodiesList));
+
+    if (out_num_body_ids) *out_num_body_ids = 0;
+
+    for (uint32_t i = 0; i < physics_system->mBodyManager.mNumActiveBodies; ++i)
+    {
+        const JPH::BodyID body_id = physics_system->mBodyManager.mActiveBodies[i];
+        *out_body_ids = body_id.GetIndexAndSequenceNumber();
+        out_body_ids += 1;
+        if (out_num_body_ids) *out_num_body_ids += 1;
+        in_max_body_ids -= 1;
+        if (in_max_body_ids == 0)
+            break;
+    }
+}
+//--------------------------------------------------------------------------------------------------
+static_assert(JPC_COLLISION_GROUP_INVALID_GROUP     == JPH::CollisionGroup::cInvalidGroup);
+static_assert(JPC_COLLISION_GROUP_INVALID_SUB_GROUP == JPH::CollisionGroup::cInvalidSubGroup);
+static_assert(JPC_BODY_ID_INVALID                   == JPH::BodyID::cInvalidBodyID);
+static_assert(JPC_BODY_ID_INDEX_BITS                == JPH::BodyID::cMaxBodyIndex);
+static_assert(_JPC_IS_FREED_BODY_BIT                == JPH::BodyManager::cIsFreedBody);
+static_assert(JPC_SUB_SHAPE_ID_EMPTY                == JPH::SubShapeID::cEmpty);
+
+static_assert((JPC_BODY_ID_SEQUENCE_BITS >> JPC_BODY_ID_SEQUENCE_SHIFT) == JPH::BodyID::cMaxSequenceNumber);
+//--------------------------------------------------------------------------------------------------
+#define ENSURE_SIZE_ALIGN(type0, type1) \
+    static_assert(sizeof(type0) == sizeof(type1)); \
+    static_assert(alignof(type0) == alignof(type1));
+
+ENSURE_SIZE_ALIGN(JPH::BodyID,                  JPC_BodyID)
+ENSURE_SIZE_ALIGN(JPH::SubShapeID,              JPC_SubShapeID)
+ENSURE_SIZE_ALIGN(JPH::SubShapeIDCreator,       JPC_SubShapeIDCreator)
+ENSURE_SIZE_ALIGN(JPH::EShapeType,              JPC_ShapeType)
+ENSURE_SIZE_ALIGN(JPH::EShapeSubType,           JPC_ShapeSubType)
+ENSURE_SIZE_ALIGN(JPH::EMotionType,             JPC_MotionType)
+ENSURE_SIZE_ALIGN(JPH::EMotionQuality,          JPC_MotionQuality)
+ENSURE_SIZE_ALIGN(JPH::EBackFaceMode,           JPC_BackFaceMode)
+ENSURE_SIZE_ALIGN(JPH::EOverrideMassProperties, JPC_OverrideMassProperties)
+ENSURE_SIZE_ALIGN(JPH::EActivation,             JPC_Activation)
+ENSURE_SIZE_ALIGN(JPH::ValidateResult,          JPC_ValidateResult)
+ENSURE_SIZE_ALIGN(JPH::BroadPhaseLayer,         JPC_BroadPhaseLayer)
+ENSURE_SIZE_ALIGN(JPH::ObjectLayer,             JPC_ObjectLayer)
+
+ENSURE_SIZE_ALIGN(JPH::CollisionGroup::GroupID,    JPC_CollisionGroupID)
+ENSURE_SIZE_ALIGN(JPH::CollisionGroup::SubGroupID, JPC_CollisionSubGroupID)
+
+ENSURE_SIZE_ALIGN(JPH::MassProperties,       JPC_MassProperties)
+ENSURE_SIZE_ALIGN(JPH::MotionProperties,     JPC_MotionProperties)
+ENSURE_SIZE_ALIGN(JPH::CollisionGroup,       JPC_CollisionGroup)
+ENSURE_SIZE_ALIGN(JPH::BodyCreationSettings, JPC_BodyCreationSettings)
+ENSURE_SIZE_ALIGN(JPH::ContactManifold,      JPC_ContactManifold)
+ENSURE_SIZE_ALIGN(JPH::ContactSettings,      JPC_ContactSettings)
+ENSURE_SIZE_ALIGN(JPH::SubShapeIDPair,       JPC_SubShapeIDPair)
+ENSURE_SIZE_ALIGN(JPH::CollideShapeResult,   JPC_CollideShapeResult)
+ENSURE_SIZE_ALIGN(JPH::TransformedShape,     JPC_TransformedShape)
+ENSURE_SIZE_ALIGN(JPH::Body,                 JPC_Body)
+
+ENSURE_SIZE_ALIGN(JPH::BodyLockRead,  JPC_BodyLockRead)
+ENSURE_SIZE_ALIGN(JPH::BodyLockWrite, JPC_BodyLockWrite)
+
+ENSURE_SIZE_ALIGN(JPH::RRayCast, JPC_RRayCast)
+ENSURE_SIZE_ALIGN(JPH::RayCastResult, JPC_RayCastResult)
+ENSURE_SIZE_ALIGN(JPH::RayCastSettings, JPC_RayCastSettings)
+//--------------------------------------------------------------------------------------------------
+#define ENSURE_ENUM_EQ(c_const, cpp_enum) static_assert(c_const == static_cast<int>(cpp_enum))
+
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_CONVEX,       JPH::EShapeType::Convex);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_COMPOUND,     JPH::EShapeType::Compound);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_DECORATED,    JPH::EShapeType::Decorated);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_MESH,         JPH::EShapeType::Mesh);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_HEIGHT_FIELD, JPH::EShapeType::HeightField);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_USER1,        JPH::EShapeType::User1);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_USER2,        JPH::EShapeType::User2);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_USER3,        JPH::EShapeType::User3);
+ENSURE_ENUM_EQ(JPC_SHAPE_TYPE_USER4,        JPH::EShapeType::User4);
+
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_SPHERE,                JPH::EShapeSubType::Sphere);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_BOX,                   JPH::EShapeSubType::Box);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_TRIANGLE,              JPH::EShapeSubType::Triangle);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_CAPSULE,               JPH::EShapeSubType::Capsule);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_TAPERED_CAPSULE,       JPH::EShapeSubType::TaperedCapsule);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_CYLINDER,              JPH::EShapeSubType::Cylinder);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_CONVEX_HULL,           JPH::EShapeSubType::ConvexHull);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_STATIC_COMPOUND,       JPH::EShapeSubType::StaticCompound);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_MUTABLE_COMPOUND,      JPH::EShapeSubType::MutableCompound);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_ROTATED_TRANSLATED,    JPH::EShapeSubType::RotatedTranslated);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_SCALED,                JPH::EShapeSubType::Scaled);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_OFFSET_CENTER_OF_MASS, JPH::EShapeSubType::OffsetCenterOfMass);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_MESH,                  JPH::EShapeSubType::Mesh);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_HEIGHT_FIELD,          JPH::EShapeSubType::HeightField);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER1,                 JPH::EShapeSubType::User1);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER2,                 JPH::EShapeSubType::User2);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER3,                 JPH::EShapeSubType::User3);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER4,                 JPH::EShapeSubType::User4);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER5,                 JPH::EShapeSubType::User5);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER6,                 JPH::EShapeSubType::User6);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER7,                 JPH::EShapeSubType::User7);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER8,                 JPH::EShapeSubType::User8);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX1,          JPH::EShapeSubType::UserConvex1);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX2,          JPH::EShapeSubType::UserConvex2);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX3,          JPH::EShapeSubType::UserConvex3);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX4,          JPH::EShapeSubType::UserConvex4);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX5,          JPH::EShapeSubType::UserConvex5);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX6,          JPH::EShapeSubType::UserConvex6);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX7,          JPH::EShapeSubType::UserConvex7);
+ENSURE_ENUM_EQ(JPC_SHAPE_SUB_TYPE_USER_CONVEX8,          JPH::EShapeSubType::UserConvex8);
+
+ENSURE_ENUM_EQ(JPC_MOTION_TYPE_STATIC,    JPH::EMotionType::Static);
+ENSURE_ENUM_EQ(JPC_MOTION_TYPE_KINEMATIC, JPH::EMotionType::Kinematic);
+ENSURE_ENUM_EQ(JPC_MOTION_TYPE_DYNAMIC,   JPH::EMotionType::Dynamic);
+
+ENSURE_ENUM_EQ(JPC_MOTION_QUALITY_DISCRETE,    JPH::EMotionQuality::Discrete);
+ENSURE_ENUM_EQ(JPC_MOTION_QUALITY_LINEAR_CAST, JPH::EMotionQuality::LinearCast);
+
+ENSURE_ENUM_EQ(JPC_ACTIVATION_ACTIVATE,      JPH::EActivation::Activate);
+ENSURE_ENUM_EQ(JPC_ACTIVATION_DONT_ACTIVATE, JPH::EActivation::DontActivate);
+
+ENSURE_ENUM_EQ(JPC_OVERRIDE_MASS_PROPS_CALC_MASS_INERTIA,
+               JPH::EOverrideMassProperties::CalculateMassAndInertia);
+ENSURE_ENUM_EQ(JPC_OVERRIDE_MASS_PROPS_CALC_INERTIA,
+               JPH::EOverrideMassProperties::CalculateInertia);
+ENSURE_ENUM_EQ(JPC_OVERRIDE_MASS_PROPS_MASS_INERTIA_PROVIDED,
+               JPH::EOverrideMassProperties::MassAndInertiaProvided);
+
+ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_ACCEPT_ALL_CONTACTS,
+               JPH::ValidateResult::AcceptAllContactsForThisBodyPair);
+ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_ACCEPT_CONTACT,
+               JPH::ValidateResult::AcceptContact);
+ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_REJECT_CONTACT,
+               JPH::ValidateResult::RejectContact);
+ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_REJECT_ALL_CONTACTS,
+               JPH::ValidateResult::RejectAllContactsForThisBodyPair);
+
+ENSURE_ENUM_EQ(JPC_MAX_PHYSICS_JOBS,     JPH::cMaxPhysicsJobs);
+ENSURE_ENUM_EQ(JPC_MAX_PHYSICS_BARRIERS, JPH::cMaxPhysicsBarriers);
+
+ENSURE_ENUM_EQ(JPC_BACK_FACE_IGNORE,  JPH::EBackFaceMode::IgnoreBackFaces);
+ENSURE_ENUM_EQ(JPC_BACK_FACE_COLLIDE, JPH::EBackFaceMode::CollideWithBackFaces);
+//--------------------------------------------------------------------------------------------------
+static_assert(
+    offsetof(JPH::BodyCreationSettings, mInertiaMultiplier) ==
+    offsetof(JPC_BodyCreationSettings, inertia_multiplier));
+static_assert(
+    offsetof(JPH::BodyCreationSettings, mIsSensor) == offsetof(JPC_BodyCreationSettings, is_sensor));
+static_assert(
+    offsetof(JPH::BodyCreationSettings, mAngularDamping) == offsetof(JPC_BodyCreationSettings, angular_damping));
+
+static_assert(
+    offsetof(JPH::ContactManifold, mWorldSpaceNormal) == offsetof(JPC_ContactManifold, normal));
+static_assert(
+    offsetof(JPH::ContactManifold, mPenetrationDepth) == offsetof(JPC_ContactManifold, penetration_depth));
+static_assert(
+        offsetof(JPH::ContactManifold, mRelativeContactPointsOn1) ==
+        offsetof(JPC_ContactManifold, shape1_relative_contact));
+static_assert(
+    offsetof(JPH::ContactManifold, mRelativeContactPointsOn2) ==
+    offsetof(JPC_ContactManifold, shape2_relative_contact));
+
+static_assert(
+    offsetof(JPH::CollideShapeResult, mPenetrationDepth) == offsetof(JPC_CollideShapeResult, penetration_depth));
+static_assert(
+    offsetof(JPH::CollideShapeResult, mShape1Face) == offsetof(JPC_CollideShapeResult, shape1_face));
+static_assert(
+    offsetof(JPH::CollideShapeResult, mShape2Face) == offsetof(JPC_CollideShapeResult, shape2_face));
+static_assert(
+    offsetof(JPH::CollideShapeResult, mPenetrationDepth) == offsetof(JPC_CollideShapeResult, penetration_depth));
+static_assert(
+    offsetof(JPH::CollideShapeResult, mBodyID2) == offsetof(JPC_CollideShapeResult, body2_id));
+
+static_assert(offsetof(JPH::MotionProperties, mForce) == offsetof(JPC_MotionProperties, force));
+static_assert(offsetof(JPH::MotionProperties, mTorque) == offsetof(JPC_MotionProperties, torque));
+static_assert(offsetof(JPH::MotionProperties, mMotionQuality) == offsetof(JPC_MotionProperties, motion_quality));
+static_assert(offsetof(JPH::MotionProperties, mGravityFactor) == offsetof(JPC_MotionProperties, gravity_factor));
+#if JPC_ENABLE_ASSERTS == 1
+static_assert(
+    offsetof(JPH::MotionProperties, mCachedMotionType) == offsetof(JPC_MotionProperties, cached_motion_type));
+#endif
+
+static_assert(offsetof(JPH::MassProperties, mInertia) == offsetof(JPC_MassProperties, inertia));
+
+static_assert(offsetof(JPH::SubShapeIDPair, mBody2ID) == offsetof(JPC_SubShapeIDPair, second));
+
+static_assert(offsetof(JPH::SubShapeIDCreator, mCurrentBit) == offsetof(JPC_SubShapeIDCreator, current_bit));
+
+static_assert(offsetof(JPH::CollisionGroup, mGroupID) == offsetof(JPC_CollisionGroup, group_id));
+
+static_assert(offsetof(JPH::Body, mFlags) == offsetof(JPC_Body, flags));
+static_assert(offsetof(JPH::Body, mMotionProperties) == offsetof(JPC_Body, motion_properties));
+static_assert(offsetof(JPH::Body, mObjectLayer) == offsetof(JPC_Body, object_layer));
+static_assert(offsetof(JPH::Body, mRotation) == offsetof(JPC_Body, rotation));
+static_assert(offsetof(JPH::Body, mID) == offsetof(JPC_Body, id));
+
+static_assert(offsetof(JPH::BodyLockRead, mBodyLockInterface) == offsetof(JPC_BodyLockRead, lock_interface));
+static_assert(offsetof(JPH::BodyLockRead, mBodyLockMutex) == offsetof(JPC_BodyLockRead, mutex));
+static_assert(offsetof(JPH::BodyLockRead, mBody) == offsetof(JPC_BodyLockRead, body));
+
+static_assert(offsetof(JPH::RayCastResult, mBodyID) == offsetof(JPC_RayCastResult, body_id));
+static_assert(offsetof(JPH::RayCastResult, mFraction) == offsetof(JPC_RayCastResult, fraction));
+static_assert(offsetof(JPH::RayCastResult, mSubShapeID2) == offsetof(JPC_RayCastResult, sub_shape_id));
+
+static_assert(offsetof(JPH::RayCastSettings, mBackFaceMode) == offsetof(JPC_RayCastSettings, back_face_mode));
+static_assert(offsetof(JPH::RayCastSettings, mTreatConvexAsSolid) ==
+    offsetof(JPC_RayCastSettings, treat_convex_as_solid));
+
+static_assert(offsetof(JPH::RRayCast, mOrigin) == offsetof(JPC_RRayCast, origin));
+static_assert(offsetof(JPH::RRayCast, mDirection) == offsetof(JPC_RRayCast, direction));
+
+static_assert(sizeof(JPH::BodyID) == 4);
+static_assert(sizeof(JPH::SubShapeID) == 4);
+static_assert(sizeof(JPH::CollisionGroup::GroupID) == 4);
+static_assert(sizeof(JPH::CollisionGroup::SubGroupID) == 4);
+//--------------------------------------------------------------------------------------------------

+ 856 - 0
JoltC/JoltPhysicsC_Tests.c

@@ -0,0 +1,856 @@
+#include "JoltPhysicsC.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+//#define PRINT_OUTPUT
+
+// Object layers
+#define NUM_OBJ_LAYERS 2
+#define OBJ_LAYER_NON_MOVING 0
+#define OBJ_LAYER_MOVING 1
+
+// Broad phase layers
+#define NUM_BP_LAYERS 2
+#define BP_LAYER_NON_MOVING 0
+#define BP_LAYER_MOVING 1
+//--------------------------------------------------------------------------------------------------
+// BPLayerInterface
+//--------------------------------------------------------------------------------------------------
+typedef struct BPLayerInterfaceImpl
+{
+    const JPC_BroadPhaseLayerInterfaceVTable *vtable; // VTable has to be the first field in the struct.
+    JPC_BroadPhaseLayer                       object_to_broad_phase[NUM_OBJ_LAYERS];
+} BPLayerInterfaceImpl;
+
+static uint32_t
+BPLayerInterface_GetNumBroadPhaseLayers(const void *in_self)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "BPLayerInterface_GetNumBroadPhaseLayers()\n");
+#endif
+    return NUM_BP_LAYERS;
+}
+
+#ifdef _MSC_VER
+static const JPC_BroadPhaseLayer *
+BPLayerInterface_GetBroadPhaseLayer(const void *in_self, JPC_BroadPhaseLayer *out_layer, JPC_ObjectLayer in_layer)
+#else
+static JPC_BroadPhaseLayer
+BPLayerInterface_GetBroadPhaseLayer(const void *in_self, JPC_ObjectLayer in_layer)
+#endif
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "BPLayerInterface_GetBroadPhaseLayer()\n");
+#endif
+    assert(in_layer < NUM_BP_LAYERS);
+    const BPLayerInterfaceImpl *self = (BPLayerInterfaceImpl *)in_self;
+#ifdef _MSC_VER
+    *out_layer = self->object_to_broad_phase[in_layer];
+    return out_layer;
+#else
+    return self->object_to_broad_phase[in_layer];
+#endif
+}
+
+static BPLayerInterfaceImpl
+BPLayerInterface_Init(void)
+{
+    static const JPC_BroadPhaseLayerInterfaceVTable vtable =
+    {
+        .GetNumBroadPhaseLayers = BPLayerInterface_GetNumBroadPhaseLayers,
+        .GetBroadPhaseLayer     = BPLayerInterface_GetBroadPhaseLayer,
+    };
+    BPLayerInterfaceImpl impl =
+    {
+        .vtable = &vtable,
+    };
+    impl.object_to_broad_phase[OBJ_LAYER_NON_MOVING] = BP_LAYER_NON_MOVING;
+    impl.object_to_broad_phase[OBJ_LAYER_MOVING]     = BP_LAYER_MOVING;
+
+    return impl;
+}
+//--------------------------------------------------------------------------------------------------
+// MyContactListener
+//--------------------------------------------------------------------------------------------------
+typedef struct MyContactListener
+{
+    const JPC_ContactListenerVTable *vtable; // VTable has to be the first field in the struct.
+} MyContactListener;
+
+static JPC_ValidateResult
+MyContactListener_OnContactValidate(void *in_self,
+                                    const JPC_Body *in_body1,
+                                    const JPC_Body *in_body2,
+                                    const JPC_Real in_base_offset[3],
+                                    const JPC_CollideShapeResult *in_collision_result)
+{
+    const JPC_BodyID body1_id = JPC_Body_GetID(in_body1);
+    const JPC_BodyID body2_id = JPC_Body_GetID(in_body2);
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnContactValidate(): First BodyID is (%d, %d), second BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(body1_id), JPC_BodyID_GetIndex(body1_id),
+            JPC_BodyID_GetSequenceNumber(body2_id), JPC_BodyID_GetIndex(body2_id));
+    fprintf(stderr,
+            "\tOnContactValidate(): in_base_offset (%f, %f, %f)\n",
+            in_base_offset[0], in_base_offset[1], in_base_offset[2]);
+    fprintf(stderr, "\tOnContactValidate(): penetration_depth (%f)\n", in_collision_result->penetration_depth);
+    fprintf(stderr, "\tOnContactValidate(): shape1_sub_shape_id (%d)\n", in_collision_result->shape1_sub_shape_id);
+    fprintf(stderr, "\tOnContactValidate(): shape2_sub_shape_id (%d)\n", in_collision_result->shape2_sub_shape_id);
+    fprintf(stderr, "\tOnContactValidate(): body2_id (%d)\n", in_collision_result->body2_id);
+#endif
+    return JPC_VALIDATE_RESULT_ACCEPT_ALL_CONTACTS;
+}
+
+static void
+MyContactListener_OnContactAdded(void *in_self,
+                                 const JPC_Body *in_body1,
+                                 const JPC_Body *in_body2,
+                                 const JPC_ContactManifold *in_manifold,
+                                 JPC_ContactSettings *io_settings)
+{
+    const JPC_BodyID body1_id = JPC_Body_GetID(in_body1);
+    const JPC_BodyID body2_id = JPC_Body_GetID(in_body2);
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnContactAdded(): First BodyID is (%d, %d), second BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(body1_id), JPC_BodyID_GetIndex(body1_id),
+            JPC_BodyID_GetSequenceNumber(body2_id), JPC_BodyID_GetIndex(body2_id));
+#endif
+}
+
+static void
+MyContactListener_OnContactPersisted(void *in_self,
+                                     const JPC_Body *in_body1,
+                                     const JPC_Body *in_body2,
+                                     const JPC_ContactManifold *in_manifold,
+                                     JPC_ContactSettings *io_settings)
+{
+    const JPC_BodyID body1_id = JPC_Body_GetID(in_body1);
+    const JPC_BodyID body2_id = JPC_Body_GetID(in_body2);
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnContactPersisted(): First BodyID is (%d, %d), second BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(body1_id), JPC_BodyID_GetIndex(body1_id),
+            JPC_BodyID_GetSequenceNumber(body2_id), JPC_BodyID_GetIndex(body2_id));
+#endif
+}
+
+static void
+MyContactListener_OnContactRemoved(void *in_self, const JPC_SubShapeIDPair *in_sub_shape_pair)
+{
+    const JPC_BodyID body1_id = in_sub_shape_pair->first.body_id;
+    const JPC_BodyID body2_id = in_sub_shape_pair->second.body_id;
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnContactRemoved(): First BodyID is (%d, %d), second BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(body1_id), JPC_BodyID_GetIndex(body1_id),
+            JPC_BodyID_GetSequenceNumber(body2_id), JPC_BodyID_GetIndex(body2_id));
+#endif
+}
+
+static MyContactListener
+MyContactListener_Init(void)
+{
+    static const JPC_ContactListenerVTable vtable =
+    {
+        .OnContactValidate  = MyContactListener_OnContactValidate,
+        .OnContactAdded     = MyContactListener_OnContactAdded,
+        .OnContactPersisted = MyContactListener_OnContactPersisted,
+        .OnContactRemoved   = MyContactListener_OnContactRemoved,
+    };
+    MyContactListener impl =
+    {
+        .vtable = &vtable,
+    };
+    return impl;
+}
+//--------------------------------------------------------------------------------------------------
+// MyDebugRenderer
+//--------------------------------------------------------------------------------------------------
+#if JPC_DEBUG_RENDERER == 1
+
+typedef struct MyRenderPrimitive
+{
+    // Actual render data goes here
+    int foobar;
+} MyRenderPrimitive;
+
+typedef struct MyDebugRenderer
+{
+    const JPC_DebugRendererVTable *vtable; // VTable has to be the first field in the struct.
+    struct MyRenderPrimitive prims[32];
+    int prim_head;
+} MyDebugRenderer;
+
+static void
+MyDebugRenderer_DrawLine(void *in_self, JPC_Real in_from[3], JPC_Real in_to[3], JPC_Color in_color)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: DrawLine called.\n");
+#endif
+}
+
+static void
+MyDebugRenderer_DrawTriangle(void *in_self, JPC_Real in_v1[3], JPC_Real in_v2[3], JPC_Real in_v3[3], JPC_Color in_color)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: DrawTriangle called.\n");
+#endif
+}
+
+static JPC_DebugRenderer_TriangleBatch *
+MyDebugRenderer_CreateTriangleBatch(void *in_self,
+                                    const JPC_DebugRenderer_Triangle *in_triangles,
+                                    uint32_t in_triangle_count)
+{
+    struct MyDebugRenderer *self = (struct MyDebugRenderer*) in_self;
+    struct MyRenderPrimitive *prim = &self->prims[self->prim_head++];
+    JPC_DebugRenderer_TriangleBatch *batch = JPC_DebugRenderer_TriangleBatch_Create(
+        (JPC_DebugRenderer_Primitive *)prim
+        );
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: CreateTriangleBatch called. Created primitive %x\n", prim);
+#endif
+    return batch;
+}
+
+static JPC_DebugRenderer_TriangleBatch *
+MyDebugRenderer_CreateTriangleBatchIndexed(void *in_self,
+                                           const JPC_DebugRenderer_Vertex *in_vertices,
+                                           uint32_t in_vertex_count,
+                                           const uint32_t *in_indices,
+                                           uint32_t in_index_count)
+{
+    struct MyDebugRenderer *self = (struct MyDebugRenderer*) in_self;
+    struct MyRenderPrimitive *prim = &self->prims[self->prim_head++];
+    JPC_DebugRenderer_TriangleBatch *batch = JPC_DebugRenderer_TriangleBatch_Create(
+        (JPC_DebugRenderer_Primitive *)prim
+        );
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: CreateTriangleBatchIndexed called. Created primitive %x\n", prim);
+#endif
+    return batch;
+}
+
+static void
+MyDebugRenderer_DrawGeometry(void *in_self,
+                             const float inModelMatrix[16],
+                             const JPC_AABox *inWorldSpaceBounds,
+                             float inLODScaleSq,
+                             JPC_Color inColor,
+                             const JPC_DebugRenderer_Geometry *in_geometry,
+                             JPC_CullMode in_cull_mode,
+                             JPC_CastShadow in_cast_shadow,
+                             JPC_DrawMode in_draw_mode)
+{
+    if (in_geometry->num_LODs == 0) return;
+    JPC_DebugRenderer_TriangleBatch *batch = in_geometry->LODs[0].batch;
+    const JPC_DebugRenderer_Primitive *prim = JPC_DebugRenderer_TriangleBatch_GetPrimitive(batch);
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: DrawGeometry called for %x\n", prim);
+#endif
+}
+
+static void
+MyDebugRenderer_DrawText3D(void *in_self,
+                           JPC_Real in_position[3],
+                           const char *in_string,
+                           JPC_Color in_color,
+                           float in_height)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tDebugRenderer: DrawText3D called.\n");
+#endif
+}
+
+static MyDebugRenderer
+MyDebugRenderer_Init(void)
+{
+    static const JPC_DebugRendererVTable vtable =
+        {
+              .DrawLine = MyDebugRenderer_DrawLine,
+              .DrawTriangle = MyDebugRenderer_DrawTriangle,
+              .CreateTriangleBatch = MyDebugRenderer_CreateTriangleBatch,
+              .CreateTriangleBatchIndexed = MyDebugRenderer_CreateTriangleBatchIndexed,
+              .DrawGeometry = MyDebugRenderer_DrawGeometry,
+              .DrawText3D = MyDebugRenderer_DrawText3D,
+        };
+    MyDebugRenderer impl =
+        {
+              .vtable = &vtable,
+              .prim_head = 0
+        };
+    return impl;
+}
+
+/// This function can be passed to JPC_PhysicsSystem.DrawBodies as the filter, deciding which bodies draw.
+static bool BodyShouldDraw(const JPC_Body *) {
+    return true;
+}
+#endif //JPC_DEBUG_RENDERER
+//--------------------------------------------------------------------------------------------------
+// MyActivationListener
+//--------------------------------------------------------------------------------------------------
+typedef struct MyActivationListener
+{
+    const JPC_BodyActivationListenerVTable *vtable; // VTable has to be the first field in the struct.
+} MyActivationListener;
+
+static void
+MyActivationListener_OnBodyActivated(void *in_self, const JPC_BodyID *in_body_id, uint64_t in_user_data)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnBodyActivated(): BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(*in_body_id),
+            JPC_BodyID_GetIndex(*in_body_id));
+#endif
+}
+
+static void
+MyActivationListener_OnBodyDeactivated(void *in_self, const JPC_BodyID *in_body_id, uint64_t in_user_data)
+{
+#ifdef PRINT_OUTPUT
+    fprintf(stderr, "\tOnBodyDeactivated(): BodyID is (%d, %d)\n",
+            JPC_BodyID_GetSequenceNumber(*in_body_id),
+            JPC_BodyID_GetIndex(*in_body_id));
+#endif
+}
+
+static MyActivationListener
+MyActivationListener_Init(void)
+{
+    static const JPC_BodyActivationListenerVTable vtable =
+    {
+        .OnBodyActivated   = MyActivationListener_OnBodyActivated,
+        .OnBodyDeactivated = MyActivationListener_OnBodyDeactivated,
+    };
+    MyActivationListener impl =
+    {
+        .vtable = &vtable,
+    };
+    return impl;
+}
+//--------------------------------------------------------------------------------------------------
+// MyObjectFilter
+//--------------------------------------------------------------------------------------------------
+typedef struct MyObjectFilter
+{
+    const JPC_ObjectLayerPairFilterVTable *vtable; // VTable has to be the first field in the struct.
+} MyObjectFilter;
+
+static bool
+MyObjectFilter_ShouldCollide(const void *in_self, JPC_ObjectLayer in_object1, JPC_ObjectLayer in_object2)
+{
+    switch (in_object1)
+    {
+        case OBJ_LAYER_NON_MOVING:
+            return in_object2 == OBJ_LAYER_MOVING;
+        case OBJ_LAYER_MOVING:
+            return true;
+        default:
+            assert(false);
+            return false;
+    }
+}
+
+static MyObjectFilter
+MyObjectFilter_Init(void)
+{
+    static const JPC_ObjectLayerPairFilterVTable vtable =
+    {
+        .ShouldCollide = MyObjectFilter_ShouldCollide,
+    };
+    MyObjectFilter impl =
+    {
+        .vtable = &vtable,
+    };
+    return impl;
+}
+//--------------------------------------------------------------------------------------------------
+// MyBroadPhaseFilter
+//--------------------------------------------------------------------------------------------------
+typedef struct MyBroadPhaseFilter
+{
+    const JPC_ObjectVsBroadPhaseLayerFilterVTable *vtable; // VTable has to be the first field in the struct.
+} MyBroadPhaseFilter;
+
+static bool
+MyBroadPhaseFilter_ShouldCollide(const void *in_self, JPC_ObjectLayer in_layer1, JPC_BroadPhaseLayer in_layer2)
+{
+    switch (in_layer1)
+    {
+        case OBJ_LAYER_NON_MOVING:
+            return in_layer2 == BP_LAYER_MOVING;
+        case OBJ_LAYER_MOVING:
+            return true;
+        default:
+            assert(false);
+            return false;
+    }
+}
+
+static MyBroadPhaseFilter
+MyBroadPhaseFilter_Init(void)
+{
+    static const JPC_ObjectVsBroadPhaseLayerFilterVTable vtable =
+    {
+        .ShouldCollide = MyBroadPhaseFilter_ShouldCollide,
+    };
+    MyBroadPhaseFilter impl =
+    {
+        .vtable = &vtable,
+    };
+    return impl;
+}
+//--------------------------------------------------------------------------------------------------
+// Basic1
+//--------------------------------------------------------------------------------------------------
+uint32_t
+JoltCTest_Basic1(void)
+{
+    JPC_RegisterDefaultAllocator();
+    JPC_CreateFactory();
+    JPC_RegisterTypes();
+
+    const uint32_t max_bodies = 1024;
+    const uint32_t num_body_mutexes = 0;
+    const uint32_t max_body_pairs = 1024;
+    const uint32_t max_contact_constraints = 1024;
+
+    BPLayerInterfaceImpl *broad_phase_layer_interface = malloc(sizeof(BPLayerInterfaceImpl));
+    *broad_phase_layer_interface = BPLayerInterface_Init();
+
+    MyBroadPhaseFilter *broad_phase_filter = malloc(sizeof(MyBroadPhaseFilter));
+    *broad_phase_filter = MyBroadPhaseFilter_Init();
+
+    MyObjectFilter *object_filter = malloc(sizeof(MyObjectFilter));
+    *object_filter = MyObjectFilter_Init();
+
+    JPC_PhysicsSystem *physics_system = JPC_PhysicsSystem_Create(
+        max_bodies,
+        num_body_mutexes,
+        max_body_pairs,
+        max_contact_constraints,
+        broad_phase_layer_interface,
+        broad_phase_filter,
+        object_filter);
+
+    JPC_BoxShapeSettings *box_settings = JPC_BoxShapeSettings_Create((float[]){ 10.0, 20.0, 30.0 });
+
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)box_settings) != 1) return 0;
+    JPC_ShapeSettings_AddRef((JPC_ShapeSettings *)box_settings);
+    JPC_ShapeSettings_Release((JPC_ShapeSettings *)box_settings);
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)box_settings) != 1) return 0;
+
+    JPC_BoxShapeSettings_SetConvexRadius(box_settings, 1.0);
+    if (JPC_BoxShapeSettings_GetConvexRadius(box_settings) != 1.0) return 0;
+
+    JPC_ConvexShapeSettings_SetDensity((JPC_ConvexShapeSettings *)box_settings, 100.0);
+    if (JPC_ConvexShapeSettings_GetDensity((JPC_ConvexShapeSettings *)box_settings) != 100.0) return 0;
+
+    JPC_Shape *box_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings *)box_settings);
+    if (box_shape == NULL) return 0;
+    if (JPC_Shape_GetType(box_shape) != JPC_SHAPE_TYPE_CONVEX) return 0;
+    if (JPC_Shape_GetSubType(box_shape) != JPC_SHAPE_SUB_TYPE_BOX) return 0;
+
+    if (JPC_Shape_GetRefCount(box_shape) != 2) return 0;
+
+    JPC_ShapeSettings_CreateShape((JPC_ShapeSettings *)box_settings);
+    if (JPC_Shape_GetRefCount(box_shape) != 3) return 0;
+    JPC_Shape_Release(box_shape);
+    if (JPC_Shape_GetRefCount(box_shape) != 2) return 0;
+
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)box_settings) != 1) return 0;
+    JPC_ShapeSettings_Release((JPC_ShapeSettings *)box_settings);
+    box_settings = NULL;
+
+    if (JPC_Shape_GetRefCount(box_shape) != 1) return 0;
+    JPC_Shape_Release(box_shape);
+    box_shape = NULL;
+
+    JPC_PhysicsSystem_Destroy(physics_system);
+    physics_system = NULL;
+
+    JPC_DestroyFactory();
+
+    return 1;
+}
+//--------------------------------------------------------------------------------------------------
+// Basic2
+//--------------------------------------------------------------------------------------------------
+uint32_t
+JoltCTest_Basic2(void)
+{
+    JPC_RegisterDefaultAllocator();
+    JPC_CreateFactory();
+    JPC_RegisterTypes();
+
+    JPC_TempAllocator *temp_allocator = JPC_TempAllocator_Create(10 * 1024 * 1024);
+    JPC_JobSystem *job_system = JPC_JobSystem_Create(JPC_MAX_PHYSICS_JOBS, JPC_MAX_PHYSICS_BARRIERS, -1);
+
+    const uint32_t max_bodies = 1024;
+    const uint32_t num_body_mutexes = 0;
+    const uint32_t max_body_pairs = 1024;
+    const uint32_t max_contact_constraints = 1024;
+
+    BPLayerInterfaceImpl broad_phase_layer_interface = BPLayerInterface_Init();
+    MyBroadPhaseFilter broad_phase_filter = MyBroadPhaseFilter_Init();
+    MyObjectFilter object_filter = MyObjectFilter_Init();
+
+    JPC_PhysicsSystem *physics_system = JPC_PhysicsSystem_Create(
+        max_bodies,
+        num_body_mutexes,
+        max_body_pairs,
+        max_contact_constraints,
+        &broad_phase_layer_interface,
+        &broad_phase_filter,
+        &object_filter);
+
+    MyActivationListener body_activation_listener = MyActivationListener_Init();
+    JPC_PhysicsSystem_SetBodyActivationListener(physics_system, &body_activation_listener);
+
+    MyContactListener contact_listener = MyContactListener_Init();
+    JPC_PhysicsSystem_SetContactListener(physics_system, &contact_listener);
+    JPC_PhysicsSystem_SetContactListener(physics_system, NULL);
+    JPC_PhysicsSystem_SetContactListener(physics_system, &contact_listener);
+
+    JPC_BoxShapeSettings *floor_shape_settings = JPC_BoxShapeSettings_Create((float[]){ 100.0f, 1.0f, 100.0f });
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)floor_shape_settings) != 1) return 0;
+
+    JPC_Shape *floor_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings *)floor_shape_settings);
+    if (floor_shape == NULL) return 0;
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)floor_shape_settings) != 1) return 0;
+    if (JPC_Shape_GetRefCount(floor_shape) != 2) return 0;
+
+    JPC_BodyCreationSettings floor_settings;
+    JPC_BodyCreationSettings_Set(
+        &floor_settings,
+        floor_shape,
+        (JPC_Real[]){ 0.0f, -1.0f, 0.0f },
+        (float[]){ 0.0f, 0.0f, 0.0f, 1.0f },
+        JPC_MOTION_TYPE_STATIC,
+        OBJ_LAYER_NON_MOVING);
+
+    JPC_BodyInterface *body_interface = JPC_PhysicsSystem_GetBodyInterface(physics_system);
+
+    JPC_Body *floor = JPC_BodyInterface_CreateBody(body_interface, &floor_settings);
+    if (floor == NULL) return 0;
+    const JPC_BodyID floor_id = JPC_Body_GetID(floor);
+    if (((floor_id & JPC_BODY_ID_SEQUENCE_BITS) >> JPC_BODY_ID_SEQUENCE_SHIFT) != 1) return 0;
+    if ((floor_id & JPC_BODY_ID_INDEX_BITS) != 0) return 0;
+    if (JPC_Body_IsStatic(floor) == false) return 0;
+    if (JPC_Body_IsDynamic(floor) == true) return 0;
+
+    if (JPC_Shape_GetRefCount(floor_shape) != 3) return 0;
+
+    JPC_Body *floor1 = JPC_BodyInterface_CreateBody(body_interface, &floor_settings);
+    if (floor1 == NULL) return 0;
+    const JPC_BodyID floor1_id = JPC_Body_GetID(floor1);
+    if (((floor1_id & JPC_BODY_ID_SEQUENCE_BITS) >> JPC_BODY_ID_SEQUENCE_SHIFT) != 1) return 0;
+    if ((floor1_id & JPC_BODY_ID_INDEX_BITS) != 1) return 0;
+
+    if (JPC_BodyInterface_IsAdded(body_interface, floor_id) != false) return 0;
+    if (JPC_BodyInterface_IsAdded(body_interface, floor1_id) != false) return 0;
+
+    JPC_BodyInterface_AddBody(body_interface, floor_id, JPC_ACTIVATION_ACTIVATE);
+    if (JPC_BodyInterface_IsAdded(body_interface, floor_id) != true) return 0;
+
+    JPC_PhysicsSystem_OptimizeBroadPhase(physics_system);
+    JPC_PhysicsUpdateError update_err = JPC_PhysicsSystem_Update(physics_system, 1.0f / 60.0f, 1, 1, temp_allocator, job_system);
+    if (update_err != JPC_PHYSICS_UPDATE_NO_ERROR) return 0;
+
+    JPC_BodyInterface_RemoveBody(body_interface, floor_id);
+    if (JPC_BodyInterface_IsAdded(body_interface, floor_id) != false) return 0;
+
+    if (JPC_Shape_GetRefCount(floor_shape) != 4) return 0;
+
+    if (JPC_ShapeSettings_GetRefCount((JPC_ShapeSettings *)floor_shape_settings) != 1) return 0;
+    JPC_ShapeSettings_Release((JPC_ShapeSettings *)floor_shape_settings);
+    if (JPC_Shape_GetRefCount(floor_shape) != 3) return 0;
+
+    JPC_BodyInterface_DestroyBody(body_interface, floor_id);
+    if (JPC_Shape_GetRefCount(floor_shape) != 2) return 0;
+
+    JPC_BodyInterface_DestroyBody(body_interface, floor1_id);
+    if (JPC_Shape_GetRefCount(floor_shape) != 1) return 0;
+
+    JPC_Shape_Release(floor_shape);
+
+    JPC_PhysicsSystem_Destroy(physics_system);
+    JPC_JobSystem_Destroy(job_system);
+    JPC_TempAllocator_Destroy(temp_allocator);
+
+    JPC_DestroyFactory();
+
+    return 1;
+}
+//--------------------------------------------------------------------------------------------------
+// HelloWorld
+//--------------------------------------------------------------------------------------------------
+uint32_t
+JoltCTest_HelloWorld(void)
+{
+    JPC_RegisterDefaultAllocator();
+    JPC_CreateFactory();
+    JPC_RegisterTypes();
+
+    JPC_TempAllocator *temp_allocator = JPC_TempAllocator_Create(10 * 1024 * 1024);
+    JPC_JobSystem *job_system = JPC_JobSystem_Create(JPC_MAX_PHYSICS_JOBS, JPC_MAX_PHYSICS_BARRIERS, -1);
+
+    const uint32_t max_bodies = 1024;
+    const uint32_t num_body_mutexes = 0;
+    const uint32_t max_body_pairs = 1024;
+    const uint32_t max_contact_constraints = 1024;
+
+    BPLayerInterfaceImpl broad_phase_layer_interface = BPLayerInterface_Init();
+    MyBroadPhaseFilter broad_phase_filter = MyBroadPhaseFilter_Init();
+    MyObjectFilter object_filter = MyObjectFilter_Init();
+
+    JPC_PhysicsSystem *physics_system = JPC_PhysicsSystem_Create(
+        max_bodies,
+        num_body_mutexes,
+        max_body_pairs,
+        max_contact_constraints,
+        &broad_phase_layer_interface,
+        &broad_phase_filter,
+        &object_filter);
+
+    MyActivationListener body_activation_listener = MyActivationListener_Init();
+    JPC_PhysicsSystem_SetBodyActivationListener(physics_system, &body_activation_listener);
+
+    MyContactListener contact_listener = MyContactListener_Init();
+    JPC_PhysicsSystem_SetContactListener(physics_system, &contact_listener);
+
+    JPC_BodyInterface *body_interface = JPC_PhysicsSystem_GetBodyInterface(physics_system);
+
+#if JPC_DEBUG_RENDERER == 1
+    MyDebugRenderer debug_renderer = MyDebugRenderer_Init();
+    enum JPC_DebugRendererResult result = JPC_CreateDebugRendererSingleton(&debug_renderer);
+    assert(result == JPC_DEBUGRENDERER_SUCCESS);
+    JPC_BodyManager_DrawSettings *body_draw_settings = JPC_BodyManager_DrawSettings_Create();
+    JPC_BodyDrawFilter *body_draw_filter = JPC_BodyDrawFilter_Create(&BodyShouldDraw);
+#endif //JPC_DEBUG_RENDERER
+
+    //
+    // Static floor
+    //
+    JPC_BoxShapeSettings *floor_shape_settings = JPC_BoxShapeSettings_Create((float[]){ 100.0, 1.0, 100.0 });
+    JPC_Shape *floor_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings *)floor_shape_settings);
+
+    JPC_BodyCreationSettings floor_settings;
+    JPC_BodyCreationSettings_Set(
+        &floor_settings,
+        floor_shape,
+        (JPC_Real[]){ 0.0f, -1.0f, 0.0f },
+        (float[]){ 0.0f, 0.0f, 0.0f, 1.0f },
+        JPC_MOTION_TYPE_STATIC,
+        OBJ_LAYER_NON_MOVING);
+
+    JPC_Body *floor = JPC_BodyInterface_CreateBody(body_interface, &floor_settings);
+    const JPC_BodyID floor_id = JPC_Body_GetID(floor);
+    JPC_BodyInterface_AddBody(body_interface, floor_id, JPC_ACTIVATION_DONT_ACTIVATE);
+
+    //
+    // Falling sphere
+    //
+    JPC_SphereShapeSettings *sphere_shape_settings = JPC_SphereShapeSettings_Create(0.5f);
+    JPC_Shape *sphere_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings *)sphere_shape_settings);
+
+    JPC_BodyCreationSettings sphere_settings;
+    JPC_BodyCreationSettings_Set(
+        &sphere_settings,
+        sphere_shape,
+        (JPC_Real[]){ 0.0f, 2.0f, 0.0f },
+        (float[]){ 0.0f, 0.0f, 0.0f, 1.0f },
+        JPC_MOTION_TYPE_DYNAMIC,
+        OBJ_LAYER_MOVING);
+
+    const JPC_BodyID sphere_id = JPC_BodyInterface_CreateAndAddBody(
+        body_interface,
+        &sphere_settings,
+        JPC_ACTIVATION_ACTIVATE);
+
+    if (JPC_Body_IsStatic(floor) == false) return 0;
+    if (JPC_Body_IsDynamic(floor) == true) return 0;
+
+    JPC_BodyInterface_SetLinearVelocity(body_interface, sphere_id, (float[]){ 0.0f, -5.0f, 0.0f });
+
+    JPC_PhysicsSystem_OptimizeBroadPhase(physics_system);
+
+    // Test JPC_PhysicsSystem_GetBodyIDs()
+    {
+        JPC_BodyID body_ids[2];
+        uint32_t num_body_ids = 0;
+        JPC_PhysicsSystem_GetBodyIDs(physics_system, 2, &num_body_ids, &body_ids[0]);
+        if (num_body_ids != 2) return 0;
+        if (body_ids[0] != floor_id) return 0;
+        if (body_ids[1] != sphere_id) return 0;
+    }
+
+    // Test JPC_PhysicsSystem_GetActiveBodyIDs()
+    {
+        JPC_BodyID body_ids[2];
+        uint32_t num_body_ids = 0;
+        JPC_PhysicsSystem_GetActiveBodyIDs(physics_system, 2, &num_body_ids, &body_ids[0]);
+        if (num_body_ids != 1) return 0;
+        if (body_ids[0] != sphere_id) return 0;
+    }
+
+#ifdef PRINT_OUTPUT
+    if (sizeof(JPC_Real) == 8)
+        fprintf(stderr, "Using double precision computation...\n");
+#endif
+
+    uint32_t step = 0;
+    while (JPC_BodyInterface_IsActive(body_interface, sphere_id))
+    {
+        step += 1;
+
+        JPC_Real position[3];
+        JPC_BodyInterface_GetCenterOfMassPosition(body_interface, sphere_id, &position[0]);
+
+        float velocity[3];
+        JPC_BodyInterface_GetLinearVelocity(body_interface, sphere_id, &velocity[0]);
+
+        const float delta_time = 1.0f / 60.0f;
+        const int collision_steps = 1;
+        const int integration_sub_steps = 1;
+
+        JPC_PhysicsUpdateError update_err = JPC_PhysicsSystem_Update(
+            physics_system,
+            delta_time,
+            collision_steps,
+            integration_sub_steps,
+            temp_allocator,
+            job_system);
+
+        if (update_err != JPC_PHYSICS_UPDATE_NO_ERROR) {
+            return 0;
+        }
+
+#ifdef PRINT_OUTPUT
+        fprintf(stderr, "Step %d\n\tPosition = (%f, %f, %f), Velocity(%f, %f, %f)\n",
+                step,
+                position[0], position[1], position[2],
+                velocity[0], velocity[1], velocity[2]);
+#endif
+
+        // Safe, lock protected way of accessing all bodies (use when you interact with Jolt from multiple threads).
+        {
+            JPC_BodyID body_ids[16]; // You can use JPC_PhysicsSystem_GetMaxBodies() to pre-allocate storage
+            uint32_t num_body_ids = 0;
+            JPC_PhysicsSystem_GetBodyIDs(physics_system, 16, &num_body_ids, &body_ids[0]);
+
+            const JPC_BodyLockInterface *lock_iface = JPC_PhysicsSystem_GetBodyLockInterface(physics_system);
+            //const JPC_BodyLockInterface *lock_iface = JPC_PhysicsSystem_GetBodyLockInterfaceNoLock(physics_system);
+
+            for (uint32_t i = 0; i < num_body_ids; ++i)
+            {
+                JPC_BodyLockRead lock;
+                JPC_BodyLockInterface_LockRead(lock_iface, body_ids[i], &lock);
+                //JPC_BodyLockWrite lock;
+                //JPC_BodyLockInterface_LockWrite(lock_iface, body_ids[i], &lock);
+                if (lock.body)
+                {
+                    // Body has been locked, you can safely use `JPC_Body_*()` functions.
+                }
+                JPC_BodyLockInterface_UnlockRead(lock_iface, &lock);
+                //JPC_BodyLockInterface_UnlockWrite(lock_iface, &lock);
+            }
+        }
+
+        // Low-level, advanced way of accessing body data. Not protected by a lock, no function calls overhead.
+        // Use when you interact with Jolt only from one thread or when you are sure that JPC_PhysicsSystem_Update()
+        // has already completed in a given frame.
+        {
+            JPC_Body **bodies = JPC_PhysicsSystem_GetBodiesUnsafe(physics_system);
+
+            // Access a single body (get the body pointer from a body id).
+            {
+                JPC_Body *sphere = JPC_TRY_GET_BODY(bodies, sphere_id);
+                if (sphere)
+                {
+                    sphere->friction = 0.2f;
+                }
+            }
+
+            // Access all body pointers.
+            for (uint32_t i = 0; i < JPC_PhysicsSystem_GetNumBodies(physics_system); ++i)
+            {
+                JPC_Body *body = bodies[i];
+                if (JPC_IS_VALID_BODY_POINTER(body))
+                {
+                    // Body pointer is valid (not freed) you can access the data.
+                }
+            }
+        }
+
+        // Test body access.
+        {
+            JPC_Body **bodies = JPC_PhysicsSystem_GetBodiesUnsafe(physics_system);
+
+            const JPC_BodyLockInterface *lock_iface = JPC_PhysicsSystem_GetBodyLockInterface(physics_system);
+
+            JPC_BodyLockRead lock;
+            JPC_BodyLockInterface_LockRead(lock_iface, sphere_id, &lock);
+            if (lock.body)
+            {
+                JPC_Body *body = bodies[sphere_id & JPC_BODY_ID_INDEX_BITS];
+                if (!JPC_IS_VALID_BODY_POINTER(body)) return 0;
+
+                if (JPC_Body_IsDynamic(body) != true) return 0;
+
+                JPC_Body *body_checked = JPC_TRY_GET_BODY(bodies, sphere_id);
+                if (body_checked == NULL) return 0;
+
+                if (body_checked != body) return 0;
+                if (body_checked->id != body->id) return 0;
+
+                if (body != lock.body) return 0;
+                if (body->id != sphere_id) return 0;
+            }
+            JPC_BodyLockInterface_UnlockRead(lock_iface, &lock);
+        }
+
+#if JPC_DEBUG_RENDERER == 1
+        // Test Debug Renderer - should get calls to DrawGeometry each frame, once for floor, once for ball.
+        JPC_PhysicsSystem_DrawBodies(physics_system, body_draw_settings, body_draw_filter);
+#endif // JPC_DEBUG_RENDERER
+
+    }
+
+#if JPC_DEBUG_RENDERER == 1
+    // Test other drawing functions besides DrawBodies at least once at the end
+    JPC_PhysicsSystem_DrawConstraints(physics_system);
+    JPC_PhysicsSystem_DrawConstraintLimits(physics_system);
+    JPC_PhysicsSystem_DrawConstraintReferenceFrame(physics_system);
+#endif // JPC_DEBUG_RENDERER
+
+#if JPC_DEBUG_RENDERER == 1
+    JPC_BodyDrawFilter_Destroy(body_draw_filter);
+    JPC_BodyManager_DrawSettings_Destroy(body_draw_settings);
+    JPC_DestroyDebugRendererSingleton();
+#endif // JPC_DEBUG_RENDERER
+
+    JPC_BodyInterface_RemoveBody(body_interface, sphere_id);
+    JPC_BodyInterface_DestroyBody(body_interface, sphere_id);
+
+    JPC_BodyInterface_RemoveBody(body_interface, floor_id);
+    JPC_BodyInterface_DestroyBody(body_interface, floor_id);
+
+    JPC_ShapeSettings_Release((JPC_ShapeSettings *)floor_shape_settings);
+    if (JPC_Shape_GetRefCount(floor_shape) != 1) return 0;
+    JPC_Shape_Release(floor_shape);
+
+    JPC_ShapeSettings_Release((JPC_ShapeSettings *)sphere_shape_settings);
+    if (JPC_Shape_GetRefCount(sphere_shape) != 1) return 0;
+    JPC_Shape_Release(sphere_shape);
+
+    JPC_PhysicsSystem_Destroy(physics_system);
+    JPC_JobSystem_Destroy(job_system);
+    JPC_TempAllocator_Destroy(temp_allocator);
+
+    JPC_DestroyFactory();
+
+    return 1;
+}
+//--------------------------------------------------------------------------------------------------

+ 1 - 0
JoltPhysics

@@ -0,0 +1 @@
+Subproject commit c1ee107a476e7d7402bd5b09920bcfbafea42500

+ 22 - 0
LICENSE

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

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+# JoltC
+C wrapper for [Jolt Physics](https://github.com/jrouwe/JoltPhysics).
+
+## Other C Wrapper
+Other C wrappers for Jolt Physics include:
+- "JoltC", part of the [zphysics] Zig library started by [Michal Ziulek][michal-ziulek]
+- "JoltC", part of the [jolt-rs] Rust library started by [cohaereo] and a fork of the zphysics C wrapper
+- "joltc", part of the [JoltPhysicsSharp] C# library started by [Amer Koleci][amerkoleci]
+
+The goal of this project is to be the first C wrapper around Jolt Physics that is not part of a larger binding project. It's intended to be useful for any other language-specific bindings and to reduce the need to duplicate work.
+
+## License
+This project began as a fork of the C bindings used by the [zig-gamedev zphysics library][zphysics]. Copyright of portions of this project remain owned by that project's original author, [Michal Ziulek][michal-ziulek].
+
+The copyright of the remaining portions of the project are held by Second Half Games and made available under the terms of the MIT license.
+
+See [LICENSE](LICENSE) for more details.
+
+[zphysics]: https://github.com/zig-gamedev/zig-gamedev/tree/main/libs/zphysics
+[jolt-rs]: https://github.com/cohaereo/jolt-rs
+[JoltPhysicsSharp]: https://github.com/amerkoleci/JoltPhysicsSharp
+[michal-ziulek]: https://github.com/michal-z
+[amerkoleci]: https://github.com/amerkoleci
+[cohaereo]: https://github.com/cohaereo