feat(physics): wire physx sdk into build
This commit is contained in:
265
engine/third_party/physx/source/geomutils/src/GuPruningPool.cpp
vendored
Normal file
265
engine/third_party/physx/source/geomutils/src/GuPruningPool.cpp
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
// 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-2025 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 "GuPruningPool.h"
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "common/PxProfileZone.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
PruningPool::PruningPool(PxU64 contextID, TransformCacheMode mode) :
|
||||
mNbObjects (0),
|
||||
mMaxNbObjects (0),
|
||||
mObjects (NULL),
|
||||
mTransforms (NULL),
|
||||
mTransformCacheMode (mode),
|
||||
mHandleToIndex (NULL),
|
||||
mIndexToHandle (NULL),
|
||||
mFirstRecycledHandle(INVALID_PRUNERHANDLE),
|
||||
mContextID (contextID)
|
||||
{
|
||||
}
|
||||
|
||||
PruningPool::~PruningPool()
|
||||
{
|
||||
mWorldBoxes.release();
|
||||
PX_FREE(mIndexToHandle);
|
||||
PX_FREE(mHandleToIndex);
|
||||
PX_FREE(mTransforms);
|
||||
PX_FREE(mObjects);
|
||||
}
|
||||
|
||||
bool PruningPool::resize(PxU32 newCapacity)
|
||||
{
|
||||
PX_PROFILE_ZONE("PruningPool::resize", mContextID);
|
||||
|
||||
const bool useTransforms = mTransformCacheMode!=TRANSFORM_CACHE_UNUSED;
|
||||
PxTransform* newTransforms = useTransforms ? PX_ALLOCATE(PxTransform, newCapacity, "Pruner transforms") : NULL;
|
||||
if(useTransforms && !newTransforms)
|
||||
return false;
|
||||
|
||||
PrunerPayload* newData = PX_ALLOCATE(PrunerPayload, newCapacity, "PrunerPayload*");
|
||||
PrunerHandle* newIndexToHandle = PX_ALLOCATE(PrunerHandle, newCapacity, "Pruner Index Mapping");
|
||||
PoolIndex* newHandleToIndex = PX_ALLOCATE(PoolIndex, newCapacity, "Pruner Index Mapping");
|
||||
if( (!newData) || (!newIndexToHandle) || (!newHandleToIndex))
|
||||
{
|
||||
PX_FREE(newHandleToIndex);
|
||||
PX_FREE(newIndexToHandle);
|
||||
PX_FREE(newTransforms);
|
||||
PX_FREE(newData);
|
||||
return false;
|
||||
}
|
||||
|
||||
mWorldBoxes.resize(newCapacity, mNbObjects);
|
||||
|
||||
if(mObjects) PxMemCopy(newData, mObjects, mNbObjects*sizeof(PrunerPayload));
|
||||
if(mTransforms) PxMemCopy(newTransforms, mTransforms, mNbObjects*sizeof(PxTransform));
|
||||
if(mIndexToHandle) PxMemCopy(newIndexToHandle, mIndexToHandle, mNbObjects*sizeof(PrunerHandle));
|
||||
if(mHandleToIndex) PxMemCopy(newHandleToIndex, mHandleToIndex, mMaxNbObjects*sizeof(PoolIndex)); // PT: why mMaxNbObjects here? on purpose?
|
||||
mMaxNbObjects = newCapacity;
|
||||
|
||||
PX_FREE(mIndexToHandle);
|
||||
PX_FREE(mHandleToIndex);
|
||||
PX_FREE(mTransforms);
|
||||
PX_FREE(mObjects);
|
||||
mObjects = newData;
|
||||
mTransforms = newTransforms;
|
||||
mHandleToIndex = newHandleToIndex;
|
||||
mIndexToHandle = newIndexToHandle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PruningPool::preallocate(PxU32 newCapacity)
|
||||
{
|
||||
if(newCapacity>mMaxNbObjects)
|
||||
resize(newCapacity);
|
||||
}
|
||||
|
||||
PxU32 PruningPool::addObjects(PrunerHandle* results, const PxBounds3* bounds, const PrunerPayload* data, const PxTransform* transforms, PxU32 count)
|
||||
{
|
||||
PX_PROFILE_ZONE("PruningPool::addObjects", mContextID);
|
||||
|
||||
PX_ASSERT((!transforms && mTransformCacheMode==TRANSFORM_CACHE_UNUSED) || (transforms && mTransformCacheMode!=TRANSFORM_CACHE_UNUSED));
|
||||
|
||||
for(PxU32 i=0;i<count;i++)
|
||||
{
|
||||
if(mNbObjects==mMaxNbObjects) // increase the capacity on overflow
|
||||
{
|
||||
const PxU32 newCapacity = PxU32(float(mMaxNbObjects)*1.5f);
|
||||
if(!resize(PxMax<PxU32>(newCapacity, 64)))
|
||||
//if(!resize(PxMax<PxU32>(mMaxNbObjects*2, 64)))
|
||||
{
|
||||
// pool can return an invalid handle if memory alloc fails
|
||||
// should probably have an error here or not handle this
|
||||
results[i] = INVALID_PRUNERHANDLE; // PT: we need to write the potentially invalid handle to let users know which object failed first
|
||||
return i;
|
||||
}
|
||||
}
|
||||
PX_ASSERT(mNbObjects!=mMaxNbObjects);
|
||||
|
||||
const PoolIndex index = mNbObjects++;
|
||||
|
||||
// update mHandleToIndex and mIndexToHandle mappings
|
||||
PrunerHandle handle;
|
||||
if(mFirstRecycledHandle != INVALID_PRUNERHANDLE)
|
||||
{
|
||||
// mFirstRecycledHandle is an entry into a freelist for removed slots
|
||||
// this path is only taken if we have any removed slots
|
||||
handle = mFirstRecycledHandle;
|
||||
mFirstRecycledHandle = mHandleToIndex[handle];
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = index;
|
||||
}
|
||||
|
||||
// PT: TODO: investigate why we added mIndexToHandle/mHandleToIndex. The initial design with 'Prunable' objects didn't need these arrays.
|
||||
|
||||
// PT: these arrays are "parallel"
|
||||
mWorldBoxes.getBounds() [index] = bounds[i]; // store the payload/userData and AABB in parallel arrays
|
||||
mObjects [index] = data[i];
|
||||
mIndexToHandle [index] = handle;
|
||||
if(transforms && mTransforms)
|
||||
mTransforms [index] = transforms[i];
|
||||
|
||||
mHandleToIndex[handle] = index;
|
||||
results[i] = handle;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
PoolIndex PruningPool::removeObject(PrunerHandle h, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
PX_PROFILE_ZONE("PruningPool::removeObject", mContextID);
|
||||
|
||||
PX_ASSERT(mNbObjects);
|
||||
|
||||
// remove the object and its AABB by provided PrunerHandle and update mHandleToIndex and mIndexToHandle mappings
|
||||
const PoolIndex indexOfRemovedObject = mHandleToIndex[h]; // retrieve object's index from handle
|
||||
|
||||
if(removalCallback)
|
||||
removalCallback->invoke(1, &mObjects[indexOfRemovedObject]);
|
||||
|
||||
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
|
||||
// PT: TODO: investigate where this double-mapping comes from. It was not needed in the original design.
|
||||
|
||||
// PT: these arrays are "parallel"
|
||||
PxBounds3* bounds = mWorldBoxes.getBounds();
|
||||
const PrunerHandle handleOfLastObject = mIndexToHandle[indexOfLastObject];
|
||||
bounds [indexOfRemovedObject] = bounds [indexOfLastObject];
|
||||
mObjects [indexOfRemovedObject] = mObjects [indexOfLastObject];
|
||||
if(mTransforms)
|
||||
mTransforms [indexOfRemovedObject] = mTransforms [indexOfLastObject];
|
||||
mIndexToHandle [indexOfRemovedObject] = handleOfLastObject;
|
||||
|
||||
mHandleToIndex[handleOfLastObject] = indexOfRemovedObject;
|
||||
}
|
||||
|
||||
// mHandleToIndex also stores the freelist for removed handles (in place of holes formed by removed handles)
|
||||
mHandleToIndex[h] = mFirstRecycledHandle; // update linked list of available recycled handles
|
||||
mFirstRecycledHandle = h; // update the list head
|
||||
|
||||
return indexOfLastObject;
|
||||
}
|
||||
|
||||
void PruningPool::shiftOrigin(const PxVec3& shift)
|
||||
{
|
||||
PX_PROFILE_ZONE("PruningPool::shiftOrigin", mContextID);
|
||||
|
||||
const PxU32 nb = mNbObjects;
|
||||
PxBounds3* bounds = mWorldBoxes.getBounds();
|
||||
for(PxU32 i=0; i<nb; i++)
|
||||
{
|
||||
bounds[i].minimum -= shift;
|
||||
bounds[i].maximum -= shift;
|
||||
}
|
||||
|
||||
if(mTransforms && mTransformCacheMode==TRANSFORM_CACHE_GLOBAL)
|
||||
{
|
||||
for(PxU32 i=0; i<nb; i++)
|
||||
mTransforms[i].p -= shift;
|
||||
}
|
||||
}
|
||||
|
||||
template<const bool hasTransforms>
|
||||
static void updateAndInflateBounds(PruningPool& pool, const PrunerHandle* PX_RESTRICT handles, const PxU32* PX_RESTRICT boundsIndices, const PxBounds3* PX_RESTRICT newBounds,
|
||||
const PxTransform32* PX_RESTRICT newTransforms, PxU32 count, float epsilon)
|
||||
{
|
||||
PxBounds3* PX_RESTRICT bounds = pool.mWorldBoxes.getBounds();
|
||||
PxTransform* PX_RESTRICT transforms = hasTransforms ? pool.mTransforms : NULL;
|
||||
|
||||
if(boundsIndices)
|
||||
{
|
||||
while(count--)
|
||||
{
|
||||
const PoolIndex poolIndex = pool.getIndex(*handles++);
|
||||
PX_ASSERT(poolIndex!=INVALID_PRUNERHANDLE);
|
||||
|
||||
const PxU32 remappedIndex = *boundsIndices++;
|
||||
|
||||
if(hasTransforms)
|
||||
transforms[poolIndex] = newTransforms[remappedIndex];
|
||||
|
||||
inflateBounds<true>(bounds[poolIndex], newBounds[remappedIndex], epsilon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(count--)
|
||||
{
|
||||
const PoolIndex poolIndex = pool.getIndex(*handles++);
|
||||
PX_ASSERT(poolIndex!=INVALID_PRUNERHANDLE);
|
||||
|
||||
if(hasTransforms)
|
||||
{
|
||||
transforms[poolIndex] = *newTransforms;
|
||||
newTransforms++;
|
||||
}
|
||||
|
||||
inflateBounds<true>(bounds[poolIndex], *newBounds++, epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PruningPool::updateAndInflateBounds(const PrunerHandle* handles, const PxU32* boundsIndices, const PxBounds3* newBounds,
|
||||
const PxTransform32* newTransforms, PxU32 count, float epsilon)
|
||||
{
|
||||
PX_PROFILE_ZONE("PruningPool::updateAndInflateBounds", mContextID);
|
||||
|
||||
if(mTransforms)
|
||||
::updateAndInflateBounds<1>(*this, handles, boundsIndices, newBounds, newTransforms, count, epsilon);
|
||||
else
|
||||
::updateAndInflateBounds<0>(*this, handles, boundsIndices, newBounds, NULL, count, epsilon);
|
||||
}
|
||||
Reference in New Issue
Block a user