Revision control

++ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
++ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
++ // SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
++ // SPDX-License-Identifier: Apache-2.0
++
++ #ifndef GU_PCM_CONTACT_MESH_CALLBACK_H
++ #define GU_PCM_CONTACT_MESH_CALLBACK_H
++
++ #include "GuMidphaseInterface.h"
++ #include "GuEntityReport.h"
++ #include "GuHeightFieldUtil.h"
++ #include "GuTriangleCache.h"
++ #include "GuConvexEdgeFlags.h"
++
++ namespace physx
++ {
++ namespace Gu
++ {
++ template <typename Derived>
++ struct PCMMeshContactGenerationCallback : MeshHitCallback<PxGeomRaycastHit>
++ {
++ public:
++ const Cm::FastVertex2ShapeScaling& mMeshScaling;
++ const PxU8* PX_RESTRICT mExtraTrigData;
++ bool mIdtMeshScale;
++ static const PxU32 CacheSize = 16;
++ Gu::TriangleCache<CacheSize> mCache;
++
++ PCMMeshContactGenerationCallback(const Cm::FastVertex2ShapeScaling& meshScaling, const PxU8* extraTrigData, bool idtMeshScale)
++ : MeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE),
++ mMeshScaling(meshScaling), mExtraTrigData(extraTrigData), mIdtMeshScale(idtMeshScale)
++ {
++ }
++
++ void flushCache()
++ {
++ if (!mCache.isEmpty())
++ {
++ (static_cast<Derived*>(this))->template processTriangleCache< CacheSize >(mCache);
++ mCache.reset();
++ }
++ }
++
++ virtual PxAgain processHit(
++ const PxGeomRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32* vinds) PX_OVERRIDE
++ {
++ if (!(static_cast<Derived*>(this))->doTest(v0, v1, v2))
++ return true;
++
++ const PxU32 triangleIndex = hit.faceIndex;
++ PxU8 extraData = getConvexEdgeFlags(mExtraTrigData, triangleIndex);
++
++ const PxU32* vertexIndices = vinds;
++ PxVec3 v[3];
++ PxU32 localStorage[3];
++ if(mIdtMeshScale)
++ {
++ v[0] = v0;
++ v[1] = v1;
++ v[2] = v2;
++ }
++ else
++ {
++ const PxI32 winding = mMeshScaling.flipsNormal() ? 1 : 0;
++ v[0] = mMeshScaling * v0;
++ v[1 + winding] = mMeshScaling * v1;
++ v[2 - winding] = mMeshScaling * v2;
++
++ if(winding)
++ {
++ flipConvexEdgeFlags(extraData);
++ localStorage[0] = vinds[0];
++ localStorage[1] = vinds[2];
++ localStorage[2] = vinds[1];
++ vertexIndices = localStorage;
++ }
++ }
++
++ if (mCache.isFull())
++ {
++ (static_cast<Derived*>(this))->template processTriangleCache< CacheSize >(mCache);
++ mCache.reset();
++ }
++ mCache.addTriangle(v, vertexIndices, triangleIndex, extraData);
++
++ return true;
++ }
++
++ protected:
++ PCMMeshContactGenerationCallback& operator=(const PCMMeshContactGenerationCallback&);
++ };
++
++ template <typename Derived>
++ struct PCMHeightfieldContactGenerationCallback : Gu::OverlapReport
++ {
++ public:
++ const Gu::HeightFieldUtil& mHfUtil;
++ const PxTransform& mHeightfieldTransform;
++ bool mBoundaryCollisions;
++
++ PCMHeightfieldContactGenerationCallback(const Gu::HeightFieldUtil& hfUtil, const PxTransform& heightfieldTransform) :
++ mHfUtil(hfUtil), mHeightfieldTransform(heightfieldTransform)
++ {
++ mBoundaryCollisions = !(hfUtil.getHeightField().getFlags() & PxHeightFieldFlag::eNO_BOUNDARY_EDGES);
++ }
++
++ // PT: TODO: refactor/unify with similar code in other places
++ virtual bool reportTouchedTris(PxU32 nb, const PxU32* indices) PX_OVERRIDE
++ {
++ const PxU32 CacheSize = 16;
++ Gu::TriangleCache<CacheSize> cache;
++
++ const PxU32 nbPasses = (nb+(CacheSize-1))/CacheSize;
++ PxU32 nbTrigs = nb;
++ const PxU32* inds0 = indices;
++
++ const PxU8 nextInd[] = {2,0,1};
++
++ for(PxU32 i = 0; i < nbPasses; ++i)
++ {
++ cache.mNumTriangles = 0;
++ PxU32 trigCount = PxMin(nbTrigs, CacheSize);
++ nbTrigs -= trigCount;
++ while(trigCount--)
++ {
++ PxU32 triangleIndex = *(inds0++);
++ PxU32 vertIndices[3];
++
++ PxTriangle currentTriangle; // in world space
++
++ PxU32 adjInds[3];
++ mHfUtil.getTriangle(mHeightfieldTransform, currentTriangle, vertIndices, adjInds, triangleIndex, false, false);
++
++ PxVec3 normal;
++ currentTriangle.normal(normal);
++
++ PxU8 triFlags = 0; //KS - temporary until we can calculate triFlags for HF
++
++ for(PxU32 a = 0; a < 3; ++a)
++ {
++ if (adjInds[a] != 0xFFFFFFFF)
++ {
++ PxTriangle adjTri;
++ PxU32 inds[3];
++ mHfUtil.getTriangle(mHeightfieldTransform, adjTri, inds, NULL, adjInds[a], false, false);
++ //We now compare the triangles to see if this edge is active
++
++ PX_ASSERT(inds[0] == vertIndices[a] || inds[1] == vertIndices[a] || inds[2] == vertIndices[a]);
++ PX_ASSERT(inds[0] == vertIndices[(a + 1) % 3] || inds[1] == vertIndices[(a + 1) % 3] || inds[2] == vertIndices[(a + 1) % 3]);
++
++ PxVec3 adjNormal;
++ adjTri.denormalizedNormal(adjNormal);
++ PxU32 otherIndex = nextInd[a];
++ PxF32 projD = adjNormal.dot(currentTriangle.verts[otherIndex] - adjTri.verts[0]);
++
++ if (projD < 0.f)
++ {
++ adjNormal.normalize();
++
++ PxF32 proj = adjNormal.dot(normal);
++
++ if (proj < 0.997f)
++ {
++ triFlags |= (1 << (a + 3));
++ }
++ }
++ }
++ else if (mBoundaryCollisions)
++ {
++ triFlags |= (1 << (a + 3)); //Mark boundary edge active
++ }
++ else
++ triFlags |= (1 << a); //Mark as silhouette edge
++ }
++
++ cache.addTriangle(currentTriangle.verts, vertIndices, triangleIndex, triFlags);
++ }
++ PX_ASSERT(cache.mNumTriangles <= 16);
++
++ (static_cast<Derived*>(this))->template processTriangleCache< CacheSize >(cache);
++ }
++ return true;
++ }
++ protected:
++ PCMHeightfieldContactGenerationCallback& operator=(const PCMHeightfieldContactGenerationCallback&);
++ };
++
++ template <typename Derived>
++ struct PCMTetMeshContactGenerationCallback : TetMeshHitCallback<PxGeomRaycastHit>
++ {
++ public:
++
++ static const PxU32 CacheSize = 16;
++ Gu::TetrahedronCache<CacheSize> mCache;
++
++ PCMTetMeshContactGenerationCallback(): TetMeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE)
++ {
++ }
++
++ void flushCache()
++ {
++ if (!mCache.isEmpty())
++ {
++ (static_cast<Derived*>(this))->template processTetrahedronCache< CacheSize >(mCache);
++ mCache.reset();
++ }
++ }
++
++ virtual PxAgain processHit(
++ const PxGeomRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, const PxVec3& v3, PxReal&, const PxU32* vinds) PX_OVERRIDE
++ {
++ if (!(static_cast<Derived*>(this))->doTest(v0, v1, v2, v3))
++ return true;
++
++ PxVec3 v[4] = { v0, v1, v2, v3 };
++
++ const PxU32 tetIndex = hit.faceIndex;
++
++ if (mCache.isFull())
++ {
++ (static_cast<Derived*>(this))->template processTetrahedronCache< CacheSize >(mCache);
++ mCache.reset();
++ }
++ mCache.addTetrahedrons(v, vinds, tetIndex);
++
++ return true;
++ }
++
++ protected:
++ PCMTetMeshContactGenerationCallback& operator=(const PCMTetMeshContactGenerationCallback&);
++ };
++
++ }//Gu
++ }//physx
++
++ #endif