feat(physics): wire physx sdk into build
This commit is contained in:
46
engine/third_party/physx/source/scenequery/include/SqFactory.h
vendored
Normal file
46
engine/third_party/physx/source/scenequery/include/SqFactory.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_FACTORY_H
|
||||
#define SQ_FACTORY_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "GuFactory.h"
|
||||
#include "SqTypedef.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
class CompoundPruner;
|
||||
|
||||
CompoundPruner* createCompoundPruner(PxU64 contextID);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
197
engine/third_party/physx/source/scenequery/include/SqManager.h
vendored
Normal file
197
engine/third_party/physx/source/scenequery/include/SqManager.h
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_MANAGER_H
|
||||
#define SQ_MANAGER_H
|
||||
|
||||
// PT: SQ-API LEVEL 2 (Level 1 = SqPruner.h)
|
||||
// PT: this file is part of a "high-level" set of files within Sq. The SqPruner API doesn't rely on them.
|
||||
// PT: this should really be at Np level but moving it to Sq allows us to share it.
|
||||
|
||||
#include "common/PxPhysXCommonConfig.h"
|
||||
|
||||
#include "foundation/PxBitMap.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "SqPruner.h"
|
||||
#include "geometry/PxGeometryHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
// PrunerManager-level adapter
|
||||
class Adapter
|
||||
{
|
||||
public:
|
||||
Adapter() {}
|
||||
virtual ~Adapter() {}
|
||||
|
||||
// Retrieves the PxGeometry associated with a given PrunerPayload. This will be called by
|
||||
// the PrunerManager class when computing bounds.
|
||||
virtual const PxGeometry& getGeometry(const Gu::PrunerPayload& payload) const = 0;
|
||||
};
|
||||
|
||||
// PT: extended pruner structure. We might want to move the additional data to the pruner itself later.
|
||||
struct PrunerExt : public PxUserAllocated
|
||||
{
|
||||
// private:
|
||||
PrunerExt();
|
||||
~PrunerExt();
|
||||
|
||||
void init(Gu::Pruner* pruner);
|
||||
void flushMemory();
|
||||
void preallocate(PxU32 nbShapes);
|
||||
|
||||
void addToDirtyList(Gu::PrunerHandle handle, bool dynamic, const PxTransform& transform);
|
||||
void removeFromDirtyList(Gu::PrunerHandle handle);
|
||||
bool processDirtyList(PxU32 index, const Adapter& adapter, float inflation);
|
||||
// void growDirtyList(Gu::PrunerHandle handle);
|
||||
|
||||
PX_FORCE_INLINE Gu::Pruner* pruner() { return mPruner; }
|
||||
PX_FORCE_INLINE const Gu::Pruner* pruner() const { return mPruner; }
|
||||
|
||||
Gu::Pruner* mPruner;
|
||||
PxBitMap mDirtyMap;
|
||||
PxArray<Gu::PrunerHandle> mDirtyList;
|
||||
bool mDirtyStatic; // true if dirty list contains a static
|
||||
|
||||
PX_NOCOPY(PrunerExt)
|
||||
|
||||
friend class PrunerManager;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include "foundation/PxHashSet.h"
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
class CompoundPruner;
|
||||
typedef PxPair<PrunerCompoundId, Gu::PrunerHandle> CompoundPair;
|
||||
typedef PxCoalescedHashSet<CompoundPair > CompoundPrunerSet;
|
||||
// AB: extended compound pruner structure, buffers compound shape changes and flushes them.
|
||||
struct CompoundPrunerExt : public PxUserAllocated
|
||||
{
|
||||
// private:
|
||||
CompoundPrunerExt();
|
||||
~CompoundPrunerExt();
|
||||
|
||||
void flushMemory();
|
||||
void preallocate(PxU32 nbShapes);
|
||||
void flushShapes(const Adapter& adapter, float inflation);
|
||||
void addToDirtyList(PrunerCompoundId compoundId, Gu::PrunerHandle handle, const PxTransform& transform);
|
||||
void removeFromDirtyList(PrunerCompoundId compoundId, Gu::PrunerHandle handle);
|
||||
|
||||
PX_FORCE_INLINE const CompoundPruner* pruner() const { return mPruner; }
|
||||
PX_FORCE_INLINE CompoundPruner* pruner() { return mPruner; }
|
||||
|
||||
CompoundPruner* mPruner;
|
||||
CompoundPrunerSet mDirtyList;
|
||||
|
||||
PX_NOCOPY(CompoundPrunerExt)
|
||||
|
||||
friend class PrunerManager;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include "foundation/PxMutex.h"
|
||||
#include "SqPrunerData.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxRenderOutput;
|
||||
class PxBVH;
|
||||
class PxSceneLimits; // PT: TODO: decouple from PxSceneLimits
|
||||
|
||||
namespace Sq
|
||||
{
|
||||
class PrunerManager : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PrunerManager(PxU64 contextID, Gu::Pruner* staticPruner, Gu::Pruner* dynamicPruner,
|
||||
PxU32 dynamicTreeRebuildRateHint, float inflation,
|
||||
const PxSceneLimits& limits, const Adapter& adapter);
|
||||
~PrunerManager();
|
||||
|
||||
PrunerData addPrunerShape(const Gu::PrunerPayload& payload, bool dynamic, PrunerCompoundId compoundId, const PxBounds3& bounds, const PxTransform& transform, bool hasPruningStructure=false);
|
||||
void addCompoundShape(const PxBVH& bvh, PrunerCompoundId compoundId, const PxTransform& compoundTransform, PrunerData* prunerData, const Gu::PrunerPayload* payloads, const PxTransform* transforms, bool isDynamic);
|
||||
void markForUpdate(PrunerCompoundId compoundId, PrunerData s, const PxTransform& transform);
|
||||
void removePrunerShape(PrunerCompoundId compoundId, PrunerData shapeData, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
|
||||
PX_FORCE_INLINE const Gu::Pruner* getPruner(PruningIndex::Enum index) const { return mPrunerExt[index].mPruner; }
|
||||
PX_FORCE_INLINE Gu::Pruner* getPruner(PruningIndex::Enum index) { return mPrunerExt[index].mPruner; }
|
||||
PX_FORCE_INLINE const CompoundPruner* getCompoundPruner() const { return mCompoundPrunerExt.mPruner; }
|
||||
PX_FORCE_INLINE PxU64 getContextId() const { return mContextID; }
|
||||
|
||||
void preallocate(PxU32 prunerIndex, PxU32 nbShapes);
|
||||
|
||||
void setDynamicTreeRebuildRateHint(PxU32 dynTreeRebuildRateHint);
|
||||
PX_FORCE_INLINE PxU32 getDynamicTreeRebuildRateHint() const { return mRebuildRateHint; }
|
||||
|
||||
void flushUpdates();
|
||||
void forceRebuildDynamicTree(PxU32 prunerIndex);
|
||||
|
||||
void updateCompoundActor(PrunerCompoundId compoundId, const PxTransform& compoundTransform);
|
||||
void removeCompoundActor(PrunerCompoundId compoundId, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
|
||||
void* prepareSceneQueriesUpdate(PruningIndex::Enum index);
|
||||
void sceneQueryBuildStep(void* handle);
|
||||
|
||||
void sync(const Gu::PrunerHandle* handles, const PxU32* boundsIndices, const PxBounds3* bounds, const PxTransform32* transforms, PxU32 count, const PxBitMap& ignoredIndices);
|
||||
void afterSync(bool buildStep, bool commit);
|
||||
void shiftOrigin(const PxVec3& shift);
|
||||
void visualize(PxU32 prunerIndex, PxRenderOutput& out) const;
|
||||
|
||||
void flushMemory();
|
||||
PX_FORCE_INLINE PxU32 getStaticTimestamp() const { return mStaticTimestamp; }
|
||||
PX_FORCE_INLINE const Adapter& getAdapter() const { return mAdapter; }
|
||||
private:
|
||||
const Adapter& mAdapter;
|
||||
PrunerExt mPrunerExt[PruningIndex::eCOUNT];
|
||||
CompoundPrunerExt mCompoundPrunerExt;
|
||||
|
||||
const PxU64 mContextID;
|
||||
PxU32 mStaticTimestamp;
|
||||
PxU32 mRebuildRateHint;
|
||||
const float mInflation; // SQ_PRUNER_EPSILON
|
||||
|
||||
PxMutex mSQLock; // to make sure only one query updates the dirty pruner structure if multiple queries run in parallel
|
||||
|
||||
volatile bool mPrunerNeedsUpdating;
|
||||
|
||||
void flushShapes();
|
||||
PX_FORCE_INLINE void invalidateStaticTimestamp() { mStaticTimestamp++; }
|
||||
|
||||
PX_NOCOPY(PrunerManager)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
188
engine/third_party/physx/source/scenequery/include/SqPruner.h
vendored
Normal file
188
engine/third_party/physx/source/scenequery/include/SqPruner.h
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_PRUNER_H
|
||||
#define SQ_PRUNER_H
|
||||
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxFlags.h"
|
||||
#include "GuPruner.h"
|
||||
#include "SqTypedef.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class BVH;
|
||||
}
|
||||
namespace Sq
|
||||
{
|
||||
|
||||
/**
|
||||
\brief Compound-pruner-specific flags for scene queries.
|
||||
*/
|
||||
struct PxCompoundPrunerQueryFlag
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
eSTATIC = (1<<0), //!< Traverse static compounds
|
||||
eDYNAMIC = (1<<1), //!< Traverse dynamic compounds
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Flags typedef for the set of bits defined in PxCompoundPrunerQueryFlag.
|
||||
*/
|
||||
typedef PxFlags<PxCompoundPrunerQueryFlag::Enum,PxU32> PxCompoundPrunerQueryFlags;
|
||||
PX_FLAGS_OPERATORS(PxCompoundPrunerQueryFlag::Enum,PxU32)
|
||||
|
||||
struct CompoundPrunerRaycastCallback
|
||||
{
|
||||
CompoundPrunerRaycastCallback() {}
|
||||
virtual ~CompoundPrunerRaycastCallback() {}
|
||||
|
||||
virtual bool invoke(PxReal& distance, PxU32 primIndex, const Gu::PrunerPayload* payloads, const PxTransform* transforms, const PxTransform* compoundPose) = 0;
|
||||
};
|
||||
|
||||
struct CompoundPrunerOverlapCallback
|
||||
{
|
||||
CompoundPrunerOverlapCallback() {}
|
||||
virtual ~CompoundPrunerOverlapCallback() {}
|
||||
|
||||
virtual bool invoke(PxU32 primIndex, const Gu::PrunerPayload* payloads, const PxTransform* transforms, const PxTransform* compoundPose) = 0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Pruner holding compound objects
|
||||
*/
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CompoundPruner : public Gu::BasePruner
|
||||
{
|
||||
public:
|
||||
virtual ~CompoundPruner() {}
|
||||
|
||||
/**
|
||||
\brief Adds compound to the pruner.
|
||||
\param results [out] an array for resulting handles
|
||||
\param bvh [in] BVH
|
||||
\param compoundId [in] compound id
|
||||
\param transform [in] compound transform
|
||||
\param data [in] an array of object data
|
||||
|
||||
\return true if success, false if internal allocation failed. The first failing add results in a INVALID_PRUNERHANDLE.
|
||||
|
||||
Handles are usable as indices. Each handle is either be a recycled handle returned by the client via removeObjects(),
|
||||
or a fresh handle that is either zero, or one greater than the last fresh handle returned.
|
||||
*/
|
||||
virtual bool addCompound(Gu::PrunerHandle* results, const Gu::BVH& bvh, PrunerCompoundId compoundId, const PxTransform& transform, bool isDynamic, const Gu::PrunerPayload* data, const PxTransform* transforms) = 0;
|
||||
|
||||
/**
|
||||
Removes compound from the pruner.
|
||||
\param compoundId [in] compound to remove
|
||||
*/
|
||||
virtual bool removeCompound(PrunerCompoundId compoundId, Gu::PrunerPayloadRemovalCallback* removalCallback) = 0;
|
||||
|
||||
/**
|
||||
Updates compound object
|
||||
\param compoundId [in] compound to update
|
||||
\param transform [in] compound transformation
|
||||
*/
|
||||
virtual bool updateCompound(PrunerCompoundId compoundId, const PxTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
Updates object after manually updating their bounds via "getPayload" calls.
|
||||
\param compoundId [in] compound that the object belongs to
|
||||
\param handle [in] the object to update
|
||||
*/
|
||||
virtual void updateObjectAfterManualBoundsUpdates(PrunerCompoundId compoundId, const Gu::PrunerHandle handle) = 0;
|
||||
|
||||
/**
|
||||
Removes object from compound pruner.
|
||||
\param compoundId [in] compound that the object belongs to
|
||||
\param handle [in] the object to remove
|
||||
*/
|
||||
virtual void removeObject(PrunerCompoundId compoundId, const Gu::PrunerHandle handle, Gu::PrunerPayloadRemovalCallback* removalCallback) = 0;
|
||||
|
||||
/**
|
||||
\brief Adds object to the pruner.
|
||||
\param compoundId [in] compound that the object belongs to
|
||||
\param result [out] an array for resulting handles
|
||||
\param bounds [in] an array of bounds. These bounds are used as-is so they should be pre-inflated if inflation is needed.
|
||||
\param userData [in] an array of object data
|
||||
|
||||
\return true if success, false if internal allocation failed. The first failing add results in a INVALID_PRUNERHANDLE.
|
||||
*/
|
||||
virtual bool addObject(PrunerCompoundId compoundId, Gu::PrunerHandle& result, const PxBounds3& bounds, const Gu::PrunerPayload userData, const PxTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
* Query functions
|
||||
*
|
||||
* Note: return value may disappear if PrunerCallback contains the necessary information
|
||||
* currently it is still used for the dynamic pruner internally (to decide if added objects must be queried)
|
||||
*/
|
||||
virtual bool raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback&, PxCompoundPrunerQueryFlags flags) const = 0;
|
||||
virtual bool overlap(const Gu::ShapeData& queryVolume, CompoundPrunerOverlapCallback&, PxCompoundPrunerQueryFlags flags) const = 0;
|
||||
virtual bool sweep(const Gu::ShapeData& queryVolume, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback&, PxCompoundPrunerQueryFlags flags) const = 0;
|
||||
|
||||
/**
|
||||
\brief Retrieves the object's payload and data associated with the handle.
|
||||
|
||||
This function returns the payload associated with a given handle. Additionally it can return the
|
||||
destination addresses for the object's bounds & transform. The user can then write the new bounds
|
||||
and transform there, before eventually calling updateObjects().
|
||||
|
||||
\param[in] handle Object handle (initially returned by addObjects())
|
||||
\param[in] compoundId The compound id
|
||||
\param[out] data Optional location where to store the internal data associated with the payload.
|
||||
|
||||
\return The payload associated with the given handle.
|
||||
*/
|
||||
virtual const Gu::PrunerPayload& getPayloadData(Gu::PrunerHandle handle, PrunerCompoundId compoundId, Gu::PrunerPayloadData* data) const = 0;
|
||||
|
||||
/**
|
||||
\brief Preallocate space
|
||||
|
||||
\param[in] nbEntries The number of entries to preallocate space for
|
||||
*/
|
||||
virtual void preallocate(PxU32 nbEntries) = 0;
|
||||
|
||||
// PT: beware, shape transform
|
||||
virtual bool setTransform(Gu::PrunerHandle handle, PrunerCompoundId compoundId, const PxTransform& transform) = 0;
|
||||
|
||||
// PT: beware, actor transform
|
||||
virtual const PxTransform& getTransform(PrunerCompoundId compoundId) const = 0;
|
||||
|
||||
virtual void visualizeEx(PxRenderOutput& out, PxU32 color, bool drawStatic, bool drawDynamic) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
60
engine/third_party/physx/source/scenequery/include/SqPrunerData.h
vendored
Normal file
60
engine/third_party/physx/source/scenequery/include/SqPrunerData.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_PRUNER_DATA_H
|
||||
#define SQ_PRUNER_DATA_H
|
||||
|
||||
|
||||
#include "SqTypedef.h"
|
||||
|
||||
// PT: SQ-API LEVEL 2 (Level 1 = SqPruner.h)
|
||||
// PT: this file is part of a "high-level" set of files within Sq. The SqPruner API doesn't rely on them.
|
||||
// PT: this should really be at Np level but moving it to Sq allows us to share it.
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
struct PruningIndex
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
eSTATIC = 0, // PT: must match PX_SCENE_PRUNER_STATIC
|
||||
eDYNAMIC = 1, // PT: must match PX_SCENE_PRUNER_DYNAMIC
|
||||
|
||||
eCOUNT = 2
|
||||
};
|
||||
};
|
||||
|
||||
PX_FORCE_INLINE PrunerData createPrunerData(PxU32 index, Gu::PrunerHandle h) { return PrunerData((h << 1) | index); }
|
||||
PX_FORCE_INLINE PxU32 getPrunerIndex(PrunerData data) { return PxU32(data & 1); }
|
||||
PX_FORCE_INLINE Gu::PrunerHandle getPrunerHandle(PrunerData data) { return Gu::PrunerHandle(data >> 1); }
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
143
engine/third_party/physx/source/scenequery/include/SqQuery.h
vendored
Normal file
143
engine/third_party/physx/source/scenequery/include/SqQuery.h
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_QUERY_H
|
||||
#define SQ_QUERY_H
|
||||
|
||||
// PT: SQ-API LEVEL 3 (Level 1 = SqPruner.h, Level 2 = SqManager/SqPrunerData)
|
||||
// PT: this file is part of a "high-level" set of files within Sq. The SqPruner API doesn't rely on them.
|
||||
// PT: this should really be at Np level but moving it to Sq allows us to share it.
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "geometry/PxGeometryQueryFlags.h"
|
||||
|
||||
#include "SqManager.h"
|
||||
#include "PxQueryReport.h"
|
||||
#include "GuCachedFuncs.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxGeometry;
|
||||
struct PxQueryFilterData;
|
||||
struct PxFilterData;
|
||||
class PxQueryFilterCallback;
|
||||
|
||||
namespace Sq
|
||||
{
|
||||
struct MultiQueryInput;
|
||||
|
||||
class PVDCapture
|
||||
{
|
||||
public:
|
||||
PVDCapture() {}
|
||||
virtual ~PVDCapture() {}
|
||||
|
||||
virtual bool transmitSceneQueries() = 0;
|
||||
|
||||
virtual void raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal distance, const PxRaycastHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData, bool multipleHits) = 0;
|
||||
virtual void sweep(const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, PxReal distance, const PxSweepHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData, bool multipleHits) = 0;
|
||||
virtual void overlap(const PxGeometry& geometry, const PxTransform& pose, const PxOverlapHit* hit, PxU32 hitsNum, const PxQueryFilterData& filterData) = 0;
|
||||
};
|
||||
|
||||
// SceneQueries-level adapter. Augments the PrunerManager-level adapter with functions needed to perform queries.
|
||||
class QueryAdapter : public Adapter
|
||||
{
|
||||
public:
|
||||
QueryAdapter() {}
|
||||
virtual ~QueryAdapter() {}
|
||||
|
||||
// PT: TODO: decouple from PxQueryCache?
|
||||
virtual Gu::PrunerHandle findPrunerHandle(const PxQueryCache& cache, PrunerCompoundId& compoundId, PxU32& prunerIndex) const = 0;
|
||||
|
||||
// PT: TODO: return reference? but this version is at least consistent with getActorShape
|
||||
virtual void getFilterData(const Gu::PrunerPayload& payload, PxFilterData& filterData) const = 0;
|
||||
virtual void getActorShape(const Gu::PrunerPayload& payload, PxActorShape& actorShape) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class SceneQueries
|
||||
{
|
||||
PX_NOCOPY(SceneQueries)
|
||||
public:
|
||||
SceneQueries(Sq::PVDCapture* pvd, PxU64 contextID, Gu::Pruner* staticPruner, Gu::Pruner* dynamicPruner,
|
||||
PxU32 dynamicTreeRebuildRateHint, float inflation,
|
||||
const PxSceneLimits& limits, const Sq::QueryAdapter& adapter);
|
||||
~SceneQueries();
|
||||
|
||||
PX_FORCE_INLINE Sq::PrunerManager& getPrunerManagerFast() { return mSQManager; }
|
||||
PX_FORCE_INLINE const Sq::PrunerManager& getPrunerManagerFast() const { return mSQManager; }
|
||||
|
||||
template<typename QueryHit>
|
||||
bool multiQuery(
|
||||
const Sq::MultiQueryInput& in,
|
||||
PxHitCallback<QueryHit>& hits, PxHitFlags hitFlags, const PxQueryCache* cache,
|
||||
const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall) const;
|
||||
|
||||
bool _raycast(
|
||||
const PxVec3& origin, const PxVec3& unitDir, const PxReal distance, // Ray data
|
||||
PxRaycastCallback& hitCall, PxHitFlags hitFlags,
|
||||
const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall,
|
||||
const PxQueryCache* cache, PxGeometryQueryFlags flags) const;
|
||||
|
||||
bool _sweep(
|
||||
const PxGeometry& geometry, const PxTransform& pose, // GeomObject data
|
||||
const PxVec3& unitDir, const PxReal distance, // Ray data
|
||||
PxSweepCallback& hitCall, PxHitFlags hitFlags,
|
||||
const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall,
|
||||
const PxQueryCache* cache, const PxReal inflation, PxGeometryQueryFlags flags) const;
|
||||
|
||||
bool _overlap(
|
||||
const PxGeometry& geometry, const PxTransform& transform, // GeomObject data
|
||||
PxOverlapCallback& hitCall,
|
||||
const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall,
|
||||
const PxQueryCache* cache, PxGeometryQueryFlags flags) const;
|
||||
|
||||
PX_FORCE_INLINE PxU64 getContextId() const { return mSQManager.getContextId(); }
|
||||
Sq::PrunerManager mSQManager;
|
||||
public:
|
||||
Gu::CachedFuncs mCachedFuncs;
|
||||
|
||||
Sq::PVDCapture* mPVD;
|
||||
};
|
||||
|
||||
#if PX_SUPPORT_EXTERN_TEMPLATE
|
||||
//explicit template instantiation declaration
|
||||
extern template
|
||||
bool SceneQueries::multiQuery<PxRaycastHit>(const Sq::MultiQueryInput&, PxHitCallback<PxRaycastHit>&, PxHitFlags, const PxQueryCache*, const PxQueryFilterData&, PxQueryFilterCallback*) const;
|
||||
|
||||
extern template
|
||||
bool SceneQueries::multiQuery<PxOverlapHit>(const Sq::MultiQueryInput&, PxHitCallback<PxOverlapHit>&, PxHitFlags, const PxQueryCache*, const PxQueryFilterData&, PxQueryFilterCallback*) const;
|
||||
|
||||
extern template
|
||||
bool SceneQueries::multiQuery<PxSweepHit>(const Sq::MultiQueryInput&, PxHitCallback<PxSweepHit>&, PxHitFlags, const PxQueryCache*, const PxQueryFilterData&, PxQueryFilterCallback*) const;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
47
engine/third_party/physx/source/scenequery/include/SqTypedef.h
vendored
Normal file
47
engine/third_party/physx/source/scenequery/include/SqTypedef.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_TYPEDEF_H
|
||||
#define SQ_TYPEDEF_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "GuPrunerTypedef.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
typedef PxU32 PrunerCompoundId;
|
||||
static const PrunerCompoundId INVALID_COMPOUND_ID = 0xffffffff;
|
||||
|
||||
typedef PxU32 PrunerData;
|
||||
#define SQ_INVALID_PRUNER_DATA 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
786
engine/third_party/physx/source/scenequery/src/SqCompoundPruner.cpp
vendored
Normal file
786
engine/third_party/physx/source/scenequery/src/SqCompoundPruner.cpp
vendored
Normal file
@@ -0,0 +1,786 @@
|
||||
// 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 "SqCompoundPruner.h"
|
||||
#include "GuSqInternal.h"
|
||||
#include "GuIncrementalAABBTree.h"
|
||||
#include "GuPruningPool.h"
|
||||
#include "GuAABBTreeQuery.h"
|
||||
#include "GuAABBTreeNode.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuBox.h"
|
||||
#include "GuCapsule.h"
|
||||
#include "GuBVH.h"
|
||||
#include "GuQuery.h"
|
||||
#include "GuInternal.h"
|
||||
#include "common/PxRenderBuffer.h"
|
||||
#include "common/PxRenderOutput.h"
|
||||
#include "CmVisualization.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
using namespace Sq;
|
||||
|
||||
// PT: TODO: this is copied from SqBounds.h, should be either moved to Gu and shared or passed as a user parameter
|
||||
#define SQ_PRUNER_EPSILON 0.005f
|
||||
#define SQ_PRUNER_INFLATION (1.0f + SQ_PRUNER_EPSILON) // pruner test shape inflation (not narrow phase shape)
|
||||
|
||||
#define PARANOIA_CHECKS 0
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BVHCompoundPruner::BVHCompoundPruner(PxU64 contextID) : mCompoundTreePool(contextID), mDrawStatic(false), mDrawDynamic(false)
|
||||
{
|
||||
preallocate(32);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BVHCompoundPruner::~BVHCompoundPruner()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::addCompound(PrunerHandle* results, const BVH& bvh, PrunerCompoundId compoundId, const PxTransform& transform, bool isDynamic, const PrunerPayload* data, const PxTransform* transforms)
|
||||
{
|
||||
PX_ASSERT(bvh.getNbBounds());
|
||||
|
||||
const PxBounds3 compoundBounds = PxBounds3::transformFast(transform, bvh.getNodes()->mBV);
|
||||
const PoolIndex poolIndex = mCompoundTreePool.addCompound(results, bvh, compoundBounds, transform, isDynamic, data, transforms);
|
||||
|
||||
mChangedLeaves.clear();
|
||||
IncrementalAABBTreeNode* node = mMainTree.insert(poolIndex, mCompoundTreePool.getCurrentCompoundBounds(), mChangedLeaves);
|
||||
updateMapping(poolIndex, node);
|
||||
|
||||
mActorPoolMap[compoundId] = poolIndex;
|
||||
mPoolActorMap[poolIndex] = compoundId;
|
||||
|
||||
#if PARANOIA_CHECKS
|
||||
test();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::updateMapping(const PoolIndex poolIndex, IncrementalAABBTreeNode* node)
|
||||
{
|
||||
// resize mapping if needed
|
||||
if(mMainTreeUpdateMap.size() <= poolIndex)
|
||||
{
|
||||
const PxU32 resizeSize = mMainTreeUpdateMap.size() * 2;
|
||||
mMainTreeUpdateMap.resize(resizeSize);
|
||||
mPoolActorMap.resize(resizeSize);
|
||||
}
|
||||
|
||||
// if a node was split we need to update the node indices and also the sibling indices
|
||||
if(!mChangedLeaves.empty())
|
||||
{
|
||||
if(node && node->isLeaf())
|
||||
{
|
||||
for(PxU32 j = 0; j < node->getNbPrimitives(); j++)
|
||||
{
|
||||
mMainTreeUpdateMap[node->getPrimitives(NULL)[j]] = node;
|
||||
}
|
||||
}
|
||||
|
||||
for(PxU32 i = 0; i < mChangedLeaves.size(); i++)
|
||||
{
|
||||
IncrementalAABBTreeNode* changedNode = mChangedLeaves[i];
|
||||
PX_ASSERT(changedNode->isLeaf());
|
||||
|
||||
for(PxU32 j = 0; j < changedNode->getNbPrimitives(); j++)
|
||||
{
|
||||
mMainTreeUpdateMap[changedNode->getPrimitives(NULL)[j]] = changedNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mMainTreeUpdateMap[poolIndex] = node;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::removeCompound(PrunerCompoundId compoundId, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
|
||||
bool isDynamic = false;
|
||||
|
||||
if(poolIndexEntry)
|
||||
{
|
||||
const PoolIndex poolIndex = poolIndexEntry->second;
|
||||
|
||||
CompoundTree& compoundTree = mCompoundTreePool.getCompoundTrees()[poolIndex];
|
||||
isDynamic = compoundTree.mFlags & PxCompoundPrunerQueryFlag::eDYNAMIC;
|
||||
|
||||
const PoolIndex poolRelocatedLastIndex = mCompoundTreePool.removeCompound(poolIndex, removalCallback);
|
||||
|
||||
IncrementalAABBTreeNode* node = mMainTree.remove(mMainTreeUpdateMap[poolIndex], poolIndex, mCompoundTreePool.getCurrentCompoundBounds());
|
||||
// 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];
|
||||
mMainTreeUpdateMap[index] = node;
|
||||
}
|
||||
}
|
||||
|
||||
// fix indices if we made a swap
|
||||
if(poolRelocatedLastIndex != poolIndex)
|
||||
{
|
||||
mMainTreeUpdateMap[poolIndex] = mMainTreeUpdateMap[poolRelocatedLastIndex];
|
||||
mMainTree.fixupTreeIndices(mMainTreeUpdateMap[poolIndex], poolRelocatedLastIndex, poolIndex);
|
||||
|
||||
mActorPoolMap[mPoolActorMap[poolRelocatedLastIndex]] = poolIndex;
|
||||
mPoolActorMap[poolIndex] = mPoolActorMap[poolRelocatedLastIndex];
|
||||
}
|
||||
|
||||
mActorPoolMap.erase(compoundId);
|
||||
}
|
||||
|
||||
#if PARANOIA_CHECKS
|
||||
test();
|
||||
#endif
|
||||
|
||||
return isDynamic;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::updateCompound(PrunerCompoundId compoundId, const PxTransform& transform)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
|
||||
bool isDynamic = false;
|
||||
|
||||
if(poolIndexEntry)
|
||||
{
|
||||
const PxU32 poolIndex = poolIndexEntry->second;
|
||||
|
||||
CompoundTree& compoundTree = mCompoundTreePool.getCompoundTrees()[poolIndex];
|
||||
isDynamic = compoundTree.mFlags & PxCompoundPrunerQueryFlag::eDYNAMIC;
|
||||
|
||||
compoundTree.mGlobalPose = transform;
|
||||
|
||||
PxBounds3 localBounds;
|
||||
const IncrementalAABBTreeNode* node = compoundTree.mTree->getNodes();
|
||||
V4StoreU(node->mBVMin, &localBounds.minimum.x);
|
||||
PX_ALIGN(16, PxVec4) max4;
|
||||
V4StoreA(node->mBVMax, &max4.x);
|
||||
localBounds.maximum = PxVec3(max4.x, max4.y, max4.z);
|
||||
|
||||
const PxBounds3 compoundBounds = PxBounds3::transformFast(transform, localBounds);
|
||||
mCompoundTreePool.getCurrentCompoundBounds()[poolIndex] = compoundBounds;
|
||||
mChangedLeaves.clear();
|
||||
IncrementalAABBTreeNode* mainTreeNode = mMainTree.update(mMainTreeUpdateMap[poolIndex], poolIndex, mCompoundTreePool.getCurrentCompoundBounds(), mChangedLeaves);
|
||||
// we removed node during update, need to update the mapping
|
||||
updateMapping(poolIndex, mainTreeNode);
|
||||
}
|
||||
|
||||
#if PARANOIA_CHECKS
|
||||
test();
|
||||
#endif
|
||||
|
||||
return isDynamic;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::test()
|
||||
{
|
||||
if(mMainTree.getNodes())
|
||||
{
|
||||
for(PxU32 i = 0; i < mCompoundTreePool.getNbObjects(); i++)
|
||||
{
|
||||
mMainTree.checkTreeLeaf(mMainTreeUpdateMap[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::release()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Queries implementation
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CompoundCallbackRaycastAdapter
|
||||
{
|
||||
PX_FORCE_INLINE CompoundCallbackRaycastAdapter(CompoundPrunerRaycastCallback& pcb, const CompoundTree& tree) : mCallback(pcb), mTree(tree) {}
|
||||
|
||||
PX_FORCE_INLINE bool invoke(PxReal& distance, PxU32 primIndex)
|
||||
{
|
||||
return mCallback.invoke(distance, primIndex, mTree.mPruningPool->getObjects(), mTree.mPruningPool->getTransforms(), &mTree.mGlobalPose);
|
||||
}
|
||||
|
||||
CompoundPrunerRaycastCallback& mCallback;
|
||||
const CompoundTree& mTree;
|
||||
PX_NOCOPY(CompoundCallbackRaycastAdapter)
|
||||
};
|
||||
|
||||
struct CompoundCallbackOverlapAdapter
|
||||
{
|
||||
PX_FORCE_INLINE CompoundCallbackOverlapAdapter(CompoundPrunerOverlapCallback& pcb, const CompoundTree& tree) : mCallback(pcb), mTree(tree) {}
|
||||
|
||||
PX_FORCE_INLINE bool invoke(PxU32 primIndex)
|
||||
{
|
||||
return mCallback.invoke(primIndex, mTree.mPruningPool->getObjects(), mTree.mPruningPool->getTransforms(), &mTree.mGlobalPose);
|
||||
}
|
||||
|
||||
CompoundPrunerOverlapCallback& mCallback;
|
||||
const CompoundTree& mTree;
|
||||
PX_NOCOPY(CompoundCallbackOverlapAdapter)
|
||||
};
|
||||
}
|
||||
|
||||
template<class PrunerCallback>
|
||||
struct MainTreeCompoundPrunerCallback
|
||||
{
|
||||
MainTreeCompoundPrunerCallback(PrunerCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: mPrunerCallback(prunerCallback), mQueryFlags(flags), mCompoundTrees(compoundTrees)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MainTreeCompoundPrunerCallback() {}
|
||||
|
||||
PX_FORCE_INLINE bool filtering(const CompoundTree& compoundTree) const
|
||||
{
|
||||
if(!(compoundTree.mFlags & mQueryFlags) || !compoundTree.mTree->getNodes())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
PrunerCallback& mPrunerCallback;
|
||||
const PxCompoundPrunerQueryFlags mQueryFlags;
|
||||
const CompoundTree* mCompoundTrees;
|
||||
|
||||
PX_NOCOPY(MainTreeCompoundPrunerCallback)
|
||||
};
|
||||
|
||||
// Raycast/sweeps callback for main AABB tree
|
||||
template<bool tInflate>
|
||||
struct MainTreeRaycastCompoundPrunerCallback : MainTreeCompoundPrunerCallback<CompoundPrunerRaycastCallback>
|
||||
{
|
||||
MainTreeRaycastCompoundPrunerCallback(const PxVec3& origin, const PxVec3& unitDir, const PxVec3& extent, CompoundPrunerRaycastCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeCompoundPrunerCallback(prunerCallback, flags, compoundTrees), mOrigin(origin), mUnitDir(unitDir), mExtent(extent)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MainTreeRaycastCompoundPrunerCallback() {}
|
||||
|
||||
bool invoke(PxReal& distance, PxU32 primIndex)
|
||||
{
|
||||
const CompoundTree& compoundTree = mCompoundTrees[primIndex];
|
||||
|
||||
if(filtering(compoundTree))
|
||||
return true;
|
||||
|
||||
// transfer to actor local space
|
||||
const PxVec3 localOrigin = compoundTree.mGlobalPose.transformInv(mOrigin);
|
||||
const PxVec3 localDir = compoundTree.mGlobalPose.q.rotateInv(mUnitDir);
|
||||
PxVec3 localExtent = mExtent;
|
||||
|
||||
if(tInflate)
|
||||
{
|
||||
const PxBounds3 wBounds = PxBounds3::centerExtents(mOrigin, mExtent);
|
||||
const PxBounds3 localBounds = PxBounds3::transformSafe(compoundTree.mGlobalPose.getInverse(), wBounds);
|
||||
localExtent = localBounds.getExtents();
|
||||
}
|
||||
|
||||
// raycast the merged tree
|
||||
CompoundCallbackRaycastAdapter pcb(mPrunerCallback, compoundTree);
|
||||
return AABBTreeRaycast<tInflate, true, IncrementalAABBTree, IncrementalAABBTreeNode, CompoundCallbackRaycastAdapter>()
|
||||
(compoundTree.mPruningPool->getCurrentAABBTreeBounds(), *compoundTree.mTree, localOrigin, localDir, distance, localExtent, pcb);
|
||||
}
|
||||
|
||||
PX_NOCOPY(MainTreeRaycastCompoundPrunerCallback)
|
||||
|
||||
private:
|
||||
const PxVec3& mOrigin;
|
||||
const PxVec3& mUnitDir;
|
||||
const PxVec3& mExtent;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// raycast against the compound pruner
|
||||
bool BVHCompoundPruner::raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback& prunerCallback, PxCompoundPrunerQueryFlags flags) const
|
||||
{
|
||||
bool again = true;
|
||||
|
||||
// search the main tree if there are nodes
|
||||
if(mMainTree.getNodes())
|
||||
{
|
||||
const PxVec3 extent(0.0f);
|
||||
// main tree callback
|
||||
MainTreeRaycastCompoundPrunerCallback<false> pcb(origin, unitDir, extent, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
// traverse the main tree
|
||||
again = AABBTreeRaycast<false, true, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeRaycastCompoundPrunerCallback<false> >()
|
||||
(mCompoundTreePool.getCurrentAABBTreeBounds(), mMainTree, origin, unitDir, inOutDistance, extent, pcb);
|
||||
}
|
||||
|
||||
return again;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// overlap main tree callback
|
||||
// A.B. templated version is complicated due to test transformations, will do a callback per primitive
|
||||
struct MainTreeOverlapCompoundPrunerCallback : MainTreeCompoundPrunerCallback<CompoundPrunerOverlapCallback>
|
||||
{
|
||||
MainTreeOverlapCompoundPrunerCallback(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeCompoundPrunerCallback(prunerCallback, flags, compoundTrees), mQueryVolume(queryVolume)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MainTreeOverlapCompoundPrunerCallback() {}
|
||||
|
||||
PX_NOCOPY(MainTreeOverlapCompoundPrunerCallback)
|
||||
|
||||
protected:
|
||||
const ShapeData& mQueryVolume;
|
||||
};
|
||||
|
||||
// OBB
|
||||
struct MainTreeOBBOverlapCompoundPrunerCallback : public MainTreeOverlapCompoundPrunerCallback
|
||||
{
|
||||
MainTreeOBBOverlapCompoundPrunerCallback(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeOverlapCompoundPrunerCallback(queryVolume, prunerCallback, flags, compoundTrees) {}
|
||||
|
||||
bool invoke(PxU32 primIndex)
|
||||
{
|
||||
const CompoundTree& compoundTree = mCompoundTrees[primIndex];
|
||||
|
||||
if(filtering(compoundTree))
|
||||
return true;
|
||||
|
||||
const PxVec3 localPos = compoundTree.mGlobalPose.transformInv(mQueryVolume.getPrunerWorldPos());
|
||||
const PxMat33 transfMat(compoundTree.mGlobalPose.q);
|
||||
const PxMat33 localRot = transfMat.getTranspose()*mQueryVolume.getPrunerWorldRot33();
|
||||
|
||||
const OBBAABBTest localTest(localPos, localRot, mQueryVolume.getPrunerBoxGeomExtentsInflated());
|
||||
// overlap the compound local tree
|
||||
CompoundCallbackOverlapAdapter pcb(mPrunerCallback, compoundTree);
|
||||
return AABBTreeOverlap<true, OBBAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, CompoundCallbackOverlapAdapter>()
|
||||
(compoundTree.mPruningPool->getCurrentAABBTreeBounds(), *compoundTree.mTree, localTest, pcb);
|
||||
}
|
||||
|
||||
PX_NOCOPY(MainTreeOBBOverlapCompoundPrunerCallback)
|
||||
};
|
||||
|
||||
// AABB
|
||||
struct MainTreeAABBOverlapCompoundPrunerCallback : public MainTreeOverlapCompoundPrunerCallback
|
||||
{
|
||||
MainTreeAABBOverlapCompoundPrunerCallback(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeOverlapCompoundPrunerCallback(queryVolume, prunerCallback, flags, compoundTrees) {}
|
||||
|
||||
bool invoke(PxU32 primIndex)
|
||||
{
|
||||
const CompoundTree& compoundTree = mCompoundTrees[primIndex];
|
||||
|
||||
if(filtering(compoundTree))
|
||||
return true;
|
||||
|
||||
const PxVec3 localPos = compoundTree.mGlobalPose.transformInv(mQueryVolume.getPrunerWorldPos());
|
||||
const PxMat33 transfMat(compoundTree.mGlobalPose.q);
|
||||
const PxMat33 localRot = transfMat.getTranspose()*mQueryVolume.getPrunerWorldRot33();
|
||||
|
||||
// A.B. we dont have the AABB in local space, either we test OBB local space or
|
||||
// we retest the AABB with the worldSpace AABB of the local tree???
|
||||
const OBBAABBTest localTest(localPos, localRot, mQueryVolume.getPrunerBoxGeomExtentsInflated());
|
||||
// overlap the compound local tree
|
||||
CompoundCallbackOverlapAdapter pcb(mPrunerCallback, compoundTree);
|
||||
return AABBTreeOverlap<true, OBBAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, CompoundCallbackOverlapAdapter>()
|
||||
(compoundTree.mPruningPool->getCurrentAABBTreeBounds(), *compoundTree.mTree, localTest, pcb);
|
||||
}
|
||||
|
||||
PX_NOCOPY(MainTreeAABBOverlapCompoundPrunerCallback)
|
||||
};
|
||||
|
||||
// Capsule
|
||||
struct MainTreeCapsuleOverlapCompoundPrunerCallback : public MainTreeOverlapCompoundPrunerCallback
|
||||
{
|
||||
MainTreeCapsuleOverlapCompoundPrunerCallback(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeOverlapCompoundPrunerCallback(queryVolume, prunerCallback, flags, compoundTrees) {}
|
||||
|
||||
bool invoke(PxU32 primIndex)
|
||||
{
|
||||
const CompoundTree& compoundTree = mCompoundTrees[primIndex];
|
||||
|
||||
if(filtering(compoundTree))
|
||||
return true;
|
||||
|
||||
const PxMat33 transfMat(compoundTree.mGlobalPose.q);
|
||||
const Capsule& capsule = mQueryVolume.getGuCapsule();
|
||||
const CapsuleAABBTest localTest(
|
||||
compoundTree.mGlobalPose.transformInv(capsule.p1),
|
||||
transfMat.getTranspose()*mQueryVolume.getPrunerWorldRot33().column0,
|
||||
mQueryVolume.getCapsuleHalfHeight()*2.0f, PxVec3(capsule.radius*SQ_PRUNER_INFLATION));
|
||||
|
||||
// overlap the compound local tree
|
||||
CompoundCallbackOverlapAdapter pcb(mPrunerCallback, compoundTree);
|
||||
return AABBTreeOverlap<true, CapsuleAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, CompoundCallbackOverlapAdapter>()
|
||||
(compoundTree.mPruningPool->getCurrentAABBTreeBounds(), *compoundTree.mTree, localTest, pcb);
|
||||
}
|
||||
|
||||
PX_NOCOPY(MainTreeCapsuleOverlapCompoundPrunerCallback)
|
||||
};
|
||||
|
||||
// Sphere
|
||||
struct MainTreeSphereOverlapCompoundPrunerCallback : public MainTreeOverlapCompoundPrunerCallback
|
||||
{
|
||||
MainTreeSphereOverlapCompoundPrunerCallback(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags, const CompoundTree* compoundTrees)
|
||||
: MainTreeOverlapCompoundPrunerCallback(queryVolume, prunerCallback, flags, compoundTrees) {}
|
||||
|
||||
bool invoke(PxU32 primIndex)
|
||||
{
|
||||
const CompoundTree& compoundTree = mCompoundTrees[primIndex];
|
||||
|
||||
if(filtering(compoundTree))
|
||||
return true;
|
||||
|
||||
const Sphere& sphere = mQueryVolume.getGuSphere();
|
||||
const SphereAABBTest localTest(compoundTree.mGlobalPose.transformInv(sphere.center), sphere.radius);
|
||||
|
||||
// overlap the compound local tree
|
||||
CompoundCallbackOverlapAdapter pcb(mPrunerCallback, compoundTree);
|
||||
return AABBTreeOverlap<true, SphereAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, CompoundCallbackOverlapAdapter>()
|
||||
(compoundTree.mPruningPool->getCurrentAABBTreeBounds(), *compoundTree.mTree, localTest, pcb);
|
||||
}
|
||||
|
||||
PX_NOCOPY(MainTreeSphereOverlapCompoundPrunerCallback)
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// overlap implementation
|
||||
bool BVHCompoundPruner::overlap(const ShapeData& queryVolume, CompoundPrunerOverlapCallback& prunerCallback, PxCompoundPrunerQueryFlags flags) const
|
||||
{
|
||||
if(!mMainTree.getNodes())
|
||||
return true;
|
||||
|
||||
bool again = true;
|
||||
|
||||
const Gu::AABBTreeBounds& bounds = mCompoundTreePool.getCurrentAABBTreeBounds();
|
||||
|
||||
switch (queryVolume.getType())
|
||||
{
|
||||
case PxGeometryType::eBOX:
|
||||
{
|
||||
if(queryVolume.isOBB())
|
||||
{
|
||||
const DefaultOBBAABBTest test(queryVolume);
|
||||
MainTreeOBBOverlapCompoundPrunerCallback pcb(queryVolume, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeOverlap<true, OBBAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeOBBOverlapCompoundPrunerCallback>()(bounds, mMainTree, test, pcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
const DefaultAABBAABBTest test(queryVolume);
|
||||
MainTreeAABBOverlapCompoundPrunerCallback pcb(queryVolume, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeOverlap<true, AABBAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeAABBOverlapCompoundPrunerCallback>()(bounds, mMainTree, test, pcb);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PxGeometryType::eCAPSULE:
|
||||
{
|
||||
const DefaultCapsuleAABBTest test(queryVolume, SQ_PRUNER_INFLATION);
|
||||
MainTreeCapsuleOverlapCompoundPrunerCallback pcb(queryVolume, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeOverlap<true, CapsuleAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeCapsuleOverlapCompoundPrunerCallback >()(bounds, mMainTree, test, pcb);
|
||||
}
|
||||
break;
|
||||
case PxGeometryType::eSPHERE:
|
||||
{
|
||||
const DefaultSphereAABBTest test(queryVolume);
|
||||
MainTreeSphereOverlapCompoundPrunerCallback pcb(queryVolume, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeOverlap<true, SphereAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeSphereOverlapCompoundPrunerCallback>()(bounds, mMainTree, test, pcb);
|
||||
}
|
||||
break;
|
||||
case PxGeometryType::eCONVEXMESH:
|
||||
{
|
||||
const DefaultOBBAABBTest test(queryVolume);
|
||||
MainTreeOBBOverlapCompoundPrunerCallback pcb(queryVolume, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeOverlap<true, OBBAABBTest, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeOBBOverlapCompoundPrunerCallback>()(bounds, mMainTree, test, pcb);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PX_ALWAYS_ASSERT_MESSAGE("unsupported overlap query volume geometry type");
|
||||
}
|
||||
|
||||
return again;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::sweep(const ShapeData& queryVolume, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback& prunerCallback, PxCompoundPrunerQueryFlags flags) const
|
||||
{
|
||||
bool again = true;
|
||||
|
||||
if(mMainTree.getNodes())
|
||||
{
|
||||
const PxBounds3& aabb = queryVolume.getPrunerInflatedWorldAABB();
|
||||
const PxVec3 extents = aabb.getExtents();
|
||||
const PxVec3 center = aabb.getCenter();
|
||||
MainTreeRaycastCompoundPrunerCallback<true> pcb(center, unitDir, extents, prunerCallback, flags, mCompoundTreePool.getCompoundTrees());
|
||||
again = AABBTreeRaycast<true, true, IncrementalAABBTree, IncrementalAABBTreeNode, MainTreeRaycastCompoundPrunerCallback<true> >()
|
||||
(mCompoundTreePool.getCurrentAABBTreeBounds(), mMainTree, center, unitDir, inOutDistance, extents, pcb);
|
||||
}
|
||||
return again;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const PrunerPayload& BVHCompoundPruner::getPayloadData(PrunerHandle handle, PrunerCompoundId compoundId, PrunerPayloadData* data) const
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
|
||||
return mCompoundTreePool.getCompoundTrees()[poolIndexEntry->second].mPruningPool->getPayloadData(handle, data);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::preallocate(PxU32 nbEntries)
|
||||
{
|
||||
mCompoundTreePool.preallocate(nbEntries);
|
||||
mMainTreeUpdateMap.resizeUninitialized(nbEntries);
|
||||
mPoolActorMap.resizeUninitialized(nbEntries);
|
||||
mChangedLeaves.reserve(nbEntries);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::setTransform(PrunerHandle handle, PrunerCompoundId compoundId, const PxTransform& transform)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
|
||||
return mCompoundTreePool.getCompoundTrees()[poolIndexEntry->second].mPruningPool->setTransform(handle, transform);
|
||||
}
|
||||
|
||||
const PxTransform& BVHCompoundPruner::getTransform(PrunerCompoundId compoundId) const
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
|
||||
return mCompoundTreePool.getCompoundTrees()[poolIndexEntry->second].mGlobalPose;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::updateObjectAfterManualBoundsUpdates(PrunerCompoundId compoundId, const PrunerHandle handle)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
if(!poolIndexEntry)
|
||||
return;
|
||||
|
||||
mCompoundTreePool.getCompoundTrees()[poolIndexEntry->second].updateObjectAfterManualBoundsUpdates(handle);
|
||||
|
||||
const PxU32 poolIndex = poolIndexEntry->second;
|
||||
updateMainTreeNode(poolIndex);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::removeObject(PrunerCompoundId compoundId, const PrunerHandle handle, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
if(!poolIndexEntry)
|
||||
return;
|
||||
|
||||
const PxU32 poolIndex = poolIndexEntry->second;
|
||||
|
||||
mCompoundTreePool.getCompoundTrees()[poolIndex].removeObject(handle, removalCallback);
|
||||
|
||||
// edge case, we removed all objects for the compound tree, we need to remove it now completely
|
||||
if(!mCompoundTreePool.getCompoundTrees()[poolIndex].mTree->getNodes())
|
||||
removeCompound(compoundId, removalCallback);
|
||||
else
|
||||
updateMainTreeNode(poolIndex);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BVHCompoundPruner::addObject(PrunerCompoundId compoundId, PrunerHandle& result, const PxBounds3& bounds, const PrunerPayload userData, const PxTransform& transform)
|
||||
{
|
||||
const ActorIdPoolIndexMap::Entry* poolIndexEntry = mActorPoolMap.find(compoundId);
|
||||
PX_ASSERT(poolIndexEntry);
|
||||
if(!poolIndexEntry)
|
||||
return false;
|
||||
|
||||
mCompoundTreePool.getCompoundTrees()[poolIndexEntry->second].addObject(result, bounds, userData, transform);
|
||||
|
||||
const PxU32 poolIndex = poolIndexEntry->second;
|
||||
updateMainTreeNode(poolIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::updateMainTreeNode(PoolIndex poolIndex)
|
||||
{
|
||||
PxBounds3 localBounds;
|
||||
const IncrementalAABBTreeNode* node = mCompoundTreePool.getCompoundTrees()[poolIndex].mTree->getNodes();
|
||||
V4StoreU(node->mBVMin, &localBounds.minimum.x);
|
||||
PX_ALIGN(16, PxVec4) max4;
|
||||
V4StoreA(node->mBVMax, &max4.x);
|
||||
localBounds.maximum = PxVec3(max4.x, max4.y, max4.z);
|
||||
const PxBounds3 compoundBounds = PxBounds3::transformFast(mCompoundTreePool.getCompoundTrees()[poolIndex].mGlobalPose, localBounds);
|
||||
mCompoundTreePool.getCurrentCompoundBounds()[poolIndex] = compoundBounds;
|
||||
|
||||
mChangedLeaves.clear();
|
||||
IncrementalAABBTreeNode* mainTreeNode = mMainTree.update(mMainTreeUpdateMap[poolIndex], poolIndex, mCompoundTreePool.getCurrentCompoundBounds(), mChangedLeaves);
|
||||
// we removed node during update, need to update the mapping
|
||||
updateMapping(poolIndex, mainTreeNode);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BVHCompoundPruner::shiftOrigin(const PxVec3& shift)
|
||||
{
|
||||
mCompoundTreePool.shiftOrigin(shift);
|
||||
|
||||
mMainTree.shiftOrigin(shift);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
class CompoundTreeVizCb : public DebugVizCallback
|
||||
{
|
||||
PX_NOCOPY(CompoundTreeVizCb)
|
||||
public:
|
||||
|
||||
CompoundTreeVizCb(PxRenderOutput& out, const CompoundTree& tree) :
|
||||
mOut (out),
|
||||
mPose (tree.mGlobalPose)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool visualizeNode(const IncrementalAABBTreeNode& /*node*/, const PxBounds3& bounds)
|
||||
{
|
||||
if(0)
|
||||
{
|
||||
Cm::renderOutputDebugBox(mOut, PxBounds3::transformSafe(mPose, bounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
PxVec3 pts[8];
|
||||
computeBoxPoints(bounds, pts);
|
||||
for(PxU32 i=0;i<8;i++)
|
||||
pts[i] = mPose.transform(pts[i]);
|
||||
|
||||
const PxU8* edges = getBoxEdges();
|
||||
for(PxU32 i=0;i<12;i++)
|
||||
{
|
||||
const PxVec3& p0 = pts[*edges++];
|
||||
const PxVec3& p1 = pts[*edges++];
|
||||
mOut.outputSegment(p0, p1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PxRenderOutput& mOut;
|
||||
const PxTransform& mPose;
|
||||
};
|
||||
|
||||
class CompoundPrunerDebugVizCb : public DebugVizCallback
|
||||
{
|
||||
PX_NOCOPY(CompoundPrunerDebugVizCb)
|
||||
public:
|
||||
|
||||
CompoundPrunerDebugVizCb(PxRenderOutput& out, const CompoundTree* trees, bool debugStatic, bool debugDynamic) :
|
||||
mOut (out),
|
||||
mTrees (trees),
|
||||
mDebugVizStatic (debugStatic),
|
||||
mDebugVizDynamic(debugDynamic)
|
||||
{}
|
||||
|
||||
virtual bool visualizeNode(const IncrementalAABBTreeNode& node, const PxBounds3& /*bounds*/)
|
||||
{
|
||||
if(node.isLeaf())
|
||||
{
|
||||
PxU32 nbPrims = node.getNbPrimitives();
|
||||
const PxU32* prims = node.getPrimitives(NULL);
|
||||
while(nbPrims--)
|
||||
{
|
||||
const CompoundTree& compoundTree = mTrees[*prims++];
|
||||
|
||||
const bool isDynamic = compoundTree.mFlags & PxCompoundPrunerQueryFlag::eDYNAMIC;
|
||||
|
||||
if((mDebugVizDynamic && isDynamic) || (mDebugVizStatic && !isDynamic))
|
||||
{
|
||||
const PxU32 color = isDynamic ? SQ_DEBUG_VIZ_DYNAMIC_COLOR : SQ_DEBUG_VIZ_STATIC_COLOR;
|
||||
CompoundTreeVizCb leafCB(mOut, compoundTree);
|
||||
visualizeTree(mOut, color, compoundTree.mTree, &leafCB);
|
||||
mOut << SQ_DEBUG_VIZ_COMPOUND_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PxRenderOutput& mOut;
|
||||
const CompoundTree* mTrees;
|
||||
const bool mDebugVizStatic;
|
||||
const bool mDebugVizDynamic;
|
||||
};
|
||||
}
|
||||
|
||||
void BVHCompoundPruner::visualize(PxRenderOutput& out, PxU32 primaryColor, PxU32 /*secondaryColor*/) const
|
||||
{
|
||||
if(mDrawStatic || mDrawDynamic)
|
||||
{
|
||||
CompoundPrunerDebugVizCb cb(out, mCompoundTreePool.getCompoundTrees(), mDrawStatic, mDrawDynamic);
|
||||
visualizeTree(out, primaryColor, &mMainTree, &cb);
|
||||
}
|
||||
}
|
||||
|
||||
void BVHCompoundPruner::visualizeEx(PxRenderOutput& out, PxU32 color, bool drawStatic, bool drawDynamic) const
|
||||
{
|
||||
mDrawStatic = drawStatic;
|
||||
mDrawDynamic = drawDynamic;
|
||||
visualize(out, color, color);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
102
engine/third_party/physx/source/scenequery/src/SqCompoundPruner.h
vendored
Normal file
102
engine/third_party/physx/source/scenequery/src/SqCompoundPruner.h
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_COMPOUND_PRUNER_H
|
||||
#define SQ_COMPOUND_PRUNER_H
|
||||
|
||||
#include "SqCompoundPruningPool.h"
|
||||
#include "GuSqInternal.h"
|
||||
#include "GuPrunerMergeData.h"
|
||||
#include "GuIncrementalAABBTree.h"
|
||||
#include "GuPruningPool.h"
|
||||
#include "foundation/PxHashMap.h"
|
||||
#include "foundation/PxArray.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Sq
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef PxHashMap<PrunerCompoundId, Gu::PoolIndex> ActorIdPoolIndexMap;
|
||||
typedef PxArray<PrunerCompoundId> PoolIndexActorIdMap;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BVHCompoundPruner : public CompoundPruner
|
||||
{
|
||||
public:
|
||||
BVHCompoundPruner(PxU64 contextID);
|
||||
virtual ~BVHCompoundPruner();
|
||||
|
||||
void release();
|
||||
|
||||
// BasePruner
|
||||
DECLARE_BASE_PRUNER_API
|
||||
//~BasePruner
|
||||
|
||||
// CompoundPruner
|
||||
// compound level
|
||||
virtual bool addCompound(Gu::PrunerHandle* results, const Gu::BVH& bvh, PrunerCompoundId compoundId, const PxTransform& transform, bool isDynamic, const Gu::PrunerPayload* data, const PxTransform* transforms);
|
||||
virtual bool removeCompound(PrunerCompoundId compoundId, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
virtual bool updateCompound(PrunerCompoundId compoundId, const PxTransform& transform);
|
||||
// object level
|
||||
virtual void updateObjectAfterManualBoundsUpdates(PrunerCompoundId compoundId, const Gu::PrunerHandle handle);
|
||||
virtual void removeObject(PrunerCompoundId compoundId, const Gu::PrunerHandle handle, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
virtual bool addObject(PrunerCompoundId compoundId, Gu::PrunerHandle& result, const PxBounds3& bounds, const Gu::PrunerPayload userData, const PxTransform& transform);
|
||||
//queries
|
||||
virtual bool raycast(const PxVec3& origin, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback&, PxCompoundPrunerQueryFlags flags) const;
|
||||
virtual bool overlap(const Gu::ShapeData& queryVolume, CompoundPrunerOverlapCallback&, PxCompoundPrunerQueryFlags flags) const;
|
||||
virtual bool sweep(const Gu::ShapeData& queryVolume, const PxVec3& unitDir, PxReal& inOutDistance, CompoundPrunerRaycastCallback&, PxCompoundPrunerQueryFlags flags) const;
|
||||
virtual const Gu::PrunerPayload& getPayloadData(Gu::PrunerHandle handle, PrunerCompoundId compoundId, Gu::PrunerPayloadData* data) const;
|
||||
virtual void preallocate(PxU32 nbEntries);
|
||||
virtual bool setTransform(Gu::PrunerHandle handle, PrunerCompoundId compoundId, const PxTransform& transform);
|
||||
virtual const PxTransform& getTransform(PrunerCompoundId compoundId) const;
|
||||
virtual void visualizeEx(PxRenderOutput& out, PxU32 color, bool drawStatic, bool drawDynamic) const;
|
||||
// ~CompoundPruner
|
||||
|
||||
private:
|
||||
void updateMapping(const Gu::PoolIndex poolIndex, Gu::IncrementalAABBTreeNode* node);
|
||||
void updateMainTreeNode(Gu::PoolIndex index);
|
||||
|
||||
void test();
|
||||
|
||||
Gu::IncrementalAABBTree mMainTree;
|
||||
UpdateMap mMainTreeUpdateMap;
|
||||
|
||||
CompoundTreePool mCompoundTreePool;
|
||||
ActorIdPoolIndexMap mActorPoolMap;
|
||||
PoolIndexActorIdMap mPoolActorMap;
|
||||
Gu::NodeList mChangedLeaves;
|
||||
mutable bool mDrawStatic;
|
||||
mutable bool mDrawDynamic;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
271
engine/third_party/physx/source/scenequery/src/SqCompoundPruningPool.cpp
vendored
Normal file
271
engine/third_party/physx/source/scenequery/src/SqCompoundPruningPool.cpp
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
// 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 "foundation/PxAllocator.h"
|
||||
#include "SqCompoundPruningPool.h"
|
||||
#include "GuPruningPool.h"
|
||||
#include "GuAABBTree.h"
|
||||
#include "GuBVH.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cm;
|
||||
using namespace Gu;
|
||||
using namespace Sq;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
const PoolIndex poolIndex = mPruningPool->getIndex(handle); // save the pool index for removed object
|
||||
const PoolIndex poolRelocatedLastIndex = mPruningPool->removeObject(handle, removalCallback); // 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& data, const PxTransform& transform)
|
||||
{
|
||||
mPruningPool->addObjects(&result, &bounds, &data, &transform, 1);
|
||||
if (mPruningPool->mMaxNbObjects > mUpdateMap->size())
|
||||
mUpdateMap->resize(mPruningPool->mMaxNbObjects);
|
||||
|
||||
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(PxU64 contextID) :
|
||||
mNbObjects (0),
|
||||
mMaxNbObjects (0),
|
||||
mCompoundTrees (NULL),
|
||||
mContextID (contextID)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CompoundTreePool::~CompoundTreePool()
|
||||
{
|
||||
PX_FREE(mCompoundTrees);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CompoundTreePool::resize(PxU32 newCapacity)
|
||||
{
|
||||
mCompoundBounds.resize(newCapacity, mNbObjects);
|
||||
|
||||
CompoundTree* newTrees = PX_ALLOCATE(CompoundTree, newCapacity, "IncrementalTrees*");
|
||||
if(!newTrees)
|
||||
return false;
|
||||
|
||||
// memzero, we need to set the pointers in the compound tree to NULL
|
||||
PxMemZero(newTrees, sizeof(CompoundTree)*newCapacity);
|
||||
if(mCompoundTrees)
|
||||
PxMemCopy(newTrees, mCompoundTrees, mNbObjects*sizeof(CompoundTree));
|
||||
mMaxNbObjects = newCapacity;
|
||||
PX_FREE(mCompoundTrees);
|
||||
mCompoundTrees = newTrees;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CompoundTreePool::preallocate(PxU32 newCapacity)
|
||||
{
|
||||
if(newCapacity>mMaxNbObjects)
|
||||
resize(newCapacity);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CompoundTreePool::shiftOrigin(const PxVec3& shift)
|
||||
{
|
||||
PxBounds3* bounds = mCompoundBounds.getBounds();
|
||||
for(PxU32 i=0; i < mNbObjects; i++)
|
||||
{
|
||||
bounds[i].minimum -= shift;
|
||||
bounds[i].maximum -= shift;
|
||||
|
||||
mCompoundTrees[i].mGlobalPose.p -= shift;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PoolIndex CompoundTreePool::addCompound(PrunerHandle* results, const BVH& bvh, const PxBounds3& compoundBounds, const PxTransform& transform, bool isDynamic, const PrunerPayload* data, const PxTransform* transforms)
|
||||
{
|
||||
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
|
||||
PxGetFoundation().error(PxErrorCode::eOUT_OF_MEMORY, PX_FL, "CompoundTreePool::addCompound memory allocation in resize failed.");
|
||||
return INVALID_PRUNERHANDLE;
|
||||
}
|
||||
}
|
||||
PX_ASSERT(mNbObjects!=mMaxNbObjects);
|
||||
|
||||
const PoolIndex index = mNbObjects++;
|
||||
|
||||
mCompoundBounds.getBounds()[index] = compoundBounds;
|
||||
|
||||
const PxU32 nbObjects = bvh.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 = isDynamic ? PxCompoundPrunerQueryFlag::eDYNAMIC : PxCompoundPrunerQueryFlag::eSTATIC;
|
||||
|
||||
// prepare the pruning pool
|
||||
PruningPool* pool = PX_NEW(PruningPool)(mContextID, TRANSFORM_CACHE_LOCAL);
|
||||
pool->preallocate(nbObjects);
|
||||
pool->addObjects(results, bvh.getBounds(), data, transforms, nbObjects);
|
||||
tree.mPruningPool = pool;
|
||||
|
||||
// prepare update map
|
||||
UpdateMap* map = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(UpdateMap), "Update map"), UpdateMap);
|
||||
map->resizeUninitialized(nbObjects);
|
||||
tree.mUpdateMap = map;
|
||||
|
||||
IncrementalAABBTree* iTree = PX_NEW(IncrementalAABBTree);
|
||||
iTree->copy(bvh, *map);
|
||||
tree.mTree = iTree;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PoolIndex CompoundTreePool::removeCompound(PoolIndex indexOfRemovedObject, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
PX_ASSERT(mNbObjects);
|
||||
|
||||
// release the tree
|
||||
PX_DELETE(mCompoundTrees[indexOfRemovedObject].mTree);
|
||||
|
||||
mCompoundTrees[indexOfRemovedObject].mUpdateMap->clear();
|
||||
mCompoundTrees[indexOfRemovedObject].mUpdateMap->~PxArray();
|
||||
PX_FREE(mCompoundTrees[indexOfRemovedObject].mUpdateMap);
|
||||
|
||||
if(removalCallback)
|
||||
{
|
||||
const PruningPool* pool = mCompoundTrees[indexOfRemovedObject].mPruningPool;
|
||||
removalCallback->invoke(pool->getNbActiveObjects(), pool->getObjects());
|
||||
}
|
||||
|
||||
PX_DELETE(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.getBounds() [indexOfRemovedObject] = mCompoundBounds.getBounds() [indexOfLastObject];
|
||||
mCompoundTrees [indexOfRemovedObject] = mCompoundTrees [indexOfLastObject];
|
||||
|
||||
mCompoundTrees [indexOfLastObject].mPruningPool = NULL;
|
||||
mCompoundTrees [indexOfLastObject].mUpdateMap = NULL;
|
||||
mCompoundTrees [indexOfLastObject].mTree = NULL;
|
||||
}
|
||||
|
||||
return indexOfLastObject;
|
||||
}
|
||||
|
||||
112
engine/third_party/physx/source/scenequery/src/SqCompoundPruningPool.h
vendored
Normal file
112
engine/third_party/physx/source/scenequery/src/SqCompoundPruningPool.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SQ_COMPOUND_PRUNING_POOL_H
|
||||
#define SQ_COMPOUND_PRUNING_POOL_H
|
||||
|
||||
#include "SqPruner.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "GuPrunerMergeData.h"
|
||||
#include "GuIncrementalAABBTree.h"
|
||||
#include "GuAABBTreeBounds.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class PruningPool;
|
||||
}
|
||||
|
||||
namespace Sq
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef PxArray<Gu::IncrementalAABBTreeNode*> UpdateMap;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CompoundTree
|
||||
{
|
||||
public:
|
||||
void updateObjectAfterManualBoundsUpdates(Gu::PrunerHandle handle);
|
||||
void removeObject(Gu::PrunerHandle handle, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
bool addObject(Gu::PrunerHandle& result, const PxBounds3& bounds, const Gu::PrunerPayload& data, const PxTransform& transform);
|
||||
|
||||
private:
|
||||
void updateMapping(const Gu::PoolIndex poolIndex, Gu::IncrementalAABBTreeNode* node, const Gu::NodeList& changedLeaves);
|
||||
|
||||
public:
|
||||
Gu::IncrementalAABBTree* mTree;
|
||||
Gu::PruningPool* mPruningPool;
|
||||
UpdateMap* mUpdateMap;
|
||||
PxTransform mGlobalPose;
|
||||
PxCompoundPrunerQueryFlags mFlags;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CompoundTreePool
|
||||
{
|
||||
public:
|
||||
CompoundTreePool(PxU64 contextID);
|
||||
~CompoundTreePool();
|
||||
|
||||
void preallocate(PxU32 newCapacity);
|
||||
|
||||
Gu::PoolIndex addCompound(Gu::PrunerHandle* results, const Gu::BVH& bvh, const PxBounds3& compoundBounds, const PxTransform& transform, bool isDynamic, const Gu::PrunerPayload* data, const PxTransform* transforms);
|
||||
Gu::PoolIndex removeCompound(Gu::PoolIndex index, Gu::PrunerPayloadRemovalCallback* removalCallback);
|
||||
|
||||
void shiftOrigin(const PxVec3& shift);
|
||||
|
||||
PX_FORCE_INLINE const Gu::AABBTreeBounds& getCurrentAABBTreeBounds() const { return mCompoundBounds; }
|
||||
PX_FORCE_INLINE const PxBounds3* getCurrentCompoundBounds() const { return mCompoundBounds.getBounds(); }
|
||||
PX_FORCE_INLINE PxBounds3* getCurrentCompoundBounds() { return mCompoundBounds.getBounds(); }
|
||||
|
||||
PX_FORCE_INLINE const CompoundTree* getCompoundTrees() const { return mCompoundTrees; }
|
||||
PX_FORCE_INLINE CompoundTree* getCompoundTrees() { return mCompoundTrees; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbObjects() const { return mNbObjects; }
|
||||
|
||||
private:
|
||||
bool resize(PxU32 newCapacity);
|
||||
|
||||
PxU32 mNbObjects; //!< Current number of objects
|
||||
PxU32 mMaxNbObjects; //!< Max. number of objects (capacity for mWorldBoxes, mObjects)
|
||||
|
||||
//!< these arrays are parallel
|
||||
Gu::AABBTreeBounds mCompoundBounds; //!< List of compound world boxes, stores mNbObjects, capacity=mMaxNbObjects
|
||||
CompoundTree* mCompoundTrees;
|
||||
|
||||
PxU64 mContextID;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
39
engine/third_party/physx/source/scenequery/src/SqFactory.cpp
vendored
Normal file
39
engine/third_party/physx/source/scenequery/src/SqFactory.cpp
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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 "SqFactory.h"
|
||||
#include "SqCompoundPruner.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Sq;
|
||||
|
||||
CompoundPruner* physx::Sq::createCompoundPruner(PxU64 contextID)
|
||||
{
|
||||
return PX_NEW(BVHCompoundPruner)(contextID);
|
||||
}
|
||||
|
||||
577
engine/third_party/physx/source/scenequery/src/SqManager.cpp
vendored
Normal file
577
engine/third_party/physx/source/scenequery/src/SqManager.cpp
vendored
Normal file
@@ -0,0 +1,577 @@
|
||||
// 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.
|
||||
|
||||
// PT: SQ-API LEVEL 2 (Level 1 = SqPruner.h)
|
||||
// PT: this file is part of a "high-level" set of files within Sq. The SqPruner API doesn't rely on them.
|
||||
// PT: this should really be at Np level but moving it to Sq allows us to share it.
|
||||
|
||||
#include "SqManager.h"
|
||||
#include "GuSqInternal.h"
|
||||
#include "GuBounds.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Sq;
|
||||
using namespace Gu;
|
||||
|
||||
PrunerExt::PrunerExt() : mPruner(NULL), mDirtyList("SQmDirtyList"), mDirtyStatic(false)
|
||||
{
|
||||
}
|
||||
|
||||
PrunerExt::~PrunerExt()
|
||||
{
|
||||
PX_DELETE(mPruner);
|
||||
}
|
||||
|
||||
void PrunerExt::init(Pruner* pruner)
|
||||
{
|
||||
mPruner = pruner;
|
||||
}
|
||||
|
||||
void PrunerExt::preallocate(PxU32 nbShapes)
|
||||
{
|
||||
// if(nbShapes > mDirtyMap.size())
|
||||
// mDirtyMap.resize(nbShapes);
|
||||
|
||||
if(mPruner)
|
||||
mPruner->preallocate(nbShapes);
|
||||
}
|
||||
|
||||
void PrunerExt::flushMemory()
|
||||
{
|
||||
if(!mDirtyList.size())
|
||||
mDirtyList.reset();
|
||||
|
||||
// PT: TODO: flush bitmap here
|
||||
|
||||
// PT: TODO: flush pruner here?
|
||||
}
|
||||
|
||||
void PrunerExt::addToDirtyList(PrunerHandle handle, bool dynamic, const PxTransform& transform)
|
||||
{
|
||||
if(mPruner)
|
||||
mPruner->setTransform(handle, transform);
|
||||
|
||||
PxBitMap& dirtyMap = mDirtyMap;
|
||||
{
|
||||
if(dirtyMap.size() <= handle)
|
||||
{
|
||||
PxU32 size = PxMax<PxU32>(dirtyMap.size()*2, 1024);
|
||||
const PxU32 minSize = handle+1;
|
||||
if(minSize>size)
|
||||
size = minSize*2;
|
||||
dirtyMap.resize(size);
|
||||
PX_ASSERT(handle<dirtyMap.size());
|
||||
PX_ASSERT(!dirtyMap.test(handle));
|
||||
}
|
||||
}
|
||||
|
||||
if(!dirtyMap.test(handle))
|
||||
{
|
||||
dirtyMap.set(handle);
|
||||
mDirtyList.pushBack(handle);
|
||||
}
|
||||
|
||||
if(!dynamic)
|
||||
mDirtyStatic = true;
|
||||
}
|
||||
|
||||
void PrunerExt::removeFromDirtyList(PrunerHandle handle)
|
||||
{
|
||||
PxBitMap& dirtyMap = mDirtyMap;
|
||||
// if(dirtyMap.test(handle))
|
||||
if(dirtyMap.boundedTest(handle))
|
||||
{
|
||||
dirtyMap.reset(handle);
|
||||
mDirtyList.findAndReplaceWithLast(handle);
|
||||
}
|
||||
|
||||
// PT: if we remove the object that made us set mDirtyStatic to true, tough luck,
|
||||
// we don't bother fixing that bool here. It's going to potentially cause an
|
||||
// unnecessary update of the character controller's caches, which is not a big deal.
|
||||
}
|
||||
|
||||
bool PrunerExt::processDirtyList(PxU32 index, const Adapter& adapter, float inflation)
|
||||
{
|
||||
const PxU32 numDirtyList = mDirtyList.size();
|
||||
if(!numDirtyList)
|
||||
return false;
|
||||
const PrunerHandle* const prunerHandles = mDirtyList.begin();
|
||||
|
||||
for(PxU32 i=0; i<numDirtyList; i++)
|
||||
{
|
||||
const PrunerHandle handle = prunerHandles[i];
|
||||
mDirtyMap.reset(handle);
|
||||
|
||||
// PT: we compute the new bounds and store them directly in the pruner structure to avoid copies. We delay the updateObjects() call
|
||||
// to take advantage of batching.
|
||||
PX_UNUSED(index);
|
||||
|
||||
PrunerPayloadData ppd;
|
||||
const PrunerPayload& pp = mPruner->getPayloadData(handle, &ppd);
|
||||
|
||||
computeBounds(*ppd.mBounds, adapter.getGeometry(pp), *ppd.mTransform, 0.0f, inflation);
|
||||
}
|
||||
// PT: batch update happens after the loop instead of once per loop iteration
|
||||
mPruner->updateObjects(prunerHandles, numDirtyList);
|
||||
mDirtyList.clear();
|
||||
|
||||
const bool ret = mDirtyStatic;
|
||||
mDirtyStatic = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// PT: TODO: re-inline this
|
||||
/*void PrunerExt::growDirtyList(PrunerHandle handle)
|
||||
{
|
||||
// pruners must either provide indices in order or reuse existing indices, so this 'if' is enough to ensure we have space for the new handle
|
||||
// PT: TODO: fix this. There is just no need for any of it. The pruning pool itself could support the feature for free, similar to what we do
|
||||
// in MBP. There would be no need for the bitmap or the dirty list array. However doing this through the virtual interface would be clumsy,
|
||||
// adding the cost of virtual calls for very cheap & simple operations. It would be a lot easier to drop it and go back to what we had before.
|
||||
|
||||
PxBitMap& dirtyMap = mDirtyMap;
|
||||
if(dirtyMap.size() <= handle)
|
||||
dirtyMap.resize(PxMax<PxU32>(dirtyMap.size() * 2, 1024));
|
||||
PX_ASSERT(handle<dirtyMap.size());
|
||||
dirtyMap.reset(handle);
|
||||
}*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CompoundPrunerExt::CompoundPrunerExt() :
|
||||
mPruner (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CompoundPrunerExt::~CompoundPrunerExt()
|
||||
{
|
||||
PX_DELETE(mPruner);
|
||||
}
|
||||
|
||||
void CompoundPrunerExt::preallocate(PxU32 nbShapes)
|
||||
{
|
||||
// if(nbShapes > mDirtyList.size())
|
||||
// mDirtyList.reserve(nbShapes);
|
||||
|
||||
if(mPruner)
|
||||
mPruner->preallocate(nbShapes);
|
||||
}
|
||||
|
||||
void CompoundPrunerExt::flushMemory()
|
||||
{
|
||||
if(!mDirtyList.size())
|
||||
mDirtyList.clear();
|
||||
}
|
||||
|
||||
void CompoundPrunerExt::flushShapes(const Adapter& adapter, float inflation)
|
||||
{
|
||||
const PxU32 numDirtyList = mDirtyList.size();
|
||||
if(!numDirtyList)
|
||||
return;
|
||||
|
||||
const CompoundPair* const compoundPairs = mDirtyList.getEntries();
|
||||
|
||||
for(PxU32 i=0; i<numDirtyList; i++)
|
||||
{
|
||||
const PrunerHandle handle = compoundPairs[i].second;
|
||||
const PrunerCompoundId compoundId = compoundPairs[i].first;
|
||||
|
||||
// PT: we compute the new bounds and store them directly in the pruner structure to avoid copies. We delay the updateObjects() call
|
||||
// to take advantage of batching.
|
||||
PrunerPayloadData ppd;
|
||||
const PrunerPayload& pp = mPruner->getPayloadData(handle, compoundId, &ppd);
|
||||
|
||||
computeBounds(*ppd.mBounds, adapter.getGeometry(pp), *ppd.mTransform, 0.0f, inflation);
|
||||
|
||||
// A.B. not very effective, we might do better here
|
||||
mPruner->updateObjectAfterManualBoundsUpdates(compoundId, handle);
|
||||
}
|
||||
|
||||
mDirtyList.clear();
|
||||
}
|
||||
|
||||
void CompoundPrunerExt::addToDirtyList(PrunerCompoundId compoundId, PrunerHandle handle, const PxTransform& transform)
|
||||
{
|
||||
if(mPruner)
|
||||
mPruner->setTransform(handle, compoundId, transform);
|
||||
|
||||
mDirtyList.insert(CompoundPair(compoundId, handle));
|
||||
}
|
||||
|
||||
void CompoundPrunerExt::removeFromDirtyList(PrunerCompoundId compoundId, PrunerHandle handle)
|
||||
{
|
||||
mDirtyList.erase(CompoundPair(compoundId, handle));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SqFactory.h"
|
||||
#include "common/PxProfileZone.h"
|
||||
#include "common/PxRenderBuffer.h"
|
||||
#include "GuBVH.h"
|
||||
#include "foundation/PxAlloca.h"
|
||||
#include "PxSceneDesc.h" // PT: for PxSceneLimits TODO: remove
|
||||
|
||||
namespace
|
||||
{
|
||||
enum PxScenePrunerIndex
|
||||
{
|
||||
PX_SCENE_PRUNER_STATIC = 0,
|
||||
PX_SCENE_PRUNER_DYNAMIC = 1,
|
||||
PX_SCENE_COMPOUND_PRUNER = 0xffffffff,
|
||||
};
|
||||
}
|
||||
|
||||
PrunerManager::PrunerManager( PxU64 contextID, Pruner* staticPruner, Pruner* dynamicPruner,
|
||||
PxU32 dynamicTreeRebuildRateHint, float inflation,
|
||||
const PxSceneLimits& limits, const Adapter& adapter) :
|
||||
mAdapter (adapter),
|
||||
mContextID (contextID),
|
||||
mStaticTimestamp (0),
|
||||
mInflation (inflation)
|
||||
{
|
||||
mPrunerExt[PruningIndex::eSTATIC].init(staticPruner);
|
||||
mPrunerExt[PruningIndex::eDYNAMIC].init(dynamicPruner);
|
||||
|
||||
setDynamicTreeRebuildRateHint(dynamicTreeRebuildRateHint);
|
||||
|
||||
mCompoundPrunerExt.mPruner = createCompoundPruner(contextID);
|
||||
|
||||
preallocate(PruningIndex::eSTATIC, limits.maxNbStaticShapes);
|
||||
preallocate(PruningIndex::eDYNAMIC, limits.maxNbDynamicShapes);
|
||||
preallocate(PxU32(PX_SCENE_COMPOUND_PRUNER), 32);
|
||||
|
||||
mPrunerNeedsUpdating = false;
|
||||
}
|
||||
|
||||
PrunerManager::~PrunerManager()
|
||||
{
|
||||
}
|
||||
|
||||
void PrunerManager::preallocate(PxU32 prunerIndex, PxU32 nbShapes)
|
||||
{
|
||||
if(prunerIndex==PruningIndex::eSTATIC)
|
||||
mPrunerExt[PruningIndex::eSTATIC].preallocate(nbShapes);
|
||||
else if(prunerIndex==PruningIndex::eDYNAMIC)
|
||||
mPrunerExt[PruningIndex::eDYNAMIC].preallocate(nbShapes);
|
||||
else if(prunerIndex==PX_SCENE_COMPOUND_PRUNER)
|
||||
mCompoundPrunerExt.preallocate(nbShapes);
|
||||
}
|
||||
|
||||
void PrunerManager::flushMemory()
|
||||
{
|
||||
for(PxU32 i=0;i<PruningIndex::eCOUNT;i++)
|
||||
mPrunerExt[i].flushMemory();
|
||||
|
||||
mCompoundPrunerExt.flushMemory();
|
||||
}
|
||||
|
||||
PrunerData PrunerManager::addPrunerShape(const PrunerPayload& payload, bool dynamic, PrunerCompoundId compoundId, const PxBounds3& bounds, const PxTransform& transform, bool hasPruningStructure)
|
||||
{
|
||||
mPrunerNeedsUpdating = true;
|
||||
|
||||
const PxU32 index = PxU32(dynamic);
|
||||
|
||||
if(!index)
|
||||
invalidateStaticTimestamp();
|
||||
|
||||
PrunerHandle handle;
|
||||
if(compoundId == INVALID_COMPOUND_ID)
|
||||
{
|
||||
PX_ASSERT(mPrunerExt[index].pruner());
|
||||
mPrunerExt[index].pruner()->addObjects(&handle, &bounds, &payload, &transform, 1, hasPruningStructure);
|
||||
//mPrunerExt[index].growDirtyList(handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(mCompoundPrunerExt.pruner());
|
||||
mCompoundPrunerExt.pruner()->addObject(compoundId, handle, bounds, payload, transform);
|
||||
}
|
||||
|
||||
return createPrunerData(index, handle);
|
||||
}
|
||||
|
||||
void PrunerManager::removePrunerShape(PrunerCompoundId compoundId, PrunerData data, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
mPrunerNeedsUpdating = true;
|
||||
const PxU32 index = getPrunerIndex(data);
|
||||
const PrunerHandle handle = getPrunerHandle(data);
|
||||
|
||||
if(!index)
|
||||
invalidateStaticTimestamp();
|
||||
|
||||
if(compoundId == INVALID_COMPOUND_ID)
|
||||
{
|
||||
PX_ASSERT(mPrunerExt[index].pruner());
|
||||
|
||||
mPrunerExt[index].removeFromDirtyList(handle);
|
||||
mPrunerExt[index].pruner()->removeObjects(&handle, 1, removalCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCompoundPrunerExt.removeFromDirtyList(compoundId, handle);
|
||||
mCompoundPrunerExt.pruner()->removeObject(compoundId, handle, removalCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void PrunerManager::markForUpdate(PrunerCompoundId compoundId, PrunerData data, const PxTransform& transform)
|
||||
{
|
||||
mPrunerNeedsUpdating = true;
|
||||
const PxU32 index = getPrunerIndex(data);
|
||||
const PrunerHandle handle = getPrunerHandle(data);
|
||||
|
||||
if(!index)
|
||||
invalidateStaticTimestamp();
|
||||
|
||||
if(compoundId == INVALID_COMPOUND_ID)
|
||||
// PT: TODO: at this point do we still need a dirty list? we could just update the bounds directly?
|
||||
mPrunerExt[index].addToDirtyList(handle, index!=0, transform);
|
||||
else
|
||||
mCompoundPrunerExt.addToDirtyList(compoundId, handle, transform);
|
||||
}
|
||||
|
||||
void PrunerManager::setDynamicTreeRebuildRateHint(PxU32 rebuildRateHint)
|
||||
{
|
||||
mRebuildRateHint = rebuildRateHint;
|
||||
|
||||
for(PxU32 i=0;i<PruningIndex::eCOUNT;i++)
|
||||
{
|
||||
Pruner* pruner = mPrunerExt[i].pruner();
|
||||
if(pruner && pruner->isDynamic())
|
||||
static_cast<DynamicPruner*>(pruner)->setRebuildRateHint(rebuildRateHint);
|
||||
}
|
||||
}
|
||||
|
||||
void PrunerManager::afterSync(bool buildStep, bool commit)
|
||||
{
|
||||
PX_PROFILE_ZONE("Sim.sceneQueryBuildStep", mContextID);
|
||||
|
||||
if(!buildStep && !commit)
|
||||
{
|
||||
mPrunerNeedsUpdating = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// flush user modified objects
|
||||
flushShapes();
|
||||
|
||||
for(PxU32 i=0; i<PruningIndex::eCOUNT; i++)
|
||||
{
|
||||
Pruner* pruner = mPrunerExt[i].pruner();
|
||||
if(pruner)
|
||||
{
|
||||
if(pruner->isDynamic())
|
||||
static_cast<DynamicPruner*>(pruner)->buildStep(true);
|
||||
|
||||
if(commit)
|
||||
pruner->commit();
|
||||
}
|
||||
}
|
||||
|
||||
mPrunerNeedsUpdating = !commit;
|
||||
}
|
||||
|
||||
void PrunerManager::flushShapes()
|
||||
{
|
||||
PX_PROFILE_ZONE("SceneQuery.flushShapes", mContextID);
|
||||
|
||||
// must already have acquired writer lock here
|
||||
|
||||
const float inflation = 1.0f + mInflation;
|
||||
|
||||
bool mustInvalidateStaticTimestamp = false;
|
||||
for(PxU32 i=0; i<PruningIndex::eCOUNT; i++)
|
||||
{
|
||||
if(mPrunerExt[i].processDirtyList(i, mAdapter, inflation))
|
||||
mustInvalidateStaticTimestamp = true;
|
||||
}
|
||||
|
||||
if(mustInvalidateStaticTimestamp)
|
||||
invalidateStaticTimestamp();
|
||||
|
||||
mCompoundPrunerExt.flushShapes(mAdapter, inflation);
|
||||
}
|
||||
|
||||
void PrunerManager::flushUpdates()
|
||||
{
|
||||
PX_PROFILE_ZONE("SceneQuery.flushUpdates", mContextID);
|
||||
|
||||
if(mPrunerNeedsUpdating)
|
||||
{
|
||||
// no need to take lock if manual sq update is enabled
|
||||
// as flushUpdates will only be called from NpScene::flushQueryUpdates()
|
||||
mSQLock.lock();
|
||||
|
||||
if(mPrunerNeedsUpdating)
|
||||
{
|
||||
flushShapes();
|
||||
|
||||
for(PxU32 i=0; i<PruningIndex::eCOUNT; i++)
|
||||
if(mPrunerExt[i].pruner())
|
||||
mPrunerExt[i].pruner()->commit();
|
||||
|
||||
PxMemoryBarrier();
|
||||
mPrunerNeedsUpdating = false;
|
||||
}
|
||||
mSQLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void PrunerManager::forceRebuildDynamicTree(PxU32 prunerIndex)
|
||||
{
|
||||
PX_PROFILE_ZONE("SceneQuery.forceDynamicTreeRebuild", mContextID);
|
||||
|
||||
PxMutex::ScopedLock lock(mSQLock);
|
||||
Pruner* pruner = mPrunerExt[prunerIndex].pruner();
|
||||
if(pruner && pruner->isDynamic())
|
||||
{
|
||||
static_cast<DynamicPruner*>(pruner)->purge();
|
||||
static_cast<DynamicPruner*>(pruner)->commit();
|
||||
}
|
||||
}
|
||||
|
||||
void* PrunerManager::prepareSceneQueriesUpdate(PruningIndex::Enum index)
|
||||
{
|
||||
bool retVal = false;
|
||||
Pruner* pruner = mPrunerExt[index].pruner();
|
||||
if(pruner && pruner->isDynamic())
|
||||
retVal = static_cast<DynamicPruner*>(pruner)->prepareBuild();
|
||||
|
||||
return retVal ? pruner : NULL;
|
||||
}
|
||||
|
||||
void PrunerManager::sceneQueryBuildStep(void* handle)
|
||||
{
|
||||
PX_PROFILE_ZONE("SceneQuery.sceneQueryBuildStep", mContextID);
|
||||
|
||||
Pruner* pruner = reinterpret_cast<Pruner*>(handle);
|
||||
if(pruner && pruner->isDynamic())
|
||||
{
|
||||
const bool buildFinished = static_cast<DynamicPruner*>(pruner)->buildStep(false);
|
||||
if(buildFinished)
|
||||
mPrunerNeedsUpdating = true;
|
||||
}
|
||||
}
|
||||
|
||||
// PT: TODO: revisit this. Perhaps it should be the user's responsibility to call the pruner's
|
||||
// visualize functions directly, when & how he wants.
|
||||
void PrunerManager::visualize(PxU32 prunerIndex, PxRenderOutput& out) const
|
||||
{
|
||||
if(prunerIndex==PX_SCENE_PRUNER_STATIC)
|
||||
{
|
||||
if(getPruner(PruningIndex::eSTATIC))
|
||||
getPruner(PruningIndex::eSTATIC)->visualize(out, SQ_DEBUG_VIZ_STATIC_COLOR, SQ_DEBUG_VIZ_STATIC_COLOR2);
|
||||
}
|
||||
else if(prunerIndex==PX_SCENE_PRUNER_DYNAMIC)
|
||||
{
|
||||
if(getPruner(PruningIndex::eDYNAMIC))
|
||||
getPruner(PruningIndex::eDYNAMIC)->visualize(out, SQ_DEBUG_VIZ_DYNAMIC_COLOR, SQ_DEBUG_VIZ_DYNAMIC_COLOR2);
|
||||
}
|
||||
else if(prunerIndex==PX_SCENE_COMPOUND_PRUNER)
|
||||
{
|
||||
const CompoundPruner* cp = mCompoundPrunerExt.pruner();
|
||||
if(cp)
|
||||
cp->visualizeEx(out, SQ_DEBUG_VIZ_COMPOUND_COLOR, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PrunerManager::shiftOrigin(const PxVec3& shift)
|
||||
{
|
||||
for(PxU32 i=0; i<PruningIndex::eCOUNT; i++)
|
||||
mPrunerExt[i].pruner()->shiftOrigin(shift);
|
||||
|
||||
mCompoundPrunerExt.pruner()->shiftOrigin(shift);
|
||||
}
|
||||
|
||||
void PrunerManager::addCompoundShape(const PxBVH& pxbvh, PrunerCompoundId compoundId, const PxTransform& compoundTransform, PrunerData* prunerData, const PrunerPayload* payloads, const PxTransform* transforms, bool isDynamic)
|
||||
{
|
||||
const BVH& bvh = static_cast<const BVH&>(pxbvh);
|
||||
const PxU32 nbShapes = bvh.Gu::BVH::getNbBounds();
|
||||
|
||||
PX_ALLOCA(res, PrunerHandle, nbShapes);
|
||||
|
||||
PX_ASSERT(mCompoundPrunerExt.mPruner);
|
||||
mCompoundPrunerExt.mPruner->addCompound(res, bvh, compoundId, compoundTransform, isDynamic, payloads, transforms);
|
||||
const PxU32 index = PxU32(isDynamic);
|
||||
if(!index)
|
||||
invalidateStaticTimestamp();
|
||||
|
||||
for(PxU32 i = 0; i < nbShapes; i++)
|
||||
prunerData[i] = createPrunerData(index, res[i]);
|
||||
}
|
||||
|
||||
void PrunerManager::updateCompoundActor(PrunerCompoundId compoundId, const PxTransform& compoundTransform)
|
||||
{
|
||||
PX_ASSERT(mCompoundPrunerExt.mPruner);
|
||||
const bool isDynamic = mCompoundPrunerExt.mPruner->updateCompound(compoundId, compoundTransform);
|
||||
if(!isDynamic)
|
||||
invalidateStaticTimestamp();
|
||||
}
|
||||
|
||||
void PrunerManager::removeCompoundActor(PrunerCompoundId compoundId, PrunerPayloadRemovalCallback* removalCallback)
|
||||
{
|
||||
PX_ASSERT(mCompoundPrunerExt.mPruner);
|
||||
const bool isDynamic = mCompoundPrunerExt.mPruner->removeCompound(compoundId, removalCallback);
|
||||
if(!isDynamic)
|
||||
invalidateStaticTimestamp();
|
||||
}
|
||||
|
||||
void PrunerManager::sync(const PrunerHandle* handles, const PxU32* boundsIndices, const PxBounds3* bounds, const PxTransform32* transforms, PxU32 count, const PxBitMap& ignoredIndices)
|
||||
{
|
||||
if(!count)
|
||||
return;
|
||||
|
||||
Pruner* dynamicPruner = getPruner(PruningIndex::eDYNAMIC);
|
||||
if(!dynamicPruner)
|
||||
return;
|
||||
|
||||
PxU32 startIndex = 0;
|
||||
PxU32 numIndices = count;
|
||||
|
||||
// if shape sim map is not empty, parse the indices and skip update for the dirty one
|
||||
if(ignoredIndices.count())
|
||||
{
|
||||
// PT: I think this codepath was used with SCB / buffered changes, but it's not needed anymore
|
||||
numIndices = 0;
|
||||
|
||||
for(PxU32 i=0; i<count; i++)
|
||||
{
|
||||
// if(ignoredIndices.test(boundsIndices[i]))
|
||||
if(ignoredIndices.boundedTest(boundsIndices[i]))
|
||||
{
|
||||
dynamicPruner->updateObjects(handles + startIndex, numIndices, mInflation, boundsIndices + startIndex, bounds, transforms);
|
||||
numIndices = 0;
|
||||
startIndex = i + 1;
|
||||
}
|
||||
else
|
||||
numIndices++;
|
||||
}
|
||||
// PT: we fallback to the next line on purpose - no "else"
|
||||
}
|
||||
|
||||
dynamicPruner->updateObjects(handles + startIndex, numIndices, mInflation, boundsIndices + startIndex, bounds, transforms);
|
||||
}
|
||||
1066
engine/third_party/physx/source/scenequery/src/SqQuery.cpp
vendored
Normal file
1066
engine/third_party/physx/source/scenequery/src/SqQuery.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user