From d02b25d32a083b3dbeaacc8d2dc24aad13661eb5 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 15 Mar 2019 17:27:11 +0100 Subject: [PATCH] The proxy-shapes are now entities --- CHANGELOG.md | 3 + CMakeLists.txt | 2 + src/body/CollisionBody.cpp | 138 ++++++----- src/body/CollisionBody.h | 10 +- src/body/RigidBody.cpp | 56 +++-- src/collision/CollisionDetection.cpp | 54 ++--- src/collision/ProxyShape.cpp | 60 ++--- src/collision/ProxyShape.h | 22 +- src/components/BodyComponents.cpp | 294 +++++++++++++++++++++++ src/components/BodyComponents.h | 161 +++++++++++++ src/components/Components.h | 5 + src/components/ProxyShapesComponents.cpp | 260 ++++---------------- src/components/ProxyShapesComponents.h | 183 ++++++-------- src/components/TransformComponents.cpp | 57 ++--- src/components/TransformComponents.h | 27 +-- src/engine/CollisionWorld.cpp | 41 ++-- src/engine/CollisionWorld.h | 7 +- src/engine/DynamicsWorld.cpp | 8 +- src/systems/BroadPhaseSystem.cpp | 4 +- testbed/src/SceneDemo.cpp | 7 +- 20 files changed, 836 insertions(+), 563 deletions(-) create mode 100644 src/components/BodyComponents.cpp create mode 100644 src/components/BodyComponents.h diff --git a/CHANGELOG.md b/CHANGELOG.md index eaaa6771..cedb3ff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7933c812..b773f621 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index eda0523c..013bee26 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -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(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 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& 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& 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& 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& 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& 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& 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& 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); diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 6d6d35df..a9bbd729 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -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; diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index e2072f81..384682d1 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -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& 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& 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& 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& 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(); } } diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 698883fd..dd541c44 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -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& body1ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body1->getEntity()); + const List& 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& 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& body1ProxyShapesEntities = mWorld->mBodyComponents.getProxyShapes(body1->getEntity()); + const List& 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& 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(); } } diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index 37b63376..df3a2fe0 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -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); } diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 7381c01c..743ed443 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -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 diff --git a/src/components/BodyComponents.cpp b/src/components/BodyComponents.cpp new file mode 100644 index 00000000..41b7577b --- /dev/null +++ b/src/components/BodyComponents.cpp @@ -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 +#include + +// 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(newBuffer); + Body** newBodies = reinterpret_cast(newBodiesEntities + nbComponentsToAllocate); + List* newProxyShapes = reinterpret_cast*>(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)); + + // 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(mMemoryAllocator); + + // Map the entity with the new component lookup index + mMapEntityToComponentIndex.add(Pair(bodyEntity, index)); + + mNbComponents++; + + assert(mSleepingStartIndex <= mNbComponents); + assert(mNbComponents == static_cast(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(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(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(mProxyShapes[srcIndex]); + + // Destroy the source component + destroyComponent(srcIndex); + + assert(!mMapEntityToComponentIndex.containsKey(entity)); + + // Update the entity to component index mapping + mMapEntityToComponentIndex.add(Pair(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 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(proxyShapes1); + mBodies[index2] = body1; + + // Update the entity to component index mapping + mMapEntityToComponentIndex.add(Pair(entity1, index2)); + + assert(mMapEntityToComponentIndex[mBodiesEntities[index1]] == index1); + assert(mMapEntityToComponentIndex[mBodiesEntities[index2]] == index2); + assert(mNbComponents == static_cast(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(); +} diff --git a/src/components/BodyComponents.h b/src/components/BodyComponents.h new file mode 100644 index 00000000..0af35206 --- /dev/null +++ b/src/components/BodyComponents.h @@ -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); + + // -------------------- 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* 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& 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& BodyComponents::getProxyShapes(Entity bodyEntity) const { + + assert(mMapEntityToComponentIndex.containsKey(bodyEntity)); + + return mProxyShapes[mMapEntityToComponentIndex[bodyEntity]]; +} + +} + +#endif diff --git a/src/components/Components.h b/src/components/Components.h index 409cd8f8..9a7b4b54 100644 --- a/src/components/Components.h +++ b/src/components/Components.h @@ -86,6 +86,11 @@ class Components { virtual ~Components() { } + + /// Return the number of components + uint32 getNbComponents() const { + return mNbComponents; + } }; } diff --git a/src/components/ProxyShapesComponents.cpp b/src/components/ProxyShapesComponents.cpp index f623d006..4464f7f8 100644 --- a/src/components/ProxyShapesComponents.cpp +++ b/src/components/ProxyShapesComponents.cpp @@ -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(newBuffer); - ProxyShape** newProxyShapes = reinterpret_cast(newEntities + nbComponentsToAllocate); + Entity* newProxyShapesEntities = static_cast(newBuffer); + Entity* newBodiesEntities = reinterpret_cast(newProxyShapesEntities + nbComponentsToAllocate); + ProxyShape** newProxyShapes = reinterpret_cast(newBodiesEntities + nbComponentsToAllocate); int* newBroadPhaseIds = reinterpret_cast(newProxyShapes + nbComponentsToAllocate); AABB* newLocalBounds = reinterpret_cast(newBroadPhaseIds + nbComponentsToAllocate); Transform* newLocalToBodyTransforms = reinterpret_cast(newLocalBounds + nbComponentsToAllocate); CollisionShape** newCollisionShapes = reinterpret_cast(newLocalToBodyTransforms + nbComponentsToAllocate); decimal* newMasses = reinterpret_cast(newCollisionShapes + nbComponentsToAllocate); - uint32* newPreviousBodyProxyShapes = reinterpret_cast(newMasses + nbComponentsToAllocate); - uint32* newNextBodyProxyShapes = reinterpret_cast(newPreviousBodyProxyShapes + nbComponentsToAllocate); - unsigned short* newCollisionCategoryBits = reinterpret_cast(newNextBodyProxyShapes + nbComponentsToAllocate); + unsigned short* newCollisionCategoryBits = reinterpret_cast(newMasses + nbComponentsToAllocate); unsigned short* newCollideWithMaskBits = reinterpret_cast(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, 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(component.proxyShape, index)); + // Map the entity with the new component lookup index + mMapEntityToComponentIndex.add(Pair(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(proxyShapeEntity, destIndex)); - mMapProxyShapeToComponentIndex.add(Pair(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(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(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(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(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(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); } diff --git a/src/components/ProxyShapesComponents.h b/src/components/ProxyShapesComponents.h index d2e58233..017c775a 100644 --- a/src/components/ProxyShapesComponents.h +++ b/src/components/ProxyShapesComponents.h @@ -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 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; } } diff --git a/src/components/TransformComponents.cpp b/src/components/TransformComponents.cpp index 526f36a2..038fea97 100644 --- a/src/components/TransformComponents.cpp +++ b/src/components/TransformComponents.cpp @@ -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, index)); + mMapEntityToComponentIndex.add(Pair(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, 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(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(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)); -} diff --git a/src/components/TransformComponents.h b/src/components/TransformComponents.h index da5cf0a4..10d14e6b 100644 --- a/src/components/TransformComponents.h +++ b/src/components/TransformComponents.h @@ -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; } } diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index ef711c1c..cbc5e897 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -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::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& 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 diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index a3b2922b..c29f8c34 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -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 -------------------- // diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 22ad2914..2025e461 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -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::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(); diff --git a/src/systems/BroadPhaseSystem.cpp b/src/systems/BroadPhaseSystem.cpp index 0a75b5dd..9c47fd95 100644 --- a/src/systems/BroadPhaseSystem.cpp +++ b/src/systems/BroadPhaseSystem.cpp @@ -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); diff --git a/testbed/src/SceneDemo.cpp b/testbed/src/SceneDemo.cpp index 97d0779e..3ecaee92 100644 --- a/testbed/src/SceneDemo.cpp +++ b/testbed/src/SceneDemo.cpp @@ -380,8 +380,9 @@ void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix) for (std::vector::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(); } } }