The proxy-shapes are now entities

This commit is contained in:
Daniel Chappuis 2019-03-15 17:27:11 +01:00
parent 4b919fb4fc
commit d02b25d32a
20 changed files with 836 additions and 563 deletions

View File

@ -22,6 +22,9 @@
- The CollisionWorld::setCollisionDispatch() method has been removed. In order to use a custom collision
algorithm, you must not get the collision dispatch object with the
CollisionWorld::getCollisionDispatch() method and set a collision algorithm to this object.
- The methods CollisionBody::getProxyShapesList() has been remove. You can now use the
CollisionBody::getNbProxyShapes() method to know the number of proxy-shapes of a body and the
CollisionBody::getProxyShape(uint proxyShapeIndex) method to get a given proxy-shape of the body.
## Version 0.7.0 (May 1, 2018)

View File

@ -140,6 +140,7 @@ SET (REACTPHYSICS3D_HEADERS
"src/engine/Timer.h"
"src/systems/BroadPhaseSystem.h"
"src/components/Components.h"
"src/components/BodyComponents.h"
"src/components/TransformComponents.h"
"src/components/ProxyShapesComponents.h"
"src/collision/CollisionCallback.h"
@ -230,6 +231,7 @@ SET (REACTPHYSICS3D_SOURCES
"src/engine/Entity.cpp"
"src/engine/EntityManager.cpp"
"src/systems/BroadPhaseSystem.cpp"
"src/components/BodyComponents.cpp"
"src/components/TransformComponents.cpp"
"src/components/ProxyShapesComponents.cpp"
"src/collision/CollisionCallback.cpp"

View File

@ -72,19 +72,24 @@ CollisionBody::~CollisionBody() {
ProxyShape* CollisionBody::addCollisionShape(CollisionShape* collisionShape,
const Transform& transform) {
// Create a new entity for the proxy-shape
Entity proxyShapeEntity = mWorld.mEntityManager.createEntity();
// Create a new proxy collision shape to attach the collision shape to the body
ProxyShape* proxyShape = new (mWorld.mMemoryManager.allocate(MemoryManager::AllocationType::Pool,
sizeof(ProxyShape))) ProxyShape(this, mWorld.mMemoryManager);
sizeof(ProxyShape))) ProxyShape(proxyShapeEntity, this, mWorld.mMemoryManager);
// Add the proxy-shape component to the entity of the body
Vector3 localBoundsMin;
Vector3 localBoundsMax;
// TODO : Maybe this method can directly returns an AABB
collisionShape->getLocalBounds(localBoundsMin, localBoundsMax);
ProxyShapesComponents::ProxyShapeComponent proxyShapeComponent(proxyShape, -1,
ProxyShapesComponents::ProxyShapeComponent proxyShapeComponent(mEntity, proxyShape, -1,
AABB(localBoundsMin, localBoundsMax),
transform, collisionShape, decimal(1), 0x0001, 0xFFFF);
mWorld.mProxyShapesComponents.addComponent(mEntity, mIsSleeping, proxyShapeComponent);
mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, mIsSleeping, proxyShapeComponent);
mWorld.mBodyComponents.addProxyShapeToBody(mEntity, proxyShapeEntity);
#ifdef IS_PROFILING_ACTIVE
@ -118,22 +123,38 @@ ProxyShape* CollisionBody::addCollisionShape(CollisionShape* collisionShape,
return proxyShape;
}
// Return the linked list of proxy shapes of that body
// Return the number of proxy-shapes associated with this body
/**
* @return The pointer of the first proxy shape of the linked-list of all the
* proxy shapes of the body
* @return The number of proxy-shapes associated with this body
*/
ProxyShape* CollisionBody::getProxyShapesList() {
return mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity);
uint CollisionBody::getNbProxyShapes() const {
return static_cast<uint>(mWorld.mBodyComponents.getProxyShapes(mEntity).size());
}
// Return the linked list of proxy shapes of that body
// Return a const pointer to a given proxy-shape of the body
/**
* @return The pointer of the first proxy shape of the linked-list of all the
* proxy shapes of the body
* @return The const pointer of a given proxy-shape of the body
*/
const ProxyShape* CollisionBody::getProxyShapesList() const {
return mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity);
const ProxyShape* CollisionBody::getProxyShape(uint proxyShapeIndex) const {
assert(proxyShapeIndex < getNbProxyShapes());
Entity proxyShapeEntity = mWorld.mBodyComponents.getProxyShapes(mEntity)[proxyShapeIndex];
return mWorld.mProxyShapesComponents.getProxyShape(proxyShapeEntity);
}
// Return a pointer to a given proxy-shape of the body
/**
* @return The pointer of a given proxy-shape of the body
*/
ProxyShape* CollisionBody::getProxyShape(uint proxyShapeIndex) {
assert(proxyShapeIndex < getNbProxyShapes());
Entity proxyShapeEntity = mWorld.mBodyComponents.getProxyShapes(mEntity)[proxyShapeIndex];
return mWorld.mProxyShapesComponents.getProxyShape(proxyShapeEntity);
}
// Remove a collision shape from the body
@ -148,14 +169,16 @@ void CollisionBody::removeCollisionShape(ProxyShape* proxyShape) {
RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::Body,
"Body " + std::to_string(mID) + ": Proxy shape " + std::to_string(proxyShape->getBroadPhaseId()) + " removed from body");
// Remove the proxy-shape component
mWorld.mProxyShapesComponents.removeComponent(proxyShape);
// Remove the proxy-shape from the broad-phase
if (mIsActive && proxyShape->getBroadPhaseId() != -1) {
if (proxyShape->getBroadPhaseId() != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(proxyShape);
}
mWorld.mBodyComponents.removeProxyShapeFromBody(mEntity, proxyShape->getEntity());
// Remove the proxy-shape component
mWorld.mProxyShapesComponents.removeComponent(proxyShape->getEntity());
// Call the constructor of the proxy-shape
proxyShape->~ProxyShape();
@ -166,27 +189,13 @@ void CollisionBody::removeCollisionShape(ProxyShape* proxyShape) {
// Remove all the collision shapes
void CollisionBody::removeAllCollisionShapes() {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity);
// Look for the proxy shape that contains the collision shape in parameter.
// Note that we need to copy the list of proxy shapes entities because we are deleting them in a loop.
const List<Entity> proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
// Look for the proxy shape that contains the collision shape in parameter
while(proxyShape != nullptr) {
if (mIsActive && proxyShape->getBroadPhaseId() != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(proxyShape);
}
// Destroy the proxy-shape
proxyShape->~ProxyShape();
mWorld.mMemoryManager.release(MemoryManager::AllocationType::Pool, proxyShape, sizeof(ProxyShape));
// Get the next element in the list
proxyShape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(proxyShape);
removeCollisionShape(mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]));
}
// Remove all the proxy-shapes components
mWorld.mProxyShapesComponents.removeComponents(mEntity);
}
// Reset the contact manifold lists
@ -222,10 +231,13 @@ const Transform& CollisionBody::getTransform() const {
void CollisionBody::updateBroadPhaseState() const {
// For all the proxy collision shapes of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Update the proxy
updateProxyShapeInBroadPhase(shape);
updateProxyShapeInBroadPhase(proxyShape);
}
}
@ -262,25 +274,31 @@ void CollisionBody::setIsActive(bool isActive) {
const Transform& transform = mWorld.mTransformComponents.getTransform(mEntity);
// For each proxy shape of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Compute the world-space AABB of the new collision shape
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, transform * mWorld.mProxyShapesComponents.getLocalToBodyTransform(shape));
proxyShape->getCollisionShape()->computeAABB(aabb, transform * mWorld.mProxyShapesComponents.getLocalToBodyTransform(proxyShape->getEntity()));
// Add the proxy shape to the collision detection
mWorld.mCollisionDetection.addProxyCollisionShape(shape, aabb);
mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb);
}
}
else { // If we have to deactivate the body
// For each proxy shape of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
if (shape->getBroadPhaseId() != -1) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
if (proxyShape->getBroadPhaseId() != -1) {
// Remove the proxy shape from the collision detection
mWorld.mCollisionDetection.removeProxyCollisionShape(shape);
mWorld.mCollisionDetection.removeProxyCollisionShape(proxyShape);
}
}
@ -298,9 +316,12 @@ void CollisionBody::setIsActive(bool isActive) {
void CollisionBody::askForBroadPhaseCollisionCheck() const {
// For all the proxy collision shapes of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape);
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(proxyShape);
}
}
@ -333,10 +354,13 @@ int CollisionBody::resetIsAlreadyInIslandAndCountManifolds() {
bool CollisionBody::testPointInside(const Vector3& worldPoint) const {
// For each collision shape of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Test if the point is inside the collision shape
if (shape->testPointInside(worldPoint)) return true;
if (proxyShape->testPointInside(worldPoint)) return true;
}
return false;
@ -359,10 +383,13 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
Ray rayTemp(ray);
// For each collision shape of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Test if the ray hits the collision shape
if (shape->raycast(rayTemp, raycastInfo)) {
if (proxyShape->raycast(rayTemp, raycastInfo)) {
rayTemp.maxFraction = raycastInfo.hitFraction;
isHit = true;
}
@ -379,21 +406,24 @@ AABB CollisionBody::getAABB() const {
AABB bodyAABB;
if (mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity) == nullptr) return bodyAABB;
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
if (proxyShapesEntities.size() == 0) return bodyAABB;
// TODO : Make sure we compute this in a system
const Transform& transform = mWorld.mTransformComponents.getTransform(mEntity);
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity);
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[0]);
proxyShape->getCollisionShape()->computeAABB(bodyAABB, transform * proxyShape->getLocalToBodyTransform());
// For each proxy shape of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
for (uint i=1; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Compute the world-space AABB of the collision shape
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, transform * shape->getLocalToBodyTransform());
proxyShape->getCollisionShape()->computeAABB(aabb, transform * proxyShape->getLocalToBodyTransform());
// Merge the proxy shape AABB with the current body AABB
bodyAABB.mergeWithAABB(aabb);

View File

