浏览代码

Document macros, partial implementation of ContactListener interface

Lucien Greathouse 10 月之前
父节点
当前提交
18ada7d0a6
共有 5 个文件被更改,包括 250 次插入18 次删除
  1. 29 7
      JoltC/Enums.h
  2. 111 0
      JoltC/Functions.h
  3. 73 0
      JoltC/JoltC.cpp
  4. 1 0
      JoltC/JoltC.h
  5. 36 11
      JoltC/Test.cpp

+ 29 - 7
JoltC/Enums.h

@@ -6,9 +6,15 @@ const int JPC_MAX_PHYSICS_JOBS = 2048;
 const int JPC_MAX_PHYSICS_BARRIERS = 8;
 const int JPC_MAX_PHYSICS_BARRIERS = 8;
 const float JPC_DEFAULT_COLLISION_TOLERANCE = 1.0e-4f;
 const float JPC_DEFAULT_COLLISION_TOLERANCE = 1.0e-4f;
 const float JPC_DEFAULT_PENETRATION_TOLERANCE = 1.0e-4f;
 const float JPC_DEFAULT_PENETRATION_TOLERANCE = 1.0e-4f;
+const float JPC_DEFAULT_CONVEX_RADIUS = 0.05f;
+const float JPC_CAPSULE_PROJECTION_SLOP = 0.02f;
 
 
-ENSURE_EQUAL(JPC_MAX_PHYSICS_JOBS, JPH::cMaxPhysicsJobs);
-ENSURE_EQUAL(JPC_MAX_PHYSICS_BARRIERS, JPH::cMaxPhysicsBarriers);
+ENSURE_EQUAL(JPC_MAX_PHYSICS_JOBS, JPH::cMaxPhysicsJobs)
+ENSURE_EQUAL(JPC_MAX_PHYSICS_BARRIERS, JPH::cMaxPhysicsBarriers)
+ENSURE_EQUAL(JPC_DEFAULT_COLLISION_TOLERANCE, JPH::cDefaultCollisionTolerance)
+ENSURE_EQUAL(JPC_DEFAULT_PENETRATION_TOLERANCE, JPH::cDefaultPenetrationTolerance)
+ENSURE_EQUAL(JPC_DEFAULT_CONVEX_RADIUS, JPH::cDefaultConvexRadius)
+ENSURE_EQUAL(JPC_CAPSULE_PROJECTION_SLOP, JPH::cCapsuleProjectionSlop)
 
 
 typedef enum JPC_ShapeType: uint8_t {
 typedef enum JPC_ShapeType: uint8_t {
     JPC_SHAPE_TYPE_CONVEX,
     JPC_SHAPE_TYPE_CONVEX,
@@ -231,10 +237,10 @@ ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_REJECT_CONTACT,
 ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_REJECT_ALL_CONTACTS,
 ENSURE_ENUM_EQ(JPC_VALIDATE_RESULT_REJECT_ALL_CONTACTS,
                JPH::ValidateResult::RejectAllContactsForThisBodyPair);
                JPH::ValidateResult::RejectAllContactsForThisBodyPair);
 
 
-typedef enum JPC_BackFaceMode: uint8_t {
-    JPC_BACK_FACE_MODE_IGNORE,
-    JPC_BACK_FACE_MODE_COLLIDE,
-} JPC_BackFaceMode;
+// EBackFaceMode
+typedef uint8_t JPC_BackFaceMode;
+const JPC_BackFaceMode JPC_BACK_FACE_MODE_IGNORE = 0;
+const JPC_BackFaceMode JPC_BACK_FACE_MODE_COLLIDE = 1;
 
 
 ENSURE_ENUM_EQ(JPC_BACK_FACE_MODE_IGNORE, JPH::EBackFaceMode::IgnoreBackFaces)
 ENSURE_ENUM_EQ(JPC_BACK_FACE_MODE_IGNORE, JPH::EBackFaceMode::IgnoreBackFaces)
 ENSURE_ENUM_EQ(JPC_BACK_FACE_MODE_COLLIDE, JPH::EBackFaceMode::CollideWithBackFaces)
 ENSURE_ENUM_EQ(JPC_BACK_FACE_MODE_COLLIDE, JPH::EBackFaceMode::CollideWithBackFaces)
@@ -309,4 +315,20 @@ const JPC_SoftBodyConstraintColor JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_ORDE
 
 
 ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_TYPE, JPH::ESoftBodyConstraintColor::ConstraintType);
 ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_TYPE, JPH::ESoftBodyConstraintColor::ConstraintType);
 ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_GROUP, JPH::ESoftBodyConstraintColor::ConstraintGroup);
 ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_GROUP, JPH::ESoftBodyConstraintColor::ConstraintGroup);
-ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_ORDER, JPH::ESoftBodyConstraintColor::ConstraintOrder);
+ENSURE_ENUM_EQ(JPC_SOFT_BODY_CONSTRAINT_COLOR_CONSTRAINT_ORDER, JPH::ESoftBodyConstraintColor::ConstraintOrder);
+
+// EActiveEdgeMode
+typedef uint8_t JPC_ActiveEdgeMode;
+const JPC_ActiveEdgeMode JPC_ACTIVE_EDGE_MODE_COLLIDE_ONLY_WITH_ACTIVE = 0;
+const JPC_ActiveEdgeMode JPC_ACTIVE_EDGE_MODE_COLLIDE_WITH_ALL = 1;
+
+ENSURE_ENUM_EQ(JPC_ACTIVE_EDGE_MODE_COLLIDE_ONLY_WITH_ACTIVE, JPH::EActiveEdgeMode::CollideOnlyWithActive);
+ENSURE_ENUM_EQ(JPC_ACTIVE_EDGE_MODE_COLLIDE_WITH_ALL, JPH::EActiveEdgeMode::CollideWithAll);
+
+// ECollectFacesMode
+typedef uint8_t JPC_CollectFacesMode;
+const JPC_CollectFacesMode JPC_COLLECT_FACES_MODE_COLLECT_FACES = 0;
+const JPC_CollectFacesMode JPC_COLLECT_FACES_MODE_NO_FACES = 1;
+
+ENSURE_ENUM_EQ(JPC_COLLECT_FACES_MODE_COLLECT_FACES, JPH::ECollectFacesMode::CollectFaces);
+ENSURE_ENUM_EQ(JPC_COLLECT_FACES_MODE_NO_FACES, JPH::ECollectFacesMode::NoFaces);

+ 111 - 0
JoltC/Functions.h

