From 91416ae5ba1d23db211186ca5ce44c9ddd93f86a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 16 Mar 2019 07:50:34 +0100 Subject: [PATCH] Refactor components --- CMakeLists.txt | 1 + src/components/BodyComponents.cpp | 151 +----------------- src/components/BodyComponents.h | 24 +-- src/components/Components.cpp | 189 +++++++++++++++++++++++ src/components/Components.h | 47 ++++-- src/components/ProxyShapesComponents.cpp | 153 ++---------------- src/components/ProxyShapesComponents.h | 29 +--- src/components/TransformComponents.cpp | 151 +----------------- src/components/TransformComponents.h | 27 +--- 9 files changed, 273 insertions(+), 499 deletions(-) create mode 100644 src/components/Components.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b773f621..7850396b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,6 +231,7 @@ SET (REACTPHYSICS3D_SOURCES "src/engine/Entity.cpp" "src/engine/EntityManager.cpp" "src/systems/BroadPhaseSystem.cpp" + "src/components/Components.cpp" "src/components/BodyComponents.cpp" "src/components/TransformComponents.cpp" "src/components/ProxyShapesComponents.cpp" diff --git a/src/components/BodyComponents.cpp b/src/components/BodyComponents.cpp index 41b7577b..b5f38609 100644 --- a/src/components/BodyComponents.cpp +++ b/src/components/BodyComponents.cpp @@ -34,30 +34,10 @@ using namespace reactphysics3d; // Constructor BodyComponents::BodyComponents(MemoryAllocator& allocator) - :Components(allocator), mSleepingStartIndex(0){ + :Components(allocator, sizeof(Entity) + sizeof(Body*) + sizeof(List)) { // 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(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -66,7 +46,7 @@ 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; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); @@ -86,7 +66,7 @@ void BodyComponents::allocate(uint32 nbComponentsToAllocate) { memcpy(newProxyShapes, mProxyShapes, mNbComponents * sizeof(List)); // Deallocate previous memory - mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE); + mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize); } mBuffer = newBuffer; @@ -99,35 +79,8 @@ void BodyComponents::allocate(uint32 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++; - } + // Prepare to add new component (allocate memory if necessary and compute insertion index) + uint32 index = prepareAddComponent(isSleeping); // Insert the new component data new (mBodiesEntities + index) Entity(bodyEntity); @@ -143,95 +96,6 @@ void BodyComponents::addComponent(Entity bodyEntity, bool isSleeping, const Body 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) { @@ -283,7 +147,8 @@ void BodyComponents::swapComponents(uint32 index1, uint32 index2) { // Destroy a component at a given index void BodyComponents::destroyComponent(uint32 index) { - assert(index < mNbComponents); + Components::destroyComponent(index); + assert(mMapEntityToComponentIndex[mBodiesEntities[index]] == index); mMapEntityToComponentIndex.remove(mBodiesEntities[index]); diff --git a/src/components/BodyComponents.h b/src/components/BodyComponents.h index 0af35206..e04d44a4 100644 --- a/src/components/BodyComponents.h +++ b/src/components/BodyComponents.h @@ -49,15 +49,8 @@ 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; @@ -69,14 +62,17 @@ class BodyComponents : public Components { // -------------------- Methods -------------------- // + /// Allocate memory for a given number of components + virtual void allocate(uint32 nbComponentsToAllocate) override; + /// Destroy a component at a given index - void destroyComponent(uint32 index); + virtual void destroyComponent(uint32 index) override; /// Move a component from a source to a destination index in the components array - void moveComponentToIndex(uint32 srcIndex, uint32 destIndex); + virtual void moveComponentToIndex(uint32 srcIndex, uint32 destIndex) override; /// Swap two components in the array - void swapComponents(uint32 index1, uint32 index2); + virtual void swapComponents(uint32 index1, uint32 index2) override; public: @@ -97,17 +93,11 @@ class BodyComponents : public Components { BodyComponents(MemoryAllocator& allocator); /// Destructor - virtual ~BodyComponents(); - - /// Allocate memory for a given number of components - void allocate(uint32 nbComponentsToAllocate); + virtual ~BodyComponents() override = default; /// 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); diff --git a/src/components/Components.cpp b/src/components/Components.cpp new file mode 100644 index 00000000..5faa85ce --- /dev/null +++ b/src/components/Components.cpp @@ -0,0 +1,189 @@ +/******************************************************************************** +* 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 "Components.h" +#include + +// We want to use the ReactPhysics3D namespace +using namespace reactphysics3d; + +// Constructor +Components::Components(MemoryAllocator& allocator, size_t componentDataSize) + : mMemoryAllocator(allocator), mNbComponents(0), mComponentDataSize(componentDataSize), + mNbAllocatedComponents(0), mBuffer(nullptr), mMapEntityToComponentIndex(allocator), + mSleepingStartIndex(0) { + +} + +Components::~Components() { + + // If there are allocated components + if (mNbAllocatedComponents > 0) { + + // Destroy all the remaining components + for (uint32 i = 0; i < mNbComponents; i++) { + + destroyComponent(i); + } + + // Size for the data of a single component (in bytes) + const size_t totalSizeBytes = mNbAllocatedComponents * mComponentDataSize; + + // Release the allocated memory + mMemoryAllocator.release(mBuffer, totalSizeBytes); + } +} + +// Compute the index where we need to insert the new component +uint32 Components::prepareAddComponent(bool isSleeping) { + + // 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++; + } + + return index; +} + +// Destroy a component at a given index +void Components::destroyComponent(uint32 index) { + + assert(index < mNbComponents); +} + +// Remove a component at a given index +void Components::removeComponent(Entity entity) { + + assert(mMapEntityToComponentIndex.containsKey(entity)); + + uint index = mMapEntityToComponentIndex[entity]; + + 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 Components::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())); +} diff --git a/src/components/Components.h b/src/components/Components.h index 9a7b4b54..ab235321 100644 --- a/src/components/Components.h +++ b/src/components/Components.h @@ -48,8 +48,9 @@ class Components { // -------------------- Constants -------------------- // + /// Number of components to allocated at the beginning - const uint32 INIT_ALLOCATED_COMPONENTS = 10; + const uint32 INIT_NB_ALLOCATED_COMPONENTS = 10; /// Number of valid entities to hit before stopping garbage collection const uint32 GARBAGE_COLLECTION_MAX_VALID_ENTITIES = 5; @@ -62,6 +63,9 @@ class Components { /// Current number of components uint32 mNbComponents; + // Size (in bytes) of a single component + size_t mComponentDataSize; + /// Number of allocated components uint32 mNbAllocatedComponents; @@ -71,28 +75,49 @@ class Components { /// Map an entity to the index of its component in the array Map mMapEntityToComponentIndex; + /// Index of the first component of a sleeping entity (sleeping components are stored at the end) + uint32 mSleepingStartIndex; + + /// Compute the index where we need to insert the new component + uint32 prepareAddComponent(bool isSleeping); + + /// Allocate memory for a given number of components + virtual void allocate(uint32 nbComponentsToAllocate)=0; + + /// Destroy a component at a given index + virtual void destroyComponent(uint32 index); + + /// Move a component from a source to a destination index in the components array + virtual void moveComponentToIndex(uint32 srcIndex, uint32 destIndex)=0; + + /// Swap two components in the array + virtual void swapComponents(uint32 index1, uint32 index2)=0; + public: // -------------------- Methods -------------------- // /// Constructor - Components(MemoryAllocator& allocator) - : mMemoryAllocator(allocator), mNbComponents(0), mNbAllocatedComponents(0), - mBuffer(nullptr), mMapEntityToComponentIndex(allocator) { - - } + Components(MemoryAllocator& allocator, size_t componentDataSize); /// Destructor - virtual ~Components() { + virtual ~Components(); - } + /// Remove a component + void removeComponent(Entity entity); + + // Notify if a given entity is sleeping or not + void setIsEntitySleeping(Entity entity, bool isSleeping); /// Return the number of components - uint32 getNbComponents() const { - return mNbComponents; - } + uint32 getNbComponents() const; }; +// Return the number of components +inline uint32 Components::getNbComponents() const { + return mNbComponents; +} + } #endif diff --git a/src/components/ProxyShapesComponents.cpp b/src/components/ProxyShapesComponents.cpp index 4464f7f8..eb49ce2f 100644 --- a/src/components/ProxyShapesComponents.cpp +++ b/src/components/ProxyShapesComponents.cpp @@ -35,31 +35,12 @@ using namespace reactphysics3d; // Constructor ProxyShapesComponents::ProxyShapesComponents(MemoryAllocator& allocator) - :Components(allocator), - mSleepingStartIndex(0) { + :Components(allocator, sizeof(Entity) + sizeof(Entity) + sizeof(ProxyShape*) + sizeof(int) + sizeof(AABB) + + sizeof(Transform) + sizeof(CollisionShape*) + sizeof(decimal) + sizeof(unsigned short) + + sizeof(unsigned short)) { // Allocate memory for the components data - allocate(INIT_ALLOCATED_COMPONENTS); -} - -// Destructor -ProxyShapesComponents::~ProxyShapesComponents() { - - 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(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -68,7 +49,7 @@ void ProxyShapesComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * COMPONENT_DATA_SIZE; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); @@ -102,7 +83,7 @@ void ProxyShapesComponents::allocate(uint32 nbComponentsToAllocate) { memcpy(newCollideWithMaskBits, mCollideWithMaskBits, mNbComponents * sizeof(unsigned short)); // Deallocate previous memory - mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE); + mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize); } mBuffer = newBuffer; @@ -124,35 +105,8 @@ void ProxyShapesComponents::allocate(uint32 nbComponentsToAllocate) { // Add a component void ProxyShapesComponents::addComponent(Entity proxyShapeEntity, bool isSleeping, const ProxyShapeComponent& 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 - 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++; - } + // Prepare to add new component (allocate memory if necessary and compute insertion index) + uint32 index = prepareAddComponent(isSleeping); // Insert the new component data new (mProxyShapesEntities + index) Entity(proxyShapeEntity); @@ -243,61 +197,11 @@ void ProxyShapesComponents::swapComponents(uint32 index1, uint32 index2) { assert(mNbComponents == static_cast(mMapEntityToComponentIndex.size())); } -// Remove a component at a given index -void ProxyShapesComponents::removeComponent(Entity proxyShapeEntity) { - - assert(mMapEntityToComponentIndex.containsKey(proxyShapeEntity)); - - uint index = mMapEntityToComponentIndex[proxyShapeEntity]; - - 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())); -} - // Destroy a component at a given index void ProxyShapesComponents::destroyComponent(uint32 index) { - assert(index < mNbComponents); + Components::destroyComponent(index); + assert(mMapEntityToComponentIndex[mProxyShapesEntities[index]] == index); mMapEntityToComponentIndex.remove(mProxyShapesEntities[index]); @@ -309,40 +213,3 @@ void ProxyShapesComponents::destroyComponent(uint32 index) { mLocalToBodyTransforms[index].~Transform(); mCollisionShapes[index] = nullptr; } - -// Notify if a given entity is sleeping or not -void ProxyShapesComponents::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); -} diff --git a/src/components/ProxyShapesComponents.h b/src/components/ProxyShapesComponents.h index 017c775a..add72c28 100644 --- a/src/components/ProxyShapesComponents.h +++ b/src/components/ProxyShapesComponents.h @@ -53,17 +53,8 @@ class ProxyShapesComponents : public Components { private: - // -------------------- Constants -------------------- // - - 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; - /// Array of entities of each component Entity* mBodiesEntities; @@ -104,14 +95,17 @@ class ProxyShapesComponents : public Components { // -------------------- Methods -------------------- // + /// Allocate memory for a given number of components + virtual void allocate(uint32 nbComponentsToAllocate) override; + /// Destroy a component at a given index - void destroyComponent(uint32 index); + virtual void destroyComponent(uint32 index) override; /// Move a component from a source to a destination index in the components array - void moveComponentToIndex(uint32 srcIndex, uint32 destIndex); + virtual void moveComponentToIndex(uint32 srcIndex, uint32 destIndex) override; /// Swap two components in the array - void swapComponents(uint32 index1, uint32 index2); + virtual void swapComponents(uint32 index1, uint32 index2) override; public: @@ -144,20 +138,11 @@ class ProxyShapesComponents : public Components { ProxyShapesComponents(MemoryAllocator& allocator); /// Destructor - virtual ~ProxyShapesComponents(); - - /// Allocate memory for a given number of components - void allocate(uint32 nbComponentsToAllocate); + virtual ~ProxyShapesComponents() override = default; /// Add a component void addComponent(Entity proxyShapeEntity, bool isSleeping, const ProxyShapeComponent& component); - /// 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(Entity proxyShapeEntity) const; diff --git a/src/components/TransformComponents.cpp b/src/components/TransformComponents.cpp index 038fea97..aefeb0ba 100644 --- a/src/components/TransformComponents.cpp +++ b/src/components/TransformComponents.cpp @@ -35,30 +35,10 @@ using namespace reactphysics3d; // Constructor TransformComponents::TransformComponents(MemoryAllocator& allocator) - :Components(allocator), mSleepingStartIndex(0){ + :Components(allocator, sizeof(Entity) + sizeof(Transform)) { // Allocate memory for the components data - allocate(INIT_ALLOCATED_COMPONENTS); -} - -// Destructor -TransformComponents::~TransformComponents() { - - 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(INIT_NB_ALLOCATED_COMPONENTS); } // Allocate memory for a given number of components @@ -67,7 +47,7 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) { assert(nbComponentsToAllocate > mNbAllocatedComponents); // Size for the data of a single component (in bytes) - const size_t totalSizeBytes = nbComponentsToAllocate * COMPONENT_DATA_SIZE; + const size_t totalSizeBytes = nbComponentsToAllocate * mComponentDataSize; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); @@ -85,7 +65,7 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) { memcpy(newEntities, mBodies, mNbComponents * sizeof(Entity)); // Deallocate previous memory - mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE); + mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize); } mBuffer = newBuffer; @@ -97,35 +77,8 @@ void TransformComponents::allocate(uint32 nbComponentsToAllocate) { // Add a component void TransformComponents::addComponent(Entity bodyEntity, bool isSleeping, const TransformComponent& 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++; - } + // Prepare to add new component (allocate memory if necessary and compute insertion index) + uint32 index = prepareAddComponent(isSleeping); // Insert the new component data new (mBodies + index) Entity(bodyEntity); @@ -140,95 +93,6 @@ void TransformComponents::addComponent(Entity bodyEntity, bool isSleeping, const assert(mNbComponents == static_cast(mMapEntityToComponentIndex.size())); } -// Remove a component at a given index -void TransformComponents::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 TransformComponents::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 TransformComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) { @@ -277,7 +141,8 @@ void TransformComponents::swapComponents(uint32 index1, uint32 index2) { // Destroy a component at a given index void TransformComponents::destroyComponent(uint32 index) { - assert(index < mNbComponents); + Components::destroyComponent(index); + assert(mMapEntityToComponentIndex[mBodies[index]] == index); mMapEntityToComponentIndex.remove(mBodies[index]); diff --git a/src/components/TransformComponents.h b/src/components/TransformComponents.h index 10d14e6b..925a2ab7 100644 --- a/src/components/TransformComponents.h +++ b/src/components/TransformComponents.h @@ -49,15 +49,8 @@ class TransformComponents : public Components { private: - // -------------------- Constants -------------------- // - - const size_t COMPONENT_DATA_SIZE = sizeof(Entity) + sizeof(Transform); - // -------------------- 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* mBodies; @@ -66,14 +59,17 @@ class TransformComponents : public Components { // -------------------- Methods -------------------- // + /// Allocate memory for a given number of components + virtual void allocate(uint32 nbComponentsToAllocate) override; + /// Destroy a component at a given index - void destroyComponent(uint32 index); + virtual void destroyComponent(uint32 index) override; /// Move a component from a source to a destination index in the components array - void moveComponentToIndex(uint32 srcIndex, uint32 destIndex); + virtual void moveComponentToIndex(uint32 srcIndex, uint32 destIndex) override; /// Swap two components in the array - void swapComponents(uint32 index1, uint32 index2); + virtual void swapComponents(uint32 index1, uint32 index2) override; public: @@ -94,25 +90,16 @@ class TransformComponents : public Components { TransformComponents(MemoryAllocator& allocator); /// Destructor - virtual ~TransformComponents(); - - /// Allocate memory for a given number of components - void allocate(uint32 nbComponentsToAllocate); + virtual ~TransformComponents() override = default; /// Add a component void addComponent(Entity bodyEntity, bool isSleeping, const TransformComponent& component); - /// Remove a component at a given index - void removeComponent(Entity bodyEntity); - /// Return the transform of an entity Transform& getTransform(Entity bodyEntity) const; /// Set the transform of an entity void setTransform(Entity bodyEntity, const Transform& transform); - - /// Notify if a given entity is sleeping or not - void setIsEntitySleeping(Entity bodyEntity, bool isSleeping); }; // Return the transform of an entity