@ -166,12 +166,18 @@ class CollisionBody : public Body {
/// Compute and return the AABB of the body by merging all proxy shapes AABBs
AABB getAABB() const;
/// Return the linked list of proxy shapes of that body
ProxyShape* getProxyShapesList();
/// Return a const pointer to a given proxy-shape of the body
const ProxyShape* getProxyShape(uint proxyShapeIndex) const;
/// Return a pointer to a given proxy-shape of the body
ProxyShape* getProxyShape(uint proxyShapeIndex);
/// Return the linked list of proxy shapes of that body
const ProxyShape* getProxyShapesList() const;
/// Return the number of proxy-shapes associated with this body
uint getNbProxyShapes() const;
/// Return the world-space coordinates of a point given the local-space coordinates of the body
Vector3 getWorldPoint(const Vector3& localPoint) const;

View File

@ -281,9 +281,12 @@ ProxyShape* RigidBody::addCollisionShape(CollisionShape* collisionShape,
const Transform& transform,
decimal mass) {
// Create a new entity for the proxy-shape
Entity proxyShapeEntity = mWorld.mEntityManager.createEntity();
// Create a new proxy collision shape to attach the collision shape to the body
ProxyShape* proxyShape = new (mWorld.mMemoryManager.allocate(MemoryManager::AllocationType::Pool,
sizeof(ProxyShape))) ProxyShape(this, mWorld.mMemoryManager);
sizeof(ProxyShape))) ProxyShape(proxyShapeEntity, this, mWorld.mMemoryManager);
// Add the proxy-shape component to the entity of the body
Vector3 localBoundsMin;
@ -291,10 +294,12 @@ ProxyShape* RigidBody::addCollisionShape(CollisionShape* collisionShape,
// TODO : Maybe this method can directly returns an AABB
collisionShape->getLocalBounds(localBoundsMin, localBoundsMax);
ProxyShapesComponents::ProxyShapeComponent proxyShapeComponent(proxyShape, -1,
ProxyShapesComponents::ProxyShapeComponent proxyShapeComponent(mEntity, proxyShape, -1,
AABB(localBoundsMin, localBoundsMax),
transform, collisionShape, mass, 0x0001, 0xFFFF);
mWorld.mProxyShapesComponents.addComponent(mEntity, mIsSleeping, proxyShapeComponent);
mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, mIsSleeping, proxyShapeComponent);
mWorld.mBodyComponents.addProxyShapeToBody(mEntity, proxyShapeEntity);
#ifdef IS_PROFILING_ACTIVE
@ -500,11 +505,13 @@ void RigidBody::recomputeMassInformation() {
assert(mType == BodyType::DYNAMIC);
// Compute the total mass of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
mInitMass += shape->getMass();
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
mInitMass += proxyShape->getMass();
if (!mIsCenterOfMassSetByUser) {
mCenterOfMassLocal += shape->getLocalToBodyTransform().getPosition() * shape->getMass();
mCenterOfMassLocal += proxyShape->getLocalToBodyTransform().getPosition() * proxyShape->getMass();
}
}
@ -528,14 +535,17 @@ void RigidBody::recomputeMassInformation() {
if (!mIsInertiaTensorSetByUser) {
// Compute the inertia tensor using all the collision shapes
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Get the inertia tensor of the collision shape in its local-space
Matrix3x3 inertiaTensor;
shape->getCollisionShape()->computeLocalInertiaTensor(inertiaTensor, shape->getMass());
proxyShape->getCollisionShape()->computeLocalInertiaTensor(inertiaTensor, proxyShape->getMass());
// Convert the collision shape inertia tensor into the local-space of the body
const Transform& shapeTransform = shape->getLocalToBodyTransform();
const Transform& shapeTransform = proxyShape->getLocalToBodyTransform();
Matrix3x3 rotationMatrix = shapeTransform.getOrientation().getMatrix();
inertiaTensor = rotationMatrix * inertiaTensor * rotationMatrix.getTranspose();
@ -550,7 +560,7 @@ void RigidBody::recomputeMassInformation() {
offsetMatrix[0] += offset * (-offset.x);
offsetMatrix[1] += offset * (-offset.y);
offsetMatrix[2] += offset * (-offset.z);
offsetMatrix *= shape->getMass();
offsetMatrix *= proxyShape->getMass();
inertiaTensorLocal += inertiaTensor + offsetMatrix;
}
@ -579,14 +589,20 @@ void RigidBody::updateBroadPhaseState() const {
const Vector3 displacement = world.mTimeStep * mLinearVelocity;
// For all the proxy collision shapes of the body
for (ProxyShape* shape = mWorld.mProxyShapesComponents.getFirstProxyShapeOfBody(mEntity); shape != nullptr; shape = mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(shape)) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
// Recompute the world-space AABB of the collision shape
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, transform * shape->getLocalToBodyTransform());
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
// Update the broad-phase state for the proxy collision shape
mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb, displacement);
if (proxyShape->getBroadPhaseId() != -1) {
// Recompute the world-space AABB of the collision shape
AABB aabb;
proxyShape->getCollisionShape()->computeAABB(aabb, transform * proxyShape->getLocalToBodyTransform());
// Update the broad-phase state for the proxy collision shape
mWorld.mCollisionDetection.updateProxyCollisionShape(proxyShape, aabb, displacement);
}
}
}
@ -598,12 +614,12 @@ void RigidBody::setProfiler(Profiler* profiler) {
CollisionBody::setProfiler(profiler);
// Set the profiler for each proxy shape
ProxyShape* proxyShape = getProxyShapesList();
while (proxyShape != nullptr) {
const List<Entity>& proxyShapesEntities = mWorld.mBodyComponents.getProxyShapes(mEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* proxyShape = mWorld.mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
proxyShape->setProfiler(profiler);
proxyShape = proxyShape->getNext();
}
}

View File

@ -608,14 +608,18 @@ bool CollisionDetection::testOverlap(CollisionBody* body1, CollisionBody* body2)
NarrowPhaseInput narrowPhaseInput(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the first body
ProxyShape* body1ProxyShape = body1->getProxyShapesList();
while (body1ProxyShape != nullptr) {
const List<Entity>& body1ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body1->getEntity());
const List<Entity>& body2ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body2->getEntity());
for (uint i=0; i < body1ProxyShapesEntities.size(); i++) {
ProxyShape* body1ProxyShape = mWorld->mProxyShapesComponents.getProxyShape(body1ProxyShapesEntities[i]);
AABB aabb1 = body1ProxyShape->getWorldAABB();
// For each proxy shape of the second body
ProxyShape* body2ProxyShape = body2->getProxyShapesList();
while (body2ProxyShape != nullptr) {
for (uint j=0; j < body2ProxyShapesEntities.size(); j++) {
ProxyShape* body2ProxyShape = mWorld->mProxyShapesComponents.getProxyShape(body2ProxyShapesEntities[j]);
AABB aabb2 = body2ProxyShape->getWorldAABB();
@ -630,13 +634,7 @@ bool CollisionDetection::testOverlap(CollisionBody* body1, CollisionBody* body2)
computeMiddlePhaseForProxyShapes(&pair, narrowPhaseInput);
}
// Go to the next proxy shape
body2ProxyShape = body2ProxyShape->getNext();
}
// Go to the next proxy shape
body1ProxyShape = body1ProxyShape->getNext();
}
// Test narrow-phase collision
@ -656,8 +654,10 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
NarrowPhaseInput narrowPhaseInput(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the body
ProxyShape* bodyProxyShape = body->getProxyShapesList();
while (bodyProxyShape != nullptr) {
const List<Entity>& proxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body->getEntity());
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* bodyProxyShape = mWorld->mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
if (bodyProxyShape->getBroadPhaseId() != -1) {
@ -713,9 +713,6 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
element = element->next;
}
}
// Go to the next proxy shape
bodyProxyShape = bodyProxyShape->getNext();
}
}
@ -728,14 +725,18 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
OverlappingPairMap overlappingPairs(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the first body
ProxyShape* body1ProxyShape = body1->getProxyShapesList();
while (body1ProxyShape != nullptr) {
const List<Entity>& body1ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body1->getEntity());
const List<Entity>& body2ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body2->getEntity());
for (uint i=0; i < body1ProxyShapesEntities.size(); i++) {
ProxyShape* body1ProxyShape = mWorld->mProxyShapesComponents.getProxyShape(body1ProxyShapesEntities[i]);
AABB aabb1 = body1ProxyShape->getWorldAABB();
// For each proxy shape of the second body
ProxyShape* body2ProxyShape = body2->getProxyShapesList();
while (body2ProxyShape != nullptr) {
for (uint j=0; j < body2ProxyShapesEntities.size(); j++) {
ProxyShape* body2ProxyShape = mWorld->mProxyShapesComponents.getProxyShape(body2ProxyShapesEntities[i]);
AABB aabb2 = body2ProxyShape->getWorldAABB();
@ -767,13 +768,7 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
// Compute the middle-phase collision detection between the two shapes
computeMiddlePhaseForProxyShapes(pair, narrowPhaseInput);
}
// Go to the next proxy shape
body2ProxyShape = body2ProxyShape->getNext();
}
// Go to the next proxy shape
body1ProxyShape = body1ProxyShape->getNext();
}
// Test narrow-phase collision
@ -812,8 +807,10 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
OverlappingPairMap overlappingPairs(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the body
ProxyShape* bodyProxyShape = body->getProxyShapesList();
while (bodyProxyShape != nullptr) {
const List<Entity>& proxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body->getEntity());
for (uint i=0; i < proxyShapesEntities.size(); i++) {
ProxyShape* bodyProxyShape = mWorld->mProxyShapesComponents.getProxyShape(proxyShapesEntities[i]);
if (bodyProxyShape->getBroadPhaseId() != -1) {
@ -870,9 +867,6 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
// Go to the next overlapping proxy shape
element = element->next;
}
// Go to the next proxy shape
bodyProxyShape = bodyProxyShape->getNext();
}
}

View File

