Browse Source

Some trigger work

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
d6e8d7cc98

+ 2 - 3
src/anki/physics/Common.cpp

@@ -17,9 +17,8 @@ void PhysicsPtrDeleter::operator()(PhysicsObject* ptr)
 		return;
 	}
 
-	auto alloc = ptr->getAllocator();
-	ptr->~PhysicsObject();
-	alloc.getMemoryPool().free(ptr);
+	PhysicsWorld& world = ptr->getWorld();
+	world.destroyObject(ptr);
 }
 
 } // end namespace anki

+ 2 - 1
src/anki/physics/Common.h

@@ -11,7 +11,7 @@
 #include <anki/Math.h>
 
 #pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Winfinite-recursion"
+#pragma GCC diagnostic ignored "-Wall"
 #define BT_THREADSAFE 0
 #define BT_NO_PROFILE 1
 #include <btBulletCollisionCommon.h>
@@ -51,6 +51,7 @@ public:
 template<typename T>
 using PhysicsPtr = IntrusivePtr<T, PhysicsPtrDeleter>;
 
+using PhysicsObjectPtr = PhysicsPtr<PhysicsObject>;
 using PhysicsCollisionShapePtr = PhysicsPtr<PhysicsCollisionShape>;
 using PhysicsBodyPtr = PhysicsPtr<PhysicsBody>;
 using PhysicsPlayerControllerPtr = PhysicsPtr<PhysicsPlayerController>;

+ 3 - 3
src/anki/physics/PhysicsBody.cpp

@@ -27,7 +27,7 @@ public:
 };
 
 PhysicsBody::PhysicsBody(PhysicsWorld* world, const PhysicsBodyInitInfo& init)
-	: PhysicsObject(PhysicsObjectType::BODY, world)
+	: PhysicsObject(CLASS_TYPE, world)
 {
 	const Bool dynamic = init.m_mass > 0.0f;
 	m_shape = init.m_shape;
@@ -53,7 +53,7 @@ PhysicsBody::PhysicsBody(PhysicsWorld* world, const PhysicsBodyInitInfo& init)
 	m_body->setUserPointer(static_cast<PhysicsObject*>(this));
 
 	// Add to world
-	auto lock = getWorld().lockWorld();
+	auto lock = getWorld().lockBtWorld();
 	getWorld().getBtWorld()->addRigidBody(m_body);
 }
 
