Refactor components

This commit is contained in:
Daniel Chappuis 2019-03-16 07:50:34 +01:00
parent d02b25d32a
commit 91416ae5ba
9 changed files with 273 additions and 499 deletions

View File

@ -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"

View File

@ -34,30 +34,10 @@ using namespace reactphysics3d;
// Constructor
BodyComponents::BodyComponents(MemoryAllocator& allocator)
:Components(allocator), mSleepingStartIndex(0){
:Components(allocator, sizeof(Entity) + sizeof(Body*) + sizeof(List<Entity>)) {
// 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<Entity>));
// 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<uint32>(mMapEntityToComponentIndex.size()));
}
// Remove a component at a given index
void BodyComponents::removeComponent(Entity bodyEntity) {
assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
uint index = mMapEntityToComponentIndex[bodyEntity];
assert(index < mNbComponents);
// We want to keep the arrays tightly packed. Therefore, when a component is removed,
// we replace it with the last element of the array. But we need to make sure that sleeping
// and non-sleeping components stay grouped together.
// Destroy the component
destroyComponent(index);
// If the component to remove is sleeping
if (index >= mSleepingStartIndex) {
// If the component is not the last one
if (index != mNbComponents - 1) {
// We replace it by the last sleeping component
moveComponentToIndex(mNbComponents - 1, index);
}
}
else { // If the component to remove is not sleeping
// If it not the last awake component
if (index != mSleepingStartIndex - 1) {
// We replace it by the last awake component
moveComponentToIndex(mSleepingStartIndex - 1, index);
}
// If there are sleeping components at the end
if (mSleepingStartIndex != mNbComponents) {
// We replace the last awake component by the last sleeping component
moveComponentToIndex(mNbComponents - 1, mSleepingStartIndex - 1);
}
mSleepingStartIndex--;
}
mNbComponents--;
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Notify if a given entity is sleeping or not
void BodyComponents::setIsEntitySleeping(Entity entity, bool isSleeping) {
const uint32 index = mMapEntityToComponentIndex[entity];
// If the component was sleeping and is not sleeping anymore
if (!isSleeping && index >= mSleepingStartIndex) {
assert(mSleepingStartIndex < mNbComponents);
// If the sleeping component is not the first sleeping component
if (mSleepingStartIndex != index) {
// Swap the first sleeping component with the one we need to wake up
swapComponents(index, mSleepingStartIndex);
}
mSleepingStartIndex++;
}
// If the component was awake and must now go to sleep
else if (isSleeping && index < mSleepingStartIndex) {
assert(mSleepingStartIndex > 0);
// If the awake component is not the only awake component
if (index != mSleepingStartIndex - 1) {
// Swap the last awake component with the one we need to put to sleep
swapComponents(index, mSleepingStartIndex - 1);
}
mSleepingStartIndex--;
}
assert(mSleepingStartIndex <= mNbComponents);
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
}
// Move a component from a source to a destination index in the components array
// The destination location must contain a constructed object
void BodyComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) {
@ -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]);

View File

@ -49,15 +49,8 @@ class BodyComponents : public Components {
private:
// -------------------- Constants -------------------- //
const size_t COMPONENT_DATA_SIZE = sizeof(Entity) + sizeof(Body*) + sizeof(List<Entity>);
// -------------------- Attributes -------------------- //
/// Index of the first component of a sleeping entity (sleeping components are stored at the end)
uint32 mSleepingStartIndex;
/// Array of body entities of each component
Entity* mBodiesEntities;
@ -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);

View File

@ -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 <cassert>
// 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<uint32>(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<uint32>(mMapEntityToComponentIndex.size()));
}

View File

@ -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<Entity, uint32> 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

View File

@ -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<uint32>(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<uint32>(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);
}

View File

@ -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;

View File

@ -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<uint32>(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<uint32>(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<uint32>(mMapEntityToComponentIndex.size()));
}
// Move a component from a source to a destination index in the components array
// The destination location must contain a constructed object
void 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]);

View File

@ -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