@ -39,8 +39,8 @@ using namespace reactphysics3d;
* @param transform Transformation from collision shape local-space to body local-space
* @param mass Mass of the collision shape (in kilograms)
*/
ProxyShape::ProxyShape(CollisionBody* body, MemoryManager& memoryManager)
:mMemoryManager(memoryManager), mBody(body),
ProxyShape::ProxyShape(Entity entity, CollisionBody* body, MemoryManager& memoryManager)
:mMemoryManager(memoryManager), mEntity(entity), mBody(body),
mUserData(nullptr) {
}
@ -55,7 +55,7 @@ ProxyShape::~ProxyShape() {
* @return Mass of the collision shape (in kilograms)
*/
decimal ProxyShape::getMass() const {
return mBody->mWorld.mProxyShapesComponents.getMass(this);
return mBody->mWorld.mProxyShapesComponents.getMass(mEntity);
}
@ -66,9 +66,9 @@ decimal ProxyShape::getMass() const {
*/
bool ProxyShape::testPointInside(const Vector3& worldPoint) {
const Transform localToWorld = mBody->mWorld.mTransformComponents.getTransform(mBody->getEntity()) *
mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(this);
mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(mEntity);
const Vector3 localPoint = localToWorld.getInverse() * worldPoint;
const CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
const CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
return collisionShape->testPointInside(localPoint, this);
}
@ -78,9 +78,9 @@ bool ProxyShape::testPointInside(const Vector3& worldPoint) {
*/
void ProxyShape::setCollisionCategoryBits(unsigned short collisionCategoryBits) {
mBody->mWorld.mProxyShapesComponents.setCollisionCategoryBits(this, collisionCategoryBits);
mBody->mWorld.mProxyShapesComponents.setCollisionCategoryBits(mEntity, collisionCategoryBits);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(this);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(mEntity);
RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::ProxyShape,
"ProxyShape " + std::to_string(broadPhaseId) + ": Set collisionCategoryBits=" +
@ -93,9 +93,9 @@ void ProxyShape::setCollisionCategoryBits(unsigned short collisionCategoryBits)
*/
void ProxyShape::setCollideWithMaskBits(unsigned short collideWithMaskBits) {
mBody->mWorld.mProxyShapesComponents.setCollideWithMaskBits(this, collideWithMaskBits);
mBody->mWorld.mProxyShapesComponents.setCollideWithMaskBits(mEntity, collideWithMaskBits);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(this);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(mEntity);
RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::ProxyShape,
"ProxyShape " + std::to_string(broadPhaseId) + ": Set collideWithMaskBits=" +
@ -106,14 +106,14 @@ void ProxyShape::setCollideWithMaskBits(unsigned short collideWithMaskBits) {
void ProxyShape::setLocalToBodyTransform(const Transform& transform) {
//mLocalToBodyTransform = transform;
mBody->mWorld.mProxyShapesComponents.setLocalToBodyTransform(this, transform);
mBody->mWorld.mProxyShapesComponents.setLocalToBodyTransform(mEntity, transform);
mBody->setIsSleeping(false);
// Notify the body that the proxy shape has to be updated in the broad-phase
mBody->updateProxyShapeInBroadPhase(this, true);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(this);
int broadPhaseId = mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(mEntity);
RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::ProxyShape,
"ProxyShape " + std::to_string(broadPhaseId) + ": Set localToBodyTransform=" +
@ -126,7 +126,7 @@ void ProxyShape::setLocalToBodyTransform(const Transform& transform) {
*/
const AABB ProxyShape::getWorldAABB() const {
AABB aabb;
CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
collisionShape->computeAABB(aabb, getLocalToWorldTransform());
return aabb;
}
@ -136,7 +136,7 @@ const AABB ProxyShape::getWorldAABB() const {
* @return Pointer to the internal collision shape
*/
const CollisionShape* ProxyShape::getCollisionShape() const {
return mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
return mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
}
// Return the collision shape
@ -144,12 +144,12 @@ const CollisionShape* ProxyShape::getCollisionShape() const {
* @return Pointer to the internal collision shape
*/
CollisionShape* ProxyShape::getCollisionShape() {
return mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
return mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
}
// Return the broad-phase id
int ProxyShape::getBroadPhaseId() const {
return mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(this);
return mBody->mWorld.mProxyShapesComponents.getBroadPhaseId(mEntity);
}
// Return the local to parent body transform
@ -158,25 +158,7 @@ int ProxyShape::getBroadPhaseId() const {
* to the local-space of the parent body
*/
const Transform& ProxyShape::getLocalToBodyTransform() const {
return mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(this);
}
// Return the next proxy shape in the linked list of proxy shapes
/**
* @return Pointer to the next proxy shape in the linked list of proxy shapes
*/
ProxyShape* ProxyShape::getNext() {
// TODO : Delete this method
return mBody->mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(this);
}
// Return the next proxy shape in the linked list of proxy shapes
/**
* @return Pointer to the next proxy shape in the linked list of proxy shapes
*/
const ProxyShape* ProxyShape::getNext() const {
// TODO : Delete this method
return mBody->mWorld.mProxyShapesComponents.getNextProxyShapeOfBody(this);
return mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(mEntity);
}
// Raycast method with feedback information
@ -198,7 +180,7 @@ bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
worldToLocalTransform * ray.point2,
ray.maxFraction);
const CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
const CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
bool isHit = collisionShape->raycast(rayLocal, raycastInfo, this, mMemoryManager.getPoolAllocator());
// Convert the raycast info into world-space
@ -214,7 +196,7 @@ bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
* @return The collision category bits mask of the proxy shape
*/
unsigned short ProxyShape::getCollisionCategoryBits() const {
return mBody->mWorld.mProxyShapesComponents.getCollisionCategoryBits(this);
return mBody->mWorld.mProxyShapesComponents.getCollisionCategoryBits(mEntity);
}
// Return the collision bits mask
@ -222,7 +204,7 @@ unsigned short ProxyShape::getCollisionCategoryBits() const {
* @return The bits mask that specifies with which collision category this shape will collide
*/
unsigned short ProxyShape::getCollideWithMaskBits() const {
return mBody->mWorld.mProxyShapesComponents.getCollideWithMaskBits(this);
return mBody->mWorld.mProxyShapesComponents.getCollideWithMaskBits(mEntity);
}
// Return the local to world transform
@ -232,7 +214,7 @@ unsigned short ProxyShape::getCollideWithMaskBits() const {
*/
const Transform ProxyShape::getLocalToWorldTransform() const {
return mBody->mWorld.mTransformComponents.getTransform(mBody->getEntity()) *
mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(this);
mBody->mWorld.mProxyShapesComponents.getLocalToBodyTransform(mEntity);
}
#ifdef IS_PROFILING_ACTIVE
@ -242,7 +224,7 @@ void ProxyShape::setProfiler(Profiler* profiler) {
mProfiler = profiler;
CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(this);
CollisionShape* collisionShape = mBody->mWorld.mProxyShapesComponents.getCollisionShape(mEntity);
collisionShape->setProfiler(profiler);
}

View File

@ -54,6 +54,9 @@ class ProxyShape {
/// Reference to the memory manager
MemoryManager& mMemoryManager;
/// Identifier of the entity in the ECS
Entity mEntity;
/// Pointer to the parent body
CollisionBody* mBody;
@ -111,7 +114,7 @@ class ProxyShape {
// -------------------- Methods -------------------- //
/// Constructor
ProxyShape(CollisionBody* body, MemoryManager& memoryManager);
ProxyShape(Entity entity, CollisionBody* body, MemoryManager& memoryManager);
/// Destructor
virtual ~ProxyShape();
@ -122,6 +125,9 @@ class ProxyShape {
/// Deleted assignment operator
ProxyShape& operator=(const ProxyShape& proxyShape) = delete;
/// Return the corresponding entity of the proxy-shape
Entity getEntity() const;
/// Return the collision shape
const CollisionShape* getCollisionShape() const;
@ -170,12 +176,6 @@ class ProxyShape {
/// Set the collision category bits
void setCollisionCategoryBits(unsigned short collisionCategoryBits);
/// Return the next proxy shape in the linked list of proxy shapes
ProxyShape* getNext();
/// Return the next proxy shape in the linked list of proxy shapes
const ProxyShape* getNext() const;
/// Return the broad-phase id
int getBroadPhaseId() const;
@ -209,6 +209,14 @@ class ProxyShape {
};
// Return the corresponding entity of the proxy-shape
/**
* @return The entity of the proxy-shape
*/
inline Entity ProxyShape::getEntity() const {
return mEntity;
}
// Return the parent body
/**
* @return Pointer to the parent body

View File

@ -0,0 +1,294 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2018 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 "BodyComponents.h"
#include "engine/EntityManager.h"
#include <cassert>
#include <random>
// We want to use the ReactPhysics3D namespace
using namespace reactphysics3d;
// Constructor
BodyComponents::BodyComponents(MemoryAllocator& allocator)
:Components(allocator), mSleepingStartIndex(0){
// Allocate memory for the components data
allocate(INIT_ALLOCATED_COMPONENTS);
}
// Destructor
BodyComponents::~BodyComponents() {
if (mNbAllocatedComponents > 0) {
// Destroy all the remaining components
for (uint32 i = 0; i < mNbComponents; i++) {
// TODO : MAke sure we do not delete already deleted components
destroyComponent(i);
}
// Size for the data of a single component (in bytes)
const size_t totalSizeBytes = mNbAllocatedComponents * COMPONENT_DATA_SIZE;
// Release the allocated memory
mMemoryAllocator.release(mBuffer, totalSizeBytes);
}
}
// Allocate memory for a given number of components
void BodyComponents::allocate(uint32 nbComponentsToAllocate) {
assert(nbComponentsToAllocate > mNbAllocatedComponents);
// Size for the data of a single component (in bytes)
const size_t totalSizeBytes = nbComponentsToAllocate * COMPONENT_DATA_SIZE;
// Allocate memory
void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes);
assert(newBuffer != nullptr);
// New pointers to components data
Entity* newBodiesEntities = static_cast<Entity*>(newBuffer);
Body** newBodies = reinterpret_cast<Body**>(newBodiesEntities + nbComponentsToAllocate);
List<Entity>* newProxyShapes = reinterpret_cast<List<Entity>*>(newBodies + nbComponentsToAllocate);
// If there was already components before
if (mNbComponents > 0) {
// Copy component data from the previous buffer to the new one
memcpy(newBodiesEntities, mBodiesEntities, mNbComponents * sizeof(Entity));
memcpy(newBodies, mBodies, mNbComponents * sizeof(Body*));
memcpy(newProxyShapes, mProxyShapes, mNbComponents * sizeof(List<Entity>));
// Deallocate previous memory
mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE);
}
mBuffer = newBuffer;
mBodiesEntities = newBodiesEntities;
mBodies = newBodies;
mProxyShapes = newProxyShapes;
mNbAllocatedComponents = nbComponentsToAllocate;
}
// Add a component
void BodyComponents::addComponent(Entity bodyEntity, bool isSleeping, const BodyComponent& component) {
// If we need to allocate more components
if (mNbComponents == mNbAllocatedComponents) {
allocate(mNbAllocatedComponents * 2);
}
uint32 index;
// If the component to add is part of a sleeping entity or there are no sleeping entity
if (isSleeping) {
// Add the component at the end of the array
index = mNbComponents;
mSleepingStartIndex = index;
}
// If the component to add is not part of a sleeping entity
else {
// If there already are sleeping components
if (mSleepingStartIndex != mNbComponents) {
// Move the first sleeping component to the end of the array
moveComponentToIndex(mSleepingStartIndex, mNbComponents);
}
index = mSleepingStartIndex;
mSleepingStartIndex++;
}
// Insert the new component data
new (mBodiesEntities + index) Entity(bodyEntity);
mBodies[index] = component.body;
new (mProxyShapes + index) List<Entity>(mMemoryAllocator);
// Map the entity with the new component lookup index
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(bodyEntity, index));
mNbComponents++;
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Remove a component at a given index
void BodyComponents::removeComponent(Entity bodyEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
uint index = mMapEntityToComponentIndex[bodyEntity];
assert(index < mNbComponents);
// We want to keep the arrays tightly packed. Therefore, when a component is removed,
// we replace it with the last element of the array. But we need to make sure that sleeping
// and non-sleeping components stay grouped together.
// Destroy the component
destroyComponent(index);
// If the component to remove is sleeping
if (index >= mSleepingStartIndex) {
// If the component is not the last one
if (index != mNbComponents - 1) {
// We replace it by the last sleeping component
moveComponentToIndex(mNbComponents - 1, index);
}
}
else { // If the component to remove is not sleeping
// If it not the last awake component
if (index != mSleepingStartIndex - 1) {
// We replace it by the last awake component
moveComponentToIndex(mSleepingStartIndex - 1, index);
}
// If there are sleeping components at the end
if (mSleepingStartIndex != mNbComponents) {
// We replace the last awake component by the last sleeping component
moveComponentToIndex(mNbComponents - 1, mSleepingStartIndex - 1);
}
mSleepingStartIndex--;
}
mNbComponents--;
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Notify if a given entity is sleeping or not
void BodyComponents::setIsEntitySleeping(Entity entity, bool isSleeping) {
const uint32 index = mMapEntityToComponentIndex[entity];
// If the component was sleeping and is not sleeping anymore
if (!isSleeping && index >= mSleepingStartIndex) {
assert(mSleepingStartIndex < mNbComponents);
// If the sleeping component is not the first sleeping component
if (mSleepingStartIndex != index) {
// Swap the first sleeping component with the one we need to wake up
swapComponents(index, mSleepingStartIndex);
}
mSleepingStartIndex++;
}
// If the component was awake and must now go to sleep
else if (isSleeping && index < mSleepingStartIndex) {
assert(mSleepingStartIndex > 0);
// If the awake component is not the only awake component
if (index != mSleepingStartIndex - 1) {
// Swap the last awake component with the one we need to put to sleep
swapComponents(index, mSleepingStartIndex - 1);
}
mSleepingStartIndex--;
}
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Move a component from a source to a destination index in the components array
// The destination location must contain a constructed object
void BodyComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) {
const Entity entity = mBodiesEntities[srcIndex];
// Copy the data of the source component to the destination location
new (mBodiesEntities + destIndex) Entity(mBodiesEntities[srcIndex]);
mBodies[destIndex] = mBodies[srcIndex];
new (mProxyShapes + destIndex) List<Entity>(mProxyShapes[srcIndex]);
// Destroy the source component
destroyComponent(srcIndex);
assert(!mMapEntityToComponentIndex.containsKey(entity));
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity, destIndex));
assert(mMapEntityToComponentIndex[mBodiesEntities[destIndex]] == destIndex);
}
// Swap two components in the array
void BodyComponents::swapComponents(uint32 index1, uint32 index2) {
// Copy component 1 data
Entity entity1(mBodiesEntities[index1]);
Body* body1 = mBodies[index1];
List<Entity> proxyShapes1(mProxyShapes[index1]);
// Destroy component 1
destroyComponent(index1);
moveComponentToIndex(index2, index1);
// Reconstruct component 1 at component 2 location
new (mBodiesEntities + index2) Entity(entity1);
new (mProxyShapes + index2) List<Entity>(proxyShapes1);
mBodies[index2] = body1;
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity1, index2));
assert(mMapEntityToComponentIndex[mBodiesEntities[index1]] == index1);
assert(mMapEntityToComponentIndex[mBodiesEntities[index2]] == index2);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Destroy a component at a given index
void BodyComponents::destroyComponent(uint32 index) {
assert(index < mNbComponents);
assert(mMapEntityToComponentIndex[mBodiesEntities[index]] == index);
mMapEntityToComponentIndex.remove(mBodiesEntities[index]);
mBodiesEntities[index].~Entity();
mBodies[index] = nullptr;
mProxyShapes[index].~List<Entity>();
}

View File

@ -0,0 +1,161 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2018 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. *
* *
********************************************************************************/
#ifndef REACTPHYSICS3D_BODY_COMPONENTS_H
#define REACTPHYSICS3D_BODY_COMPONENTS_H
// Libraries
#include "mathematics/Transform.h"
#include "engine/Entity.h"
#include "components/Components.h"
#include "containers/Map.h"
// ReactPhysics3D namespace
namespace reactphysics3d {
// Class declarations
class MemoryAllocator;
class EntityManager;
class Body;
// Class BodyComponents
/**
* This class represent the component of the ECS that contains data about a physics body.
* The components of the sleeping entities (bodies) are always stored at the end of the array.
*/
class BodyComponents : public Components {
private:
// -------------------- Constants -------------------- //
const size_t COMPONENT_DATA_SIZE = sizeof(Entity) + sizeof(Body*) + sizeof(List<Entity>);
// -------------------- Attributes -------------------- //
/// Index of the first component of a sleeping entity (sleeping components are stored at the end)
uint32 mSleepingStartIndex;
/// Array of body entities of each component
Entity* mBodiesEntities;
/// Array of pointers to the corresponding bodies
Body** mBodies;
/// Array with the list of proxy-shapes of each body
List<Entity>* mProxyShapes;
// -------------------- Methods -------------------- //
/// Destroy a component at a given index
void destroyComponent(uint32 index);
/// Move a component from a source to a destination index in the components array
void moveComponentToIndex(uint32 srcIndex, uint32 destIndex);
/// Swap two components in the array
void swapComponents(uint32 index1, uint32 index2);
public:
/// Structure for the data of a body component
struct BodyComponent {
Body* body;
/// Constructor
BodyComponent(Body* body) : body(body) {
}
};
// -------------------- Methods -------------------- //
/// Constructor
BodyComponents(MemoryAllocator& allocator);
/// Destructor
virtual ~BodyComponents();
/// Allocate memory for a given number of components
void allocate(uint32 nbComponentsToAllocate);
/// Add a component
void addComponent(Entity bodyEntity, bool isSleeping, const BodyComponent& component);
/// Remove a component at a given index
void removeComponent(Entity bodyEntity);
/// Add a proxy-shape to a body component
void addProxyShapeToBody(Entity bodyEntity, Entity proxyShapeEntity);
/// Set the transform of an entity
void removeProxyShapeFromBody(Entity bodyEntity, Entity proxyShapeEntity);
/// Return a pointer to a body
Body* getBody(Entity bodyEntity);
/// Return the list of proxy-shapes of a body
const List<Entity>& getProxyShapes(Entity bodyEntity) const;
/// Notify if a given entity is sleeping or not
void setIsEntitySleeping(Entity bodyEntity, bool isSleeping);
};
// Add a proxy-shape to a body component
inline void BodyComponents::addProxyShapeToBody(Entity bodyEntity, Entity proxyShapeEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
mProxyShapes[mMapEntityToComponentIndex[bodyEntity]].add(proxyShapeEntity);
}
// Set the transform of an entity
inline void BodyComponents::removeProxyShapeFromBody(Entity bodyEntity, Entity proxyShapeEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
mProxyShapes[mMapEntityToComponentIndex[bodyEntity]].remove(proxyShapeEntity);
}
// Return a pointer to a body
inline Body* BodyComponents::getBody(Entity bodyEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
return mBodies[mMapEntityToComponentIndex[bodyEntity]];
}
// Return the list of proxy-shapes of a body
inline const List<Entity>& BodyComponents::getProxyShapes(Entity bodyEntity) const {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
return mProxyShapes[mMapEntityToComponentIndex[bodyEntity]];
}
}
#endif

View File

@ -86,6 +86,11 @@ class Components {
virtual ~Components() {
}
/// Return the number of components
uint32 getNbComponents() const {
return mNbComponents;
}
};
}

View File

@ -36,8 +36,7 @@ using namespace reactphysics3d;
// Constructor
ProxyShapesComponents::ProxyShapesComponents(MemoryAllocator& allocator)
:Components(allocator),
mSleepingStartIndex(0),
mMapProxyShapeToComponentIndex(allocator) {
mSleepingStartIndex(0) {
// Allocate memory for the components data
allocate(INIT_ALLOCATED_COMPONENTS);
@ -76,31 +75,29 @@ void ProxyShapesComponents::allocate(uint32 nbComponentsToAllocate) {
assert(newBuffer != nullptr);
// New pointers to components data
Entity* newEntities = static_cast<Entity*>(newBuffer);
ProxyShape** newProxyShapes = reinterpret_cast<ProxyShape**>(newEntities + nbComponentsToAllocate);
Entity* newProxyShapesEntities = static_cast<Entity*>(newBuffer);
Entity* newBodiesEntities = reinterpret_cast<Entity*>(newProxyShapesEntities + nbComponentsToAllocate);
ProxyShape** newProxyShapes = reinterpret_cast<ProxyShape**>(newBodiesEntities + nbComponentsToAllocate);
int* newBroadPhaseIds = reinterpret_cast<int*>(newProxyShapes + nbComponentsToAllocate);
AABB* newLocalBounds = reinterpret_cast<AABB*>(newBroadPhaseIds + nbComponentsToAllocate);
Transform* newLocalToBodyTransforms = reinterpret_cast<Transform*>(newLocalBounds + nbComponentsToAllocate);
CollisionShape** newCollisionShapes = reinterpret_cast<CollisionShape**>(newLocalToBodyTransforms + nbComponentsToAllocate);
decimal* newMasses = reinterpret_cast<decimal*>(newCollisionShapes + nbComponentsToAllocate);
uint32* newPreviousBodyProxyShapes = reinterpret_cast<uint32*>(newMasses + nbComponentsToAllocate);
uint32* newNextBodyProxyShapes = reinterpret_cast<uint32*>(newPreviousBodyProxyShapes + nbComponentsToAllocate);
unsigned short* newCollisionCategoryBits = reinterpret_cast<unsigned short*>(newNextBodyProxyShapes + nbComponentsToAllocate);
unsigned short* newCollisionCategoryBits = reinterpret_cast<unsigned short*>(newMasses + nbComponentsToAllocate);
unsigned short* newCollideWithMaskBits = reinterpret_cast<unsigned short*>(newCollisionCategoryBits + nbComponentsToAllocate);
// If there was already components before
if (mNbComponents > 0) {
// Copy component data from the previous buffer to the new one
memcpy(newEntities, mEntities, mNbComponents * sizeof(Entity));
memcpy(newProxyShapesEntities, mProxyShapesEntities, mNbComponents * sizeof(Entity));
memcpy(newBodiesEntities, mBodiesEntities, mNbComponents * sizeof(Entity));
memcpy(newProxyShapes, mProxyShapes, mNbComponents * sizeof(ProxyShape*));
memcpy(newBroadPhaseIds, mBroadPhaseIds, mNbComponents * sizeof(int));
memcpy(newLocalBounds, mLocalBounds, mNbComponents * sizeof(AABB));
memcpy(newLocalToBodyTransforms, mLocalToBodyTransforms, mNbComponents * sizeof(Transform));
memcpy(newCollisionShapes, mCollisionShapes, mNbComponents * sizeof(CollisionShape*));
memcpy(newMasses, mMasses, mNbComponents * sizeof(decimal));
memcpy(newPreviousBodyProxyShapes, mPreviousBodyProxyShapes, mNbComponents * sizeof(uint32));
memcpy(newNextBodyProxyShapes, mNextBodyProxyShapes, mNbComponents * sizeof(uint32));
memcpy(newCollisionCategoryBits, mCollisionCategoryBits, mNbComponents * sizeof(unsigned short));
memcpy(newCollideWithMaskBits, mCollideWithMaskBits, mNbComponents * sizeof(unsigned short));
@ -109,63 +106,23 @@ void ProxyShapesComponents::allocate(uint32 nbComponentsToAllocate) {
}
mBuffer = newBuffer;
mEntities = newEntities;
mProxyShapesEntities = newProxyShapesEntities;
mBodiesEntities = newBodiesEntities;
mProxyShapesEntities = newProxyShapesEntities;
mProxyShapes = newProxyShapes;
mBroadPhaseIds = newBroadPhaseIds;
mLocalBounds = newLocalBounds;
mLocalToBodyTransforms = newLocalToBodyTransforms;
mCollisionShapes = newCollisionShapes;
mMasses = newMasses;
mPreviousBodyProxyShapes = newPreviousBodyProxyShapes;
mNextBodyProxyShapes = newNextBodyProxyShapes;
mCollisionCategoryBits = newCollisionCategoryBits;
mCollideWithMaskBits = newCollideWithMaskBits;
mNbAllocatedComponents = nbComponentsToAllocate;
}
// Add a new proxy-shape at the beginning of the linked-list of proxy-shapes of a given entity
// If it is the first proxy-shape for the entity, it will create the first item of the linked-list
void ProxyShapesComponents::linkProxyShapeWithEntity(Entity entity, uint32 proxyShapeComponentIndex) {
auto it = mMapEntityToComponentIndex.find(entity);
if (it != mMapEntityToComponentIndex.end()) {
// Get the first proxy-shape of the linked-list
uint32 firstProxyShapeIndex = (*it).second;
assert(!hasPreviousProxyShape(firstProxyShapeIndex));
// Update the previous index of the first item of the list
mPreviousBodyProxyShapes[firstProxyShapeIndex] = proxyShapeComponentIndex;
// Map the entity to the new head of the linked-list
mMapEntityToComponentIndex[entity] = proxyShapeComponentIndex;
// Add the new proxy-shape at the beginning of the linked-list
const uint32 nextIndex = firstProxyShapeIndex;
const uint32 previousIndex = proxyShapeComponentIndex;
new (mNextBodyProxyShapes + proxyShapeComponentIndex) uint32(nextIndex);
new (mPreviousBodyProxyShapes + proxyShapeComponentIndex) uint32(previousIndex);
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[proxyShapeComponentIndex]] == proxyShapeComponentIndex);
}
else { // If the entity does not have a proxy-shape yet
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity, proxyShapeComponentIndex));
// The new proxy-shape has no previous/next components in the linked-list
new (mNextBodyProxyShapes + proxyShapeComponentIndex) uint32(proxyShapeComponentIndex);
new (mPreviousBodyProxyShapes + proxyShapeComponentIndex) uint32(proxyShapeComponentIndex);
assert(!hasNextProxyShape(proxyShapeComponentIndex));
}
assert(!hasPreviousProxyShape(proxyShapeComponentIndex));
}
// Add a component
void ProxyShapesComponents::addComponent(Entity entity, bool isSleeping, const ProxyShapeComponent& component) {
void ProxyShapesComponents::addComponent(Entity proxyShapeEntity, bool isSleeping, const ProxyShapeComponent& component) {
// If we need to allocate more components
if (mNbComponents == mNbAllocatedComponents) {
@ -198,8 +155,9 @@ void ProxyShapesComponents::addComponent(Entity entity, bool isSleeping, const P
}
// Insert the new component data
new (mEntities + index) Entity(entity);
mProxyShapes[index] = (component.proxyShape);
new (mProxyShapesEntities + index) Entity(proxyShapeEntity);
new (mBodiesEntities + index) Entity(component.bodyEntity);
mProxyShapes[index] = component.proxyShape;
new (mBroadPhaseIds + index) int(component.broadPhaseId);
new (mLocalBounds + index) AABB(component.localBounds);
new (mLocalToBodyTransforms + index) Transform(component.localToBodyTransform);
@ -208,133 +166,89 @@ void ProxyShapesComponents::addComponent(Entity entity, bool isSleeping, const P
new (mCollisionCategoryBits + index) unsigned short(component.collisionCategoryBits);
new (mCollideWithMaskBits + index) unsigned short(component.collideWithMaskBits);
mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(component.proxyShape, index));
// Map the entity with the new component lookup index
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(proxyShapeEntity, index));
mNbComponents++;
// Map the entity with the new component lookup index
linkProxyShapeWithEntity(entity, index);
assert(mSleepingStartIndex <= mNbComponents);
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index || !hasNextProxyShape(index));
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
}
// Move a component from a source to a destination index in the components array
// The destination location must contain a constructed object
void ProxyShapesComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) {
const Entity entity = mEntities[srcIndex];
const bool isFirstProxyShapeOfBody = mMapEntityToComponentIndex[entity] == srcIndex;
assert(isFirstProxyShapeOfBody || hasPreviousProxyShape(srcIndex));
const Entity proxyShapeEntity = mProxyShapesEntities[srcIndex];
// Copy the data of the source component to the destination location
new (mEntities + destIndex) Entity(mEntities[srcIndex]);
new (mProxyShapesEntities + destIndex) Entity(mProxyShapesEntities[srcIndex]);
new (mBodiesEntities + destIndex) Entity(mBodiesEntities[srcIndex]);
mProxyShapes[destIndex] = mProxyShapes[srcIndex];
new (mBroadPhaseIds + destIndex) int(mBroadPhaseIds[srcIndex]);
new (mLocalBounds + destIndex) AABB(mLocalBounds[srcIndex]);
new (mLocalToBodyTransforms + destIndex) Transform(mLocalToBodyTransforms[srcIndex]);
mCollisionShapes[destIndex] = mCollisionShapes[srcIndex];
new (mMasses + destIndex) decimal(mMasses[srcIndex]);
new (mPreviousBodyProxyShapes + destIndex) uint32(hasPreviousProxyShape(srcIndex) ? mPreviousBodyProxyShapes[srcIndex] : destIndex);
new (mNextBodyProxyShapes + destIndex) uint32(hasNextProxyShape(srcIndex) ? mNextBodyProxyShapes[srcIndex] : destIndex);
new (mCollisionCategoryBits + destIndex) unsigned short(mCollisionCategoryBits[srcIndex]);
new (mCollideWithMaskBits + destIndex) unsigned short(mCollideWithMaskBits[srcIndex]);
// Update the the next proxy-shape index of the previous proxy-shape
if (hasPreviousProxyShape(destIndex)) {
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[destIndex]] == srcIndex);
mNextBodyProxyShapes[mPreviousBodyProxyShapes[destIndex]] = destIndex;
}
// Update the the previous proxy-shape index of the next proxy-shape
if (hasNextProxyShape(destIndex)) {
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[destIndex]] == srcIndex);
mPreviousBodyProxyShapes[mNextBodyProxyShapes[destIndex]] = destIndex;
}
// Destroy the source component
destroyComponent(srcIndex);
// Update the entity to component index mapping if it is the first proxy-shape of the body
if (isFirstProxyShapeOfBody) {
assert(!mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
mMapEntityToComponentIndex[entity] = destIndex;
assert(mMapEntityToComponentIndex[mEntities[destIndex]] == destIndex);
}
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(proxyShapeEntity, destIndex));
mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(mProxyShapes[destIndex], destIndex));
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[destIndex]] == destIndex || !hasNextProxyShape(destIndex));
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[destIndex]] == destIndex || !hasPreviousProxyShape(destIndex));
assert(mMapEntityToComponentIndex[mProxyShapesEntities[destIndex]] == destIndex);
}
// Swap two components in the array
void ProxyShapesComponents::swapComponents(uint32 index1, uint32 index2) {
// Copy component 1 data
Entity entity1(mEntities[index1]);
Entity proxyShapeEntity1(mProxyShapesEntities[index1]);
Entity bodyEntity1(mBodiesEntities[index1]);
ProxyShape* proxyShape1 = mProxyShapes[index1];
int broadPhaseId1 = mBroadPhaseIds[index1];
AABB localBounds1 = mLocalBounds[index1];
Transform localToBodyTransform1 = mLocalToBodyTransforms[index1];
CollisionShape* collisionShape1 = mCollisionShapes[index1];
decimal mass1 = mMasses[index1];
uint32 previousProxyShape1 = hasPreviousProxyShape(index1) ? mPreviousBodyProxyShapes[index1] : index2;
uint32 nextProxyShape1 = hasNextProxyShape(index1) ? mNextBodyProxyShapes[index1] : index2;
unsigned short collisionCategoryBits1 = mCollisionCategoryBits[index1];
unsigned short collideWithMaskBits1 = mCollideWithMaskBits[index1];
const bool isFirstBodyProxyShape1 = mMapEntityToComponentIndex[mEntities[index1]] == index1;
// Destroy component 1
destroyComponent(index1);
moveComponentToIndex(index2, index1);
// Reconstruct component 1 at component 2 location
new (mEntities + index2) Entity(entity1);
new (mProxyShapesEntities + index2) Entity(proxyShapeEntity1);
new (mBodiesEntities + index2) Entity(bodyEntity1);
mProxyShapes[index2] = proxyShape1;
new (mBroadPhaseIds + index2) int(broadPhaseId1);
new (mLocalBounds + index2) AABB(localBounds1);
new (mLocalToBodyTransforms + index2) Transform(localToBodyTransform1);
mCollisionShapes[index2] = collisionShape1;
new (mMasses + index2) decimal(mass1);
new (mPreviousBodyProxyShapes + index2) uint32(previousProxyShape1);
new (mNextBodyProxyShapes + index2) uint32(nextProxyShape1);
new (mCollisionCategoryBits + index2) unsigned short(collisionCategoryBits1);
new (mCollideWithMaskBits + index2) unsigned short(collideWithMaskBits1);
// Update the the next proxy-shape index of the previous proxy-shape
if (hasPreviousProxyShape(index2)) {
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] == index1);
mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] = index2;
}
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(proxyShapeEntity1, index2));
// Update the the previous proxy-shape index of the next proxy-shape
if (hasNextProxyShape(index2)) {
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] == index1);
mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] = index2;
}
mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(mProxyShapes[index2], index2));
// Update the entity to component index mapping if it is the first body proxy-shape
if (isFirstBodyProxyShape1) {
assert(!hasPreviousProxyShape(index2));
mMapEntityToComponentIndex[entity1] = index2;
}
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index1]] == index1 || !hasNextProxyShape(index1));
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] == index2 || !hasNextProxyShape(index2));
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index1]] == index1 || !hasPreviousProxyShape(index1));
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] == index2 || !hasPreviousProxyShape(index2));
assert(mMapEntityToComponentIndex[mProxyShapesEntities[index1]] == index1);
assert(mMapEntityToComponentIndex[mProxyShapesEntities[index2]] == index2);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Remove a component at a given index
void ProxyShapesComponents::removeComponent(uint32 index) {
void ProxyShapesComponents::removeComponent(Entity proxyShapeEntity) {
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
uint index = mMapEntityToComponentIndex[proxyShapeEntity];
assert(index < mNbComponents);
@ -342,59 +256,6 @@ void ProxyShapesComponents::removeComponent(uint32 index) {
// we replace it with the last element of the array. But we need to make sure that sleeping
// and non-sleeping components stay grouped together.
// If the proxy-shape to destroy does not have a previous proxy-shape in the linked-list of proxy-shapes of its body
if (!hasPreviousProxyShape(index)) {
// Remove the mapping from entity to component index
mMapEntityToComponentIndex.remove(mEntities[index]);
// If the proxy-shape has a next proxy-shape in the linked-list
if (hasNextProxyShape(index)) {
assert(mEntities[index] == mEntities[mNextBodyProxyShapes[index]]);
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(mEntities[mNextBodyProxyShapes[index]], mNextBodyProxyShapes[index]));
}
}
// Update the linked-list of proxy-shapes of a body when a proxy-shape is removed
if (hasPreviousProxyShape(index)) {
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index);
assert(mEntities[index] == mEntities[mPreviousBodyProxyShapes[index]]);
// If the current proxy-shape to remove has a next proxy-shape in the linked-list
if (hasNextProxyShape(index)) {
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index);
// Make sure the next proxy-shape will follow the previous proxy-shape in the linked-list
mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] = mNextBodyProxyShapes[index];
}
else {
mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] = mPreviousBodyProxyShapes[index];
}
}
// Update the linked-list of proxy-shapes of a body when a proxy-shape is removed
if (hasNextProxyShape(index)) {
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index);
assert(mEntities[index] == mEntities[mNextBodyProxyShapes[index]]);
// If the current proxy-shape to remove has a previous proxy-shape in the linked-list
if (hasPreviousProxyShape(index)) {
// Make sure the previous proxy-shape will precede the next proxy-shape in the linked-list
mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] = mPreviousBodyProxyShapes[index];
}
else {
mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] = mNextBodyProxyShapes[index];
}
}
// Destroy the component
destroyComponent(index);
@ -427,30 +288,22 @@ void ProxyShapesComponents::removeComponent(uint32 index) {
mSleepingStartIndex--;
}
assert(mSleepingStartIndex <= mNbComponents);
mNbComponents--;
}
// Return true if a given proxy-shape component has a previous proxy-shape in the linked-list of proxy-shapes of a body
bool ProxyShapesComponents::hasPreviousProxyShape(uint32 index) const {
assert(index < mNbComponents);
return mPreviousBodyProxyShapes[index] != index;
}
// Return true if a given proxy-shape component has a next proxy-shape in the linked-list of proxy-shapes of a body
bool ProxyShapesComponents::hasNextProxyShape(uint32 index) const {
assert(index < mNbComponents);
return mNextBodyProxyShapes[index] != index;
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Destroy a component at a given index
void ProxyShapesComponents::destroyComponent(uint32 index) {
assert(index < mNbComponents);
assert(mMapEntityToComponentIndex[mProxyShapesEntities[index]] == index);
mMapProxyShapeToComponentIndex.remove(mProxyShapes[index]);
mMapEntityToComponentIndex.remove(mProxyShapesEntities[index]);
mEntities[index].~Entity();
mProxyShapesEntities[index].~Entity();
mBodiesEntities[index].~Entity();
mProxyShapes[index] = nullptr;
mLocalBounds[index].~AABB();
mLocalToBodyTransforms[index].~Transform();
@ -492,31 +345,4 @@ void ProxyShapesComponents::setIsEntitySleeping(Entity entity, bool isSleeping)
}
assert(mSleepingStartIndex <= mNbComponents);
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index || !hasNextProxyShape(index));
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
}
// Remove all the components of a given entity
void ProxyShapesComponents::removeComponents(Entity entity) {
auto it = mMapEntityToComponentIndex.find(entity);
// While there are components for this entity
while (it != mMapEntityToComponentIndex.end()) {
// Remove the component
removeComponent(it->second);
it = mMapEntityToComponentIndex.find(entity);
}
assert(!mMapEntityToComponentIndex.containsKey(entity));
}
// Remove a given proxy-shape
void ProxyShapesComponents::removeComponent(const ProxyShape* proxyShape) {
uint32 index = mMapProxyShapeToComponentIndex[proxyShape];
removeComponent(index);
}