@@ -61,7 +61,7 @@ PhysicsBody::~PhysicsBody()
 {
 	if(m_body)
 	{
-		auto lock = getWorld().lockWorld();
+		auto lock = getWorld().lockBtWorld();
 		getWorld().getBtWorld()->removeRigidBody(m_body);
 	}
 

+ 2 - 0
src/anki/physics/PhysicsBody.h

@@ -31,6 +31,8 @@ class PhysicsBody : public PhysicsObject
 	ANKI_PHYSICS_OBJECT
 
 public:
+	static const PhysicsObjectType CLASS_TYPE = PhysicsObjectType::BODY;
+
 	const Transform& getTransform() const
 	{
 		return m_trf;

+ 4 - 1
src/anki/physics/PhysicsCollisionShape.h

@@ -17,6 +17,9 @@ namespace anki
 /// The base of all collision shapes.
 class PhysicsCollisionShape : public PhysicsObject
 {
+public:
+	static const PhysicsObjectType CLASS_TYPE = PhysicsObjectType::COLLISION_SHAPE;
+
 anki_internal:
 	virtual btCollisionShape* getBtShape(Bool forDynamicBodies = false) const
 	{
@@ -28,7 +31,7 @@ protected:
 	btCollisionShape* m_shape = nullptr;
 
 	PhysicsCollisionShape(PhysicsWorld* world)
-		: PhysicsObject(PhysicsObjectType::COLLISION_SHAPE, world)
+		: PhysicsObject(CLASS_TYPE, world)
 	{
 	}
 

+ 1 - 1
src/anki/physics/PhysicsDrawer.cpp

@@ -11,7 +11,7 @@ namespace anki
 
 void PhysicsDrawer::drawWorld(const PhysicsWorld& world)
 {
-	auto lock = world.lockWorld();
+	auto lock = world.lockBtWorld();
 
 	btDynamicsWorld& btWorld = *world.getBtWorld();
 

+ 3 - 3
src/anki/physics/PhysicsJoint.cpp

@@ -11,7 +11,7 @@ namespace anki
 {
 
 PhysicsJoint::PhysicsJoint(PhysicsWorld* world)
-	: PhysicsObject(PhysicsObjectType::JOINT, world)
+	: PhysicsObject(CLASS_TYPE, world)
 {
 }
 
@@ -19,7 +19,7 @@ PhysicsJoint::~PhysicsJoint()
 {
 	if(m_joint)
 	{
-		auto lock = getWorld().lockWorld();
+		auto lock = getWorld().lockBtWorld();
 		getWorld().getBtWorld()->removeConstraint(m_joint);
 	}
 
@@ -31,7 +31,7 @@ void PhysicsJoint::addToWorld()
 	ANKI_ASSERT(m_joint);
 	m_joint->setUserConstraintPtr(static_cast<PhysicsObject*>(this));
 
-	auto lock = getWorld().lockWorld();
+	auto lock = getWorld().lockBtWorld();
 	getWorld().getBtWorld()->addConstraint(m_joint);
 }
 

+ 2 - 0
src/anki/physics/PhysicsJoint.h

@@ -17,6 +17,8 @@ namespace anki
 class PhysicsJoint : public PhysicsObject
 {
 public:
+	static const PhysicsObjectType CLASS_TYPE = PhysicsObjectType::JOINT;
+
 	void setBreakingImpulseThreshold(F32 impulse)
 	{
 		m_joint->setBreakingImpulseThreshold(impulse);

+ 7 - 3
src/anki/physics/PhysicsObject.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/physics/Common.h>
+#include <anki/util/List.h>
 
 namespace anki
 {
@@ -21,11 +22,15 @@ enum class PhysicsObjectType : U8
 	JOINT,
 	PLAYER_CONTROLLER,
 	TRIGGER,
-	COUNT
+
+	COUNT,
+	FIRST = 0,
+	LAST = COUNT - 1
 };
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsObjectType, inline)
 
 /// Base of all physics objects.
-class PhysicsObject
+class PhysicsObject : public IntrusiveListEnabled<PhysicsObject>
 {
 public:
 	PhysicsObject(PhysicsObjectType type, PhysicsWorld* world)
@@ -67,7 +72,6 @@ protected:
 private:
 	Atomic<I32> m_refcount = {0};
 	PhysicsObjectType m_type;
-	void* m_userData = nullptr;
 };
 
 #define ANKI_PHYSICS_OBJECT \

+ 4 - 4
src/anki/physics/PhysicsPlayerController.cpp

@@ -10,7 +10,7 @@ namespace anki
 {
 
 PhysicsPlayerController::PhysicsPlayerController(PhysicsWorld* world, const PhysicsPlayerControllerInitInfo& init)
-	: PhysicsObject(PhysicsObjectType::PLAYER_CONTROLLER, world)
+	: PhysicsObject(CLASS_TYPE, world)
 {
 	const btTransform trf = toBt(Transform(init.m_position.xyz0(), Mat3x4::getIdentity(), 1.0f));
 
@@ -25,7 +25,7 @@ PhysicsPlayerController::PhysicsPlayerController(PhysicsWorld* world, const Phys
 		m_ghostObject, m_convexShape, init.m_stepHeight, btVector3(0, 1, 0));
 
 	{
-		auto lock = getWorld().lockWorld();
+		auto lock = getWorld().lockBtWorld();
 		btDynamicsWorld* btworld = getWorld().getBtWorld();
 
 		btworld->addCollisionObject(m_ghostObject,
@@ -41,7 +41,7 @@ PhysicsPlayerController::PhysicsPlayerController(PhysicsWorld* world, const Phys
 PhysicsPlayerController::~PhysicsPlayerController()
 {
 	{
-		auto lock = getWorld().lockWorld();
+		auto lock = getWorld().lockBtWorld();
 		getWorld().getBtWorld()->removeAction(m_controller);
 		getWorld().getBtWorld()->removeCollisionObject(m_ghostObject);
 	}
@@ -53,7 +53,7 @@ PhysicsPlayerController::~PhysicsPlayerController()
 
 void PhysicsPlayerController::moveToPosition(const Vec4& position)
 {
-	auto lock = getWorld().lockWorld();
+	auto lock = getWorld().lockBtWorld();
 
 	getWorld().getBtWorld()->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(
 		m_ghostObject->getBroadphaseHandle(), getWorld().getBtWorld()->getDispatcher());

+ 2 - 0
src/anki/physics/PhysicsPlayerController.h

@@ -31,6 +31,8 @@ class PhysicsPlayerController final : public PhysicsObject
 	ANKI_PHYSICS_OBJECT
 
 public:
+	static const PhysicsObjectType CLASS_TYPE = PhysicsObjectType::PLAYER_CONTROLLER;
+
 	// Update the state machine
 	void setVelocity(F32 forwardSpeed, F32 strafeSpeed, F32 jumpSpeed, const Vec4& forwardDir)
 	{

+ 39 - 10
src/anki/physics/PhysicsTrigger.cpp

@@ -11,7 +11,7 @@ namespace anki
 {
 
 PhysicsTrigger::PhysicsTrigger(PhysicsWorld* world, PhysicsCollisionShapePtr shape)
-	: PhysicsObject(PhysicsObjectType::TRIGGER, world)
+	: PhysicsObject(CLASS_TYPE, world)
 {
 	m_shape = shape;
 
@@ -21,14 +21,14 @@ PhysicsTrigger::PhysicsTrigger(PhysicsWorld* world, PhysicsCollisionShapePtr sha
 
 	m_ghostShape->setUserPointer(static_cast<PhysicsObject*>(this));
 
-	auto lock = getWorld().lockWorld();
+	auto lock = getWorld().lockBtWorld();
 	getWorld().getBtWorld()->addCollisionObject(m_ghostShape);
 }
 
 PhysicsTrigger::~PhysicsTrigger()
 {
 	{
-		auto lock = getWorld().lockWorld();
+		auto lock = getWorld().lockBtWorld();
 		getWorld().getBtWorld()->removeCollisionObject(m_ghostShape);
 	}
 
@@ -37,16 +37,45 @@ PhysicsTrigger::~PhysicsTrigger()
 
 void PhysicsTrigger::processContacts()
 {
-	// TODO
-#if 0
-	for(U i = 0; i < m_ghostShape->getOverlappingPairCache()->getNumOverlappingPairs(); ++i)
+	if(m_filter == nullptr)
 	{
-		btBroadphasePair* collisionPair = &m_ghostShape->getOverlappingPairCache()->getOverlappingPairArray()[i];
+		return;
+	}
+
+	// Process contacts
+	const U pairCount = m_ghostShape->getOverlappingPairCache()->getNumOverlappingPairs();
+	for(U i = 0; i < pairCount; ++i)
+	{
+		btBroadphasePair& collisionPair = m_ghostShape->getOverlappingPairCache()->getOverlappingPairArray()[i];
+
+		btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair.m_pProxy0->m_clientObject);
+		btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair.m_pProxy1->m_clientObject);
+
+		PhysicsObject* aobj0 = static_cast<PhysicsObject*>(obj0->getUserPointer());
+		PhysicsObject* aobj1 = static_cast<PhysicsObject*>(obj1->getUserPointer());
+
+		if(aobj0 == nullptr || aobj1 == nullptr)
+		{
+			continue;
+		}
+
+		PhysicsObject* otherObj;
+		if(aobj0 == static_cast<PhysicsObject*>(this))
+		{
+			otherObj = aobj1;
+		}
+		else
+		{
+			ANKI_ASSERT(aobj1 == static_cast<PhysicsObject*>(this));
+			otherObj = aobj0;
+		}
 
-		btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
-        btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
+		PhysicsObjectPtr ptr(otherObj);
+		if(!m_filter->skipContact(ptr))
+		{
+			m_filter->processContact(ptr, ConstWeakArray<PhysicsTriggerContact>());
+		}
 	}
-#endif
 }
 
 } // end namespace anki

+ 32 - 0
src/anki/physics/PhysicsTrigger.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/physics/PhysicsObject.h>
+#include <anki/util/WeakArray.h>
 
 namespace anki
 {
@@ -13,25 +14,56 @@ namespace anki
 /// @addtogroup physics
 /// @{
 
+/// @memberof PhysicsTrigger
+class PhysicsTriggerContact
+{
+public:
+	Vec3 m_contactPoint; ///< In world space.
+	Vec3 m_contactNormal; ///< In world space.
+};
+
+/// An interface to process contacts.
+/// @memberof PhysicsTrigger
+class PhysicsTriggerContactFilter
+{
+public:
+	virtual Bool skipContact(const PhysicsObjectPtr& obj) = 0;
+
+	virtual void processContact(const PhysicsObjectPtr& obj, ConstWeakArray<PhysicsTriggerContact> contact) = 0;
+};
+
 /// A trigger that uses a PhysicsShape and its purpose is to collect collision events.
 class PhysicsTrigger : public PhysicsObject
 {
 	ANKI_PHYSICS_OBJECT
 
 public:
+	static const PhysicsObjectType CLASS_TYPE = PhysicsObjectType::TRIGGER;
+
 	void setTransform(const Transform& trf)
 	{
 		m_ghostShape->setWorldTransform(toBt(trf));
 	}
 
+	void setContactFilter(PhysicsTriggerContactFilter* filter)
+	{
+		m_filter = filter;
+	}
+
 private:
+	using Contact = PhysicsTriggerContact;
+
 	PhysicsCollisionShapePtr m_shape;
 	btPairCachingGhostObject* m_ghostShape = nullptr;
 
+	PhysicsTriggerContactFilter* m_filter = nullptr;
+
 	PhysicsTrigger(PhysicsWorld* world, PhysicsCollisionShapePtr shape);
 
 	~PhysicsTrigger();
 
+	void cleanupContacts();
+
 	void processContacts();
 };
 /// @}

+ 40 - 3
src/anki/physics/PhysicsWorld.cpp

@@ -6,6 +6,7 @@
 #include <anki/physics/PhysicsWorld.h>
 #include <anki/physics/PhysicsCollisionShape.h>
 #include <anki/physics/PhysicsBody.h>
+#include <anki/physics/PhysicsTrigger.h>
 #include <BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>
 
 namespace anki
@@ -32,6 +33,13 @@ PhysicsWorld::PhysicsWorld()
 
 PhysicsWorld::~PhysicsWorld()
 {
+#if ANKI_ASSERTS_ENABLED
+	for(PhysicsObjectType type = PhysicsObjectType::FIRST; type < PhysicsObjectType::COUNT; ++type)
+	{
+		ANKI_ASSERT(m_objectLists[type].isEmpty() && "Someone is holding refs to some physics objects");
+	}
+#endif
+
 	m_alloc.deleteInstance(m_world);
 	m_alloc.deleteInstance(m_solver);
 	m_alloc.deleteInstance(m_dispatcher);
@@ -45,6 +53,7 @@ PhysicsWorld::~PhysicsWorld()
 Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData)
 {
 	m_alloc = HeapAllocator<U8>(allocCb, allocCbData);
+	m_tmpAlloc = StackAllocator<U8>(allocCb, allocCbData, 1_KB, 2.0f);
 
 	// Set allocators
 	gAlloc = &m_alloc;
@@ -70,11 +79,39 @@ Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData)
 
 Error PhysicsWorld::update(Second dt)
 {
-	// Update
-	auto lock = lockWorld();
-	m_world->stepSimulation(dt, 2, 1.0 / 60.0);
+	// Update world
+	{
+		auto lock = lockBtWorld();
+		m_world->stepSimulation(dt, 2, 1.0 / 60.0);
+	}
+
+	// Process trigger contacts
+	{
+		LockGuard<Mutex> lock(m_objectListsMtx);
+
+		for(PhysicsObject& trigger : m_objectLists[PhysicsObjectType::TRIGGER])
+		{
+			static_cast<PhysicsTrigger&>(trigger).processContacts();
+		}
+	}
+
+	// Reset the pool
+	m_tmpAlloc.getMemoryPool().reset();
 
 	return Error::NONE;
 }
 
+void PhysicsWorld::destroyObject(PhysicsObject* obj)
+{
+	ANKI_ASSERT(obj);
+
+	{
+		LockGuard<Mutex> lock(m_objectListsMtx);
+		m_objectLists[obj->getType()].erase(obj);
+	}
+
+	obj->~PhysicsObject();
+	m_alloc.getMemoryPool().free(obj);
+}
+
 } // end namespace anki

+ 15 - 8
src/anki/physics/PhysicsWorld.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/physics/Common.h>
+#include <anki/physics/PhysicsObject.h>
 #include <anki/util/List.h>
 
 namespace anki
@@ -28,9 +29,12 @@ public:
 	{
 		void* mem = m_alloc.getMemoryPool().allocate(sizeof(T), alignof(T));
 		::new(mem) T(this, std::forward<TArgs>(args)...);
-		PhysicsPtr<T> out;
-		out.reset(static_cast<T*>(mem));
-		return out;
+
+		T* obj = static_cast<T*>(mem);
+		LockGuard<Mutex> lock(m_objectListsMtx);
+		m_objectLists[obj->getType()].pushBack(obj);
+
+		return PhysicsPtr<T>(obj);
 	}
 
 	/// Do the update.
@@ -58,14 +62,16 @@ anki_internal:
 		return 0.04f;
 	}
 
-	ANKI_USE_RESULT LockGuard<Mutex> lockWorld() const
+	ANKI_USE_RESULT LockGuard<Mutex> lockBtWorld() const
 	{
-		return LockGuard<Mutex>(m_mtx);
+		return LockGuard<Mutex>(m_btWorldMtx);
 	}
 
+	void destroyObject(PhysicsObject* obj);
+
 private:
 	HeapAllocator<U8> m_alloc;
-	mutable Mutex m_mtx;
+	StackAllocator<U8> m_tmpAlloc;
 
 	btBroadphaseInterface* m_broadphase = nullptr;
 	btGhostPairCallback* m_gpc = nullptr;
@@ -74,9 +80,10 @@ private:
 	btCollisionDispatcher* m_dispatcher = nullptr;
 	btSequentialImpulseConstraintSolver* m_solver = nullptr;
 	btDiscreteDynamicsWorld* m_world = nullptr;
+	mutable Mutex m_btWorldMtx;
 
-	template<typename T, typename... TArgs>
-	PhysicsPtr<T> newObjectInternal(TArgs&&... args);
+	Array<IntrusiveList<PhysicsObject>, U(PhysicsObjectType::COUNT)> m_objectLists;
+	mutable Mutex m_objectListsMtx;
 };
 /// @}
 

+ 6 - 0
src/anki/util/List.h

@@ -532,6 +532,12 @@ public:
 		Base::erase(m_alloc, position);
 	}
 
+	/// Destroy the list.
+	void destroy()
+	{
+		Base::destroy(m_alloc);
+	}
+
 private:
 	GenericMemoryPoolAllocator<T> m_alloc;
 

+ 1 - 1
tools/count_lines.sh

@@ -1 +1 @@
-wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./programs ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py' -o -name '*.glslp'`
+wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py' -o -name '*.glslp'`