/******************************************************************************** * 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 "ProxyShapesComponents.h" #include "engine/EntityManager.h" #include "collision/ProxyShape.h" #include <cassert> #include <random> // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; // Constructor ProxyShapesComponents::ProxyShapesComponents(MemoryAllocator& allocator) :mMemoryAllocator(allocator), mNbComponents(0), mNbAllocatedComponents(0), mSleepingStartIndex(0), mBuffer(nullptr), mMapEntityToComponentIndex(allocator), mMapProxyShapeToComponentIndex(allocator) { // 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 memory for a given number of components 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; // Allocate memory void* newBuffer = mMemoryAllocator.allocate(totalSizeBytes); assert(newBuffer != nullptr); // New pointers to components data Entity* newEntities = static_cast<Entity*>(newBuffer); ProxyShape** newProxyShapes = reinterpret_cast<ProxyShape**>(newEntities + nbComponentsToAllocate); int* newBroadPhaseIds = reinterpret_cast<int*>(newProxyShapes + nbComponentsToAllocate); AABB* newLocalBounds = reinterpret_cast<AABB*>(newBroadPhaseIds + nbComponentsToAllocate); Transform* newLocalToBodyTransforms = reinterpret_cast<Transform*>(newLocalBounds + nbComponentsToAllocate); CollisionShape** newCollisionShapes = reinterpret_cast<CollisionShape**>(newLocalToBodyTransforms + nbComponentsToAllocate); decimal* newMasses = reinterpret_cast<decimal*>(newCollisionShapes + nbComponentsToAllocate); uint32* newPreviousBodyProxyShapes = reinterpret_cast<uint32*>(newMasses + nbComponentsToAllocate); uint32* newNextBodyProxyShapes = reinterpret_cast<uint32*>(newPreviousBodyProxyShapes + nbComponentsToAllocate); unsigned short* newCollisionCategoryBits = reinterpret_cast<unsigned short*>(newNextBodyProxyShapes + nbComponentsToAllocate); unsigned short* newCollideWithMaskBits = reinterpret_cast<unsigned short*>(newCollisionCategoryBits + nbComponentsToAllocate); // If there was already components before if (mNbComponents > 0) { // Copy component data from the previous buffer to the new one memcpy(newEntities, mEntities, mNbComponents * sizeof(Entity)); memcpy(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)); // Deallocate previous memory mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * COMPONENT_DATA_SIZE); } mBuffer = newBuffer; mEntities = newEntities; mProxyShapes = newProxyShapes; mBroadPhaseIds = newBroadPhaseIds; mLocalBounds = newLocalBounds; mLocalToBodyTransforms = newLocalToBodyTransforms; mCollisionShapes = newCollisionShapes; mMasses = newMasses; mPreviousBodyProxyShapes = newPreviousBodyProxyShapes; mNextBodyProxyShapes = newNextBodyProxyShapes; mCollisionCategoryBits = newCollisionCategoryBits; mCollideWithMaskBits = newCollideWithMaskBits; mNbAllocatedComponents = nbComponentsToAllocate; } // Add a new proxy-shape at the beginning of the linked-list of proxy-shapes of a given entity // If it is the first proxy-shape for the entity, it will create the first item of the linked-list void ProxyShapesComponents::linkProxyShapeWithEntity(Entity entity, uint32 proxyShapeComponentIndex) { auto it = mMapEntityToComponentIndex.find(entity); if (it != mMapEntityToComponentIndex.end()) { // Get the first proxy-shape of the linked-list uint32 firstProxyShapeIndex = (*it).second; assert(!hasPreviousProxyShape(firstProxyShapeIndex)); // Update the previous index of the first item of the list mPreviousBodyProxyShapes[firstProxyShapeIndex] = proxyShapeComponentIndex; // Map the entity to the new head of the linked-list mMapEntityToComponentIndex[entity] = proxyShapeComponentIndex; // Add the new proxy-shape at the beginning of the linked-list const uint32 nextIndex = firstProxyShapeIndex; const uint32 previousIndex = proxyShapeComponentIndex; new (mNextBodyProxyShapes + proxyShapeComponentIndex) uint32(nextIndex); new (mPreviousBodyProxyShapes + proxyShapeComponentIndex) uint32(previousIndex); assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[proxyShapeComponentIndex]] == proxyShapeComponentIndex); } else { // If the entity does not have a proxy-shape yet mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity, proxyShapeComponentIndex)); // The new proxy-shape has no previous/next components in the linked-list new (mNextBodyProxyShapes + proxyShapeComponentIndex) uint32(proxyShapeComponentIndex); new (mPreviousBodyProxyShapes + proxyShapeComponentIndex) uint32(proxyShapeComponentIndex); assert(!hasNextProxyShape(proxyShapeComponentIndex)); } assert(!hasPreviousProxyShape(proxyShapeComponentIndex)); } // Add a component void ProxyShapesComponents::addComponent(Entity entity, bool isSleeping, const ProxyShapeComponent& component) { // 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++; } // Insert the new component data new (mEntities + index) Entity(entity); mProxyShapes[index] = (component.proxyShape); new (mBroadPhaseIds + index) int(component.broadPhaseId); new (mLocalBounds + index) AABB(component.localBounds); new (mLocalToBodyTransforms + index) Transform(component.localToBodyTransform); mCollisionShapes[index] = component.collisionShape; new (mMasses + index) decimal(component.mass); new (mCollisionCategoryBits + index) unsigned short(component.collisionCategoryBits); new (mCollideWithMaskBits + index) unsigned short(component.collideWithMaskBits); mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(component.proxyShape, 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)); // Copy the data of the source component to the destination location new (mEntities + destIndex) Entity(mEntities[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) { mMapEntityToComponentIndex[entity] = destIndex; assert(mMapEntityToComponentIndex[mEntities[destIndex]] == destIndex); } mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(mProxyShapes[destIndex], destIndex)); assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[destIndex]] == destIndex || !hasNextProxyShape(destIndex)); assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[destIndex]] == destIndex || !hasPreviousProxyShape(destIndex)); } // Swap two components in the array void ProxyShapesComponents::swapComponents(uint32 index1, uint32 index2) { // Copy component 1 data Entity entity1(mEntities[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); 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 the previous proxy-shape index of the next proxy-shape if (hasNextProxyShape(index2)) { assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] == index1); mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] = index2; } mMapProxyShapeToComponentIndex.add(Pair<const ProxyShape*, uint32>(mProxyShapes[index2], index2)); // Update the entity to component index mapping if it is the first body proxy-shape if (isFirstBodyProxyShape1) { assert(!hasPreviousProxyShape(index2)); mMapEntityToComponentIndex[entity1] = index2; } assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index1]] == index1 || !hasNextProxyShape(index1)); assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index2]] == index2 || !hasNextProxyShape(index2)); assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index1]] == index1 || !hasPreviousProxyShape(index1)); assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] == index2 || !hasPreviousProxyShape(index2)); } // Remove a component at a given index void ProxyShapesComponents::removeComponent(uint32 index) { 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. // If the proxy-shape to destroy does not have a previous proxy-shape in the linked-list of proxy-shapes of its body if (!hasPreviousProxyShape(index)) { // Remove the mapping from entity to component index mMapEntityToComponentIndex.remove(mEntities[index]); // If the proxy-shape has a next proxy-shape in the linked-list if (hasNextProxyShape(index)) { assert(mEntities[index] == mEntities[mNextBodyProxyShapes[index]]); mMapEntityToComponentIndex.add(Pair<Entity, uint32>(mEntities[mNextBodyProxyShapes[index]], mNextBodyProxyShapes[index])); } } // Update the linked-list of proxy-shapes of a body when a proxy-shape is removed if (hasPreviousProxyShape(index)) { assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index); assert(mEntities[index] == mEntities[mPreviousBodyProxyShapes[index]]); // If the current proxy-shape to remove has a next proxy-shape in the linked-list if (hasNextProxyShape(index)) { assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index); // Make sure the next proxy-shape will follow the previous proxy-shape in the linked-list mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] = mNextBodyProxyShapes[index]; } else { mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] = mPreviousBodyProxyShapes[index]; } } // Update the linked-list of proxy-shapes of a body when a proxy-shape is removed if (hasNextProxyShape(index)) { assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index); assert(mEntities[index] == mEntities[mNextBodyProxyShapes[index]]); // If the current proxy-shape to remove has a previous proxy-shape in the linked-list if (hasPreviousProxyShape(index)) { // Make sure the previous proxy-shape will precede the next proxy-shape in the linked-list mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] = mPreviousBodyProxyShapes[index]; } else { mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] = mNextBodyProxyShapes[index]; } } // Destroy the component destroyComponent(index); // 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--; } 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; } // Destroy a component at a given index void ProxyShapesComponents::destroyComponent(uint32 index) { assert(index < mNbComponents); mMapProxyShapeToComponentIndex.remove(mProxyShapes[index]); mEntities[index].~Entity(); mProxyShapes[index] = nullptr; mLocalBounds[index].~AABB(); 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); 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); }