Implementation of the array-based Sweep-And-Prune broad-phase collision detection algorithm from Pierre Terdiman

git-svn-id: https://reactphysics3d.googlecode.com/svn/trunk@466 92aac97c-a6ce-11dd-a772-7fcde58d38e6
This commit is contained in:
chappuis.daniel 2012-07-25 21:31:57 +00:00
parent b013204b3f
commit cd47b3e617
28 changed files with 843 additions and 331 deletions

View File

@ -32,7 +32,7 @@ using namespace reactphysics3d;
// Constructor
Body::Body(const Transform& transform, Collider* collider, decimal mass, long unsigned int id)
: collider(collider), mass(mass), transform(transform), isActive(true), id(id) {
: collider(collider), mass(mass), transform(transform), isActive(true), id(id), hasMoved(false) {
assert(mass > 0.0);
assert(collider);

View File

@ -40,7 +40,7 @@ namespace reactphysics3d {
/* -------------------------------------------------------------------
Class Body :
This class is an abstract class to represent body of the physics
This class is an abstract class to represent a body of the physics
engine.
-------------------------------------------------------------------
*/
@ -56,14 +56,17 @@ class Body {
bool isCollisionEnabled; // True if the body can collide with others bodies
AABB* aabb; // Axis-Aligned Bounding Box for Broad-Phase collision detection
luint id; // ID of the body
bool hasMoved; // True if the body has moved during the last frame
public :
Body(const Transform& transform, Collider* collider, decimal mass, long unsigned int id); // Constructor
virtual ~Body(); // Destructor
luint getID() const; // Return the id of the body
bool getHasMoved() const; // Return true if the body has moved during the last frame
void setHasMoved(bool hasMoved); // Set the hasMoved variable (true if the body has moved during the last frame)
Collider* getCollider() const; // Return the collision collider
void setCollider(Collider* collider); // Set the collision collider
void setCollider(Collider* collider); // Set the collision collider
decimal getMass() const; // Return the mass of the body
void setMass(decimal mass); // Set the mass of the body
bool getIsActive() const; // Return true if the body is active
@ -79,12 +82,28 @@ class Body {
void setIsCollisionEnabled(bool isCollisionEnabled); // Set the isCollisionEnabled value
void updateOldTransform(); // Update the old transform with the current one
void updateAABB(); // Update the Axis-Aligned Bounding Box coordinates
// Operators
bool operator<(const Body& body2) const; // Smaller than operator
bool operator>(const Body& body2) const; // Larger than operator
bool operator==(const Body& body2) const; // Equal operator
bool operator!=(const Body& body2) const; // Equal operator
};
// Return the id of the body
inline luint Body::getID() const {
return id;
}
}
// Return true if the body has moved during the last frame
inline bool Body::getHasMoved() const {
return hasMoved;
}
// Set the hasMoved variable (true if the body has moved during the last frame)
inline void Body::setHasMoved(bool hasMoved) {
this->hasMoved = hasMoved;
}
// Return the collider
inline Collider* Body::getCollider() const {
@ -146,6 +165,12 @@ inline const Transform& Body::getTransform() const {
// Set the current position and orientation
inline void Body::setTransform(const Transform& transform) {
// Check if the body has moved
if (this->transform != transform) {
hasMoved = true;
}
this->transform = transform;
}
@ -172,10 +197,32 @@ inline void Body::updateOldTransform() {
// Update the rigid body in order to reflect a change in the body state
inline void Body::updateAABB() {
// TODO : An AABB should not be updated every frame but only if the body has moved
// Update the AABB
aabb->update(transform, collider->getLocalExtents(OBJECT_MARGIN));
}
// Smaller than operator
inline bool Body::operator<(const Body& body2) const {
return (id < body2.id);
}
// Larger than operator
inline bool Body::operator>(const Body& body2) const {
return (id > body2.id);
}
// Equal operator
inline bool Body::operator==(const Body& body2) const {
return (id == body2.id);
}
// Equal operator
inline bool Body::operator!=(const Body& body2) const {
return (id != body2.id);
}
}

View File

@ -49,6 +49,12 @@ AABB::AABB() : bodyPointer(0) {
}
// Constructor
AABB::AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* bodyPointer)
:minCoordinates(minCoordinates), maxCoordinates(maxCoordinates), bodyPointer(bodyPointer) {
}
// Constructor
AABB::AABB(const Transform& transform, const Vector3& extents) : bodyPointer(0) {
update(transform, extents);

View File

@ -39,8 +39,8 @@ class Body;
Class AABB :
This class represents a bounding volume of type "Axis Aligned
Bounding Box". It's a box where all the edges are always aligned
with the world coordinate system. The AABB is defined by a center
point and three extent size in the x,y and z directions.
with the world coordinate system. The AABB is defined by the
minimum and maximum world coordinates of the three axis.
-------------------------------------------------------------------
*/
class AABB {
@ -50,13 +50,14 @@ class AABB {
Body* bodyPointer; // Pointer to the owner body (not the abstract class Body but its derivative which is instanciable)
public :
AABB(); // Constructor
AABB(const Transform& transform, const Vector3& extents); // Constructor
virtual ~AABB(); // Destructor
AABB(); // Constructor
AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* bodyPointer); // Constructor
AABB(const Transform& transform, const Vector3& extents); // Constructor
virtual ~AABB(); // Destructor
Vector3 getCenter() const; // Return the center point
const Vector3& getMinCoordinates() const; // Return the minimum coordinates of the AABB
const Vector3& getMaxCoordinates() const; // Return the maximum coordinates of the AABB
const Vector3& getMin() const; // Return the minimum coordinates of the AABB
const Vector3& getMax() const; // Return the maximum coordinates of the AABB
Body* getBodyPointer() const; // Return a pointer to the owner body
void setBodyPointer(Body* bodyPointer); // Set the body pointer
bool testCollision(const AABB& aabb) const; // Return true if the current AABB is overlapping is the AABB in argument
@ -72,12 +73,12 @@ inline Vector3 AABB::getCenter() const {
}
// Return the minimum coordinates of the AABB
inline const Vector3& AABB::getMinCoordinates() const {
inline const Vector3& AABB::getMin() const {
return minCoordinates;
}
// Return the maximum coordinates of the AABB
inline const Vector3& AABB::getMaxCoordinates() const {
inline const Vector3& AABB::getMax() const {
return maxCoordinates;
}

View File

@ -25,7 +25,9 @@
// Libraries
#include "CollisionDetection.h"
#include "../engine/PhysicsWorld.h"
#include "broadphase/SweepAndPruneAlgorithm.h"
#include "broadphase/NoBroadPhaseAlgorithm.h"
#include "../body/Body.h"
#include "../colliders/BoxCollider.h"
#include "../body/RigidBody.h"
@ -34,6 +36,9 @@
#include <complex>
#include <set>
#include <utility>
#include <utility>
#include <sys/time.h> // TODO : Delete this
#include <iostream> // TODO : Delete this
// We want to use the ReactPhysics3D namespace
using namespace reactphysics3d;
@ -42,11 +47,12 @@ using namespace std;
// Constructor
CollisionDetection::CollisionDetection(PhysicsWorld* world)
: world(world), memoryPoolContacts(NB_MAX_CONTACTS), memoryPoolOverlappingPairs(NB_MAX_COLLISION_PAIRS),
memoryPoolContactInfos(NB_MAX_CONTACTS), narrowPhaseGJKAlgorithm(*this, memoryPoolContactInfos),
narrowPhaseSphereVsSphereAlgorithm(*this, memoryPoolContactInfos) {
narrowPhaseGJKAlgorithm(memoryPoolContactInfos), memoryPoolContactInfos(NB_MAX_CONTACTS),
narrowPhaseSphereVsSphereAlgorithm(memoryPoolContactInfos) {
// Create the broad-phase algorithm that will be used (Sweep and Prune with AABB)
broadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this);
assert(broadPhaseAlgorithm);
}
// Destructor
@ -57,16 +63,31 @@ CollisionDetection::~CollisionDetection() {
(*it).second->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject((*it).second);
}
// Delete the broad-phase algorithm
delete broadPhaseAlgorithm;
}
// Compute the collision detection
bool CollisionDetection::computeCollisionDetection() {
world->removeAllContactConstraints();
// TODO : Remove this code
timeval timeValueStart;
timeval timeValueStop;
gettimeofday(&timeValueStart, NULL);
// Compute the broad-phase collision detection
computeBroadPhase();
// TODO : Remove this code
gettimeofday(&timeValueStop, NULL);
double startTime = timeValueStart.tv_sec * 1000000.0 + (timeValueStart.tv_usec);
double stopTime = timeValueStop.tv_sec * 1000000.0 + (timeValueStop.tv_usec);
double deltaTime = stopTime - startTime;
printf("Broadphase time : %f micro sec \n", deltaTime);
// Compute the narrow-phase collision detection
bool collisionExists = computeNarrowPhase();
@ -77,28 +98,20 @@ bool CollisionDetection::computeCollisionDetection() {
// Compute the broad-phase collision detection
void CollisionDetection::computeBroadPhase() {
// Notify the broad-phase algorithm about new and removed bodies in the physics world
broadPhaseAlgorithm->notifyAddedBodies(world->getAddedRigidBodies());
broadPhaseAlgorithm->notifyRemovedBodies(world->getRemovedRigidBodies());
// Clear the set of the overlapping pairs in the current step
currentStepOverlappingPairs.clear();
// Notify the broad-phase algorithm about the bodies that have moved since last frame
for (set<Body*>::iterator it = world->getBodiesBeginIterator(); it != world->getBodiesEndIterator(); it++) {
// Execute the broad-phase collision algorithm in order to compute the overlapping pairs of bodies
broadPhaseAlgorithm->computePossibleCollisionPairs();
// If the body has moved
if ((*it)->getHasMoved()) {
// Notify the broad-phase that the body has moved
broadPhaseAlgorithm->updateObject(*it, *((*it)->getAABB()));
}
}
// At this point, the pairs in the set lastStepOverlappingPairs contains
// only the pairs that are not overlapping anymore. Therefore, we can
// remove them from the overlapping pairs map
for (set<pair<luint, luint> >::iterator it = lastStepOverlappingPairs.begin(); it != lastStepOverlappingPairs.end(); it++) {
// Remove the overlapping pair from the memory pool
overlappingPairs[(*it)]->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject(overlappingPairs[(*it)]);
overlappingPairs.erase(*it);
}
// The current overlapping pairs become the last step overlapping pairs
lastStepOverlappingPairs = currentStepOverlappingPairs;
// TODO : DELETE THIS
std::cout << "Nb overlapping pairs : " << overlappingPairs.size() << std::endl;
std::cout << "Nb active pairs in pair manager : " << broadPhaseAlgorithm->getNbOverlappingPairs() << std::endl;
}
// Compute the narrow-phase collision detection
@ -129,7 +142,7 @@ bool CollisionDetection::computeNarrowPhase() {
collisionExists = true;
// Create a new contact
Contact* contact = new(memoryPoolContacts.allocateObject()) Contact(body1, body2, contactInfo);
Contact* contact = new (memoryPoolContacts.allocateObject()) Contact(body1, body2, contactInfo);
// Delete and remove the contact info from the memory pool
contactInfo->ContactInfo::~ContactInfo();
@ -149,26 +162,18 @@ bool CollisionDetection::computeNarrowPhase() {
return collisionExists;
}
// Allow the broadphase to notify the collision detection about an overlapping pair
// This method is called by a broad-phase collision detection algorithm
void CollisionDetection::broadPhaseNotifyOverlappingPair(Body* body1, Body* body2) {
void CollisionDetection::broadPhaseNotifyAddedOverlappingPair(const BroadPhasePair* addedPair) {
std::cout << "New overlapping pair : id0=" << addedPair->body1->getID() << ", id=" << addedPair->body2->getID() << std::endl;
// Construct the pair of body index
pair<luint, luint> indexPair = body1->getID() < body2->getID() ? make_pair(body1->getID(), body2->getID()) :
make_pair(body2->getID(), body1->getID());
pair<luint, luint> indexPair = addedPair->body1->getID() < addedPair->body2->getID() ? make_pair(addedPair->body1->getID(), addedPair->body2->getID()) :
make_pair(addedPair->body2->getID(), addedPair->body1->getID());
assert(indexPair.first != indexPair.second);
// Add the pair to the overlapping pairs of the current step
currentStepOverlappingPairs.insert(indexPair);
// Remove the pair from the set of overlapping pairs in the last step
// if the pair of bodies were already overlapping (used to compute the
// set of pair that were overlapping in the last step but are not overlapping
// in the current one anymore
lastStepOverlappingPairs.erase(indexPair);
// Add the pair into the set of overlapping pairs (if not there yet)
OverlappingPair* newPair = new (memoryPoolOverlappingPairs.allocateObject()) OverlappingPair(body1, body2, memoryPoolContacts);
OverlappingPair* newPair = new (memoryPoolOverlappingPairs.allocateObject()) OverlappingPair(addedPair->body1, addedPair->body2, memoryPoolContacts);
pair<map<pair<luint, luint>, OverlappingPair*>::iterator, bool> check = overlappingPairs.insert(make_pair(indexPair, newPair));
// If the overlapping pair was already in the set of overlapping pair
@ -178,3 +183,16 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(Body* body1, Body* body
memoryPoolOverlappingPairs.freeObject(newPair);
}
}
// Allow the broadphase to notify the collision detection about a removed overlapping pair
void CollisionDetection::broadPhaseNotifyRemovedOverlappingPair(const BroadPhasePair* removedPair) {
// Construct the pair of body index
pair<luint, luint> indexPair = removedPair->body1->getID() < removedPair->body2->getID() ? make_pair(removedPair->body1->getID(), removedPair->body2->getID()) :
make_pair(removedPair->body2->getID(), removedPair->body1->getID());
// Remove the overlapping pair from the memory pool
overlappingPairs[indexPair]->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject(overlappingPairs[indexPair]);
overlappingPairs.erase(indexPair);
}

View File

@ -29,7 +29,7 @@
// Libraries
#include "../body/Body.h"
#include "OverlappingPair.h"
#include "../engine/PhysicsWorld.h"
#include "broadphase/BroadPhaseAlgorithm.h"
#include "../memory/MemoryPool.h"
#include "narrowphase/GJK/GJKAlgorithm.h"
#include "narrowphase/SphereVsSphereAlgorithm.h"
@ -38,6 +38,7 @@
#include <map>
#include <set>
#include <utility>
#include <iostream> // TODO : Delete this
// ReactPhysics3D namespace
@ -45,7 +46,8 @@ namespace reactphysics3d {
// Declarations
class BroadPhaseAlgorithm;
class PhysicsWorld;
/* -------------------------------------------------------------------
Class CollisionDetection :
This class computes the collision detection algorithms. We first
@ -70,15 +72,18 @@ class CollisionDetection {
void computeBroadPhase(); // Compute the broad-phase collision detection
bool computeNarrowPhase(); // Compute the narrow-phase collision detection
NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(Collider* collider1,
Collider* collider2); // Select the narrow phase algorithm to use given two colliders
Collider* collider2); // Select the narrow phase algorithm to use given two colliders
public :
CollisionDetection(PhysicsWorld* physicsWorld); // Constructor
~CollisionDetection(); // Destructor
void addBody(Body* body); // Add a body to the collision detection
void removeBody(Body* body); // Remove a body from the collision detection
OverlappingPair* getOverlappingPair(luint body1ID, luint body2ID); // Return an overlapping pair or null
bool computeCollisionDetection(); // Compute the collision detection
void broadPhaseNotifyOverlappingPair(Body* body1, Body* body2); // Allow the broadphase to notify the collision detection about an overlapping pair
void broadPhaseNotifyAddedOverlappingPair(const BroadPhasePair* pair); // Allow the broadphase to notify the collision detection about a new overlapping pair
void broadPhaseNotifyRemovedOverlappingPair(const BroadPhasePair* pair); // Allow the broadphase to notify the collision detection about a removed overlapping pair
};
// Return an overlapping pair of bodies according to the given bodies ID
@ -88,7 +93,7 @@ inline OverlappingPair* CollisionDetection::getOverlappingPair(luint body1ID, lu
if (overlappingPairs.count(pair) == 1) {
return overlappingPairs[pair];
}
return NULL;
return 0;
}
// Select the narrow-phase collision algorithm to use given two colliders
@ -101,7 +106,21 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(Coll
else { // GJK algorithm
return narrowPhaseGJKAlgorithm;
}
}
}
// Add a body to the collision detection
inline void CollisionDetection::addBody(Body* body) {
// Add the body to the broad-phase
broadPhaseAlgorithm->addObject(body, *(body->getAABB()));
}
// Remove a body from the collision detection
inline void CollisionDetection::removeBody(Body* body) {
// Remove the body from the broad-phase
broadPhaseAlgorithm->removeObject(body);
}
} // End of the ReactPhysics3D namespace

View File

@ -31,7 +31,7 @@ using namespace reactphysics3d;
// Constructor
BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection)
:collisionDetection(collisionDetection) {
:pairManager(collisionDetection), collisionDetection(collisionDetection) {
}

View File

@ -28,7 +28,8 @@
// Libraries
#include <vector>
#include "../../body/RigidBody.h"
#include "../../body/Body.h"
#include "PairManager.h"
// Namespace ReactPhysics3D
namespace reactphysics3d {
@ -51,17 +52,40 @@ class CollisionDetection;
*/
class BroadPhaseAlgorithm {
protected :
CollisionDetection& collisionDetection; // Reference to the collision detection object
PairManager pairManager; // Pair manager that contains the active pairs of bodies
CollisionDetection& collisionDetection; // Reference to the collision detection object
public :
BroadPhaseAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~BroadPhaseAlgorithm(); // Destructor
// TODO : DELETE THIS METHOD
uint getNbOverlappingPairs() const;
virtual void addObject(Body* body, const AABB& aabb)=0; // Notify the broad-phase about a new object in the world
virtual void removeObject(Body* body)=0; // Notify the broad-phase about an object that has been removed from the world
virtual void updateObject(Body* body, const AABB& aabb)=0; // Notify the broad-phase that the AABB of an object has changed
virtual void computePossibleCollisionPairs()=0; // Compute the possible collision pairs of bodies
virtual void notifyAddedBodies(std::vector<RigidBody*> bodies)=0; // Notify the broad-phase algorithm about new bodies in the physics world
virtual void notifyRemovedBodies(std::vector<RigidBody*> bodies)=0; // Notify the broad-phase algorithm about removed bodies in the physics world
BroadPhasePair* beginOverlappingPairsPointer() const; // Return a pointer to the first active pair (used to iterate over the active pairs)
BroadPhasePair* endOverlappingPairsPointer() const; // Return a pointer to the last active pair (used to iterate over the active pairs)
};
// TODO : DELETE THIS METHOD
inline uint BroadPhaseAlgorithm::getNbOverlappingPairs() const {
return pairManager.getNbOverlappingPairs();
}
// Return a pointer to the first active pair (used to iterate over the overlapping pairs)
inline BroadPhasePair* BroadPhaseAlgorithm::beginOverlappingPairsPointer() const {
return pairManager.beginOverlappingPairsPointer();
}
// Return a pointer to the last active pair (used to iterate over the overlapping pairs)
inline BroadPhasePair* BroadPhaseAlgorithm::endOverlappingPairsPointer() const {
return pairManager.endOverlappingPairsPointer();
}
} // End of reactphysics3d namespace
#endif

View File

@ -41,31 +41,3 @@ NoBroadPhaseAlgorithm::NoBroadPhaseAlgorithm(CollisionDetection& collisionDetect
NoBroadPhaseAlgorithm::~NoBroadPhaseAlgorithm() {
}
// Compute the possible collision pairs of bodies. This broad-phase algorithm
// doesn't do anything
void NoBroadPhaseAlgorithm::computePossibleCollisionPairs() {
// For each pair of bodies
for (vector<Body*>::iterator it1 = bodies.begin(); it1 != bodies.end(); it1++) {
for (vector<Body*>::iterator it2 = it1+1; it2 != bodies.end(); it2++) {
collisionDetection.broadPhaseNotifyOverlappingPair(*it1, *it2);
}
}
}
// Notify the broad-phase algorithm about new bodies in the physics world
void NoBroadPhaseAlgorithm::notifyAddedBodies(vector<Body*> addedBodies) {
// Add the new bodies
for (vector<Body*>::iterator it = addedBodies.begin(); it < addedBodies.end(); it++) {
bodies.push_back(*it);
}
}
// Notify the broad-phase algorithm about removed bodies in the physics world
void NoBroadPhaseAlgorithm::notifyRemovedBodies(vector<Body*> removedBodies) {
// Remove the bodies to be removed
for (vector<Body*>::iterator it = removedBodies.begin(); it < removedBodies.end(); it++) {
bodies.erase(std::find(bodies.begin(), bodies.end(), *it));
}
}

View File

@ -29,6 +29,8 @@
// Libraries
#include "BroadPhaseAlgorithm.h"
#include <algorithm>
#include <set>
#include <iostream>
// Namespace ReactPhysics3D
namespace reactphysics3d {
@ -42,17 +44,57 @@ namespace reactphysics3d {
*/
class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm {
protected :
std::vector<Body*> bodies; // All bodies of the engine
std::set<Body*> bodies; // All bodies of the world
public :
NoBroadPhaseAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~NoBroadPhaseAlgorithm(); // Destructor
virtual void computePossibleCollisionPairs(); // Compute the possible collision pairs of bodies
virtual void notifyAddedBodies(std::vector<Body*> bodies); // Notify the broad-phase algorithm about new bodies in the physics world
virtual void notifyRemovedBodies(std::vector<Body*> bodies); // Notify the broad-phase algorithm about removed bodies in the physics world
virtual void addObject(Body* body, const AABB& aabb); // Notify the broad-phase about a new object in the world
virtual void removeObject(Body* body); // Notify the broad-phase about an object that has been removed from the world
virtual void updateObject(Body* body, const AABB& aabb); // Notify the broad-phase that the AABB of an object has changed
};
// Notify the broad-phase about a new object in the world
inline void NoBroadPhaseAlgorithm::addObject(Body* body, const AABB& aabb) {
std::cout << "New body in broadphase with id=" << body->getID() << std::endl;
// For each body that is already in the world
for (std::set<Body*>::iterator it = bodies.begin(); it != bodies.end(); ++it) {
// Add an overlapping pair with the new body
pairManager.addPair(*it, body);
}
// Add the new body into the list of bodies
bodies.insert(body);
}
// Notify the broad-phase about an object that has been removed from the world
inline void NoBroadPhaseAlgorithm::removeObject(Body* body) {
// For each body that is in the world
for (std::set<Body*>::iterator it = bodies.begin(); it != bodies.end(); ++it) {
if ((*it)->getID() != body->getID()) {
// Remove the overlapping pair with the new body
pairManager.removePair((*it)->getID(), body->getID());
}
}
// Remove the body from the broad-phase
bodies.erase(body);
}
// Notify the broad-phase that the AABB of an object has changed
inline void NoBroadPhaseAlgorithm::updateObject(Body* body, const AABB& aabb) {
// Do nothing
return;
}
} // End of reactphysics3d namespace
#endif

View File

@ -26,120 +26,415 @@
// Libraries
#include "SweepAndPruneAlgorithm.h"
#include "../CollisionDetection.h"
#include <algorithm>
#include "PairManager.h"
#include <climits>
// Namespaces
using namespace reactphysics3d;
using namespace std;
// Initialize the static attributes
unsigned short int SweepAndPruneAlgorithm::sortAxis = 0;
// Constructor of AABBInt
AABBInt::AABBInt(const AABB& aabb) {
for (int axis=0; axis<3; axis++) {
min[axis] = encodeFloatIntoInteger(aabb.getMin()[axis]);
max[axis] = encodeFloatIntoInteger(aabb.getMax()[axis]);
}
}
// Constructor
SweepAndPruneAlgorithm::SweepAndPruneAlgorithm(CollisionDetection& collisionDetection)
:BroadPhaseAlgorithm(collisionDetection) {
boxes = 0;
endPoints[0] = 0;
endPoints[1] = 0;
endPoints[2] = 0;
nbBoxes = 0;
nbMaxBoxes = 0;
}
// Destructor
SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() {
delete[] boxes;
delete[] endPoints[0];
delete[] endPoints[1];
delete[] endPoints[2];
}
// Notify the broad-phase algorithm about new bodies in the physics world
// This method removes the AABB representation of a given set of bodies from the sortedAABBs set
void SweepAndPruneAlgorithm::notifyRemovedBodies(vector<RigidBody*> bodies) {
vector<const AABB*>::iterator elemToRemove;
const AABB* aabb;
// Removed the AABB of the bodies that have been removed
for (vector<RigidBody*>::iterator it = bodies.begin(); it != bodies.end(); ++it) {
aabb = (*it)->getAABB();
assert(aabb);
elemToRemove = find(sortedAABBs.begin(), sortedAABBs.end(), aabb);
assert((*elemToRemove) == aabb);
sortedAABBs.erase(elemToRemove);
}
}
// Notify the broad-phase algorithm about new bodies in the physics world
// This method adds the AABB representation of a given body in the sortedAABBs set
void SweepAndPruneAlgorithm::notifyAddedBodies(vector<RigidBody*> bodies) {
const AABB* aabb;
// Notify the broad-phase about a new object in the world
// This method adds the AABB of the object ion to broad-phase
void SweepAndPruneAlgorithm::addObject(Body* body, const AABB& aabb) {
luint boxIndex;
for (vector<RigidBody*>::iterator it = bodies.begin(); it != bodies.end(); ++it) {
aabb = 0;
aabb = (*it)->getAABB();
assert(aabb);
sortedAABBs.push_back(aabb);
// If the index of the first free box is valid (means that
// there is a bucket in the middle of the array that doesn't
// contain a box anymore because it has been removed)
if (!freeBoxIndices.empty()) {
boxIndex = freeBoxIndices.back();
freeBoxIndices.pop_back();
}
}
// This method computes the possible collision pairs of bodies and notify
// the collision detection object about overlapping pairs using the
// broadPhaseNotifyOverlappingPair() method from the CollisionDetection class
void SweepAndPruneAlgorithm::computePossibleCollisionPairs() {
decimal variance[3]; // Variance of the distribution of the AABBs on the three x, y and z axis
decimal esperance[] = {0.0, 0.0, 0.0}; // Esperance of the distribution of the AABBs on the three x, y and z axis
decimal esperanceSquare[] = {0.0, 0.0, 0.0}; // Esperance of the square of the distribution values of the AABBs on the three x, y and z axis
vector<const AABB*>::iterator it; // Iterator on the sortedAABBs set
vector<const AABB*>::iterator it2; // Second iterator
Vector3 center3D; // Center of the current AABB
decimal center[3]; // Coordinates of the center of the current AABB
int i;
const Body* body; // Body pointer on the body corresponding to an AABB
uint nbAABBs = sortedAABBs.size(); // Number of AABBs
// Sort the set of AABBs
sort(sortedAABBs.begin(), sortedAABBs.end(), compareAABBs);
// Sweep the sorted set of AABBs
for (vector<const AABB*>::iterator it = sortedAABBs.begin(); it != sortedAABBs.end(); ++it) {
// If the collision of the AABB's corresponding body is disabled
if (!(*it)->getBodyPointer()->getIsCollisionEnabled()) {
// Go to the next AABB to test
continue;
else {
// If the array boxes and end-points arrays are full
if (nbBoxes == nbMaxBoxes) {
// Resize the arrays to make them larger
resizeArrays();
}
boxIndex = nbBoxes;
}
// Move the maximum limit end-point two elements further
// at the end-points array in all three axis
const luint nbSentinels = 2;
const luint indexLimitEndPoint = 2 * nbBoxes + nbSentinels - 1;
for (int axis=0; axis<3; axis++) {
EndPoint* maxLimitEndPoint = &endPoints[axis][indexLimitEndPoint];
assert(endPoints[axis][0].boxID == INVALID_INDEX && endPoints[axis][0].isMin == true);
assert(maxLimitEndPoint->boxID == INVALID_INDEX && maxLimitEndPoint->isMin == false);
EndPoint* newMaxLimitEndPoint = &endPoints[axis][indexLimitEndPoint + 2];
newMaxLimitEndPoint->setValues(maxLimitEndPoint->boxID, maxLimitEndPoint->isMin, maxLimitEndPoint->value);
}
// Create a new box
BoxAABB* box = &boxes[boxIndex];
box->body = body;
const uint minEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 2.0);
const uint maxEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 1.0);
for (uint axis=0; axis<3; axis++) {
box->min[axis] = indexLimitEndPoint;
box->max[axis] = indexLimitEndPoint + 1;
EndPoint* minimumEndPoint = &endPoints[axis][box->min[axis]];
minimumEndPoint->setValues(body->getID(), true, minEndPointValue);
EndPoint* maximumEndPoint = &endPoints[axis][box->max[axis]];
maximumEndPoint->setValues(body->getID(), false, maxEndPointValue);
}
// Add the body pointer to box index mapping
mapBodyToBoxIndex.insert(pair<Body*, luint>(body, boxIndex));
nbBoxes++;
// Center of the current AABB
center3D = (*it)->getCenter();
center[0] = center3D.getX();
center[1] = center3D.getY();
center[2] = center3D.getZ();
// Call the update method to put the end-points of the new AABB at the
// correct position in the array. This will also create the overlapping
// pairs in the pair manager if the new AABB is overlapping with others
// AABBs
updateObject(body, aabb);
}
// Update the esperance and esperanceSquare values to compute the variance
for (i=0; i<3; i++) {
esperance[i] += center[i];
esperanceSquare[i] += center[i] * center[i];
}
// Notify the broad-phase about a object that has been removed from the world
void SweepAndPruneAlgorithm::removeObject(Body* body) {
// Test collision against all possible overlapping AABBs following the current one
for (it2 = it + 1; it2 != sortedAABBs.end(); it2++) {
// Stop when the tested AABBs are beyond the end of the current AABB
if ((*it2)->getMinCoordinates()[sortAxis] > (*it)->getMaxCoordinates()[sortAxis]) {
break;
// Call the update method with an AABB that is very far away
// in order to remove all overlapping pairs from the pair manager
const decimal max = DECIMAL_LARGEST;
const Vector3 maxVector(max, max, max);
const AABB aabb(maxVector, maxVector, body);
updateObject(body, aabb);
// Get the corresponding box
luint boxIndex = mapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex];
// Add the box index into the list of free indices
freeBoxIndices.push_back(boxIndex);
mapBodyToBoxIndex.erase(body);
nbBoxes--;
}
// Notify the broad-phase that the AABB of an object has changed
void SweepAndPruneAlgorithm::updateObject(Body* body, const AABB& aabb) {
// Compute the AABB with integer coordinates
AABBInt aabbInt(aabb);
// Get the corresponding box
luint boxIndex = mapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex];
// Current axis
for (uint axis=0; axis<3; axis++) {
// Get the two others axis
const uint otherAxis1 = (1 << axis) & 3;
const uint otherAxis2 = (1 << otherAxis1) & 3;
// Get the starting end-point of the current axis
EndPoint* startEndPointsCurrentAxis = endPoints[axis];
// -------- Update the minimum end-point ------------//
EndPoint* currentMinEndPoint = &startEndPointsCurrentAxis[box->min[axis]];
assert(currentMinEndPoint->isMin);
// Get the minimum value of the AABB on the current axis
uint limit = aabbInt.min[axis];
// If the minimum value of the AABB is smaller
// than the current minimum endpoint
if (limit < currentMinEndPoint->value) {
currentMinEndPoint->value = limit;
// The minimum end-point is moving left
EndPoint savedEndPoint = *currentMinEndPoint;
luint indexEndPoint = (size_t(currentMinEndPoint) - size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint);
const luint savedEndPointIndex = indexEndPoint;
while ((--currentMinEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin;
// If it's a maximum end-point
if (!isMin) {
// The minimum end-point is moving to the left and
// passed a maximum end-point. Thus, the boxes start
// overlapping on the current axis. Therefore we test
// for box intersection
if (box != id1) {
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2) &&
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis, axis)) {
// Add an overlapping pair to the pair manager
pairManager.addPair(body, id1->body);
}
}
id1->max[axis] = indexEndPoint--;
}
else {
id1->min[axis] = indexEndPoint--;
}
*(currentMinEndPoint+1) = *currentMinEndPoint;
}
// Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
body = (*it2)->getBodyPointer();
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
}
}
else if (limit > currentMinEndPoint->value) { // The minimum of the box has moved to the right
currentMinEndPoint->value = limit;
// The minimum en-point is moving right
EndPoint savedEndPoint = *currentMinEndPoint;
luint indexEndPoint = (size_t(currentMinEndPoint) -size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint);
const luint savedEndPointIndex = indexEndPoint;
// For each end-point between the current position of the minimum
// end-point and the new position of the minimum end-point
while ((++currentMinEndPoint)->value < limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin;
// If it's a maximum end-point
if (!isMin) {
// The minimum end-point is moving to the right and
// passed a maximum end-point. Thus, the boxes stop
// overlapping on the current axis.
if (box != id1) {
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) {
// Remove the pair from the pair manager
pairManager.removePair(body->getID(), id1->body->getID());
}
}
id1->max[axis] = indexEndPoint++;
}
else {
id1->min[axis] = indexEndPoint++;
}
*(currentMinEndPoint-1) = *currentMinEndPoint;
}
// Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
// Test if both AABBs overlap
if (body->getIsCollisionEnabled() && (*it)->testCollision(*(*it2))) {
// Notify the collision detection object about this current overlapping pair of bodies
collisionDetection.broadPhaseNotifyOverlappingPair((*it)->getBodyPointer(), (*it2)->getBodyPointer());
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
}
}
// ------- Update the maximum end-point ------------ //
EndPoint* currentMaxEndPoint = &startEndPointsCurrentAxis[box->max[axis]];
assert(!currentMaxEndPoint->isMin);
// Get the maximum value of the AABB on the current axis
limit = aabbInt.max[axis];
// If the new maximum value of the AABB is larger
// than the current maximum end-point value. It means
// that the AABB is moving to the right.
if (limit > currentMaxEndPoint->value) {
currentMaxEndPoint->value = limit;
EndPoint savedEndPoint = *currentMaxEndPoint;
luint indexEndPoint = (size_t(currentMaxEndPoint) -size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint);
const luint savedEndPointIndex = indexEndPoint;
while ((++currentMaxEndPoint)->value < limit) {
// Get the next end-point
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin;
// If it's a maximum end-point
if (isMin) {
// The maximum end-point is moving to the right and
// passed a minimum end-point. Thus, the boxes start
// overlapping on the current axis. Therefore we test
// for box intersection
if (box != id1) {
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2) &&
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis,axis)) {
// Add an overlapping pair to the pair manager
pairManager.addPair(body, id1->body);
}
}
id1->min[axis] = indexEndPoint++;
}
else {
id1->max[axis] = indexEndPoint++;
}
*(currentMaxEndPoint-1) = *currentMaxEndPoint;
}
// Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
}
}
else if (limit < currentMaxEndPoint->value) { // If the AABB is moving to the left
currentMaxEndPoint->value = limit;
EndPoint savedEndPoint = *currentMaxEndPoint;
luint indexEndPoint = (size_t(currentMaxEndPoint) -size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint);
const luint savedEndPointIndex = indexEndPoint;
// For each end-point between the current position of the maximum
// end-point and the new position of the maximum end-point
while ((--currentMaxEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin;
// If it's a minimum end-point
if (isMin) {
// The maximum end-point is moving to the right and
// passed a minimum end-point. Thus, the boxes stop
// overlapping on the current axis.
if (box != id1) {
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) {
// Remove the pair from the pair manager
pairManager.removePair(body->getID(), id1->body->getID());
}
}
id1->min[axis] = indexEndPoint--;
}
else {
id1->max[axis] = indexEndPoint--;
}
*(currentMaxEndPoint+1) = *currentMaxEndPoint;
}
// Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
}
}
}
// Compute the variance of the distribution of the AABBs on the three x,y and z axis
for (i=0; i<3; i++) {
variance[i] = esperanceSquare[i] - esperance[i] * esperance[i] / nbAABBs;
}
// Update the sorted axis according to the axis with the largest variance
sortAxis = 0;
if (variance[1] > variance[0]) sortAxis = 1;
if (variance[2] > variance[sortAxis]) sortAxis = 2;
}
// Resize the boxes and end-points arrays when it is full
void SweepAndPruneAlgorithm::resizeArrays() {
// New number of boxes in the array
const luint nbSentinels = 2;
const luint newNbMaxBoxes = nbMaxBoxes ? 2 * nbMaxBoxes : 100;
const luint nbEndPoints = nbBoxes * 2 + nbSentinels;
const luint newNbEndPoints = newNbMaxBoxes * 2 + nbSentinels;
// Allocate memory for the new boxes and end-points arrays
BoxAABB* newBoxesArray = new BoxAABB[newNbMaxBoxes];
EndPoint* newEndPointsXArray = new EndPoint[newNbEndPoints];
EndPoint* newEndPointsYArray = new EndPoint[newNbEndPoints];
EndPoint* newEndPointsZArray = new EndPoint[newNbEndPoints];
assert(newBoxesArray);
assert(newEndPointsXArray);
assert(newEndPointsYArray);
assert(newEndPointsZArray);
// If the arrays were not empty before
if (nbBoxes > 0) {
// Copy the data in the old arrays into the new one
memcpy(newBoxesArray, boxes, sizeof(BoxAABB) * nbBoxes);
size_t nbBytesNewEndPoints = sizeof(EndPoint) * nbEndPoints;
memcpy(newEndPointsXArray, endPoints[0], nbBytesNewEndPoints);
memcpy(newEndPointsYArray, endPoints[1], nbBytesNewEndPoints);
memcpy(newEndPointsZArray, endPoints[2], nbBytesNewEndPoints);
}
else { // If the arrays were empty
// Add the limits endpoints (sentinels) into the array
const uint min = encodeFloatIntoInteger(DECIMAL_SMALLEST);
const uint max = encodeFloatIntoInteger(DECIMAL_LARGEST);
newEndPointsXArray[0].setValues(INVALID_INDEX, true, min);
newEndPointsXArray[1].setValues(INVALID_INDEX, false, max);
newEndPointsYArray[0].setValues(INVALID_INDEX, true, min);
newEndPointsYArray[1].setValues(INVALID_INDEX, false, max);
newEndPointsZArray[0].setValues(INVALID_INDEX, true, min);
newEndPointsZArray[1].setValues(INVALID_INDEX, false, max);
}
// Delete the old arrays
delete[] boxes;
delete[] endPoints[0];
delete[] endPoints[1];
delete[] endPoints[2];
// Assign the pointer to the new arrays
boxes = newBoxesArray;
endPoints[0] = newEndPointsXArray;
endPoints[1] = newEndPointsYArray;
endPoints[2] = newEndPointsZArray;
nbMaxBoxes = newNbMaxBoxes;
}

View File

@ -29,53 +29,127 @@
// Libraries
#include "BroadPhaseAlgorithm.h"
#include "../../colliders/AABB.h"
#include <map>
#include <vector>
// Namespace ReactPhysics3D
namespace reactphysics3d {
// EndPoint structure that represent an end-point of an AABB
// on one of the three x,y or z axis
struct EndPoint {
public:
// TODO : Use uint here
luint boxID; // ID of the AABB box corresponding to this end-point
bool isMin; // True if the end-point is a minimum end-point of a box
uint value; // Value (one dimension coordinate) of the end-point
void setValues(luint boxID, bool isMin, uint value); // Set the values of the endpoint
};
// Set the values of the endpoint
inline void EndPoint::setValues(luint boxID, bool isMin, uint value) {
this->boxID = boxID;
this->isMin = isMin;
this->value = value;
}
// Structure BoxAABB that represents an AABB in the
// Sweep-And-Prune algorithm
struct BoxAABB {
public:
luint min[3]; // Index of the three minimum end-points of the AABB over the axis X, Y and Z
luint max[3]; // Index of the three maximum end-points of the AABB over the axis X, Y and Z
Body* body; // Body that corresponds to the owner of the AABB
};
// Structure AABBInt
// Axis-Aligned Bounding box with integer coordinates
struct AABBInt {
public:
uint min[3]; // Minimum values on the three axis
uint max[3]; // Maximum values on the three axis
AABBInt(const AABB& aabb); // Constructor
};
// TODO : Use uint instead of luint here
// TODO : Rename the methods and variable to my way
// TODO : Try to replace the Body* pointer by the body ID everywhere in order that
// this class can be used in a more generic way
/* --------------------------------------------------------------------
Class SAPAlgorithm :
This class implements the Sweep and Prune (SAP) broad-phase
algorithm. This algorithm uses the AABB bounding-volume of the
bodies and keep a sorted representation of the intervals of the
bodies' AABB on the three x. y and z axis. Given this sorted
representation, we can efficiently compute the set of possible
colliding pairs of bodies. At each broad-phase computation, we
should sort the AABB according to the axis (x, y or z) with the
largest variance of the AABBs positions in order that the sorted
AABB's set does not change a lot between each computations. To do
so, we compute at each time the variance of each axis and select
the axis (sortAxis) with the largest variance for the next
broad-phase computation.
Class SweepAndPruneAlgorithm :
This class implements the Sweep-And-Prune (SAP) broad-phase
collision detection algorithm. This class implements an
array-based implementation of the algorithm from Pierre Terdiman
that is described here : www.codercorner.com/SAP.pdf.
--------------------------------------------------------------------
*/
class SweepAndPruneAlgorithm : public BroadPhaseAlgorithm {
protected :
std::vector<const AABB*> sortedAABBs; // Sorted set of AABB of the bodies on one of the x.y or z axis
static unsigned short int sortAxis; // Current sorting axis (0 for x, 1 for y, 2 for z axis)
static bool compareAABBs(const AABB* a, const AABB* b); // Static method that compare two AABBs (in order to sort them)
static const luint INVALID_INDEX = ULONG_MAX; // Invalid array index
BoxAABB* boxes; // Array that contains all the AABB boxes of the broad-phase
EndPoint* endPoints[3]; // Array of end-points on the three axis
luint nbBoxes; // Number of AABB boxes in the broad-phase
luint nbMaxBoxes; // Maximum number of boxes in the boxes array
std::vector<luint> freeBoxIndices; // Indices that are not used by any boxes
std::map<Body*, luint> mapBodyToBoxIndex; // Map a body pointer to its box index
void resizeArrays(); // Resize the boxes and end-points arrays when it's full
void addPair(Body* body1, Body* body2); // Add an overlapping pair of AABBS
bool testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2,
const EndPoint* const baseEndPoint, luint axis) const; // Check for 1D box intersection
bool testIntersect2D(const BoxAABB& box1, const BoxAABB& box2,
luint axis1, luint axis2) const; // Check for 2D box intersection
public :
SweepAndPruneAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~SweepAndPruneAlgorithm(); // Destructor
virtual void computePossibleCollisionPairs(); // Compute the possible collision pairs of bodies
virtual void notifyAddedBodies(std::vector<RigidBody*> bodies); // Notify the broad-phase algorithm about new bodies in the physics world
virtual void notifyRemovedBodies(std::vector<RigidBody*> bodies); // Notify the broad-phase algorithm about removed bodies in the physics world
virtual void addObject(Body* body, const AABB& aabb); // Notify the broad-phase about a new object in the world
virtual void removeObject(Body* body); // Notify the broad-phase about a object that has been removed from the world
virtual void updateObject(Body* body, const AABB& aabb); // Notify the broad-phase that the AABB of an object has changed
};
// Static method that compare two AABBs. This method will be used to compare to AABBs
// in order to sort them with the sort() function to obtain the sortedAABBs set.
// This method must return true if the AABB "a" goes before the AABB "b". We
// consider that "a" goes before "b" if the minimum value of "a" on the current
// sorting axis (sortAxis) is smaller than the minimum value of "b" on this same
// axis.
inline bool SweepAndPruneAlgorithm::compareAABBs(const AABB* a, const AABB* b) {
return (a->getMinCoordinates()[sortAxis] < b->getMinCoordinates()[sortAxis]);
}
// TODO : ADD Documentation for this method
// Encode a floating value into a integer value
inline uint encodeFloatIntoInteger(float number) {
uint intNumber = (uint&) number;
// If it's a negative number
if(intNumber & 0x80000000)
intNumber = ~intNumber;
else { // If it is a positive number
intNumber |= 0x80000000;
}
return intNumber;
}
// Check for 1D box intersection between two boxes that are sorted on the
// given axis. Therefore, only one test is necessary here. We know that the
// minimum of box1 cannot be larger that the maximum of box2 on the axis.
inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2,
const EndPoint* const endPointsArray, luint axis) const {
return !(endPointsArray[box1.max[axis]].value < box2.min[axis]);
}
// Check for 2D box intersection. This method is used when we know
// that two boxes already overlap on one axis and when want to test
// if they also overlap on the two others axis.
inline bool SweepAndPruneAlgorithm::testIntersect2D(const BoxAABB& box1, const BoxAABB& box2,
luint axis1, luint axis2) const {
return !(box2.max[axis1] < box1.min[axis1] || box1.max[axis1] < box2.min[axis1] ||
box2.max[axis2] < box1.min[axis2] || box1.max[axis2] < box2.min[axis2]);
}
} // End of reactphysics3d namespace

View File

@ -222,10 +222,10 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
link(EdgeEPA(face2, 1), EdgeEPA(face3, 1));
// Add the triangle faces in the candidate heap
addFaceCandidate(face0, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face1, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face2, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face3, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face0, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face1, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face2, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face3, triangleHeap, nbTriangles, DECIMAL_LARGEST);
break;
}
@ -288,12 +288,12 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
link(EdgeEPA(face5, 1), EdgeEPA(face3, 2));
// Add the candidate faces in the heap
addFaceCandidate(face0, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face1, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face2, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face3, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face4, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face5, triangleHeap, nbTriangles, DECIMAL_MAX);
addFaceCandidate(face0, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face1, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face2, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face3, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face4, triangleHeap, nbTriangles, DECIMAL_LARGEST);
addFaceCandidate(face5, triangleHeap, nbTriangles, DECIMAL_LARGEST);
nbVertices = 5;
}
@ -308,7 +308,7 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
}
TriangleEPA* triangle = 0;
decimal upperBoundSquarePenDepth = DECIMAL_MAX;
decimal upperBoundSquarePenDepth = DECIMAL_LARGEST;
do {
triangle = triangleHeap[0];

View File

@ -29,7 +29,6 @@
#include "../../../constraint/Contact.h"
#include "../../../configuration.h"
#include "../../OverlappingPair.h"
#include "../../CollisionDetection.h"
#include <algorithm>
#include <cmath>
#include <cfloat>
@ -41,8 +40,8 @@
using namespace reactphysics3d;
// Constructor
GJKAlgorithm::GJKAlgorithm(CollisionDetection& collisionDetection, MemoryPool<ContactInfo>& memoryPoolContactInfos)
:NarrowPhaseAlgorithm(collisionDetection, memoryPoolContactInfos), algoEPA(memoryPoolContactInfos) {
GJKAlgorithm::GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos)
:NarrowPhaseAlgorithm(memoryPoolContactInfos), algoEPA(memoryPoolContactInfos) {
}
@ -91,7 +90,7 @@ bool GJKAlgorithm::testCollision(const Collider* collider1, const Transform& tra
Vector3 v = currentOverlappingPair->getCachedSeparatingAxis();
// Initialize the upper bound for the square distance
decimal distSquare = DECIMAL_MAX;
decimal distSquare = DECIMAL_LARGEST;
do {
@ -252,7 +251,7 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const Collider* con
Vector3 suppB;
Vector3 w;
decimal vDotw;
decimal distSquare = DECIMAL_MAX;
decimal distSquare = DECIMAL_LARGEST;
decimal prevDistSquare;
// Transform a point from local space of body 2 to local space of body 1 (the GJK algorithm is done in local space of body 1)

View File

@ -66,8 +66,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
ContactInfo*& contactInfo, Vector3& v); // Compute the penetration depth for enlarged objects
public :
GJKAlgorithm(CollisionDetection& collisionDetection,
MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
~GJKAlgorithm(); // Destructor
virtual bool testCollision(const Collider* collider1, const Transform& transform1,

View File

@ -327,7 +327,7 @@ bool Simplex::computeClosestPoint(Vector3& v) {
// Backup the closest point
void Simplex::backupClosestPointInSimplex(Vector3& v) {
decimal minDistSquare = DECIMAL_MAX;
decimal minDistSquare = DECIMAL_LARGEST;
Bits bit;
for (bit = allBits; bit != 0x0; bit--) {

View File

@ -30,8 +30,8 @@
using namespace reactphysics3d;
// Constructor
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(CollisionDetection& collisionDetection, MemoryPool<ContactInfo>& memoryPool)
:collisionDetection(collisionDetection), memoryPoolContactInfos(memoryPool), currentOverlappingPair(0) {
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool)
:memoryPoolContactInfos(memoryPool), currentOverlappingPair(0) {
}

View File

@ -34,8 +34,6 @@
// Namespace ReactPhysics3D
namespace reactphysics3d {
// Class declarations
class CollisionDetection;
/* -------------------------------------------------------------------
Class NarrowPhaseAlgorithm :
@ -47,13 +45,12 @@ class CollisionDetection;
*/
class NarrowPhaseAlgorithm {
protected :
CollisionDetection& collisionDetection; // Reference to the collision detection object
MemoryPool<ContactInfo>& memoryPoolContactInfos; // Reference to the memory pool for contact infos
OverlappingPair* currentOverlappingPair; // Overlapping pair of the bodies currently tested for collision
public :
NarrowPhaseAlgorithm(CollisionDetection& collisionDetection, MemoryPool<ContactInfo>& memoryPool); // Constructor
virtual ~NarrowPhaseAlgorithm(); // Destructor
NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool); // Constructor
virtual ~NarrowPhaseAlgorithm(); // Destructor
void setCurrentOverlappingPair(OverlappingPair* overlappingPair); // Set the current overlapping pair of bodies
virtual bool testCollision(const Collider* collider1, const Transform& transform1,

View File

@ -31,8 +31,8 @@
using namespace reactphysics3d;
// Constructor
SphereVsSphereAlgorithm::SphereVsSphereAlgorithm(CollisionDetection& collisionDetection, MemoryPool<ContactInfo>& memoryPoolContactInfos)
:NarrowPhaseAlgorithm(collisionDetection, memoryPoolContactInfos) {
SphereVsSphereAlgorithm::SphereVsSphereAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos)
:NarrowPhaseAlgorithm(memoryPoolContactInfos) {
}

View File

@ -45,8 +45,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
protected :
public :
SphereVsSphereAlgorithm(CollisionDetection& collisionDetection,
MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
SphereVsSphereAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
virtual ~SphereVsSphereAlgorithm(); // Destructor
virtual bool testCollision(const Collider* collider1, const Transform& transform1,

View File

@ -43,10 +43,11 @@
// Type definitions
typedef unsigned int uint;
typedef long unsigned int luint;
typedef short unsigned int bodyindex; // TODO : Replace whenever possible using the bodyindex type
// Mathematical constants
const reactphysics3d::decimal DECIMAL_MIN = std::numeric_limits<reactphysics3d::decimal>::min(); // Minimun decimal value
const reactphysics3d::decimal DECIMAL_MAX = std::numeric_limits<reactphysics3d::decimal>::max(); // Maximum decimal value
const reactphysics3d::decimal DECIMAL_SMALLEST = - std::numeric_limits<reactphysics3d::decimal>::max(); // Minimun decimal value
const reactphysics3d::decimal DECIMAL_LARGEST = std::numeric_limits<reactphysics3d::decimal>::max(); // Maximum decimal value
const reactphysics3d::decimal MACHINE_EPSILON = std::numeric_limits<reactphysics3d::decimal>::epsilon(); // Machine epsilon
const reactphysics3d::decimal DECIMAL_INFINITY = std::numeric_limits<reactphysics3d::decimal>::infinity(); // Infinity
const reactphysics3d::decimal PI = 3.14159265; // Pi constant

View File

@ -31,7 +31,7 @@ namespace reactphysics3d {
#if defined(DOUBLE_PRECISION_ENABLED) // If we are compiling for double precision
typedef double decimal;
#else // If we are compiling for single precision
#else // If we are compiling for single precision
typedef float decimal;
#endif

View File

@ -32,10 +32,11 @@ using namespace std;
// Constructor
PhysicsEngine::PhysicsEngine(PhysicsWorld* world, decimal timeStep = DEFAULT_TIMESTEP)
: world(world), timer(timeStep), collisionDetection(world), constraintSolver(world),
: world(world), collisionDetection(world), timer(timeStep), constraintSolver(world),
isDeactivationActive(DEACTIVATION_ENABLED) {
assert(world);
assert(timeStep > 0.0);
world->setCollisionDetection(&collisionDetection);
}
// Destructor
@ -70,6 +71,9 @@ void PhysicsEngine::update() {
// Update the timer
timer.nextStep();
// Reset the movement boolean variable of each body to false
resetBodiesMovementVariable();
// Update the position and orientation of each body
updateAllBodiesMotion();
@ -77,9 +81,6 @@ void PhysicsEngine::update() {
if (existCollision) {
constraintSolver.cleanup();
}
// Clear the added and removed bodies from last update() method call
world->clearAddedAndRemovedBodies();
}
// Compute and set the interpolation factor to all the bodies
@ -103,7 +104,7 @@ void PhysicsEngine::updateAllBodiesMotion() {
Vector3 angularVelocityErrorCorrection;
// For each body of thephysics world
for (vector<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
for (set<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
RigidBody* rigidBody = *it;
assert(rigidBody);
@ -183,7 +184,7 @@ void PhysicsEngine::setInterpolationFactorToAllBodies() {
assert(factor >= 0.0 && factor <= 1.0);
// Set the factor to all bodies
for (vector<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
for (set<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
RigidBody* rigidBody = dynamic_cast<RigidBody*>(*it);
assert(rigidBody);
@ -196,7 +197,7 @@ void PhysicsEngine::setInterpolationFactorToAllBodies() {
void PhysicsEngine::applyGravity() {
// For each body of the physics world
for (vector<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
for (set<RigidBody*>::iterator it=world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); ++it) {
RigidBody* rigidBody = dynamic_cast<RigidBody*>(*it);
assert(rigidBody);

View File

@ -50,11 +50,13 @@ class PhysicsEngine {
CollisionDetection collisionDetection; // Collision detection
ConstraintSolver constraintSolver; // Constraint solver
bool isDeactivationActive; // True if the deactivation (sleeping) of inactive bodies is enabled
void updateAllBodiesMotion(); // Compute the motion of all bodies and update their positions and orientations
void updatePositionAndOrientationOfBody(RigidBody* body, const Vector3& newLinVelocity, const Vector3& newAngVelocity,
const Vector3& linearVelocityErrorCorrection, const Vector3& angularVelocityErrorCorrection); // Update the position and orientation of a body
void setInterpolationFactorToAllBodies(); // Compute and set the interpolation factor to all bodies
void applyGravity(); // Apply the gravity force to all bodies
void resetBodiesMovementVariable(); // Reset the boolean movement variable of each body
public :
PhysicsEngine(PhysicsWorld* world, decimal timeStep); // Constructor
@ -89,6 +91,16 @@ inline void PhysicsEngine::setIsErrorCorrectionActive(bool isErrorCorrectionActi
constraintSolver.setIsErrorCorrectionActive(isErrorCorrectionActive);
}
// Reset the boolean movement variable of each body
inline void PhysicsEngine::resetBodiesMovementVariable() {
// For each rigid body
for (std::set<RigidBody*>::iterator it = world->getRigidBodiesBeginIterator(); it != world->getRigidBodiesEndIterator(); it++) {
// Set the hasMoved variable to false
(*it)->setHasMoved(false);
}
}
}

View File

@ -35,7 +35,6 @@ using namespace std;
// Constructor
PhysicsWorld::PhysicsWorld(const Vector3& gravity)
: gravity(gravity), isGravityOn(true), currentBodyID(0), memoryPoolRigidBodies(NB_MAX_BODIES) {
}
// Destructor
@ -46,23 +45,47 @@ PhysicsWorld::~PhysicsWorld() {
// Create a rigid body into the physics world
RigidBody* PhysicsWorld::createRigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal, Collider* collider) {
// Compute the body ID
luint bodyID;
if (!freeRigidBodyIDs.empty()) {
bodyID = freeRigidBodyIDs.back();
freeRigidBodyIDs.pop_back();
}
else {
bodyID = currentBodyID;
currentBodyID++;
}
// Create the rigid body
RigidBody* rigidBody = new (memoryPoolRigidBodies.allocateObject()) RigidBody(transform, mass, inertiaTensorLocal, collider, currentBodyID);
RigidBody* rigidBody = new (memoryPoolRigidBodies.allocateObject()) RigidBody(transform, mass, inertiaTensorLocal, collider, bodyID);
currentBodyID++;
// Add the rigid body to the physics world and return it
addRigidBody(rigidBody);
// Add the rigid body to the physics world
bodies.insert(rigidBody);
rigidBodies.insert(rigidBody);
// Add the rigid body to the collision detection
collisionDetection->addBody(rigidBody);
// Return the pointer to the rigid body
return rigidBody;
}
// Destroy a rigid body
void PhysicsWorld::destroyRigidBody(RigidBody* rigidBody) {
removeRigidBody(rigidBody);
// Remove the body from the collision detection
collisionDetection->removeBody(rigidBody);
// Add the body ID to the list of free IDs
freeRigidBodyIDs.push_back(rigidBody->getID());
// Call the constructor of the rigid body
rigidBody->RigidBody::~RigidBody();
// Remove the rigid body from the list of rigid bodies
bodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
rigidBodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
// Free the object from the memory pool
memoryPoolRigidBodies.freeObject(rigidBody);
}

View File

@ -28,9 +28,11 @@
// Libraries
#include <vector>
#include <set>
#include <algorithm>
#include "../mathematics/mathematics.h"
#include "../body/Body.h"
#include "../collision/CollisionDetection.h"
#include "../constraint/Constraint.h"
#include "../constraint/Contact.h"
#include "../memory/MemoryPool.h"
@ -48,17 +50,15 @@ namespace reactphysics3d {
*/
class PhysicsWorld {
protected :
std::vector<RigidBody*> rigidBodies; // All the rigid bodies of the physics world
std::vector<RigidBody*> addedBodies; // Added bodies since last update
std::vector<RigidBody*> removedBodies; // Removed bodies since last update
CollisionDetection* collisionDetection; // Reference to the collision detection
std::set<Body*> bodies; // All the bodies (rigid and soft) of the physics world
std::set<RigidBody*> rigidBodies; // All the rigid bodies of the physics world
std::vector<luint> freeRigidBodyIDs; // List of free ID for rigid bodies
std::vector<Constraint*> constraints; // List that contains all the current constraints
Vector3 gravity; // Gravity vector of the world
bool isGravityOn; // True if the gravity force is on
long unsigned int currentBodyID; // Current body ID
luint currentBodyID; // Current body ID
MemoryPool<RigidBody> memoryPoolRigidBodies; // Memory pool for rigid bodies memory allocation
void addRigidBody(RigidBody* body); // Add a body to the physics world
void removeRigidBody(RigidBody* body); // Remove a body from the physics world
public :
PhysicsWorld(const Vector3& gravity); // Constructor
@ -67,56 +67,21 @@ class PhysicsWorld {
RigidBody* createRigidBody(const Transform& transform, decimal mass,
const Matrix3x3& inertiaTensorLocal, Collider* collider); // Create a rigid body into the physics world
void destroyRigidBody(RigidBody* rigidBody); // Destroy a rigid body
void clearAddedAndRemovedBodies(); // Clear the addedBodies and removedBodies sets
Vector3 getGravity() const; // Return the gravity vector of the world
bool getIsGravityOn() const; // Return if the gravity is on
void setIsGratityOn(bool isGravityOn); // Set the isGravityOn attribute
void setCollisionDetection(CollisionDetection* collisionDetection); // Set the collision detection reference
void addConstraint(Constraint* constraint); // Add a constraint
void removeConstraint(Constraint* constraint); // Remove a constraint
void removeAllContactConstraints(); // Remove all collision contacts constraints
void removeAllConstraints(); // Remove all constraints and delete them (free their memory)
std::vector<Constraint*>::iterator getConstraintsBeginIterator(); // Return a start iterator on the constraint list
std::vector<Constraint*>::iterator getConstraintsEndIterator(); // Return a end iterator on the constraint list
std::vector<RigidBody*>::iterator getRigidBodiesBeginIterator(); // Return an iterator to the beginning of the bodies of the physics world
std::vector<RigidBody*>::iterator getRigidBodiesEndIterator(); // Return an iterator to the end of the bodies of the physics world
std::vector<RigidBody*>& getAddedRigidBodies(); // Return the added bodies since last update of the physics engine
std::vector<RigidBody*>& getRemovedRigidBodies(); // Retrun the removed bodies since last update of the physics engine
std::set<Body*>::iterator getBodiesBeginIterator(); // Return an iterator to the beginning of the bodies of the physics world
std::set<Body*>::iterator getBodiesEndIterator(); // Return an iterator to the end of the bodies of the physics world
std::set<RigidBody*>::iterator getRigidBodiesBeginIterator(); // Return an iterator to the beginning of the rigid bodies of the physics world
std::set<RigidBody*>::iterator getRigidBodiesEndIterator(); // Return an iterator to the end of the rigid bodies of the physics world
};
// Add a body to the physics world
inline void PhysicsWorld::addRigidBody(RigidBody* body) {
std::vector<RigidBody*>::iterator it;
assert(body);
it = std::find(rigidBodies.begin(), rigidBodies.end(), body);
assert(it == rigidBodies.end());
// The body isn't already in the bodyList, therefore we add it to the list
rigidBodies.push_back(body);
addedBodies.push_back(body);
it = std::find(removedBodies.begin(), removedBodies.end(), body);
if (it != removedBodies.end()) {
removedBodies.erase(it);
}
}
// Remove a body from the physics world
inline void PhysicsWorld::removeRigidBody(RigidBody* body) {
std::vector<RigidBody*>::iterator it;
assert(body);
it = std::find(rigidBodies.begin(), rigidBodies.end(), body);
assert(*it == body);
rigidBodies.erase(it);
it = std::find(addedBodies.begin(), addedBodies.end(), body);
if (it != addedBodies.end()) {
addedBodies.erase(it);
}
removedBodies.push_back(*it);
}
// Add a constraint into the physics world
inline void PhysicsWorld::addConstraint(Constraint* constraint) {
@ -135,12 +100,6 @@ inline void PhysicsWorld::removeConstraint(Constraint* constraint) {
constraints.erase(it);
}
// Clear the addedBodies and removedBodies sets
inline void PhysicsWorld::clearAddedAndRemovedBodies() {
addedBodies.clear();
removedBodies.clear();
}
// Return the gravity vector of the world
inline Vector3 PhysicsWorld::getGravity() const {
return gravity;
@ -156,6 +115,11 @@ inline void PhysicsWorld::setIsGratityOn(bool isGravityOn) {
this->isGravityOn = isGravityOn;
}
// Set the collision detection reference
inline void PhysicsWorld::setCollisionDetection(CollisionDetection* collisionDetection) {
this->collisionDetection = collisionDetection;
}
// Return a start iterator on the constraint list
inline std::vector<Constraint*>::iterator PhysicsWorld::getConstraintsBeginIterator() {
return constraints.begin();
@ -167,25 +131,25 @@ inline std::vector<Constraint*>::iterator PhysicsWorld::getConstraintsEndIterato
}
// Return an iterator to the beginning of the bodies of the physics world
inline std::vector<RigidBody*>::iterator PhysicsWorld::getRigidBodiesBeginIterator() {
inline std::set<Body*>::iterator PhysicsWorld::getBodiesBeginIterator() {
return bodies.begin();
}
// Return an iterator to the end of the bodies of the physics world
inline std::set<Body*>::iterator PhysicsWorld::getBodiesEndIterator() {
return bodies.end();
}
// Return an iterator to the beginning of the bodies of the physics world
inline std::set<RigidBody*>::iterator PhysicsWorld::getRigidBodiesBeginIterator() {
return rigidBodies.begin();
}
// Return an iterator to the end of the bodies of the physics world
inline std::vector<RigidBody*>::iterator PhysicsWorld::getRigidBodiesEndIterator() {
inline std::set<RigidBody*>::iterator PhysicsWorld::getRigidBodiesEndIterator() {
return rigidBodies.end();
}
// Return the added bodies since last update of the physics engine
inline std::vector<RigidBody*>& PhysicsWorld::getAddedRigidBodies() {
return addedBodies;
}
// Retrun the removed bodies since last update of the physics engine
inline std::vector<RigidBody*>& PhysicsWorld::getRemovedRigidBodies() {
return removedBodies;
}
} // End of the ReactPhysics3D namespace
#endif
#endif

View File

@ -42,8 +42,8 @@ namespace reactphysics3d {
*/
class Transform {
private :
Vector3 position; // Position
Quaternion orientation; // Orientation
Vector3 position; // Position
Quaternion orientation; // Orientation
public :
Transform(); // Constructor
@ -65,6 +65,8 @@ class Transform {
Vector3 operator*(const Vector3& vector) const; // Return the transformed vector
Transform operator*(const Transform& transform2) const; // Operator of multiplication of a transform with another one
bool operator==(const Transform& transform2) const; // Return true if the two transforms are equal
bool operator!=(const Transform& transform2) const; // Return true if the two transforms are different
};
// Return the position of the transform
@ -91,7 +93,7 @@ inline void Transform::setOrientation(const Quaternion& orientation) {
inline void Transform::setToIdentity() {
position = Vector3(0.0, 0.0, 0.0);
orientation = Quaternion::identity();
}
}
// Set the transform from an OpenGL transform matrix
inline void Transform::setFromOpenGL(decimal* openglMatrix) {
@ -135,6 +137,16 @@ inline Transform Transform::operator*(const Transform& transform2) const {
return Transform(position + orientation.getMatrix() * transform2.position, orientation * transform2.orientation);
}
// Return true if the two transforms are equal
inline bool Transform::operator==(const Transform& transform2) const {
return (position == transform2.position) && (orientation == transform2.orientation);
}
// Return true if the two transforms are different
inline bool Transform::operator!=(const Transform& transform2) const {
return !(*this == transform2);
}
} // End of the ReactPhysics3D namespace
#endif

View File

@ -36,6 +36,13 @@
// TODO : Check that casting is done correctly in this class using
// C++ cast operator like reinterpret_cast<>, ...
// TODO : Rename the variable "maxNbObjects" into "capacity"
// TODO : Replace uint by luint in this class
// TODO : Make the memory pool to start without allocated memory and to grow
// by using several blocks instead of only one.
// ReactPhysics3D namespace
namespace reactphysics3d {