280 lines
9.9 KiB
C++
280 lines
9.9 KiB
C++
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved.
|
|
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
|
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
|
|
|
|
|
#include "PsFoundation.h"
|
|
#include "PsAllocator.h"
|
|
#include "SqCompoundPruningPool.h"
|
|
#include "SqAABBTree.h"
|
|
#include "SqPruningPool.h"
|
|
#include "GuBVHStructure.h"
|
|
|
|
using namespace physx;
|
|
using namespace Gu;
|
|
using namespace Sq;
|
|
using namespace Cm;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundTree::updateObjectAfterManualBoundsUpdates(PrunerHandle handle)
|
|
{
|
|
const PxBounds3* newBounds = mPruningPool->getCurrentWorldBoxes();
|
|
const PoolIndex poolIndex = mPruningPool->getIndex(handle);
|
|
NodeList changedLeaves;
|
|
changedLeaves.reserve(8);
|
|
IncrementalAABBTreeNode* node = mTree->update((*mUpdateMap)[poolIndex], poolIndex, newBounds, changedLeaves);
|
|
// we removed node during update, need to update the mapping
|
|
updateMapping(poolIndex, node, changedLeaves);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundTree::removeObject(PrunerHandle handle)
|
|
{
|
|
const PoolIndex poolIndex = mPruningPool->getIndex(handle); // save the pool index for removed object
|
|
const PoolIndex poolRelocatedLastIndex = mPruningPool->removeObject(handle); // save the lastIndex returned by removeObject
|
|
|
|
IncrementalAABBTreeNode* node = mTree->remove((*mUpdateMap)[poolIndex], poolIndex, mPruningPool->getCurrentWorldBoxes());
|
|
// if node moved to its parent
|
|
if (node && node->isLeaf())
|
|
{
|
|
for (PxU32 j = 0; j < node->getNbPrimitives(); j++)
|
|
{
|
|
const PoolIndex index = node->getPrimitives(NULL)[j];
|
|
(*mUpdateMap)[index] = node;
|
|
}
|
|
}
|
|
|
|
(*mUpdateMap)[poolIndex] = (*mUpdateMap)[poolRelocatedLastIndex];
|
|
// fix indices if we made a swap
|
|
if(poolRelocatedLastIndex != poolIndex)
|
|
mTree->fixupTreeIndices((*mUpdateMap)[poolIndex], poolRelocatedLastIndex, poolIndex);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool CompoundTree::addObject(PrunerHandle& result, const PxBounds3& bounds, const PrunerPayload payload)
|
|
{
|
|
mPruningPool->addObjects(&result, &bounds, &payload, 1);
|
|
|
|
const PoolIndex poolIndex = mPruningPool->getIndex(result);
|
|
NodeList changedLeaves;
|
|
changedLeaves.reserve(8);
|
|
IncrementalAABBTreeNode* node = mTree->insert(poolIndex, mPruningPool->getCurrentWorldBoxes(), changedLeaves);
|
|
updateMapping(poolIndex, node, changedLeaves);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundTree::updateMapping(const PoolIndex poolIndex, IncrementalAABBTreeNode* node, const NodeList& changedLeaves)
|
|
{
|
|
// if a node was split we need to update the node indices and also the sibling indices
|
|
if(!changedLeaves.empty())
|
|
{
|
|
if(node && node->isLeaf())
|
|
{
|
|
for(PxU32 j = 0; j < node->getNbPrimitives(); j++)
|
|
{
|
|
const PoolIndex index = node->getPrimitives(NULL)[j];
|
|
(*mUpdateMap)[index] = node;
|
|
}
|
|
}
|
|
|
|
for(PxU32 i = 0; i < changedLeaves.size(); i++)
|
|
{
|
|
IncrementalAABBTreeNode* changedNode = changedLeaves[i];
|
|
PX_ASSERT(changedNode->isLeaf());
|
|
|
|
for(PxU32 j = 0; j < changedNode->getNbPrimitives(); j++)
|
|
{
|
|
const PoolIndex index = changedNode->getPrimitives(NULL)[j];
|
|
(*mUpdateMap)[index] = changedNode;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*mUpdateMap)[poolIndex] = node;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CompoundTreePool::CompoundTreePool():
|
|
mNbObjects(0),
|
|
mMaxNbObjects(0),
|
|
mCompoundBounds(NULL),
|
|
mCompoundTrees(NULL)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CompoundTreePool::~CompoundTreePool()
|
|
{
|
|
PX_FREE_AND_RESET(mCompoundBounds);
|
|
PX_FREE_AND_RESET(mCompoundTrees);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool CompoundTreePool::resize(PxU32 newCapacity)
|
|
{
|
|
// PT: we always allocate one extra box, to make sure we can safely use V4 loads on the array
|
|
PxBounds3* newBoxes = reinterpret_cast<PxBounds3*>(PX_ALLOC(sizeof(PxBounds3)*(newCapacity+1), "PxBounds3"));
|
|
CompoundTree* newTrees = reinterpret_cast<CompoundTree*>(PX_ALLOC(sizeof(CompoundTree)*newCapacity, "IncrementalTrees*"));
|
|
|
|
// memzero, we need to set the pointers in the compound tree to NULL
|
|
PxMemZero(newTrees, sizeof(CompoundTree)*newCapacity);
|
|
|
|
if((NULL==newBoxes) || (NULL==newTrees))
|
|
{
|
|
PX_FREE_AND_RESET(newBoxes);
|
|
PX_FREE_AND_RESET(newTrees);
|
|
return false;
|
|
}
|
|
|
|
if(mCompoundBounds) PxMemCopy(newBoxes, mCompoundBounds, mNbObjects*sizeof(PxBounds3));
|
|
if(mCompoundTrees) PxMemCopy(newTrees, mCompoundTrees, mNbObjects*sizeof(CompoundTree));
|
|
mMaxNbObjects = newCapacity;
|
|
|
|
PX_FREE_AND_RESET(mCompoundBounds);
|
|
PX_FREE_AND_RESET(mCompoundTrees);
|
|
mCompoundBounds = newBoxes;
|
|
mCompoundTrees = newTrees;
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundTreePool::preallocate(PxU32 newCapacity)
|
|
{
|
|
if(newCapacity>mMaxNbObjects)
|
|
resize(newCapacity);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CompoundTreePool::shiftOrigin(const PxVec3& shift)
|
|
{
|
|
for(PxU32 i=0; i < mNbObjects; i++)
|
|
{
|
|
mCompoundBounds[i].minimum -= shift;
|
|
mCompoundBounds[i].maximum -= shift;
|
|
|
|
mCompoundTrees[i].mGlobalPose.p -= shift;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
PoolIndex CompoundTreePool::addCompound(PrunerHandle* results, const BVHStructure& bvhStructure, const PxBounds3& compoundBounds, const PxTransform& transform,
|
|
CompoundFlag::Enum flags, const PrunerPayload* userData)
|
|
{
|
|
if(mNbObjects==mMaxNbObjects) // increase the capacity on overflow
|
|
{
|
|
if(!resize(PxMax<PxU32>(mMaxNbObjects*2, 32)))
|
|
{
|
|
// pool can return an invalid handle if memory alloc fails
|
|
Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "CompoundTreePool::addCompound memory allocation in resize failed.");
|
|
return INVALID_PRUNERHANDLE;
|
|
}
|
|
}
|
|
PX_ASSERT(mNbObjects!=mMaxNbObjects);
|
|
|
|
const PoolIndex index = mNbObjects++;
|
|
|
|
mCompoundBounds[index] = compoundBounds;
|
|
|
|
const PxU32 nbObjects = bvhStructure.getNbBounds();
|
|
|
|
CompoundTree& tree = mCompoundTrees[index];
|
|
PX_ASSERT(tree.mPruningPool == NULL);
|
|
PX_ASSERT(tree.mTree == NULL);
|
|
PX_ASSERT(tree.mUpdateMap == NULL);
|
|
|
|
tree.mGlobalPose = transform;
|
|
tree.mFlags = flags;
|
|
|
|
// prepare the pruning pool
|
|
PruningPool* pool = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PruningPool), PX_DEBUG_EXP("Pruning pool")), PruningPool);
|
|
pool->preallocate(nbObjects);
|
|
pool->addObjects(results, bvhStructure.getBounds(), userData, nbObjects);
|
|
tree.mPruningPool = pool;
|
|
|
|
// prepare update map
|
|
UpdateMap* map = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(UpdateMap), PX_DEBUG_EXP("Update map")), UpdateMap);
|
|
map->resizeUninitialized(nbObjects);
|
|
tree.mUpdateMap = map;
|
|
|
|
IncrementalAABBTree* iTree = PX_NEW(IncrementalAABBTree)();
|
|
iTree->copy(bvhStructure, *map);
|
|
tree.mTree = iTree;
|
|
|
|
return index;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
PoolIndex CompoundTreePool::removeCompound(PoolIndex indexOfRemovedObject)
|
|
{
|
|
PX_ASSERT(mNbObjects);
|
|
|
|
// release the tree
|
|
mCompoundTrees[indexOfRemovedObject].mTree->release();
|
|
mCompoundTrees[indexOfRemovedObject].mTree->~IncrementalAABBTree();
|
|
PX_FREE_AND_RESET(mCompoundTrees[indexOfRemovedObject].mTree);
|
|
|
|
mCompoundTrees[indexOfRemovedObject].mUpdateMap->clear();
|
|
mCompoundTrees[indexOfRemovedObject].mUpdateMap->~Array();
|
|
PX_FREE_AND_RESET(mCompoundTrees[indexOfRemovedObject].mUpdateMap);
|
|
|
|
mCompoundTrees[indexOfRemovedObject].mPruningPool->~PruningPool();
|
|
PX_FREE_AND_RESET(mCompoundTrees[indexOfRemovedObject].mPruningPool);
|
|
|
|
const PoolIndex indexOfLastObject = --mNbObjects; // swap the object at last index with index
|
|
if(indexOfLastObject!=indexOfRemovedObject)
|
|
{
|
|
// PT: move last object's data to recycled spot (from removed object)
|
|
|
|
// PT: the last object has moved so we need to handle the mappings for this object
|
|
mCompoundBounds [indexOfRemovedObject] = mCompoundBounds [indexOfLastObject];
|
|
mCompoundTrees [indexOfRemovedObject] = mCompoundTrees [indexOfLastObject];
|
|
|
|
mCompoundTrees [indexOfLastObject].mPruningPool = NULL;
|
|
mCompoundTrees [indexOfLastObject].mUpdateMap = NULL;
|
|
mCompoundTrees [indexOfLastObject].mTree = NULL;
|
|
}
|
|
|
|
return indexOfLastObject;
|
|
}
|
|
|