diff --git a/test/tests/collision/TestCollisionWorld.h b/test/tests/collision/TestCollisionWorld.h old mode 100755 new mode 100644 index ad0c92cf..9161fce7 --- a/test/tests/collision/TestCollisionWorld.h +++ b/test/tests/collision/TestCollisionWorld.h @@ -29,6 +29,7 @@ // Libraries #include "reactphysics3d.h" #include "Test.h" +#include /// Reactphysics3D namespace namespace reactphysics3d { @@ -53,7 +54,7 @@ struct CollisionPointData { penetrationDepth = penDepth; } - bool isContactPointSimilarTo(const Vector3& pointBody1, const Vector3& pointBody2, decimal penDepth, decimal epsilon = 0.001) { + bool isContactPointSimilarTo(const Vector3& pointBody1, const Vector3& pointBody2, decimal penDepth, decimal epsilon = 0.001) const { return approxEqual(pointBody1, localPointBody1, epsilon) && approxEqual(pointBody2, localPointBody2, epsilon) && @@ -70,11 +71,12 @@ struct CollisionManifoldData { return contactPoints.size(); } - bool hasContactPointSimilarTo(const Vector3& localPointBody1, const Vector3& localPointBody2, decimal penetrationDepth, decimal epsilon = 0.001) { + bool hasContactPointSimilarTo(const Vector3& localPointBody1, const Vector3& localPointBody2, decimal penetrationDepth, decimal epsilon = 0.001) const { - std::vector::iterator it; - for (it = contactPoints.begin(); it != contactPoints.end(); ++it) { + std::vector::const_iterator it; + for (it = contactPoints.cbegin(); it != contactPoints.cend(); ++it) { + Vector3 vec = it->localPointBody1; if (it->isContactPointSimilarTo(localPointBody1, localPointBody2, penetrationDepth)) { return true; } @@ -109,10 +111,18 @@ struct CollisionData { return nbPoints; } - bool hasContactPointSimilarTo(const Vector3& localPointBody1, const Vector3& localPointBody2, decimal penetrationDepth, decimal epsilon = 0.001) { + const CollisionBody* getBody1() const { + return bodies.first; + } - std::vector::iterator it; - for (it = contactManifolds.begin(); it != contactManifolds.end(); ++it) { + const CollisionBody* getBody2() const { + return bodies.second; + } + + bool hasContactPointSimilarTo(const Vector3& localPointBody1, const Vector3& localPointBody2, decimal penetrationDepth, decimal epsilon = 0.001) const { + + std::vector::const_iterator it; + for (it = contactManifolds.cbegin(); it != contactManifolds.cend(); ++it) { if (it->hasContactPointSimilarTo(localPointBody1, localPointBody2, penetrationDepth)) { return true; @@ -129,7 +139,7 @@ class WorldCollisionCallback : public CollisionCallback { private: - std::vector> mCollisionData; + std::map, CollisionData> mCollisionDatas; std::pair getCollisionKeyPair(std::pair pair) const { @@ -149,15 +159,25 @@ class WorldCollisionCallback : public CollisionCallback void reset() { - mCollisionData.clear(); + mCollisionDatas.clear(); } bool hasContacts() const { - return mCollisionData.size() > 0; + return mCollisionDatas.size() > 0; } bool areProxyShapesColliding(const ProxyShape* proxyShape1, const ProxyShape* proxyShape2) { - return std::find(mCollisionData.begin(), mCollisionData.end(), getCollisionKeyPair(std::make_pair(proxyShape1, proxyShape2))) != mCollisionData.end(); + return mCollisionDatas.find(getCollisionKeyPair(std::make_pair(proxyShape1, proxyShape2))) != mCollisionDatas.end(); + } + + const CollisionData* getCollisionData(const ProxyShape* proxyShape1, const ProxyShape* proxyShape2) const { + std::map, CollisionData>::const_iterator it = mCollisionDatas.find(getCollisionKeyPair(std::make_pair(proxyShape1, proxyShape2))); + if (it != mCollisionDatas.end()) { + return &(it->second); + } + else { + return nullptr; + } } // This method will be called for each contact @@ -184,6 +204,7 @@ class WorldCollisionCallback : public CollisionCallback } collisionData.contactManifolds.push_back(collisionManifold); + mCollisionDatas.insert(std::make_pair(getCollisionKeyPair(collisionData.proxyShapes), collisionData)); element = element->getNext(); } @@ -195,7 +216,7 @@ class WorldOverlapCallback : public OverlapCallback { private: - CollisionBody* mOverlapBody; + std::vector mOverlapBodies; public: @@ -206,19 +227,19 @@ class WorldOverlapCallback : public OverlapCallback { /// This method will be called for each reported overlapping bodies virtual void notifyOverlap(CollisionBody* collisionBody) override { - + mOverlapBodies.push_back(collisionBody); } void reset() { - mOverlapBody = nullptr; + mOverlapBodies.clear(); } bool hasOverlap() const { - return mOverlapBody != nullptr; + return !mOverlapBodies.empty(); } - CollisionBody* getOverlapBody() { - return mOverlapBody; + std::vector& getOverlapBodies() { + return mOverlapBodies; } }; @@ -240,18 +261,48 @@ class TestCollisionWorld : public Test { CollisionBody* mBoxBody2; CollisionBody* mSphereBody1; CollisionBody* mSphereBody2; + CollisionBody* mCapsuleBody1; + CollisionBody* mCapsuleBody2; + CollisionBody* mConvexMeshBody1; + CollisionBody* mConvexMeshBody2; + CollisionBody* mConcaveMeshBody; // Collision shapes BoxShape* mBoxShape1; BoxShape* mBoxShape2; SphereShape* mSphereShape1; SphereShape* mSphereShape2; + CapsuleShape* mCapsuleShape1; + CapsuleShape* mCapsuleShape2; + ConvexMeshShape* mConvexMeshShape1; + ConvexMeshShape* mConvexMeshShape2; + ConcaveMeshShape* mConcaveMeshShape; // Proxy shapes ProxyShape* mBoxProxyShape1; ProxyShape* mBoxProxyShape2; ProxyShape* mSphereProxyShape1; ProxyShape* mSphereProxyShape2; + ProxyShape* mCapsuleProxyShape1; + ProxyShape* mCapsuleProxyShape2; + ProxyShape* mConvexMeshProxyShape1; + ProxyShape* mConvexMeshProxyShape2; + ProxyShape* mConcaveMeshProxyShape; + + PolygonVertexArray* mConvexMesh1PolygonVertexArray; + PolygonVertexArray* mConvexMesh2PolygonVertexArray; + PolyhedronMesh* mConvexMesh1PolyhedronMesh; + PolyhedronMesh* mConvexMesh2PolyhedronMesh; + PolygonVertexArray::PolygonFace* mConvexMeshPolygonFaces; + + TriangleVertexArray* mConcaveMeshTriangleVertexArray; + Vector3 mConvexMesh1CubeVertices[8]; + Vector3 mConvexMesh2CubeVertices[8]; + int mConvexMeshCubeIndices[24]; + + Vector3 mConcaveMeshPlaneVertices[36]; + int mConcaveMeshPlaneIndices[25 * 2 * 3]; + TriangleMesh* mConcaveTriangleMesh; // Collision callback WorldCollisionCallback mCollisionCallback; @@ -277,7 +328,7 @@ class TestCollisionWorld : public Test { Transform boxTransform2(Vector3(-10, 20, 0), Quaternion::identity()); mBoxBody2 = mWorld->createCollisionBody(boxTransform2); - mBoxShape2 = new BoxShape(Vector3(2, 2, 2)); + mBoxShape2 = new BoxShape(Vector3(4, 2, 8)); mBoxProxyShape2 = mBoxBody2->addCollisionShape(mBoxShape1, Transform::identity()); // ---------- Spheres ---------- // @@ -290,6 +341,107 @@ class TestCollisionWorld : public Test { Transform sphereTransform2(Vector3(20, 20, 0), Quaternion::identity()); mSphereBody2 = mWorld->createCollisionBody(sphereTransform2); mSphereProxyShape2 = mSphereBody2->addCollisionShape(mSphereShape2, Transform::identity()); + + // ---------- Capsules ---------- // + mCapsuleShape1 = new CapsuleShape(2, 6); + Transform capsuleTransform1(Vector3(-10, 0, 0), Quaternion::identity()); + mCapsuleBody1 = mWorld->createCollisionBody(capsuleTransform1); + mCapsuleProxyShape1 = mCapsuleBody1->addCollisionShape(mCapsuleShape1, Transform::identity()); + + mCapsuleShape2 = new CapsuleShape(3, 4); + Transform capsuleTransform2(Vector3(-20, 0, 0), Quaternion::identity()); + mCapsuleBody2 = mWorld->createCollisionBody(capsuleTransform2); + mCapsuleProxyShape2 = mCapsuleBody2->addCollisionShape(mCapsuleShape2, Transform::identity()); + + // ---------- Convex Meshes ---------- // + mConvexMesh1CubeVertices[0] = Vector3(-3, -3, 3); + mConvexMesh1CubeVertices[1] = Vector3(3, -3, 3); + mConvexMesh1CubeVertices[2] = Vector3(3, -3, -3); + mConvexMesh1CubeVertices[3] = Vector3(-3, -3, -3); + mConvexMesh1CubeVertices[4] = Vector3(-3, 3, 3); + mConvexMesh1CubeVertices[5] = Vector3(3, 3, 3); + mConvexMesh1CubeVertices[6] = Vector3(3, 3, -3); + mConvexMesh1CubeVertices[7] = Vector3(-3, 3, -3); + + mConvexMeshCubeIndices[0] = 0; mConvexMeshCubeIndices[1] = 3; mConvexMeshCubeIndices[2] = 2; mConvexMeshCubeIndices[3] = 1; + mConvexMeshCubeIndices[4] = 4; mConvexMeshCubeIndices[5] = 5; mConvexMeshCubeIndices[6] = 6; mConvexMeshCubeIndices[7] = 7; + mConvexMeshCubeIndices[8] = 0; mConvexMeshCubeIndices[9] = 1; mConvexMeshCubeIndices[10] = 5; mConvexMeshCubeIndices[11] = 4; + mConvexMeshCubeIndices[12] = 1; mConvexMeshCubeIndices[13] = 2; mConvexMeshCubeIndices[14] = 6; mConvexMeshCubeIndices[15] = 5; + mConvexMeshCubeIndices[16] = 2; mConvexMeshCubeIndices[17] = 3; mConvexMeshCubeIndices[18] = 7; mConvexMeshCubeIndices[19] = 6; + mConvexMeshCubeIndices[20] = 0; mConvexMeshCubeIndices[21] = 4; mConvexMeshCubeIndices[22] = 7; mConvexMeshCubeIndices[23] = 3; + + mConvexMeshPolygonFaces = new rp3d::PolygonVertexArray::PolygonFace[6]; + rp3d::PolygonVertexArray::PolygonFace* face = mConvexMeshPolygonFaces; + for (int f = 0; f < 6; f++) { + face->indexBase = f * 4; + face->nbVertices = 4; + face++; + } + mConvexMesh1PolygonVertexArray = new rp3d::PolygonVertexArray(8, &(mConvexMesh1CubeVertices[0]), sizeof(Vector3), + &(mConvexMeshCubeIndices[0]), sizeof(int), 6, mConvexMeshPolygonFaces, + rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE, + rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE); + mConvexMesh1PolyhedronMesh = new rp3d::PolyhedronMesh(mConvexMesh1PolygonVertexArray); + mConvexMeshShape1 = new rp3d::ConvexMeshShape(mConvexMesh1PolyhedronMesh); + Transform convexMeshTransform1(Vector3(10, 0, 0), Quaternion::identity()); + mConvexMeshBody1 = mWorld->createCollisionBody(convexMeshTransform1); + mConvexMeshProxyShape1 = mConvexMeshBody1->addCollisionShape(mConvexMeshShape1, Transform::identity()); + + mConvexMesh2CubeVertices[0] = Vector3(-4, -2, 8); + mConvexMesh2CubeVertices[1] = Vector3(4, -2, 8); + mConvexMesh2CubeVertices[2] = Vector3(4, -2, -8); + mConvexMesh2CubeVertices[3] = Vector3(-4, -2, -8); + mConvexMesh2CubeVertices[4] = Vector3(-4, 2, 8); + mConvexMesh2CubeVertices[5] = Vector3(4, 2, 8); + mConvexMesh2CubeVertices[6] = Vector3(4, 2, -8); + mConvexMesh2CubeVertices[7] = Vector3(-4, 2, -8); + + mConvexMesh2PolygonVertexArray = new rp3d::PolygonVertexArray(8, &(mConvexMesh2CubeVertices[0]), sizeof(Vector3), + &(mConvexMeshCubeIndices[0]), sizeof(int), 6, mConvexMeshPolygonFaces, + rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE, + rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE); + mConvexMesh2PolyhedronMesh = new rp3d::PolyhedronMesh(mConvexMesh2PolygonVertexArray); + mConvexMeshShape2 = new rp3d::ConvexMeshShape(mConvexMesh2PolyhedronMesh); + Transform convexMeshTransform2(Vector3(20, 0, 0), Quaternion::identity()); + mConvexMeshBody2 = mWorld->createCollisionBody(convexMeshTransform2); + mConvexMeshProxyShape2 = mConvexMeshBody2->addCollisionShape(mConvexMeshShape2, Transform::identity()); + + // ---------- Concave Meshes ---------- // + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6; j++) { + mConcaveMeshPlaneVertices[i * 6 + j] = Vector3(-2.5f + i, 0, -2.5f + j); + } + } + int triangleIndex = 0; + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + + // Triangle 1 + mConcaveMeshPlaneIndices[triangleIndex * 3] = i * 6 + j; + mConcaveMeshPlaneIndices[triangleIndex * 3 + 1] = (i+1) * 6 + (j+1); + mConcaveMeshPlaneIndices[triangleIndex * 3 + 2] = i * 6 + (j+1); + triangleIndex++; + + // Triangle 2 + mConcaveMeshPlaneIndices[triangleIndex * 3] = i * 6 + j; + mConcaveMeshPlaneIndices[triangleIndex * 3 + 1] = (i+1) * 6 + j; + mConcaveMeshPlaneIndices[triangleIndex * 3 + 2] = (i+1) * 6 + (j+1); + triangleIndex++; + } + } + + mConcaveMeshTriangleVertexArray = new rp3d::TriangleVertexArray(36, &(mConcaveMeshPlaneVertices[0]), sizeof(Vector3), + 25, &(mConcaveMeshPlaneIndices[0]), 3 * sizeof(int), + rp3d::TriangleVertexArray::VertexDataType::VERTEX_FLOAT_TYPE, + rp3d::TriangleVertexArray::IndexDataType::INDEX_INTEGER_TYPE); + + // Add the triangle vertex array of the subpart to the triangle mesh + Transform concaveMeshTransform(Vector3(0, -20, 0), Quaternion::identity()); + mConcaveTriangleMesh = new TriangleMesh(); + mConcaveTriangleMesh->addSubpart(mConcaveMeshTriangleVertexArray); + mConcaveMeshShape = new rp3d::ConcaveMeshShape(mConcaveTriangleMesh); + mConcaveMeshBody = mWorld->createCollisionBody(concaveMeshTransform); + mConcaveMeshProxyShape = mConcaveMeshBody->addCollisionShape(mConcaveMeshShape, rp3d::Transform::identity()); } /// Destructor @@ -301,6 +453,21 @@ class TestCollisionWorld : public Test { delete mSphereShape1; delete mSphereShape2; + delete mCapsuleShape1; + delete mCapsuleShape2; + + delete mConvexMeshShape1; + delete mConvexMeshShape2; + delete mConvexMesh1PolyhedronMesh; + delete mConvexMesh2PolyhedronMesh; + delete mConvexMesh1PolygonVertexArray; + delete mConvexMesh2PolygonVertexArray; + delete mConvexMeshPolygonFaces; + + delete mConcaveMeshShape; + delete mConcaveTriangleMesh; + delete mConcaveMeshTriangleVertexArray; + delete mWorld; } @@ -311,10 +478,10 @@ class TestCollisionWorld : public Test { testNoOverlap(); testNoAABBOverlap(); - testAABBOverlap(); - testSphereVsSphereCollision(); testSphereVsBoxCollision(); + testSphereVsCapsuleCollision(); + testSphereVsConvexMeshCollision(); testMultipleCollisions(); } @@ -373,7 +540,6 @@ class TestCollisionWorld : public Test { mCollisionCallback.reset(); mWorld->testCollision(mBoxBody2, mSphereBody2, &mCollisionCallback); test(!mCollisionCallback.hasContacts()); - } void testNoOverlap() { @@ -424,72 +590,1030 @@ class TestCollisionWorld : public Test { test(!mWorld->testAABBOverlap(mBoxBody2, mSphereBody2)); } - void testAABBOverlap() { - - // TODO : Test the CollisionWorld::testAABBOverlap() method here - } - void testSphereVsSphereCollision() { + Transform initTransform1 = mSphereBody1->getTransform(); + Transform initTransform2 = mSphereBody2->getTransform(); + Transform transform1(Vector3(10, 20, 50), Quaternion::identity()); + Transform transform2(Vector3(17, 20, 50), Quaternion::fromEulerAngles(rp3d::PI / 8.0f, rp3d::PI / 4.0f, rp3d::PI / 16.0f)); - // Move sphere 1 to collide with sphere 2 - mSphereBody1->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity())); + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mSphereBody2->setTransform(transform2); + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mSphereBody2)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody2, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mSphereProxyShape2)); + + // Get collision data + const CollisionData* collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mSphereProxyShape2); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + bool swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + Vector3 localBody1Point(3, 0, 0); + Vector3 localBody2Point = transform2.getInverse() * Vector3(12, 20, 50); + decimal penetrationDepth = 1.0f; + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mSphereProxyShape2)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mSphereProxyShape2); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody2, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mSphereProxyShape2)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mSphereProxyShape2); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mSphereBody2, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mSphereProxyShape2)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mSphereProxyShape2); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // Reset the init transforms + mSphereBody1->setTransform(initTransform1); + mSphereBody2->setTransform(initTransform2); } void testSphereVsBoxCollision() { - // Move sphere 1 to collide with box - mSphereBody1->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity())); + Transform initTransform1 = mSphereBody1->getTransform(); + Transform initTransform2 = mBoxBody1->getTransform(); - // --------- Test collision with inactive bodies --------- // + /******************************************************************************** + * Test Sphere vs Box Face collision * + *********************************************************************************/ - mCollisionCallback.reset(); - mBoxBody1->setIsActive(false); - mSphereBody1->setIsActive(false); - mSphereBody2->setIsActive(false); - mWorld->testCollision(&mCollisionCallback); - + Transform transform1(Vector3(10, 20, 50), Quaternion::identity()); + Transform transform2(Vector3(14, 20, 50), Quaternion::identity()); - mBoxBody1->setIsActive(true); - mSphereBody1->setIsActive(true); - mSphereBody2->setIsActive(true); + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mBoxBody1->setTransform(transform2); - // --------- Test collision with collision filtering -------- // + // ----- Test AABB overlap ----- // - //mBoxProxyShape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_3); - //mSphere1ProxyShape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_2); - //mSphere2ProxyShape->setCollideWithMaskBits(CATEGORY_1); + test(mWorld->testAABBOverlap(mSphereBody1, mBoxBody1)); - //mCollisionCallback.reset(); - //mWorld->testCollision(&mCollisionCallback); - //test(mCollisionCallback.boxCollideWithSphere1); - //test(!mCollisionCallback.sphere1CollideWithSphere2); + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); - //// Move sphere 1 to collide with sphere 2 - //mSphere1Body->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity())); + mOverlapCallback.reset(); + mWorld->testOverlap(mBoxBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); - //mCollisionCallback.reset(); - //mWorld->testCollision(&mCollisionCallback); - //test(!mCollisionCallback.boxCollideWithSphere1); - //test(mCollisionCallback.sphere1CollideWithSphere2); + // ----- Test global collision test ----- // - //mBoxProxyShape->setCollideWithMaskBits(CATEGORY_2); - //mSphere1ProxyShape->setCollideWithMaskBits(CATEGORY_2); - //mSphere2ProxyShape->setCollideWithMaskBits(CATEGORY_3); + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); - //mCollisionCallback.reset(); - //mWorld->testCollision(&mCollisionCallback); - //test(!mCollisionCallback.boxCollideWithSphere1); - //test(!mCollisionCallback.sphere1CollideWithSphere2); + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); - //// Move sphere 1 to collide with box - //mSphere1Body->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity())); + // Get collision data + const CollisionData* collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); - //mBoxProxyShape->setCollideWithMaskBits(0xFFFF); - //mSphere1ProxyShape->setCollideWithMaskBits(0xFFFF); - //mSphere2ProxyShape->setCollideWithMaskBits(0xFFFF); + // True if the bodies are swapped in the collision callback response + bool swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + Vector3 localBody1Point(3, 0, 0); + Vector3 localBody2Point(-3, 0, 0); + decimal penetrationDepth = 2.0f; + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + /******************************************************************************** + * Test Sphere vs Box Edge collision * + *********************************************************************************/ + + transform1 = Transform(Vector3(10, 20, 50), Quaternion::identity()); + transform2 = Transform(Vector3(14, 16, 50), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mBoxBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mBoxBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mBoxBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + localBody1Point = std::sqrt(4.5f) * Vector3(1, -1, 0); + localBody2Point = Vector3(-3, 3, 0); + penetrationDepth = decimal(3.0) - std::sqrt(2); + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + /******************************************************************************** + * Test Sphere vs Box Vertex collision * + *********************************************************************************/ + + transform1 = Transform(Vector3(10, 20, 50), Quaternion::identity()); + transform2 = Transform(Vector3(14, 16, 46), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mBoxBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mBoxBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mBoxBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + localBody1Point = std::sqrt(9.0f / 3.0f) * Vector3(1, -1, -1); + localBody2Point = Vector3(-3, 3, 3); + penetrationDepth = decimal(3.0) - std::sqrt(3); + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mBoxBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mBoxProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mBoxProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // Reset the init transforms + mSphereBody1->setTransform(initTransform1); + mBoxBody1->setTransform(initTransform2); + } + + void testSphereVsCapsuleCollision() { + + Transform initTransform1 = mSphereBody1->getTransform(); + Transform initTransform2 = mCapsuleBody1->getTransform(); + + /******************************************************************************** + * Test Sphere vs Capsule (sphere side) collision * + *********************************************************************************/ + + Transform transform1(Vector3(10, 20, 50), Quaternion::identity()); + Transform transform2(Vector3(10, 14, 50), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mCapsuleBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mCapsuleBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mCapsuleBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + const CollisionData* collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + bool swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + Vector3 localBody1Point(0, -3, 0); + Vector3 localBody2Point(0, 5, 0); + decimal penetrationDepth = 2.0f; + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mCapsuleBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mCapsuleBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + /******************************************************************************** + * Test Sphere vs Box Capsule (cylinder side) collision * + *********************************************************************************/ + + transform1 = Transform(Vector3(10, 20, 50), Quaternion::identity()); + transform2 = Transform(Vector3(14, 19, 50), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mCapsuleBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mCapsuleBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mCapsuleBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + localBody1Point = Vector3(3, 0, 0); + localBody2Point = Vector3(-2, 1, 0); + penetrationDepth = decimal(1.0); + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mCapsuleBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mCapsuleBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mCapsuleProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mCapsuleProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // Reset the init transforms + mSphereBody1->setTransform(initTransform1); + mCapsuleBody1->setTransform(initTransform2); + } + + void testSphereVsConvexMeshCollision() { + + Transform initTransform1 = mSphereBody1->getTransform(); + Transform initTransform2 = mConvexMeshBody1->getTransform(); + + /******************************************************************************** + * Test Sphere vs Convex Mesh (Cube Face) collision * + *********************************************************************************/ + + Transform transform1(Vector3(10, 20, 50), Quaternion::identity()); + Transform transform2(Vector3(14, 20, 50), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mConvexMeshBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mConvexMeshBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mConvexMeshBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + const CollisionData* collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + bool swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + Vector3 localBody1Point(3, 0, 0); + Vector3 localBody2Point(-3, 0, 0); + decimal penetrationDepth = 2.0f; + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + /******************************************************************************** + * Test Sphere vs Convex Mesh (Cube Edge) collision * + *********************************************************************************/ + + transform1 = Transform(Vector3(10, 20, 50), Quaternion::identity()); + transform2 = Transform(Vector3(14, 16, 50), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mConvexMeshBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mConvexMeshBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mConvexMeshBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + localBody1Point = std::sqrt(4.5f) * Vector3(1, -1, 0); + localBody2Point = Vector3(-3, 3, 0); + penetrationDepth = decimal(3.0) - std::sqrt(2); + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + /******************************************************************************** + * Test Sphere vs ConvexMesh (Cube Vertex) collision * + *********************************************************************************/ + + transform1 = Transform(Vector3(10, 20, 50), Quaternion::identity()); + transform2 = Transform(Vector3(14, 16, 46), Quaternion::identity()); + + // Move spheres to collide with each other + mSphereBody1->setTransform(transform1); + mConvexMeshBody1->setTransform(transform2); + + // ----- Test AABB overlap ----- // + + test(mWorld->testAABBOverlap(mSphereBody1, mConvexMeshBody1)); + + mOverlapCallback.reset(); + mWorld->testOverlap(mSphereBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + mOverlapCallback.reset(); + mWorld->testOverlap(mConvexMeshBody1, &mOverlapCallback); + test(mOverlapCallback.hasOverlap()); + + // ----- Test global collision test ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + localBody1Point = std::sqrt(9.0f / 3.0f) * Vector3(1, -1, -1); + localBody2Point = Vector3(-3, 3, 3); + penetrationDepth = decimal(3.0) - std::sqrt(3); + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 1 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against body 2 only ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // ----- Test collision against selected body 1 and 2 ----- // + + mCollisionCallback.reset(); + mWorld->testCollision(mSphereBody1, mConvexMeshBody1, &mCollisionCallback); + + test(mCollisionCallback.areProxyShapesColliding(mSphereProxyShape1, mConvexMeshProxyShape1)); + + // Get collision data + collisionData = mCollisionCallback.getCollisionData(mSphereProxyShape1, mConvexMeshProxyShape1); + test(collisionData != nullptr); + test(collisionData->getNbContactManifolds() == 1); + test(collisionData->getTotalNbContactPoints() == 1); + + // True if the bodies are swapped in the collision callback response + swappedBodiesCollisionData = collisionData->getBody1()->getID() != mSphereBody1->getID(); + + // Test contact points + test(collisionData->hasContactPointSimilarTo(swappedBodiesCollisionData ? localBody2Point : localBody1Point, + swappedBodiesCollisionData ? localBody1Point : localBody2Point, + penetrationDepth)); + + // Reset the init transforms + mSphereBody1->setTransform(initTransform1); + mConvexMeshBody1->setTransform(initTransform2); } void testMultipleCollisions() {