Files
XCEngine/engine/third_party/physx/source/geomutils/src/mesh/GuRTree.h

273 lines
10 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-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 GU_RTREE_H
#define GU_RTREE_H
#include "foundation/PxSimpleTypes.h"
#include "foundation/PxVec4.h"
#include "foundation/PxBounds3.h"
#include "foundation/PxAssert.h"
#include "foundation/PxIO.h"
#include "common/PxSerialFramework.h"
#include "geometry/PxTriangleMesh.h"
#include "foundation/PxUserAllocated.h" // for PxSerializationContext
#include "foundation/PxAlignedMalloc.h"
#include "foundation/PxVecMath.h"
#define RTREE_N 4 // changing this number will affect the mesh format
PX_COMPILE_TIME_ASSERT(RTREE_N == 4 || RTREE_N == 8); // using the low 5 bits for storage of index(childPtr) for dynamic rtree
namespace physx
{
#if PX_VC
#pragma warning(push)
#pragma warning(disable: 4324) // Padding was added at the end of a structure because of a __declspec(align) value.
#endif
namespace Gu {
class Box;
struct RTreePage;
typedef PxF32 RTreeValue;
/////////////////////////////////////////////////////////////////////////
// quantized untransposed RTree node - used for offline build and dynamic insertion
struct RTreeNodeQ
{
RTreeValue minx, miny, minz, maxx, maxy, maxz;
PxU32 ptr; // lowest bit is leaf flag
PX_FORCE_INLINE void setLeaf(bool set) { if (set) ptr |= 1; else ptr &= ~1; }
PX_FORCE_INLINE PxU32 isLeaf() const { return ptr & 1; }
PX_FORCE_INLINE void setEmpty();
PX_FORCE_INLINE void grow(const RTreePage& page, int nodeIndex);
PX_FORCE_INLINE void grow(const RTreeNodeQ& node);
};
/////////////////////////////////////////////////////////////////////////
// RTreePage data structure, holds RTREE_N transposed nodes
// RTreePage data structure, holds 8 transposed nodes
PX_ALIGN_PREFIX(16)
struct RTreePage
{
static const RTreeValue MN, MX;
RTreeValue minx[RTREE_N]; // [min=MX, max=MN] is used as a sentinel range for empty bounds
RTreeValue miny[RTREE_N];
RTreeValue minz[RTREE_N];
RTreeValue maxx[RTREE_N];
RTreeValue maxy[RTREE_N];
RTreeValue maxz[RTREE_N];
PxU32 ptrs[RTREE_N]; // for static rtree this is an offset relative to the first page divided by 16, for dynamics it's an absolute pointer divided by 16
PX_FORCE_INLINE PxU32 nodeCount() const; // returns the number of occupied nodes in this page
PX_FORCE_INLINE void setEmpty(PxU32 startIndex = 0);
PX_FORCE_INLINE bool isEmpty(PxU32 index) const { return minx[index] > maxx[index]; }
PX_FORCE_INLINE void copyNode(PxU32 targetIndex, const RTreePage& sourcePage, PxU32 sourceIndex);
PX_FORCE_INLINE void setNode(PxU32 targetIndex, const RTreeNodeQ& node);
PX_FORCE_INLINE void clearNode(PxU32 nodeIndex);
PX_FORCE_INLINE void getNode(PxU32 nodeIndex, RTreeNodeQ& result) const;
PX_FORCE_INLINE void computeBounds(RTreeNodeQ& bounds);
PX_FORCE_INLINE void adjustChildBounds(PxU32 index, const RTreeNodeQ& adjustedChildBounds);
PX_FORCE_INLINE void growChildBounds(PxU32 index, const RTreeNodeQ& adjustedChildBounds);
PX_FORCE_INLINE PxU32 getNodeHandle(PxU32 index) const;
PX_FORCE_INLINE PxU32 isLeaf(PxU32 index) const { return ptrs[index] & 1; }
} PX_ALIGN_SUFFIX(16);
/////////////////////////////////////////////////////////////////////////
// RTree root data structure
PX_ALIGN_PREFIX(16)
struct RTree
{
// PX_SERIALIZATION
RTree(const PxEMPTY);
void exportExtraData(PxSerializationContext&);
void importExtraData(PxDeserializationContext& context);
//~PX_SERIALIZATION
PX_INLINE RTree(); // offline static rtree constructor used with cooking
~RTree() { release(); }
PX_INLINE void release();
bool load(PxInputStream& stream, PxU32 meshVersion, bool mismatch);
////////////////////////////////////////////////////////////////////////////
// QUERIES
struct Callback
{
// result buffer should have room for at least RTREE_N items
// should return true to continue traversal. If false is returned, traversal is aborted
virtual bool processResults(PxU32 count, PxU32* buf) = 0;
virtual void profile() {}
virtual ~Callback() {}
};
struct CallbackRaycast
{
// result buffer should have room for at least RTREE_N items
// should return true to continue traversal. If false is returned, traversal is aborted
// newMaxT serves as both input and output, as input it's the maxT so far
// set it to a new value (which should be smaller) and it will become the new far clip t
virtual bool processResults(PxU32 count, PxU32* buf, PxF32& newMaxT) = 0;
virtual ~CallbackRaycast() {}
};
// callback will be issued as soon as the buffer overflows maxResultsPerBlock-RTreePage:SIZE entries
// use maxResults = RTreePage:SIZE and return false from callback for "first hit" early out
void traverseAABB(
const PxVec3& boxMin, const PxVec3& boxMax,
const PxU32 maxResultsPerBlock, PxU32* resultsBlockBuf, Callback* processResultsBlockCallback) const;
void traverseOBB(
const Gu::Box& obb,
const PxU32 maxResultsPerBlock, PxU32* resultsBlockBuf, Callback* processResultsBlockCallback) const;
template <int inflate>
void traverseRay(
const PxVec3& rayOrigin, const PxVec3& rayDir, // dir doesn't have to be normalized and is B-A for raySegment
const PxU32 maxResults, PxU32* resultsPtr,
Gu::RTree::CallbackRaycast* callback,
const PxVec3* inflateAABBs, // inflate tree's AABBs by this amount. This function turns into AABB sweep.
PxF32 maxT = PX_MAX_F32 // maximum ray t parameter, p(t)=origin+t*dir; use 1.0f for ray segment
) const;
struct CallbackRefit
{
// In this callback index is the number stored in the RTree, which is a LeafTriangles object for current PhysX mesh
virtual void recomputeBounds(PxU32 index, aos::Vec3V& mn, aos::Vec3V& mx) = 0;
virtual ~CallbackRefit() {}
};
void refitAllStaticTree(CallbackRefit& cb, PxBounds3* resultMeshBounds); // faster version of refit for static RTree only
////////////////////////////////////////////////////////////////////////////
// DEBUG HELPER FUNCTIONS
PX_PHYSX_COMMON_API void validate(CallbackRefit* cb = NULL); // verify that all children are indeed included in parent bounds
void openTextDump();
void closeTextDump();
void textDump(const char* prefix);
void maxscriptExport();
PxU32 computeBottomLevelCount(PxU32 storedToMemMultiplier) const;
////////////////////////////////////////////////////////////////////////////
// DATA
// remember to update save() and load() when adding or removing data
PxVec4 mBoundsMin, mBoundsMax, mInvDiagonal, mDiagonalScaler; // 16
PxU32 mPageSize;
PxU32 mNumRootPages;
PxU32 mNumLevels;
PxU32 mTotalNodes; // 16
PxU32 mTotalPages;
PxU32 mFlags; enum { USER_ALLOCATED = 0x1, IS_EDGE_SET = 0x2 };
RTreePage* mPages;
protected:
typedef PxU32 NodeHandle;
void validateRecursive(PxU32 level, RTreeNodeQ parentBounds, RTreePage* page, CallbackRefit* cb = NULL);
friend struct RTreePage;
} PX_ALIGN_SUFFIX(16);
#if PX_SUPPORT_EXTERN_TEMPLATE
//explicit template instantiation declaration
extern template
void RTree::traverseRay<0>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
extern template
void RTree::traverseRay<1>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
#endif
#if PX_VC
#pragma warning(pop)
#endif
/////////////////////////////////////////////////////////////////////////
PX_INLINE RTree::RTree()
{
mFlags = 0;
mPages = NULL;
mTotalNodes = 0;
mNumLevels = 0;
mPageSize = RTREE_N;
}
/////////////////////////////////////////////////////////////////////////
PX_INLINE void RTree::release()
{
if ((mFlags & USER_ALLOCATED) == 0 && mPages)
{
physx::PxAlignedAllocator<128>().deallocate(mPages);
mPages = NULL;
}
}
/////////////////////////////////////////////////////////////////////////
PX_FORCE_INLINE void RTreeNodeQ::setEmpty()
{
minx = miny = minz = RTreePage::MX;
maxx = maxy = maxz = RTreePage::MN;
}
// bit 1 is always expected to be set to differentiate between leaf and non-leaf node
PX_FORCE_INLINE PxU32 LeafGetNbTriangles(PxU32 Data) { return ((Data>>1) & 15)+1; }
PX_FORCE_INLINE PxU32 LeafGetTriangleIndex(PxU32 Data) { return Data>>5; }
PX_FORCE_INLINE PxU32 LeafSetData(PxU32 nb, PxU32 index)
{
PX_ASSERT(nb>0 && nb<=16); PX_ASSERT(index < (1<<27));
return (index<<5)|(((nb-1)&15)<<1) | 1;
}
struct LeafTriangles
{
PxU32 Data;
// Gets number of triangles in the leaf, returns the number of triangles N, with 0 < N <= 16
PX_FORCE_INLINE PxU32 GetNbTriangles() const { return LeafGetNbTriangles(Data); }
// Gets triangle index for this leaf. Indexed model's array of indices retrieved with RTreeMidphase::GetIndices()
PX_FORCE_INLINE PxU32 GetTriangleIndex() const { return LeafGetTriangleIndex(Data); }
PX_FORCE_INLINE void SetData(PxU32 nb, PxU32 index) { Data = LeafSetData(nb, index); }
};
PX_COMPILE_TIME_ASSERT(sizeof(LeafTriangles)==4); // RTree has space for 4 bytes
} // namespace Gu
}
#endif // #ifdef PX_COLLISION_RTREE