@@ -310,6 +310,117 @@ JPC_API JPC_ObjectLayerPairFilter* JPC_ObjectLayerPairFilter_new(
 
 
 JPC_API void JPC_ObjectLayerPairFilter_delete(JPC_ObjectLayerPairFilter* object);
 JPC_API void JPC_ObjectLayerPairFilter_delete(JPC_ObjectLayerPairFilter* object);
 
 
+////////////////////////////////////////////////////////////////////////////////
+// ContactListener
+
+typedef struct JPC_ContactPoints {
+	uint length;
+	JPC_Vec3 points[64];
+} JPC_ContactPoints;
+
+ENSURE_SIZE_ALIGN(JPC_ContactPoints, JPH::ContactPoints)
+
+typedef struct JPC_ContactManifold {
+	JPC_RVec3 BaseOffset;
+	JPC_Vec3 WorldSpaceNormal;
+	float PenetrationDepth;
+	JPC_SubShapeID SubShapeID1;
+	JPC_SubShapeID SubShapeID2;
+	JPC_ContactPoints RelativeContactPointsOn1;
+	JPC_ContactPoints RelativeContactPointsOn2;
+} JPC_ContactManifold;
+
+ENSURE_SIZE_ALIGN(JPC_ContactManifold, JPH::ContactManifold)
+ENSURE_NORMAL_FIELD(  ContactManifold, BaseOffset)
+ENSURE_NORMAL_FIELD(  ContactManifold, WorldSpaceNormal)
+ENSURE_NORMAL_FIELD(  ContactManifold, PenetrationDepth)
+ENSURE_NORMAL_FIELD(  ContactManifold, SubShapeID1)
+ENSURE_NORMAL_FIELD(  ContactManifold, SubShapeID2)
+ENSURE_NORMAL_FIELD(  ContactManifold, RelativeContactPointsOn1)
+ENSURE_NORMAL_FIELD(  ContactManifold, RelativeContactPointsOn2)
+
+typedef struct JPC_ContactSettings {
+	float CombinedFriction;
+	float CombinedRestitution;
+	float InvMassScale1;
+	float InvInertiaScale1;
+	float InvMassScale2;
+	float InvInertiaScale2;
+	bool IsSensor;
+	JPC_Vec3 RelativeLinearSurfaceVelocity;
+	JPC_Vec3 RelativeAngularSurfaceVelocity;
+} JPC_ContactSettings;
+
+ENSURE_SIZE_ALIGN(JPC_ContactSettings, JPH::ContactSettings)
+ENSURE_NORMAL_FIELD(  ContactSettings, CombinedFriction)
+ENSURE_NORMAL_FIELD(  ContactSettings, CombinedRestitution)
+ENSURE_NORMAL_FIELD(  ContactSettings, InvMassScale1)
+ENSURE_NORMAL_FIELD(  ContactSettings, InvInertiaScale1)
+ENSURE_NORMAL_FIELD(  ContactSettings, InvMassScale2)
+ENSURE_NORMAL_FIELD(  ContactSettings, InvInertiaScale2)
+ENSURE_NORMAL_FIELD(  ContactSettings, IsSensor)
+ENSURE_NORMAL_FIELD(  ContactSettings, RelativeLinearSurfaceVelocity)
+ENSURE_NORMAL_FIELD(  ContactSettings, RelativeAngularSurfaceVelocity)
+
+typedef struct JPC_SubShapeIDPair {
+	JPC_BodyID Body1ID;
+	JPC_SubShapeID SubShapeID1;
+	JPC_BodyID Body2ID;
+	JPC_SubShapeID SubShapeID2;
+} JPC_SubShapeIDPair;
+
+ENSURE_SIZE_ALIGN(JPC_SubShapeIDPair, JPH::SubShapeIDPair)
+
+typedef struct JPC_CollideShapeSettings {
+	// CollideSettingsBase
+	JPC_ActiveEdgeMode ActiveEdgeMode;
+	JPC_CollectFacesMode CollectFacesMode;
+	float CollisionTolerance;
+	float PenetrationTolerance;
+	JPC_Vec3 ActiveEdgeMovementDirection;
+
+	// CollideShapeSettings
+	float MaxSeparationDistance;
+	JPC_BackFaceMode BackFaceMode;
+} JPC_CollideShapeSettings;
+
+ENSURE_SIZE_ALIGN(JPC_CollideShapeSettings, JPH::CollideShapeSettings)
+
+typedef struct JPC_ContactListenerFns {
+	// ValidateResult (*OnContactValidate)(
+	// 	void *self,
+	// 	const Body &inBody1,
+	// 	const Body &inBody2,
+	// 	RVec3Arg inBaseOffset,
+	// 	const CollideShapeResult &inCollisionResult);
+
+	void (*OnContactAdded)(
+		void *self,
+		const JPC_Body *inBody1,
+		const JPC_Body *inBody2,
+		const JPC_ContactManifold *inManifold,
+		JPC_ContactSettings *ioSettings);
+
+	void (*OnContactPersisted)(
+		void *self,
+		const JPC_Body *inBody1,
+		const JPC_Body *inBody2,
+		const JPC_ContactManifold *inManifold,
+		JPC_ContactSettings *ioSettings);
+
+	void (*OnContactRemoved)(
+		void *self,
+		const JPC_SubShapeIDPair *inSubShapePair);
+} JPC_ContactListenerFns;
+
+typedef struct JPC_ContactListener JPC_ContactListener;
+
+JPC_API JPC_ContactListener* JPC_ContactListener_new(
+	void *self,
+	JPC_ContactListenerFns fns);
+
+JPC_API void JPC_ContactListener_delete(JPC_ContactListener* object);
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // CastShapeCollector
 // CastShapeCollector
 
 

+ 73 - 0
JoltC/JoltC.cpp

@@ -7,6 +7,8 @@
 #include <Jolt/Physics/Body/BodyCreationSettings.h>
 #include <Jolt/Physics/Body/BodyCreationSettings.h>
 #include <Jolt/Physics/Collision/CastResult.h>
 #include <Jolt/Physics/Collision/CastResult.h>
 #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
 #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
+#include <Jolt/Physics/Collision/ContactListener.h>
+#include <Jolt/Physics/Collision/CollideShape.h>
 #include <Jolt/Physics/Collision/RayCast.h>
 #include <Jolt/Physics/Collision/RayCast.h>
 #include <Jolt/Physics/Collision/Shape/BoxShape.h>
 #include <Jolt/Physics/Collision/Shape/BoxShape.h>
 #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
 #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
@@ -486,6 +488,77 @@ JPC_API JPC_ObjectLayerPairFilter* JPC_ObjectLayerPairFilter_new(
 	return to_jpc(new JPC_ObjectLayerPairFilterBridge(self, fns));
 	return to_jpc(new JPC_ObjectLayerPairFilterBridge(self, fns));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////////////////
+// JPC_ContactListener
+
+class JPC_ContactListenerBridge final : public JPH::ContactListener {
+public:
+	explicit JPC_ContactListenerBridge(void *self, JPC_ContactListenerFns fns) : self(self), fns(fns) {}
+
+	JPH::ValidateResult OnContactValidate(
+		const JPH::Body &inBody1,
+		const JPH::Body &inBody2,
+		JPH::RVec3Arg inBaseOffset,
+		const JPH::CollideShapeResult &inCollisionResult) override
+	{
+		// if (fns.OnContactValidate != nullptr) {
+		// 	return fns.OnContactValidate(self, to_jpc(inBody1), to_jpc(inBody2), to_jpc(inBaseOffset), to_jpc(inCollisionResult));
+		// }
+
+		return 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 (fns.OnContactAdded != nullptr) {
+			const auto* cManifold = reinterpret_cast<const JPC_ContactManifold*>(&inManifold);
+			auto* cSettings = reinterpret_cast<JPC_ContactSettings*>(&ioSettings);
+
+			fns.OnContactAdded(self, to_jpc(&inBody1), to_jpc(&inBody2), cManifold, cSettings);
+		}
+	}
+
+	void OnContactPersisted(
+		const JPH::Body &inBody1,
+		const JPH::Body &inBody2,
+		const JPH::ContactManifold &inManifold,
+		JPH::ContactSettings &ioSettings) override
+	{
+		if (fns.OnContactPersisted != nullptr) {
+			const auto* cManifold = reinterpret_cast<const JPC_ContactManifold*>(&inManifold);
+			auto* cSettings = reinterpret_cast<JPC_ContactSettings*>(&ioSettings);
+
+			fns.OnContactPersisted(self, to_jpc(&inBody1), to_jpc(&inBody2), cManifold, cSettings);
+		}
+	}
+
+	void OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) override {
+		if (fns.OnContactRemoved != nullptr) {
+			const auto* cSubShapePair = reinterpret_cast<const JPC_SubShapeIDPair*>(&inSubShapePair);
+
+			fns.OnContactRemoved(self, cSubShapePair);
+		}
+	}
+
+private:
+	void* self;
+	JPC_ContactListenerFns fns;
+};
+
+OPAQUE_WRAPPER(JPC_ContactListener, JPC_ContactListenerBridge)
+DESTRUCTOR(JPC_ContactListener)
+
+JPC_API JPC_ContactListener* JPC_ContactListener_new(
+	void *self,
+	JPC_ContactListenerFns fns)
+{
+	return to_jpc(new JPC_ContactListenerBridge(self, fns));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // JPC_CastShapeCollector
 // JPC_CastShapeCollector
 
 

+ 1 - 0
JoltC/JoltC.h

@@ -5,6 +5,7 @@
     #define ENSURE_ENUM_EQ(a, b)
     #define ENSURE_ENUM_EQ(a, b)
     #define ENSURE_SIZE_ALIGN(a, b)
     #define ENSURE_SIZE_ALIGN(a, b)
     #define ENSURE_FIELD(a, b, c, d)
     #define ENSURE_FIELD(a, b, c, d)
+	#define ENSURE_NORMAL_FIELD(a, b)
 #endif
 #endif
 
 
 #include "JoltC/Enums.h"
 #include "JoltC/Enums.h"

+ 36 - 11
JoltC/Test.cpp

@@ -1,20 +1,29 @@
+// Defines macros used for statically verifying the JoltC bindings against the
+// Jolt Physics C++ types.
+//
+// When the JoltC.h header is normally included, these macros are defined to do
+// nothing.
+
 #include <assert.h>
 #include <assert.h>
 #include <stddef.h>
 #include <stddef.h>
 #include <type_traits>
 #include <type_traits>
 
 
 #include <Jolt/Jolt.h>
 #include <Jolt/Jolt.h>
 
 
-#include <Jolt/RegisterTypes.h>
 #include <Jolt/Core/Factory.h>
 #include <Jolt/Core/Factory.h>
-#include <Jolt/Core/TempAllocator.h>
 #include <Jolt/Core/JobSystemThreadPool.h>
 #include <Jolt/Core/JobSystemThreadPool.h>
-#include <Jolt/Physics/PhysicsSettings.h>
-#include <Jolt/Physics/PhysicsSystem.h>
-#include <Jolt/Physics/Collision/Shape/BoxShape.h>
-#include <Jolt/Physics/Collision/Shape/SphereShape.h>
-#include <Jolt/Physics/Body/BodyCreationSettings.h>
+#include <Jolt/Core/TempAllocator.h>
 #include <Jolt/Physics/Body/BodyActivationListener.h>
 #include <Jolt/Physics/Body/BodyActivationListener.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
 #include <Jolt/Physics/Body/BodyManager.h>
 #include <Jolt/Physics/Body/BodyManager.h>
+#include <Jolt/Physics/Collision/ActiveEdgeMode.h>
+#include <Jolt/Physics/Collision/CollectFacesMode.h>
+#include <Jolt/Physics/Collision/CollideShape.h>
+#include <Jolt/Physics/Collision/Shape/BoxShape.h>
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
+#include <Jolt/Physics/PhysicsSettings.h>
+#include <Jolt/Physics/PhysicsSystem.h>
+#include <Jolt/RegisterTypes.h>
 
 
 template<typename E>
 template<typename E>
 constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type 
 constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type 
@@ -24,10 +33,14 @@ constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type
 
 
 #define ENSURE_TESTS
 #define ENSURE_TESTS
 
 
+// Ensures that a constant value defined in JoltC doesn't drift out of sync with
+// its Jolt Physics C++ counterpart.
 #define ENSURE_EQUAL(c_const, cpp_const) \
 #define ENSURE_EQUAL(c_const, cpp_const) \
     static_assert(c_const == cpp_const, #c_const " did not match " #cpp_const); \
     static_assert(c_const == cpp_const, #c_const " did not match " #cpp_const); \
     static_assert(std::is_same_v<decltype(c_const), decltype(cpp_const)>, "type of " #c_const " did not match type of " #cpp_const);
     static_assert(std::is_same_v<decltype(c_const), decltype(cpp_const)>, "type of " #c_const " did not match type of " #cpp_const);
 
 
+// Ensures that a C constant that represents an enum value matches the integral
+// value of a C++ enum.
 #define ENSURE_ENUM_EQ(c_const, cpp_enum) \
 #define ENSURE_ENUM_EQ(c_const, cpp_enum) \
     static_assert(c_const == to_integral(cpp_enum), #c_const " did not match " #cpp_enum); \
     static_assert(c_const == to_integral(cpp_enum), #c_const " did not match " #cpp_enum); \
     static_assert(sizeof(c_const) == sizeof(cpp_enum), #c_const " did not have same size as " #cpp_enum);
     static_assert(sizeof(c_const) == sizeof(cpp_enum), #c_const " did not have same size as " #cpp_enum);
@@ -39,12 +52,24 @@ constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type
     static_assert(alignof(c_type) == alignof(cpp_type), "align of " #c_type " did not match align of " #cpp_type); \
     static_assert(alignof(c_type) == alignof(cpp_type), "align of " #c_type " did not match align of " #cpp_type); \
     static_assert(!std::is_polymorphic_v<cpp_type>, #cpp_type " is polymorphic and cannot be mirrored");
     static_assert(!std::is_polymorphic_v<cpp_type>, #cpp_type " is polymorphic and cannot be mirrored");
 
 
-#define unsafe_offsetof(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
-#define unsafe_fieldtype(st, m) decltype((st *)(0)->m)
+// Internal macro to get the type of a struct field by name.
+#define unsafe_fieldtype(st, m) decltype(((st *)(0))->m)
 
 
+// Ensures that the field offset, size, and alignment of two fields from two
+// different structs are identical.
+//
+// Comparing the offsets and alignments of each field helps provide some guarantee that
 #define ENSURE_FIELD(type0, field0, type1, field1) \
 #define ENSURE_FIELD(type0, field0, type1, field1) \
-    static_assert(unsafe_offsetof(type0, field0) == unsafe_offsetof(type1, field1), \
+    static_assert(offsetof(type0, field0) == offsetof(type1, field1), \
         #type0 "." #field0 " did not have same offset as " #type1 "." #field1); \
         #type0 "." #field0 " did not have same offset as " #type1 "." #field1); \
-    ENSURE_SIZE_ALIGN(unsafe_fieldtype(type0, field0), unsafe_fieldtype(type1, field1));
+    ENSURE_SIZE_ALIGN(unsafe_fieldtype(type0, field0), unsafe_fieldtype(type1, field1)) \
+
+// Just like ENSURE_FIELD, but follows the normal conventions of both JoltC and
+// Jolt Physics to reduce boilerplate.
+//
+// JoltC's types begin with JPC_ while Jolt's types are in the JPH namespace.
+// Jolt prefixes public members with 'm' but JoltC strips that name away.
+#define ENSURE_NORMAL_FIELD(basetype, basefield) \
+    ENSURE_FIELD(JPC_ ## basetype, basefield, JPH:: ## basetype, m ## basefield);
 
 
 #include "JoltC/JoltC.h"
 #include "JoltC/JoltC.h"