View File

@ -45,11 +45,9 @@ class ProxyShape;
// Class ProxyShapesComponents
/**
* This class represent the component of the ECS that contains the proxy-shapes of the
* different entities. There can be several proxy shapes for each entity (body). We store
* the proxy shapes in a flat array but we keep two arrays with previous/next proxy shapes
* link information to quickly know all the proxy shapes of a given entity (body). We also make
* sure that proxy shapes of sleeping entities (bodies) are always stored at the end of the array.
* This class represent the component of the ECS that contains data about the the proxy-shapes of the
* different bodies. We also make sure that proxy shapes of sleeping entities (bodies) are
* always stored at the end of the array.
*/
class ProxyShapesComponents : public Components {
@ -57,22 +55,22 @@ class ProxyShapesComponents : public Components {
// -------------------- Constants -------------------- //
const size_t COMPONENT_DATA_SIZE = sizeof(Entity) + sizeof(ProxyShape*) + sizeof(int) + sizeof(AABB) +
sizeof(Transform) + sizeof(CollisionShape*) + sizeof(decimal) + sizeof(uint32) +
sizeof(uint32) + sizeof(unsigned short) + sizeof(unsigned short);
const size_t COMPONENT_DATA_SIZE = sizeof(Entity) + sizeof(Entity) + sizeof(ProxyShape*) + sizeof(int) + sizeof(AABB) +
sizeof(Transform) + sizeof(CollisionShape*) + sizeof(decimal) + sizeof(unsigned short) +
sizeof(unsigned short);
// -------------------- Attributes -------------------- //
/// Index of the first component of a sleeping entity (sleeping components are stored at the end)
uint32 mSleepingStartIndex;
/// Map a proxy shape to the index of the corresponding component in the array
Map<const ProxyShape*, uint32> mMapProxyShapeToComponentIndex;
/// Array of entities of each component
Entity* mBodiesEntities;
/// Array of entities of each component
Entity* mEntities;
Entity* mProxyShapesEntities;
/// Array of pointers to the proxy-shapes
/// Array of pointer to the proxy-shapes
ProxyShape** mProxyShapes;
/// Ids of the proxy-shapes for the broad-phase algorithm
@ -91,14 +89,6 @@ class ProxyShapesComponents : public Components {
/// Masses (in kilogramms) of the proxy-shapes
decimal* mMasses;
/// Index of the previous proxy-shape in the same body
/// mPreviousBodyProxyShapes[i] == i means that the proxy-shape component has no previous proxy-shape
uint32* mPreviousBodyProxyShapes;
/// Index of the next proxy-shape in the same body
/// mNextBodyProxyShapes[i] == i means that the proxy-shape component has no next proxy-shape
uint32* mNextBodyProxyShapes;
/// Array of bits used to define the collision category of this shape.
/// You can set a single bit to one to define a category value for this
/// shape. This value is one (0x0001) by default. This variable can be used
@ -114,9 +104,6 @@ class ProxyShapesComponents : public Components {
// -------------------- Methods -------------------- //
/// Remove a component at a given index
void removeComponent(uint32 index);
/// Destroy a component at a given index
void destroyComponent(uint32 index);
@ -126,20 +113,12 @@ class ProxyShapesComponents : public Components {
/// Swap two components in the array
void swapComponents(uint32 index1, uint32 index2);
/// Add a new proxy-shape at the end of the linked-list of proxy-shapes of a given entity
void linkProxyShapeWithEntity(Entity entity, uint32 proxyShapeComponentIndex);
/// Return true if a given proxy-shape component has a previous proxy-shape in the linked-list of proxy-shapes of a body
bool hasPreviousProxyShape(uint32 index) const;
/// Return true if a given proxy-shape component has a next proxy-shape in the linked-list of proxy-shapes of a body
bool hasNextProxyShape(uint32 index) const;
public:
/// Structure for the data of a proxy shape component
struct ProxyShapeComponent {
Entity bodyEntity;
ProxyShape* proxyShape;
int broadPhaseId;
AABB localBounds;
@ -150,10 +129,10 @@ class ProxyShapesComponents : public Components {
unsigned short collideWithMaskBits;
/// Constructor
ProxyShapeComponent(ProxyShape* proxyShape, int broadPhaseId, AABB localBounds, Transform localToBodyTransform,
ProxyShapeComponent(Entity bodyEntity, ProxyShape* proxyShape, int broadPhaseId, AABB localBounds, Transform localToBodyTransform,
CollisionShape* collisionShape, decimal mass, unsigned short collisionCategoryBits,
unsigned short collideWithMaskBits)
:proxyShape(proxyShape), broadPhaseId(broadPhaseId), localBounds(localBounds), localToBodyTransform(localToBodyTransform),
:bodyEntity(bodyEntity), proxyShape(proxyShape), broadPhaseId(broadPhaseId), localBounds(localBounds), localToBodyTransform(localToBodyTransform),
collisionShape(collisionShape), mass(mass), collisionCategoryBits(collisionCategoryBits), collideWithMaskBits(collideWithMaskBits) {
}
@ -165,166 +144,140 @@ class ProxyShapesComponents : public Components {
ProxyShapesComponents(MemoryAllocator& allocator);
/// Destructor
~ProxyShapesComponents();
virtual ~ProxyShapesComponents();
/// Allocate memory for a given number of components
void allocate(uint32 nbComponentsToAllocate);
/// Add a component
void addComponent(Entity entity, bool isSleeping, const ProxyShapeComponent& component);
void addComponent(Entity proxyShapeEntity, bool isSleeping, const ProxyShapeComponent& component);
/// Remove all the components of a given entity
void removeComponents(Entity entity);
/// Remove a given proxy-shape
void removeComponent(const ProxyShape* proxyShape);
/// Remove a component at a given index
void removeComponent(Entity proxyShapeEntity);
/// Notify if a given entity is sleeping or not
void setIsEntitySleeping(Entity entity, bool isSleeping);
/// Return the mass of a proxy-shape
decimal getMass(const ProxyShape* proxyShape) const;
decimal getMass(Entity proxyShapeEntity) const;
/// Return a pointer to a given proxy-shape
ProxyShape* getProxyShape(Entity proxyShapeEntity) const;
/// Return the local-to-body transform of a proxy-shape
const Transform& getLocalToBodyTransform(const ProxyShape* proxyShape) const;
const Transform& getLocalToBodyTransform(Entity proxyShapeEntity) const;
/// Set the local-to-body transform of a proxy-shape
void setLocalToBodyTransform(const ProxyShape* proxyShape, const Transform& transform);
void setLocalToBodyTransform(Entity proxyShapeEntity, const Transform& transform);
/// Return a pointer to the collision shape of a proxy-shape
CollisionShape* getCollisionShape(const ProxyShape* proxyShape) const;
CollisionShape* getCollisionShape(Entity proxyShapeEntity) const;
/// Return the broad-phase id of a given proxy shape
int getBroadPhaseId(const ProxyShape* proxyShape) const;
int getBroadPhaseId(Entity proxyShapeEntity) const;
/// Set the broad-phase id of a given proxy shape
void setBroadPhaseId(const ProxyShape* proxyShape, int broadPhaseId);
/// Return the next proxy-shape in the linked-list of all proxy-shapes of a body
ProxyShape* getNextProxyShapeOfBody(const ProxyShape* proxyShape) const;
/// Return the first proxy-shape in the linked-list of all proxy-shapes of a body
ProxyShape* getFirstProxyShapeOfBody(Entity entity) const;
void setBroadPhaseId(Entity proxyShapeEntity, int broadPhaseId);
/// Return the collision category bits of a given proxy-shape
unsigned short getCollisionCategoryBits(const ProxyShape* proxyShape) const;
unsigned short getCollisionCategoryBits(Entity proxyShapeEntity) const;
/// Set the collision category bits of a given proxy-shape
void setCollisionCategoryBits(const ProxyShape* proxyShape, unsigned short collisionCategoryBits);
void setCollisionCategoryBits(Entity proxyShapeEntity, unsigned short collisionCategoryBits);
/// Return the "collide with" mask bits of a given proxy-shape
unsigned short getCollideWithMaskBits(const ProxyShape* proxyShape) const;
unsigned short getCollideWithMaskBits(Entity proxyShapeEntity) const;
/// Set the "collide with" mask bits of a given proxy-shape
void setCollideWithMaskBits(const ProxyShape* proxyShape, unsigned short collideWithMaskBits);
void setCollideWithMaskBits(Entity proxyShapeEntity, unsigned short collideWithMaskBits);
};
// Return the mass of a proxy-shape
inline decimal ProxyShapesComponents::getMass(const ProxyShape* proxyShape) const {
inline decimal ProxyShapesComponents::getMass(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mMasses[mMapProxyShapeToComponentIndex[proxyShape]];
return mMasses[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Return a pointer to a given proxy-shape
inline ProxyShape* ProxyShapesComponents::getProxyShape(Entity proxyShapeEntity) const {
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mProxyShapes[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Return the local-to-body transform of a proxy-shape
inline const Transform& ProxyShapesComponents::getLocalToBodyTransform(const ProxyShape* proxyShape) const {
inline const Transform& ProxyShapesComponents::getLocalToBodyTransform(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mLocalToBodyTransforms[mMapProxyShapeToComponentIndex[proxyShape]];
return mLocalToBodyTransforms[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Set the local-to-body transform of a proxy-shape
inline void ProxyShapesComponents::setLocalToBodyTransform(const ProxyShape* proxyShape, const Transform& transform) {
inline void ProxyShapesComponents::setLocalToBodyTransform(Entity proxyShapeEntity, const Transform& transform) {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
mLocalToBodyTransforms[mMapProxyShapeToComponentIndex[proxyShape]] = transform;
mLocalToBodyTransforms[mMapEntityToComponentIndex[proxyShapeEntity]] = transform;
}
// Return a pointer to the collision shape of a proxy-shape
inline CollisionShape* ProxyShapesComponents::getCollisionShape(const ProxyShape* proxyShape) const {
inline CollisionShape* ProxyShapesComponents::getCollisionShape(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mCollisionShapes[mMapProxyShapeToComponentIndex[proxyShape]];
return mCollisionShapes[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Return the broad-phase id of a given proxy shape
inline int ProxyShapesComponents::getBroadPhaseId(const ProxyShape* proxyShape) const {
inline int ProxyShapesComponents::getBroadPhaseId(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mBroadPhaseIds[mMapProxyShapeToComponentIndex[proxyShape]];
return mBroadPhaseIds[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Set the broad-phase id of a given proxy shape
inline void ProxyShapesComponents::setBroadPhaseId(const ProxyShape* proxyShape, int broadPhaseId) {
inline void ProxyShapesComponents::setBroadPhaseId(Entity proxyShapeEntity, int broadPhaseId) {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
mBroadPhaseIds[mMapProxyShapeToComponentIndex[proxyShape]] = broadPhaseId;
}
// Return the next proxy-shape in the linked-list of all proxy-shapes of a body
inline ProxyShape* ProxyShapesComponents::getNextProxyShapeOfBody(const ProxyShape* proxyShape) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
uint32 proxyShapeIndex = mMapProxyShapeToComponentIndex[proxyShape];
uint32 nextProxyShapeIndex = mNextBodyProxyShapes[proxyShapeIndex];
// If the current proxy-shape has a next one
if (proxyShapeIndex != nextProxyShapeIndex) {
return mProxyShapes[nextProxyShapeIndex];
}
return nullptr;
}
// Return the first proxy-shape in the linked-list of all proxy-shapes of a body
inline ProxyShape* ProxyShapesComponents::getFirstProxyShapeOfBody(Entity entity) const {
auto it = mMapEntityToComponentIndex.find(entity);
if (it != mMapEntityToComponentIndex.end()) {
return mProxyShapes[it->second];
}
return nullptr;
mBroadPhaseIds[mMapEntityToComponentIndex[proxyShapeEntity]] = broadPhaseId;
}
// Return the collision category bits of a given proxy-shape
inline unsigned short ProxyShapesComponents::getCollisionCategoryBits(const ProxyShape* proxyShape) const {
inline unsigned short ProxyShapesComponents::getCollisionCategoryBits(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mCollisionCategoryBits[mMapProxyShapeToComponentIndex[proxyShape]];
return mCollisionCategoryBits[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Return the "collide with" mask bits of a given proxy-shape
inline unsigned short ProxyShapesComponents::getCollideWithMaskBits(const ProxyShape* proxyShape) const {
inline unsigned short ProxyShapesComponents::getCollideWithMaskBits(Entity proxyShapeEntity) const {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
return mCollideWithMaskBits[mMapProxyShapeToComponentIndex[proxyShape]];
return mCollideWithMaskBits[mMapEntityToComponentIndex[proxyShapeEntity]];
}
// Set the collision category bits of a given proxy-shape
inline void ProxyShapesComponents::setCollisionCategoryBits(const ProxyShape* proxyShape, unsigned short collisionCategoryBits) {
inline void ProxyShapesComponents::setCollisionCategoryBits(Entity proxyShapeEntity, unsigned short collisionCategoryBits) {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
mCollisionCategoryBits[mMapProxyShapeToComponentIndex[proxyShape]] = collisionCategoryBits;
mCollisionCategoryBits[mMapEntityToComponentIndex[proxyShapeEntity]] = collisionCategoryBits;
}
// Set the "collide with" mask bits of a given proxy-shape
inline void ProxyShapesComponents::setCollideWithMaskBits(const ProxyShape* proxyShape, unsigned short collideWithMaskBits) {
inline void ProxyShapesComponents::setCollideWithMaskBits(Entity proxyShapeEntity, unsigned short collideWithMaskBits) {
assert(mMapProxyShapeToComponentIndex.containsKey(proxyShape));
assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity));
mCollideWithMaskBits[mMapProxyShapeToComponentIndex[proxyShape]] = collideWithMaskBits;
mCollideWithMaskBits[mMapEntityToComponentIndex[proxyShapeEntity]] = collideWithMaskBits;
}
}

View File

@ -82,20 +82,20 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) {
// Copy component data from the previous buffer to the new one
memcpy(newTransforms, mTransforms, mNbComponents * sizeof(Transform));
memcpy(newEntities, mEntities, mNbComponents * sizeof(Entity));
memcpy(newEntities, mBodies, mNbComponents * sizeof(Entity));
// Deallocate previous memory
mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE);
}
mBuffer = newBuffer;
mEntities = newEntities;
mBodies = newEntities;
mTransforms = newTransforms;
mNbAllocatedComponents = nbComponentsToAllocate;
}
// Add a component
void TransformComponents::addComponent(Entity entity, bool isSleeping, const TransformComponent& component) {
void TransformComponents::addComponent(Entity bodyEntity, bool isSleeping, const TransformComponent& component) {
// If we need to allocate more components
if (mNbComponents == mNbAllocatedComponents) {
@ -128,11 +128,11 @@ void TransformComponents::addComponent(Entity entity, bool isSleeping, const Tra
}
// Insert the new component data
new (mEntities + index) Entity(entity);
new (mBodies + index) Entity(bodyEntity);
new (mTransforms + index) Transform(component.transform);
// Map the entity with the new component lookup index
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity, index));
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(bodyEntity, index));
mNbComponents++;
@ -141,7 +141,11 @@ void TransformComponents::addComponent(Entity entity, bool isSleeping, const Tra
}
// Remove a component at a given index
void TransformComponents::removeComponent(uint32 index) {
void TransformComponents::removeComponent(Entity bodyEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
uint index = mMapEntityToComponentIndex[bodyEntity];
assert(index < mNbComponents);
@ -229,26 +233,28 @@ void TransformComponents::setIsEntitySleeping(Entity entity, bool isSleeping) {
// The destination location must contain a constructed object
void TransformComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) {
// Copy the data of the source component to the destination location
new (mEntities + destIndex) Entity(mEntities[srcIndex]);
new (mTransforms + destIndex) Transform(mTransforms[srcIndex]);
const Entity entity = mBodies[srcIndex];
const Entity entity = mEntities[srcIndex];
// Copy the data of the source component to the destination location
new (mBodies + destIndex) Entity(mBodies[srcIndex]);
new (mTransforms + destIndex) Transform(mTransforms[srcIndex]);
// Destroy the source component
destroyComponent(srcIndex);
assert(!mMapEntityToComponentIndex.containsKey(entity));
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity, destIndex));
assert(mMapEntityToComponentIndex[mEntities[destIndex]] == destIndex);
assert(mMapEntityToComponentIndex[mBodies[destIndex]] == destIndex);
}
// Swap two components in the array
void TransformComponents::swapComponents(uint32 index1, uint32 index2) {
// Copy component 1 data
Entity entity1(mEntities[index1]);
Entity entity1(mBodies[index1]);
Transform transform1(mTransforms[index1]);
// Destroy component 1
@ -257,14 +263,14 @@ void TransformComponents::swapComponents(uint32 index1, uint32 index2) {
moveComponentToIndex(index2, index1);
// Reconstruct component 1 at component 2 location
new (mEntities + index2) Entity(entity1);
new (mBodies + index2) Entity(entity1);
new (mTransforms + index2) Transform(transform1);
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity1, index2));
assert(mMapEntityToComponentIndex[mEntities[index1]] == index1);
assert(mMapEntityToComponentIndex[mEntities[index2]] == index2);
assert(mMapEntityToComponentIndex[mBodies[index1]] == index1);
assert(mMapEntityToComponentIndex[mBodies[index2]] == index2);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
@ -272,25 +278,10 @@ void TransformComponents::swapComponents(uint32 index1, uint32 index2) {
void TransformComponents::destroyComponent(uint32 index) {
assert(index < mNbComponents);
assert(mMapEntityToComponentIndex[mEntities[index]] == index);
assert(mMapEntityToComponentIndex[mBodies[index]] == index);
mMapEntityToComponentIndex.remove(mEntities[index]);
mMapEntityToComponentIndex.remove(mBodies[index]);
mEntities[index].~Entity();
mBodies[index].~Entity();
mTransforms[index].~Transform();
}
// Remove all the components of a given entity
void TransformComponents::removeComponents(Entity entity) {
auto it = mMapEntityToComponentIndex.find(entity);
// If there is a component for this entity
if (it != mMapEntityToComponentIndex.end()) {
// Remove the component
removeComponent(it->second);
}
assert(!mMapEntityToComponentIndex.containsKey(entity));
}

View File

@ -58,17 +58,14 @@ class TransformComponents : public Components {
/// Index of the first component of a sleeping entity (sleeping components are stored at the end)
uint32 mSleepingStartIndex;
/// Array of entities of each component
Entity* mEntities;
/// Array of body entities of each component
Entity* mBodies;
/// Array of transform of each component
Transform* mTransforms;
// -------------------- Methods -------------------- //
/// Remove a component at a given index
void removeComponent(uint32 index);
/// Destroy a component at a given index
void destroyComponent(uint32 index);
@ -103,29 +100,29 @@ class TransformComponents : public Components {
void allocate(uint32 nbComponentsToAllocate);
/// Add a component
void addComponent(Entity entity, bool isSleeping, const TransformComponent& component);
void addComponent(Entity bodyEntity, bool isSleeping, const TransformComponent& component);
/// Remove all the components of a given entity
void removeComponents(Entity entity);
/// Remove a component at a given index
void removeComponent(Entity bodyEntity);
/// Return the transform of an entity
Transform& getTransform(Entity entity) const;
Transform& getTransform(Entity bodyEntity) const;
/// Set the transform of an entity
void setTransform(Entity entity, const Transform& transform);
void setTransform(Entity bodyEntity, const Transform& transform);
/// Notify if a given entity is sleeping or not
void setIsEntitySleeping(Entity entity, bool isSleeping);
void setIsEntitySleeping(Entity bodyEntity, bool isSleeping);
};
// Return the transform of an entity
inline Transform& TransformComponents::getTransform(Entity entity) const {
return mTransforms[mMapEntityToComponentIndex[entity]];
inline Transform& TransformComponents::getTransform(Entity bodyEntity) const {
return mTransforms[mMapEntityToComponentIndex[bodyEntity]];
}
// Set the transform of an entity
inline void TransformComponents::setTransform(Entity entity, const Transform& transform) {
mTransforms[mMapEntityToComponentIndex[entity]] = transform;
inline void TransformComponents::setTransform(Entity bodyEntity, const Transform& transform) {
mTransforms[mMapEntityToComponentIndex[bodyEntity]] = transform;
}
}

View File

@ -38,9 +38,10 @@ uint CollisionWorld::mNbWorlds = 0;
// Constructor
CollisionWorld::CollisionWorld(const WorldSettings& worldSettings, Logger* logger, Profiler* profiler)
: mConfig(worldSettings), mEntityManager(mMemoryManager.getPoolAllocator()),
mTransformComponents(mMemoryManager.getBaseAllocator()), mProxyShapesComponents(mMemoryManager.getBaseAllocator()),
mCollisionDetection(this, mProxyShapesComponents, mMemoryManager), mBodies(mMemoryManager.getPoolAllocator()), mCurrentBodyId(0),
mFreeBodiesIds(mMemoryManager.getPoolAllocator()), mEventListener(nullptr), mName(worldSettings.worldName),
mBodyComponents(mMemoryManager.getBaseAllocator()), mTransformComponents(mMemoryManager.getBaseAllocator()),
mProxyShapesComponents(mMemoryManager.getBaseAllocator()), mCollisionDetection(this, mProxyShapesComponents, mMemoryManager),
mBodies(mMemoryManager.getPoolAllocator()), mCurrentBodyId(0), mFreeBodiesIds(mMemoryManager.getPoolAllocator()),
mEventListener(nullptr), mName(worldSettings.worldName),
mIsProfilerCreatedByUser(profiler != nullptr),
mIsLoggerCreatedByUser(logger != nullptr) {
@ -131,6 +132,9 @@ CollisionWorld::~CollisionWorld() {
#endif
assert(mBodies.size() == 0);
assert(mBodyComponents.getNbComponents() == 0);
assert(mTransformComponents.getNbComponents() == 0);
assert(mProxyShapesComponents.getNbComponents() == 0);
}
// Create a collision body and add it to the world
@ -149,7 +153,6 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) {
// Largest index cannot be used (it is used for invalid index)
assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max());
// Add a transform component
mTransformComponents.addComponent(entity, false, TransformComponents::TransformComponent(transform));
// Create the collision body
@ -159,6 +162,10 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) {
assert(collisionBody != nullptr);
// Add the components
BodyComponents::BodyComponent bodyComponent(collisionBody);
mBodyComponents.addComponent(entity, false, bodyComponent);
// Add the collision body to the world
mBodies.add(collisionBody);
@ -197,8 +204,9 @@ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
// Reset the contact manifold list of the body
collisionBody->resetContactManifoldsList();
// Destroy the entity and its components
destroyEntity(collisionBody->getEntity());
mBodyComponents.removeComponent(collisionBody->getEntity());
mTransformComponents.removeComponent(collisionBody->getEntity());
mEntityManager.destroyEntity(collisionBody->getEntity());
// Call the destructor of the collision body
collisionBody->~CollisionBody();
@ -239,26 +247,19 @@ void CollisionWorld::resetContactManifoldListsOfBodies() {
}
// Notify the world if a body is sleeping or not
void CollisionWorld::notifyBodySleeping(Entity entity, bool isSleeping) {
void CollisionWorld::notifyBodySleeping(Entity bodyEntity, bool isSleeping) {
// TODO : Make sure we notify all the components here ...
// Notify all the components
mTransformComponents.setIsEntitySleeping(entity, isSleeping);
mProxyShapesComponents.setIsEntitySleeping(entity, isSleeping);
}
mTransformComponents.setIsEntitySleeping(bodyEntity, isSleeping);
// Destroy an entity and all the associated components
void CollisionWorld::destroyEntity(Entity entity) {
// For each proxy-shape of the body
const List<Entity>& proxyShapesEntities = mBodyComponents.getProxyShapes(bodyEntity);
for (uint i=0; i < proxyShapesEntities.size(); i++) {
// Destroy the corresponding entity
mEntityManager.destroyEntity(entity);
// TODO : Make sure we notify all the components here ...
// Notify all the components
mTransformComponents.removeComponents(entity);
mProxyShapesComponents.removeComponents(entity);
mProxyShapesComponents.setIsEntitySleeping(proxyShapesEntities[i], isSleeping);
}
}
// Test if the AABBs of two bodies overlap

View File

@ -33,6 +33,7 @@
#include "constraint/Joint.h"
#include "memory/MemoryManager.h"
#include "engine/EntityManager.h"
#include "components/BodyComponents.h"
#include "components/TransformComponents.h"
#include "components/ProxyShapesComponents.h"
@ -72,6 +73,9 @@ class CollisionWorld {
/// Entity Manager for the ECS
EntityManager mEntityManager;
/// Body Components
BodyComponents mBodyComponents;
/// Transform Components
TransformComponents mTransformComponents;
@ -128,9 +132,6 @@ class CollisionWorld {
/// Notify the world if a body is sleeping or not
void notifyBodySleeping(Entity entity, bool isSleeping);
/// Destroy an entity and all the associated components
void destroyEntity(Entity entity);
public :
// -------------------- Methods -------------------- //

View File

@ -428,7 +428,6 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) {
// Largest index cannot be used (it is used for invalid index)
assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max());
// Add a transform component
mTransformComponents.addComponent(entity, false, TransformComponents::TransformComponent(transform));
// Create the rigid body
@ -436,6 +435,9 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) {
sizeof(RigidBody))) RigidBody(transform, *this, entity, bodyID);
assert(rigidBody != nullptr);
BodyComponents::BodyComponent bodyComponent(rigidBody);
mBodyComponents.addComponent(entity, false, bodyComponent);
// Add the rigid body to the physics world
mBodies.add(rigidBody);
mRigidBodies.add(rigidBody);
@ -480,7 +482,9 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) {
rigidBody->resetContactManifoldsList();
// Destroy the corresponding entity and its components
destroyEntity(rigidBody->getEntity());
mBodyComponents.removeComponent(rigidBody->getEntity());
mTransformComponents.removeComponent(rigidBody->getEntity());
mEntityManager.destroyEntity(rigidBody->getEntity());
// Call the destructor of the rigid body
rigidBody->~RigidBody();

View File

@ -84,7 +84,7 @@ void BroadPhaseSystem::addProxyCollisionShape(ProxyShape* proxyShape, const AABB
int nodeId = mDynamicAABBTree.addObject(aabb, proxyShape);
// Set the broad-phase ID of the proxy shape
mProxyShapesComponents.setBroadPhaseId(proxyShape, nodeId);
mProxyShapesComponents.setBroadPhaseId(proxyShape->getEntity(), nodeId);
// Add the collision shape into the array of bodies that have moved (or have been created)
// during the last simulation step
@ -98,7 +98,7 @@ void BroadPhaseSystem::removeProxyCollisionShape(ProxyShape* proxyShape) {
int broadPhaseID = proxyShape->getBroadPhaseId();
mProxyShapesComponents.setBroadPhaseId(proxyShape, -1);
mProxyShapesComponents.setBroadPhaseId(proxyShape->getEntity(), -1);
// Remove the collision shape from the dynamic AABB tree
mDynamicAABBTree.removeObject(broadPhaseID);

View File

@ -380,8 +380,9 @@ void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix)
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
// For each proxy shape of the object
rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShapesList();
while (proxyShape != nullptr) {
for (uint i=0; i < (*it)->getCollisionBody()->getNbProxyShapes(); i++) {
rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShape(i);
// Get the broad-phase AABB corresponding to the proxy shape
rp3d::AABB aabb = mPhysicsWorld->getWorldAABB(proxyShape);
@ -392,8 +393,6 @@ void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix)
// Render the AABB
AABB::render(aabbCenter, aabbMax - aabbMin, Color::green(), mColorShader, worldToCameraMatrix);
proxyShape = proxyShape->getNext();
}
}
}