Projekt_Grafika/dependencies/physx-4.1/source/physxcharacterkinematic/src/CctObstacleContext.cpp

539 lines
18 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 "foundation/PxMemory.h"
#include "CctObstacleContext.h"
#include "CctCharacterControllerManager.h"
#include "PsUtilities.h"
using namespace physx;
using namespace Cct;
//! Initial list size
#define DEFAULT_HANDLEMANAGER_SIZE 2
HandleManager::HandleManager() : mCurrentNbObjects(0), mNbFreeIndices(0)
{
mMaxNbObjects = DEFAULT_HANDLEMANAGER_SIZE;
mObjects = reinterpret_cast<void**>(PX_ALLOC(sizeof(void*)*mMaxNbObjects, "HandleManager"));
mOutToIn = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager"));
mInToOut = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager"));
mStamps = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager"));
PxMemSet(mOutToIn, 0xff, mMaxNbObjects*sizeof(PxU16));
PxMemSet(mInToOut, 0xff, mMaxNbObjects*sizeof(PxU16));
PxMemZero(mStamps, mMaxNbObjects*sizeof(PxU16));
}
HandleManager::~HandleManager()
{
SetupLists();
}
bool HandleManager::SetupLists(void** objects, PxU16* oti, PxU16* ito, PxU16* stamps)
{
// Release old data
PX_FREE_AND_RESET(mStamps);
PX_FREE_AND_RESET(mInToOut);
PX_FREE_AND_RESET(mOutToIn);
PX_FREE_AND_RESET(mObjects);
// Assign new data
mObjects = objects;
mOutToIn = oti;
mInToOut = ito;
mStamps = stamps;
return true;
}
Handle HandleManager::Add(void* object)
{
// Are there any free indices I should recycle?
if(mNbFreeIndices)
{
const PxU16 FreeIndex = mInToOut[mCurrentNbObjects];// Get the recycled virtual index
mObjects[mCurrentNbObjects] = object; // The physical location is always at the end of the list (it never has holes).
mOutToIn[FreeIndex] = Ps::to16(mCurrentNbObjects++); // Update virtual-to-physical remapping table.
mNbFreeIndices--;
return Handle((mStamps[FreeIndex]<<16)|FreeIndex); // Return virtual index (handle) to the client app
}
else
{
PX_ASSERT_WITH_MESSAGE(mCurrentNbObjects<0xffff ,"Internal error - 64K objects in HandleManager!");
// Is the array large enough for another entry?
if(mCurrentNbObjects==mMaxNbObjects)
{
// Nope! Resize all arrays (could be avoided with linked lists... one day)
mMaxNbObjects<<=1; // The more you eat, the more you're given
if(mMaxNbObjects>0xffff) mMaxNbObjects = 0xffff; // Clamp to 64K
void** NewList = reinterpret_cast<void**>(PX_ALLOC(sizeof(void*)*mMaxNbObjects, "HandleManager")); // New physical list
PxU16* NewOTI = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager")); // New remapping table
PxU16* NewITO = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager")); // New remapping table
PxU16* NewStamps = reinterpret_cast<PxU16*>(PX_ALLOC(sizeof(PxU16)*mMaxNbObjects, "HandleManager")); // New stamps
PxMemCopy(NewList, mObjects, mCurrentNbObjects*sizeof(void*)); // Copy old data
PxMemCopy(NewOTI, mOutToIn, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
PxMemCopy(NewITO, mInToOut, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
PxMemCopy(NewStamps, mStamps, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
PxMemSet(NewOTI+mCurrentNbObjects, 0xff, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
PxMemSet(NewITO+mCurrentNbObjects, 0xff, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
PxMemZero(NewStamps+mCurrentNbObjects, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
SetupLists(NewList, NewOTI, NewITO, NewStamps);
}
mObjects[mCurrentNbObjects] = object; // Store object at mCurrentNbObjects = physical index = virtual index
mOutToIn[mCurrentNbObjects] = Ps::to16(mCurrentNbObjects); // Update virtual-to-physical remapping table.
mInToOut[mCurrentNbObjects] = Ps::to16(mCurrentNbObjects); // Update physical-to-virtual remapping table.
PxU32 tmp = mCurrentNbObjects++;
return (mStamps[tmp]<<16)|tmp; // Return virtual index (handle) to the client app
}
}
void HandleManager::Remove(Handle handle)
{
const PxU16 VirtualIndex = PxU16(handle);
if(VirtualIndex>=mMaxNbObjects) return; // Invalid handle
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get the physical index
if(PhysicalIndex==0xffff) return; // Value has already been deleted
if(PhysicalIndex>=mMaxNbObjects) return; // Invalid index
// There must be at least one valid entry.
if(mCurrentNbObjects)
{
if(mStamps[VirtualIndex]!=handle>>16) return; // Stamp mismatch => index has been recycled
// Update list so that there's no hole
mObjects[PhysicalIndex] = mObjects[--mCurrentNbObjects];// Move the real object so that the array has no holes.
mOutToIn[mInToOut[mCurrentNbObjects]] = PhysicalIndex; // Update virtual-to-physical remapping table.
mInToOut[PhysicalIndex] = mInToOut[mCurrentNbObjects]; // Update physical-to-virtual remapping table.
// Keep track of the recyclable virtual index
mInToOut[mCurrentNbObjects] = VirtualIndex; // Store the free virtual index/handle at the end of mInToOut
mOutToIn[VirtualIndex] = 0xffff; // Invalidate the entry
mNbFreeIndices++; // One more free index
mStamps[VirtualIndex]++; // Update stamp
}
}
void* HandleManager::GetObject(Handle handle) const
{
const PxU16 VirtualIndex = PxU16(handle);
if(VirtualIndex>=mMaxNbObjects) return NULL; // Invalid handle
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get physical index
if(PhysicalIndex==0xffff) return NULL; // Object has been deleted
if(PhysicalIndex>=mMaxNbObjects) return NULL; // Index is invalid
if(mStamps[VirtualIndex]!=handle>>16) return NULL; // Index has been recycled
return mObjects[PhysicalIndex]; // Returns stored pointer
}
bool HandleManager::UpdateObject(Handle handle, void* object)
{
const PxU16 VirtualIndex = PxU16(handle);
if(VirtualIndex>=mMaxNbObjects) return false; // Invalid handle
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get physical index
if(PhysicalIndex==0xffff) return false; // Object has been deleted
if(PhysicalIndex>=mMaxNbObjects) return false; // Index is invalid
if(mStamps[VirtualIndex]!=handle>>16) return false; // Index has been recycled
mObjects[PhysicalIndex] = object; // Updates stored pointer
return true;
}
// PT: please do not expose these functions outside of this class,
// as we want to retain the ability to easily modify the handle format if necessary.
#define NEW_ENCODING
#ifdef NEW_ENCODING
static PX_FORCE_INLINE void* encodeInternalHandle(PxU32 index, PxGeometryType::Enum type)
{
PX_ASSERT(index<=0xffff);
PX_ASSERT(PxU32(type)<=0xffff);
// PT: we do type+1 to ban internal handles with a 0 value, since it's reserved for NULL pointers
return reinterpret_cast<void*>((size_t(index)<<16)|(size_t(type)+1));
}
static PX_FORCE_INLINE PxGeometryType::Enum decodeInternalType(void* handle)
{
return PxGeometryType::Enum((PxU32(reinterpret_cast<size_t>(handle)) & 0xffff)-1);
}
static PX_FORCE_INLINE PxU32 decodeInternalIndex(void* handle)
{
return (PxU32(size_t(handle)))>>16;
}
#else
static PX_FORCE_INLINE ObstacleHandle encodeHandle(PxU32 index, PxGeometryType::Enum type)
{
PX_ASSERT(index<=0xffff);
PX_ASSERT(type<=0xffff);
return (PxU16(index)<<16)|PxU32(type);
}
static PX_FORCE_INLINE PxGeometryType::Enum decodeType(ObstacleHandle handle)
{
return PxGeometryType::Enum(handle & 0xffff);
}
static PX_FORCE_INLINE PxU32 decodeIndex(ObstacleHandle handle)
{
return handle>>16;
}
#endif
ObstacleContext::ObstacleContext(CharacterControllerManager& cctMan)
: mCCTManager(cctMan)
{
}
ObstacleContext::~ObstacleContext()
{
}
void ObstacleContext::release()
{
mCCTManager.releaseObstacleContext(*this);
}
PxControllerManager& ObstacleContext::getControllerManager() const
{
return mCCTManager;
}
ObstacleHandle ObstacleContext::addObstacle(const PxObstacle& obstacle)
{
const PxGeometryType::Enum type = obstacle.getType();
if(type==PxGeometryType::eBOX)
{
const PxU32 index = mBoxObstacles.size();
#ifdef NEW_ENCODING
const ObstacleHandle handle = mHandleManager.Add(encodeInternalHandle(index, type));
#else
const ObstacleHandle handle = encodeHandle(index, type);
#endif
mBoxObstacles.pushBack(InternalBoxObstacle(handle, static_cast<const PxBoxObstacle&>(obstacle)));
mCCTManager.onObstacleAdded(handle, this);
return handle;
}
else if(type==PxGeometryType::eCAPSULE)
{
const PxU32 index = mCapsuleObstacles.size();
#ifdef NEW_ENCODING
const ObstacleHandle handle = mHandleManager.Add(encodeInternalHandle(index, type));
#else
const ObstacleHandle handle = encodeHandle(index, type);
#endif
mCapsuleObstacles.pushBack(InternalCapsuleObstacle(handle, static_cast<const PxCapsuleObstacle&>(obstacle)));
mCCTManager.onObstacleAdded(handle, this);
return handle;
}
else return INVALID_OBSTACLE_HANDLE;
}
#ifdef NEW_ENCODING
template<class T>
static PX_FORCE_INLINE void remove(HandleManager& manager, void* object, ObstacleHandle handle, PxU32 index, PxU32 size, const Ps::Array<T>& obstacles)
{
manager.Remove(handle);
if(index!=size-1)
{
bool status = manager.UpdateObject(obstacles[size-1].mHandle, object);
PX_ASSERT(status);
PX_UNUSED(status);
}
}
#endif
bool ObstacleContext::removeObstacle(ObstacleHandle handle)
{
#ifdef NEW_ENCODING
void* object = mHandleManager.GetObject(handle);
if(!object)
return false;
const PxGeometryType::Enum type = decodeInternalType(object);
const PxU32 index = decodeInternalIndex(object);
#else
const PxGeometryType::Enum type = decodeType(handle);
const PxU32 index = decodeIndex(handle);
#endif
if(type==PxGeometryType::eBOX)
{
const PxU32 size = mBoxObstacles.size();
PX_ASSERT(index<size);
if(index>=size)
return false;
#ifdef NEW_ENCODING
remove<InternalBoxObstacle>(mHandleManager, object, handle, index, size, mBoxObstacles);
#endif
mBoxObstacles.replaceWithLast(index);
#ifdef NEW_ENCODING
mCCTManager.onObstacleRemoved(handle);
#else
mCCTManager.onObstacleRemoved(handle, encodeHandle(size-1, type));
#endif
return true;
}
else if(type==PxGeometryType::eCAPSULE)
{
const PxU32 size = mCapsuleObstacles.size();
PX_ASSERT(index<size);
if(index>=size)
return false;
#ifdef NEW_ENCODING
remove<InternalCapsuleObstacle>(mHandleManager, object, handle, index, size, mCapsuleObstacles);
#endif
mCapsuleObstacles.replaceWithLast(index);
#ifdef NEW_ENCODING
mCCTManager.onObstacleRemoved(handle);
#else
mCCTManager.onObstacleRemoved(handle, encodeHandle(size-1, type));
#endif
return true;
}
else return false;
}
bool ObstacleContext::updateObstacle(ObstacleHandle handle, const PxObstacle& obstacle)
{
#ifdef NEW_ENCODING
void* object = mHandleManager.GetObject(handle);
if(!object)
return false;
const PxGeometryType::Enum type = decodeInternalType(object);
PX_ASSERT(type==obstacle.getType());
if(type!=obstacle.getType())
return false;
const PxU32 index = decodeInternalIndex(object);
#else
const PxGeometryType::Enum type = decodeType(handle);
PX_ASSERT(type==obstacle.getType());
if(type!=obstacle.getType())
return false;
const PxU32 index = decodeIndex(handle);
#endif
if(type==PxGeometryType::eBOX)
{
const PxU32 size = mBoxObstacles.size();
PX_ASSERT(index<size);
if(index>=size)
return false;
mBoxObstacles[index].mData = static_cast<const PxBoxObstacle&>(obstacle);
mCCTManager.onObstacleUpdated(handle,this);
return true;
}
else if(type==PxGeometryType::eCAPSULE)
{
const PxU32 size = mCapsuleObstacles.size();
PX_ASSERT(index<size);
if(index>=size)
return false;
mCapsuleObstacles[index].mData = static_cast<const PxCapsuleObstacle&>(obstacle);
mCCTManager.onObstacleUpdated(handle,this);
return true;
}
else return false;
}
PxU32 ObstacleContext::getNbObstacles() const
{
return mBoxObstacles.size() + mCapsuleObstacles.size();
}
const PxObstacle* ObstacleContext::getObstacle(PxU32 i) const
{
const PxU32 nbBoxes = mBoxObstacles.size();
if(i<nbBoxes)
return &mBoxObstacles[i].mData;
i -= nbBoxes;
const PxU32 nbCapsules = mCapsuleObstacles.size();
if(i<nbCapsules)
return &mCapsuleObstacles[i].mData;
return NULL;
}
const PxObstacle* ObstacleContext::getObstacleByHandle(ObstacleHandle handle) const
{
#ifdef NEW_ENCODING
void* object = mHandleManager.GetObject(handle);
if(!object)
return NULL;
const PxGeometryType::Enum type = decodeInternalType(object);
const PxU32 index = decodeInternalIndex(object);
#else
const PxGeometryType::Enum type = decodeType(handle);
const PxU32 index = decodeIndex(handle);
#endif
if(type == PxGeometryType::eBOX)
{
const PxU32 size = mBoxObstacles.size();
if(index>=size)
return NULL;
PX_ASSERT(mBoxObstacles[index].mHandle==handle);
return &mBoxObstacles[index].mData;
}
else if(type==PxGeometryType::eCAPSULE)
{
const PxU32 size = mCapsuleObstacles.size();
if(index>=size)
return NULL;
PX_ASSERT(mCapsuleObstacles[index].mHandle==handle);
return &mCapsuleObstacles[index].mData;
}
else return NULL;
}
#include "GuRaycastTests.h"
#include "geometry/PxBoxGeometry.h"
#include "geometry/PxCapsuleGeometry.h"
#include "PsMathUtils.h"
using namespace Gu;
const PxObstacle* ObstacleContext::raycastSingle(PxRaycastHit& hit, const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, ObstacleHandle& obstacleHandle) const
{
PxRaycastHit localHit;
PxF32 t = FLT_MAX;
const PxObstacle* touchedObstacle = NULL;
const PxHitFlags hitFlags = PxHitFlags(0);
{
const RaycastFunc raycastFunc = Gu::getRaycastFuncTable()[PxGeometryType::eBOX];
PX_ASSERT(raycastFunc);
const PxU32 nbExtraBoxes = mBoxObstacles.size();
for(PxU32 i=0;i<nbExtraBoxes;i++)
{
const PxBoxObstacle& userBoxObstacle = mBoxObstacles[i].mData;
PxU32 status = raycastFunc( PxBoxGeometry(userBoxObstacle.mHalfExtents),
PxTransform(toVec3(userBoxObstacle.mPos), userBoxObstacle.mRot),
origin, unitDir, distance,
hitFlags,
1, &localHit);
if(status && localHit.distance<t)
{
t = localHit.distance;
hit = localHit;
obstacleHandle = mBoxObstacles[i].mHandle;
touchedObstacle = &userBoxObstacle;
}
}
}
{
const RaycastFunc raycastFunc = Gu::getRaycastFuncTable()[PxGeometryType::eCAPSULE];
PX_ASSERT(raycastFunc);
const PxU32 nbExtraCapsules = mCapsuleObstacles.size();
for(PxU32 i=0;i<nbExtraCapsules;i++)
{
const PxCapsuleObstacle& userCapsuleObstacle = mCapsuleObstacles[i].mData;
PxU32 status = raycastFunc( PxCapsuleGeometry(userCapsuleObstacle.mRadius, userCapsuleObstacle.mHalfHeight),
PxTransform(toVec3(userCapsuleObstacle.mPos), userCapsuleObstacle.mRot),
origin, unitDir, distance,
hitFlags,
1, &localHit);
if(status && localHit.distance<t)
{
t = localHit.distance;
hit = localHit;
obstacleHandle = mCapsuleObstacles[i].mHandle;
touchedObstacle = &userCapsuleObstacle;
}
}
}
return touchedObstacle;
}
const PxObstacle* ObstacleContext::raycastSingle(PxRaycastHit& hit, const ObstacleHandle& obstacleHandle, const PxVec3& origin, const PxVec3& unitDir, const PxReal distance) const
{
const PxHitFlags hitFlags = PxHitFlags(0);
#ifdef NEW_ENCODING
void* object = mHandleManager.GetObject(obstacleHandle);
if(!object)
return NULL;
const PxGeometryType::Enum geomType = decodeInternalType(object);
const PxU32 index = decodeInternalIndex(object);
#else
const PxGeometryType::Enum geomType = decodeType(obstacleHandle);
const PxU32 index = decodeIndex(obstacleHandle);
#endif
if(geomType == PxGeometryType::eBOX)
{
const PxBoxObstacle& userBoxObstacle = mBoxObstacles[index].mData;
PxU32 status = Gu::getRaycastFuncTable()[PxGeometryType::eBOX](
PxBoxGeometry(userBoxObstacle.mHalfExtents),
PxTransform(toVec3(userBoxObstacle.mPos), userBoxObstacle.mRot),
origin, unitDir, distance,
hitFlags,
1, &hit);
if(status)
{
return &userBoxObstacle;
}
}
else
{
PX_ASSERT(geomType == PxGeometryType::eCAPSULE);
const PxCapsuleObstacle& userCapsuleObstacle = mCapsuleObstacles[index].mData;
PxU32 status = Gu::getRaycastFuncTable()[PxGeometryType::eCAPSULE](
PxCapsuleGeometry(userCapsuleObstacle.mRadius, userCapsuleObstacle.mHalfHeight),
PxTransform(toVec3(userCapsuleObstacle.mPos), userCapsuleObstacle.mRot),
origin, unitDir, distance,
hitFlags,
1, &hit);
if(status)
{
return &userCapsuleObstacle;
}
}
return NULL;
}
void ObstacleContext::onOriginShift(const PxVec3& shift)
{
for(PxU32 i=0; i < mBoxObstacles.size(); i++)
mBoxObstacles[i].mData.mPos -= shift;
for(PxU32 i=0; i < mCapsuleObstacles.size(); i++)
mCapsuleObstacles[i].mData.mPos -= shift;
}