From 3da146eb84f7e2723fb914361d933bf29ed3bae0 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 4 Nov 2014 22:38:40 +0100 Subject: [PATCH] Implement world ray casting query --- CMakeLists.txt | 1 + src/body/CollisionBody.cpp | 2 + src/collision/BroadPhasePair.h | 2 - src/collision/CollisionDetection.h | 14 + src/collision/RaycastInfo.cpp | 49 + src/collision/RaycastInfo.h | 51 + .../broadphase/BroadPhaseAlgorithm.h | 9 + src/collision/broadphase/DynamicAABBTree.cpp | 73 ++ src/collision/broadphase/DynamicAABBTree.h | 9 + src/engine/CollisionWorld.cpp | 6 - src/engine/CollisionWorld.h | 10 +- src/mathematics/Vector2.h | 18 + src/mathematics/Vector3.h | 20 + test/tests/collision/TestRaycast.h | 1000 ++++++++++++----- test/tests/mathematics/TestVector2.h | 6 + test/tests/mathematics/TestVector3.h | 6 + 16 files changed, 1002 insertions(+), 274 deletions(-) create mode 100644 src/collision/RaycastInfo.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 177b5e19..4c25e0c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/BroadPhasePair.h" "src/collision/BroadPhasePair.cpp" "src/collision/RaycastInfo.h" + "src/collision/RaycastInfo.cpp" "src/collision/ProxyShape.h" "src/collision/ProxyShape.cpp" "src/collision/CollisionDetection.h" diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 2cb32c8e..921268ef 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -222,6 +222,8 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { // For each collision shape of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + // TODO : Test for broad-phase hit for each shape before testing actual shape raycast + // Test if the ray hits the collision shape if (shape->raycast(rayTemp, raycastInfo)) { rayTemp.maxFraction = raycastInfo.hitFraction; diff --git a/src/collision/BroadPhasePair.h b/src/collision/BroadPhasePair.h index 493332b5..a6edeaf8 100644 --- a/src/collision/BroadPhasePair.h +++ b/src/collision/BroadPhasePair.h @@ -80,8 +80,6 @@ struct BroadPhasePair { bool operator!=(const BroadPhasePair& broadPhasePair2) const; }; - - // Return the pair of bodies index inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const { diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index cedf69fd..f41655ef 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -142,6 +142,9 @@ class CollisionDetection { /// Compute the collision detection void computeCollisionDetection(); + /// Ray casting method + void raycast(RaycastCallback* raycastCallback, const Ray& ray) const; + /// Allow the broadphase to notify the collision detection about an overlapping pair. void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); @@ -200,6 +203,17 @@ inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, con mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb, displacement); } +// Ray casting method +inline void CollisionDetection::raycast(RaycastCallback* raycastCallback, + const Ray& ray) const { + + RaycastTest rayCastTest(raycastCallback); + + // Ask the broad-phase algorithm to call the testRaycastAgainstShape() + // callback method for each proxy shape hit by the ray in the broad-phase + mBroadPhaseAlgorithm.raycast(ray, rayCastTest); +} + } #endif diff --git a/src/collision/RaycastInfo.cpp b/src/collision/RaycastInfo.cpp new file mode 100644 index 00000000..ef728efe --- /dev/null +++ b/src/collision/RaycastInfo.cpp @@ -0,0 +1,49 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "decimal.h" +#include "RaycastInfo.h" +#include "ProxyShape.h" + +using namespace reactphysics3d; + +// Ray cast test against a proxy shape +decimal RaycastTest::raycastAgainstShape(ProxyShape* shape, const Ray& ray) { + + // Ray casting test against the collision shape + RaycastInfo raycastInfo; + bool isHit = shape->raycast(ray, raycastInfo); + + // If the ray hit the collision shape + if (isHit) { + + // Report the hit to the user and return the + // user hit fraction value + return userCallback->notifyRaycastHit(raycastInfo); + } + + return ray.maxFraction; +} diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index fc08aaf4..3eb4de42 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -28,6 +28,7 @@ // Libraries #include "mathematics/Vector3.h" +#include "mathematics/Ray.h" /// ReactPhysics3D namespace namespace reactphysics3d { @@ -86,6 +87,56 @@ struct RaycastInfo { } }; +// Class RaycastCallback +/** + * This class can be used to register a callback for ray casting queries. + * You should implement your own class inherited from this one and implement + * the notifyRaycastHit() method. This method will be called for each ProxyShape + * that is hit by the ray. + */ +class RaycastCallback { + + public: + + // -------------------- Methods -------------------- // + + /// Destructor + virtual ~RaycastCallback() { + + } + + /// This method will be called for each ProxyShape that is hit by the + /// ray. You cannot make any assumptions about the order of the + /// calls. You should use the return value to control the continuation + /// of the ray. The return value is the next maxFraction value to use. + /// If you return a fraction of 0.0, it means that the raycast should + /// terminate. If you return a fraction of 1.0, it indicates that the + /// ray is not clipped and the ray cast should continue as if no hit + /// occurred. If you return the fraction in the parameter (hitFraction + /// value in the RaycastInfo object), the current ray will be clipped + /// to this fraction in the next queries. If you return -1.0, it will + /// ignore this ProxyShape and continue the ray cast. + virtual decimal notifyRaycastHit(const RaycastInfo& raycastInfo)=0; + +}; + +/// Structure RaycastTest +struct RaycastTest { + + public: + + /// User callback class + RaycastCallback* userCallback; + + /// Constructor + RaycastTest(RaycastCallback* callback) { + userCallback = callback; + } + + /// Ray cast test against a proxy shape + decimal raycastAgainstShape(ProxyShape* shape, const Ray& ray); +}; + } #endif diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 31bfffea..6e4e8737 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -157,6 +157,9 @@ class BroadPhaseAlgorithm { /// Return true if the two broad-phase collision shapes are overlapping bool testOverlappingShapes(ProxyShape* shape1, ProxyShape* shape2) const; + + /// Ray casting method + void raycast(const Ray& ray, RaycastTest& raycastTest) const; }; // Method used to compare two pairs for sorting algorithm @@ -180,6 +183,12 @@ inline bool BroadPhaseAlgorithm::testOverlappingShapes(ProxyShape* shape1, return aabb1.testCollision(aabb2); } +// Ray casting method +inline void BroadPhaseAlgorithm::raycast(const Ray& ray, + RaycastTest& raycastTest) const { + mDynamicAABBTree.raycast(ray, raycastTest); +} + } #endif diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index aa2a7a09..886d4279 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -605,6 +605,79 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } } +// Ray casting method +void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const { + + decimal maxFraction = ray.maxFraction; + + // Create an AABB for the ray + Vector3 endPoint = ray.point1 + + maxFraction * (ray.point2 - ray.point1); + AABB rayAABB(Vector3::min(ray.point1, endPoint), + Vector3::max(ray.point1, endPoint)); + + Stack stack; + stack.push(mRootNodeID); + + // Walk through the tree from the root looking for proxy shapes + // that overlap with the ray AABB + while (stack.getNbElements() > 0) { + + // Get the next node in the stack + int nodeID = stack.pop(); + + // If it is a null node, skip it + if (nodeID == TreeNode::NULL_TREE_NODE) continue; + + // Get the corresponding node + const TreeNode* node = mNodes + nodeID; + + // Test if the node AABB overlaps with the ray AABB + if (!rayAABB.testCollision(node->aabb)) continue; + + // If the node is a leaf of the tree + if (node->isLeaf()) { + + Ray rayTemp(ray.point1, ray.point2, maxFraction); + + // Ask the collision detection to perform a ray cast test against + // the proxy shape of this node because the ray is overlapping + // with the shape in the broad-phase + decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape, + rayTemp); + + // If the user returned a hitFraction of zero, it means that + // the raycasting should stop here + if (hitFraction == decimal(0.0)) { + return; + } + + // If the user returned a positive fraction + if (hitFraction > decimal(0.0)) { + + // We update the maxFraction value and the ray + // AABB using the new maximum fraction + if (hitFraction < maxFraction) { + maxFraction = hitFraction; + } + endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1); + rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint); + rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint); + } + + // If the user returned a negative fraction, we continue + // the raycasting as if the proxy shape did not exist + + } + else { // If the node has children + + // Push its children in the stack of nodes to explore + stack.push(node->leftChildID); + stack.push(node->rightChildID); + } + } +} + #ifndef NDEBUG // Check if the tree structure is valid (for debugging purpose) diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index e4d07a83..49591632 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -36,6 +36,12 @@ namespace reactphysics3d { // Declarations class BroadPhaseAlgorithm; +struct RaycastTest; + +// Raycast callback method pointer type +typedef decimal (*RaycastTestCallback) (ProxyShape* shape, + RaycastCallback* userCallback, + const Ray& ray); // Structure TreeNode /** @@ -160,6 +166,9 @@ class DynamicAABBTree { /// Report all shapes overlapping with the AABB given in parameter. void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb); + + /// Ray casting method + void raycast(const Ray& ray, RaycastTest& raycastTest) const; }; // Return true if the node is a leaf of the tree diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index 1d687745..c15f70d1 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -166,10 +166,4 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { } } -/// Raycast method with feedback information -bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo) { - // TODO : Implement this method - return false; -} - diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 59cf6bae..17ae3862 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -120,8 +120,8 @@ class CollisionWorld { /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); - /// Raycast method with feedback information - bool raycast(const Ray& ray, RaycastInfo& raycastInfo); + /// Ray cast method + void raycast(const Ray& ray, RaycastCallback* raycastCallback) const; // -------------------- Friendship -------------------- // @@ -141,6 +141,12 @@ inline std::set::iterator CollisionWorld::getBodiesEndIterator() return mBodies.end(); } +// Ray cast method +inline void CollisionWorld::raycast(const Ray& ray, + RaycastCallback* raycastCallback) const { + mCollisionDetection.raycast(raycastCallback, ray); +} + } #endif diff --git a/src/mathematics/Vector2.h b/src/mathematics/Vector2.h index fc310a7a..1a57fc51 100644 --- a/src/mathematics/Vector2.h +++ b/src/mathematics/Vector2.h @@ -132,6 +132,12 @@ struct Vector2 { /// Overloaded operator Vector2& operator=(const Vector2& vector); + /// Return a vector taking the minimum components of two vectors + static Vector2 min(const Vector2& vector1, const Vector2& vector2); + + /// Return a vector taking the maximum components of two vectors + static Vector2 max(const Vector2& vector1, const Vector2& vector2); + // -------------------- Friends -------------------- // friend Vector2 operator+(const Vector2& vector1, const Vector2& vector2); @@ -291,6 +297,18 @@ inline Vector2& Vector2::operator=(const Vector2& vector) { return *this; } +// Return a vector taking the minimum components of two vectors +inline Vector2 Vector2::min(const Vector2& vector1, const Vector2& vector2) { + return Vector2(std::min(vector1.x, vector2.x), + std::min(vector1.y, vector2.y)); +} + +// Return a vector taking the maximum components of two vectors +inline Vector2 Vector2::max(const Vector2& vector1, const Vector2& vector2) { + return Vector2(std::max(vector1.x, vector2.x), + std::max(vector1.y, vector2.y)); +} + } #endif diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index 7595dd92..50fe2b10 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -138,6 +138,12 @@ struct Vector3 { /// Overloaded operator Vector3& operator=(const Vector3& vector); + /// Return a vector taking the minimum components of two vectors + static Vector3 min(const Vector3& vector1, const Vector3& vector2); + + /// Return a vector taking the maximum components of two vectors + static Vector3 max(const Vector3& vector1, const Vector3& vector2); + // -------------------- Friends -------------------- // friend Vector3 operator+(const Vector3& vector1, const Vector3& vector2); @@ -312,6 +318,20 @@ inline Vector3& Vector3::operator=(const Vector3& vector) { return *this; } +// Return a vector taking the minimum components of two vectors +inline Vector3 Vector3::min(const Vector3& vector1, const Vector3& vector2) { + return Vector3(std::min(vector1.x, vector2.x), + std::min(vector1.y, vector2.y), + std::min(vector1.z, vector2.z)); +} + +// Return a vector taking the maximum components of two vectors +inline Vector3 Vector3::max(const Vector3& vector1, const Vector3& vector2) { + return Vector3(std::max(vector1.x, vector2.x), + std::max(vector1.y, vector2.y), + std::max(vector1.z, vector2.z)); +} + } #endif diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index e5495ac3..b89b4264 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -40,6 +40,45 @@ /// Reactphysics3D namespace namespace reactphysics3d { +/// Class WorldRaycastCallback +class WorldRaycastCallback : public RaycastCallback { + + public: + + RaycastInfo raycastInfo; + ProxyShape* shapeToTest; + bool isHit; + + WorldRaycastCallback() { + isHit = false; + shapeToTest = NULL; + } + + virtual decimal notifyRaycastHit(const RaycastInfo& info) { + + if (shapeToTest->getBody()->getID() == info.body->getID()) { + raycastInfo.body = info.body; + raycastInfo.hitFraction = info.hitFraction; + raycastInfo.proxyShape = info.proxyShape; + raycastInfo.worldNormal = info.worldNormal; + raycastInfo.worldPoint = info.worldPoint; + isHit = true; + } + + // Return a fraction of 1.0 because we need to gather all hits + return decimal(1.0); + } + + void reset() { + raycastInfo.body = NULL; + raycastInfo.hitFraction = decimal(0.0); + raycastInfo.proxyShape = NULL; + raycastInfo.worldNormal.setToZero(); + raycastInfo.worldPoint.setToZero(); + isHit = false; + } +}; + // Class TestPointInside /** * Unit test for the CollisionBody::testPointInside() method. @@ -50,6 +89,9 @@ class TestRaycast : public Test { // ---------- Atributes ---------- // + // Raycast callback class + WorldRaycastCallback callback; + // Epsilon decimal epsilon; @@ -80,6 +122,8 @@ class TestRaycast : public Test { ProxyShape* mConvexMeshShape; ProxyShape* mConvexMeshShapeEdgesInfo; ProxyShape* mCylinderShape; + ProxyShape* mCompoundSphereShape; + ProxyShape* mCompoundCylinderShape; public : @@ -174,8 +218,8 @@ class TestRaycast : public Test { Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Transform shapeTransform2(positionShape2, orientationShape2); mLocalShape2ToWorld = mBodyTransform * shapeTransform2; - mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); - mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); + mCompoundCylinderShape = mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); + mCompoundSphereShape = mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); } /// Run the tests @@ -199,15 +243,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); + callback.shapeToTest = mBoxShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mBoxBody); - test(raycastInfo.proxyShape == mBoxShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mBoxBody); + test(callback.raycastInfo.proxyShape == mBoxShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -249,83 +296,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mBoxBody->raycast(ray1, raycastInfo3)); test(!mBoxShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray2, raycastInfo3)); test(!mBoxShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray3, raycastInfo3)); test(!mBoxShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray4, raycastInfo3)); test(!mBoxShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray5, raycastInfo3)); test(!mBoxShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray6, raycastInfo3)); test(!mBoxShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray7, raycastInfo3)); test(!mBoxShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray8, raycastInfo3)); test(!mBoxShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray9, raycastInfo3)); test(!mBoxShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray10, raycastInfo3)); test(!mBoxShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mBoxBody->raycast(ray11, raycastInfo3)); test(mBoxShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray12, raycastInfo3)); test(mBoxShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray13, raycastInfo3)); test(mBoxShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray14, raycastInfo3)); test(mBoxShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray15, raycastInfo3)); test(mBoxShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray16, raycastInfo3)); test(mBoxShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxySphereShape::raycast(), CollisionBody::raycast() and @@ -338,15 +445,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(-3, 0, 0); + callback.shapeToTest = mSphereShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mSphereBody); - test(raycastInfo.proxyShape == mSphereShape); - test(approxEqual(raycastInfo.hitFraction, 0.2, epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mSphereBody); + test(callback.raycastInfo.proxyShape == mSphereShape); + test(approxEqual(callback.raycastInfo.hitFraction, 0.2, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -388,83 +498,141 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mSphereBody->raycast(ray1, raycastInfo3)); test(!mSphereShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray2, raycastInfo3)); test(!mSphereShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray3, raycastInfo3)); test(!mSphereShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray4, raycastInfo3)); test(!mSphereShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray5, raycastInfo3)); test(!mSphereShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray6, raycastInfo3)); test(!mSphereShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray7, raycastInfo3)); test(!mSphereShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray8, raycastInfo3)); test(!mSphereShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray9, raycastInfo3)); test(!mSphereShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray10, raycastInfo3)); test(!mSphereShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mSphereBody->raycast(ray11, raycastInfo3)); test(mSphereShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray12, raycastInfo3)); test(mSphereShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray13, raycastInfo3)); test(mSphereShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); test(mSphereBody->raycast(ray14, raycastInfo3)); test(mSphereShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray15, raycastInfo3)); test(mSphereShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray16, raycastInfo3)); test(mSphereShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyCapsuleShape::raycast(), CollisionBody::raycast() and @@ -487,15 +655,18 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-4.5), 0); + callback.shapeToTest = mCapsuleShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mCapsuleBody); - test(raycastInfo.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mCapsuleBody); + test(callback.raycastInfo.proxyShape == mCapsuleShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -556,83 +727,142 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mCapsuleBody->raycast(ray1, raycastInfo3)); test(!mCapsuleShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray2, raycastInfo3)); test(!mCapsuleShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray3, raycastInfo3)); test(!mCapsuleShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray4, raycastInfo3)); test(!mCapsuleShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray5, raycastInfo3)); test(!mCapsuleShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray6, raycastInfo3)); test(!mCapsuleShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray7, raycastInfo3)); test(!mCapsuleShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray8, raycastInfo3)); test(!mCapsuleShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray9, raycastInfo3)); test(!mCapsuleShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray10, raycastInfo3)); test(!mCapsuleShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mCapsuleBody->raycast(ray11, raycastInfo3)); test(mCapsuleShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray12, raycastInfo3)); test(mCapsuleShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray13, raycastInfo3)); test(mCapsuleShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray14, raycastInfo3)); test(mCapsuleShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray15, raycastInfo3)); test(mCapsuleShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray16, raycastInfo3)); test(mCapsuleShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyConeShape::raycast(), CollisionBody::raycast() and @@ -650,15 +880,18 @@ class TestRaycast : public Test { Ray rayBottom(point2A, point2B); Vector3 hitPoint2 = mLocalShapeToWorld * Vector3(1, -3, 0); + callback.shapeToTest = mConeShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mConeBody); - test(raycastInfo.proxyShape == mConeShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConeBody); + test(callback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -680,14 +913,15 @@ class TestRaycast : public Test { test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); - RaycastInfo raycastInfo4; - test(mWorld->raycast(rayBottom, raycastInfo4)); - test(raycastInfo4.body == mConeBody); - test(raycastInfo4.proxyShape == mConeShape); - test(approxEqual(raycastInfo4.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo4.worldPoint.x, hitPoint2.x)); - test(approxEqual(raycastInfo4.worldPoint.y, hitPoint2.y)); - test(approxEqual(raycastInfo4.worldPoint.z, hitPoint2.z)); + callback.reset(); + mWorld->raycast(rayBottom, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConeBody); + test(callback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint2.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint2.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint2.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo5; @@ -729,83 +963,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mConeBody->raycast(ray1, raycastInfo3)); test(!mConeShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray2, raycastInfo3)); test(!mConeShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray3, raycastInfo3)); test(!mConeShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray4, raycastInfo3)); test(!mConeShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray5, raycastInfo3)); test(!mConeShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray6, raycastInfo3)); test(!mConeShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray7, raycastInfo3)); test(!mConeShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray8, raycastInfo3)); test(!mConeShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray9, raycastInfo3)); test(!mConeShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray10, raycastInfo3)); test(!mConeShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mConeBody->raycast(ray11, raycastInfo3)); test(mConeShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray12, raycastInfo3)); test(mConeShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray13, raycastInfo3)); test(mConeShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray14, raycastInfo3)); test(mConeShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray15, raycastInfo3)); test(mConeShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray16, raycastInfo3)); test(mConeShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyConvexMeshShape::raycast(), CollisionBody::raycast() and @@ -818,15 +1112,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); + callback.shapeToTest = mConvexMeshShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mConvexMeshBody); - test(raycastInfo.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConvexMeshBody); + test(callback.raycastInfo.proxyShape == mConvexMeshShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -890,113 +1187,173 @@ class TestRaycast : public Test { test(!mConvexMeshBodyEdgesInfo->raycast(ray1, raycastInfo3)); test(!mConvexMeshShape->raycast(ray1, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray2, raycastInfo3)); test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray3, raycastInfo3)); test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray4, raycastInfo3)); test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray5, raycastInfo3)); test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray6, raycastInfo3)); test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray7, raycastInfo3)); test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray8, raycastInfo3)); test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray9, raycastInfo3)); test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray10, raycastInfo3)); test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mConvexMeshBody->raycast(ray11, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray11, raycastInfo3)); test(mConvexMeshShape->raycast(ray11, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray12, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray12, raycastInfo3)); test(mConvexMeshShape->raycast(ray12, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray13, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray13, raycastInfo3)); test(mConvexMeshShape->raycast(ray13, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray14, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray14, raycastInfo3)); test(mConvexMeshShape->raycast(ray14, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray15, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray15, raycastInfo3)); test(mConvexMeshShape->raycast(ray15, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray16, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray16, raycastInfo3)); test(mConvexMeshShape->raycast(ray16, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyCylinderShape::raycast(), CollisionBody::raycast() and @@ -1019,15 +1376,18 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-2.5), 0); + callback.shapeToTest = mCylinderShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mCylinderBody); - test(raycastInfo.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mCylinderBody); + test(callback.raycastInfo.proxyShape == mCylinderShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -1089,83 +1449,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mCylinderBody->raycast(ray1, raycastInfo3)); test(!mCylinderShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray2, raycastInfo3)); test(!mCylinderShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray3, raycastInfo3)); test(!mCylinderShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray4, raycastInfo3)); test(!mCylinderShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray5, raycastInfo3)); test(!mCylinderShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray6, raycastInfo3)); test(!mCylinderShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray7, raycastInfo3)); test(!mCylinderShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray8, raycastInfo3)); test(!mCylinderShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray9, raycastInfo3)); test(!mCylinderShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray10, raycastInfo3)); test(!mCylinderShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mCylinderBody->raycast(ray11, raycastInfo3)); test(mCylinderShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray12, raycastInfo3)); test(mCylinderShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray13, raycastInfo3)); test(mCylinderShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray14, raycastInfo3)); test(mCylinderShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray15, raycastInfo3)); test(mCylinderShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray16, raycastInfo3)); test(mCylinderShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the CollisionBody::raycast() and @@ -1174,7 +1594,7 @@ class TestRaycast : public Test { // ----- Test feedback data ----- // - // Raycast hit agains the sphere shape + // Raycast hit against the sphere shape Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalShape2ToWorld * Vector3(-30, 1, 2)); Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalShape2ToWorld * Vector3(1, -30, -1)); Ray ray3(mLocalShape2ToWorld * Vector3(-1, 2, 5), mLocalShape2ToWorld * Vector3(-1, 2, -30)); @@ -1182,30 +1602,56 @@ class TestRaycast : public Test { Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalShape2ToWorld * Vector3(0, 30, 1)); Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalShape2ToWorld * Vector3(-1, 2, 30)); + callback.shapeToTest = mCompoundSphereShape; + RaycastInfo raycastInfo; test(mCompoundBody->raycast(ray1, raycastInfo)); - test(mWorld->raycast(ray1, raycastInfo)); - test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray2, raycastInfo)); - test(mWorld->raycast(ray2, raycastInfo)); - test(mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray3, raycastInfo)); - test(mWorld->raycast(ray3, raycastInfo)); - test(mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray4, raycastInfo)); - test(mWorld->raycast(ray4, raycastInfo)); - test(mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray5, raycastInfo)); - test(mWorld->raycast(ray5, raycastInfo)); - test(mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray6, raycastInfo)); - test(mWorld->raycast(ray6, raycastInfo)); - test(mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), &callback); + test(callback.isHit); // Raycast hit agains the cylinder shape Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1.5, 2)); @@ -1215,31 +1661,57 @@ class TestRaycast : public Test { Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); + callback.shapeToTest = mCompoundCylinderShape; + test(mCompoundBody->raycast(ray11, raycastInfo)); - test(mWorld->raycast(ray11, raycastInfo)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray12, raycastInfo)); - test(mWorld->raycast(ray12, raycastInfo)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray13, raycastInfo)); - test(mWorld->raycast(ray13, raycastInfo)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray14, raycastInfo)); - test(mWorld->raycast(ray14, raycastInfo)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray15, raycastInfo)); - test(mWorld->raycast(ray15, raycastInfo)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray16, raycastInfo)); - test(mWorld->raycast(ray16, raycastInfo)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } - }; +}; } diff --git a/test/tests/mathematics/TestVector2.h b/test/tests/mathematics/TestVector2.h index 6169948d..a0c5a69d 100644 --- a/test/tests/mathematics/TestVector2.h +++ b/test/tests/mathematics/TestVector2.h @@ -156,6 +156,12 @@ class TestVector2 : public Test { test(Vector2(7, 537).getMaxAxis() == 1); test(Vector2(98, 23).getMaxAxis() == 0); test(Vector2(-53, -25).getMaxAxis() == 1); + + // Test the methot that return a max/min vector + Vector2 vec1(-5, 4); + Vector2 vec2(-8, 6); + test(Vector2::min(vec1, vec2) == Vector2(-8, 4)); + test(Vector2::max(vec1, vec2) == Vector2(-5, 6)); } /// Test the operators diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 9f780325..74d70a81 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -178,6 +178,12 @@ class TestVector3 : public Test { test(Vector3(7, 533, 36).getMaxAxis() == 1); test(Vector3(98, 23, 3).getMaxAxis() == 0); test(Vector3(-53, -25, -63).getMaxAxis() == 1); + + // Test the methot that return a max/min vector + Vector3 vec1(-5, 4, 2); + Vector3 vec2(-8, 6, -1); + test(Vector3::min(vec1, vec2) == Vector3(-8, 4, -1)); + test(Vector3::max(vec1, vec2) == Vector3(-5, 6, 2)); } /// Test the operators