Files
XCEngine/engine/third_party/physx/source/geomutils/src/GuMeshFactory.cpp

1239 lines
38 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.
#include "common/PxInsertionCallback.h"
#include "GuCooking.h"
#include "GuMeshFactory.h"
#include "GuTriangleMeshBV4.h"
#include "GuTriangleMeshRTree.h"
#include "GuTetrahedronMesh.h"
#include "GuConvexMesh.h"
#include "GuBVH.h"
#include "GuHeightField.h"
#if PX_SUPPORT_OMNI_PVD
# define OMNI_PVD_NOTIFY_ADD(OBJECT) notifyListenersAdd(OBJECT)
# define OMNI_PVD_NOTIFY_REMOVE(OBJECT) notifyListenersRemove(OBJECT)
#else
# define OMNI_PVD_NOTIFY_ADD(OBJECT)
# define OMNI_PVD_NOTIFY_REMOVE(OBJECT)
#endif
using namespace physx;
using namespace Gu;
using namespace Cm;
///////////////////////////////////////////////////////////////////////////////
PX_IMPLEMENT_OUTPUT_ERROR
///////////////////////////////////////////////////////////////////////////////
// PT: TODO: refactor all this with a dedicated container
MeshFactory::MeshFactory() :
mTriangleMeshes ("mesh factory triangle mesh hash"),
mConvexMeshes ("mesh factory convex mesh hash"),
mHeightFields ("mesh factory height field hash"),
mBVHs ("BVH factory hash"),
mFactoryListeners ("FactoryListeners")
{
}
MeshFactory::~MeshFactory()
{
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
static void releaseObjects(PxCoalescedHashSet<T*>& objects)
{
while(objects.size())
{
T* object = objects.getEntries()[0];
PX_ASSERT(RefCountable_getRefCount(*object)==1);
object->release();
}
}
// PT: needed because Gu::BVH is not a PxRefCounted object, although it derives from RefCountable
static void releaseObjects(PxCoalescedHashSet<Gu::BVH*>& objects)
{
while(objects.size())
{
Gu::BVH* object = objects.getEntries()[0];
PX_ASSERT(object->getRefCount()==1);
object->release();
}
}
void MeshFactory::release()
{
// Release all objects in case the user didn't do it
releaseObjects(mTriangleMeshes);
releaseObjects(mTetrahedronMeshes);
releaseObjects(mDeformableVolumeMeshes);
releaseObjects(mConvexMeshes);
releaseObjects(mHeightFields);
releaseObjects(mBVHs);
PX_DELETE_THIS;
}
template <typename T>
static void addToHash(PxCoalescedHashSet<T*>& hash, T* element, PxMutex* mutex)
{
if(!element)
return;
if(mutex)
mutex->lock();
hash.insert(element);
if(mutex)
mutex->unlock();
}
///////////////////////////////////////////////////////////////////////////////
static void read8BitIndices(PxInputStream& stream, void* tris, PxU32 nbIndices, const bool has16BitIndices)
{
PxU8 x;
if(has16BitIndices)
{
PxU16* tris16 = reinterpret_cast<PxU16*>(tris);
for(PxU32 i=0;i<nbIndices;i++)
{
stream.read(&x, sizeof(PxU8));
*tris16++ = x;
}
}
else
{
PxU32* tris32 = reinterpret_cast<PxU32*>(tris);
for(PxU32 i=0;i<nbIndices;i++)
{
stream.read(&x, sizeof(PxU8));
*tris32++ = x;
}
}
}
static void read16BitIndices(PxInputStream& stream, void* tris, PxU32 nbIndices, const bool has16BitIndices, const bool mismatch)
{
if(has16BitIndices)
{
PxU16* tris16 = reinterpret_cast<PxU16*>(tris);
stream.read(tris16, nbIndices*sizeof(PxU16));
if(mismatch)
{
for(PxU32 i=0;i<nbIndices;i++)
flip(tris16[i]);
}
}
else
{
PxU32* tris32 = reinterpret_cast<PxU32*>(tris);
PxU16 x;
for(PxU32 i=0;i<nbIndices;i++)
{
stream.read(&x, sizeof(PxU16));
if(mismatch)
flip(x);
*tris32++ = x;
}
}
}
static void read32BitIndices(PxInputStream& stream, void* tris, PxU32 nbIndices, const bool has16BitIndices, const bool mismatch)
{
if(has16BitIndices)
{
PxU32 x;
PxU16* tris16 = reinterpret_cast<PxU16*>(tris);
for(PxU32 i=0;i<nbIndices;i++)
{
stream.read(&x, sizeof(PxU32));
if(mismatch)
flip(x);
*tris16++ = PxTo16(x);
}
}
else
{
PxU32* tris32 = reinterpret_cast<PxU32*>(tris);
stream.read(tris32, nbIndices*sizeof(PxU32));
if(mismatch)
{
for(PxU32 i=0;i<nbIndices;i++)
flip(tris32[i]);
}
}
}
static TriangleMeshData* loadMeshData(PxInputStream& stream)
{
// Import header
PxU32 version;
bool mismatch;
if(!readHeader('M', 'E', 'S', 'H', version, mismatch, stream))
return NULL;
PxU32 midphaseID = PxMeshMidPhase::eBVH33; // Default before version 14
if(version>=14) // this refers to PX_MESH_VERSION
midphaseID = readDword(mismatch, stream);
// Check if old (incompatible) mesh format is loaded
if (version <= 9) // this refers to PX_MESH_VERSION
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "Loading triangle mesh failed: "
"Deprecated mesh cooking format. Please recook your mesh in a new cooking format.");
PX_ALWAYS_ASSERT_MESSAGE("Obsolete cooked mesh found. Mesh version has been updated, please recook your meshes.");
return NULL;
}
// Import serialization flags
const PxU32 serialFlags = readDword(mismatch, stream);
// Import misc values
if (version <= 12) // this refers to PX_MESH_VERSION
{
// convexEdgeThreshold was removed in 3.4.0
readFloat(mismatch, stream);
}
TriangleMeshData* data;
if(midphaseID==PxMeshMidPhase::eBVH33)
data = PX_NEW(RTreeTriangleData);
else if(midphaseID==PxMeshMidPhase::eBVH34)
data = PX_NEW(BV4TriangleData);
else return NULL;
// Import mesh
PxVec3* verts = data->allocateVertices(readDword(mismatch, stream));
const PxU32 nbTris = readDword(mismatch, stream);
const bool force32 = (serialFlags & (IMSF_8BIT_INDICES|IMSF_16BIT_INDICES)) == 0;
//ML: this will allocate CPU triangle indices and GPU triangle indices if we have GRB data built
void* tris = data->allocateTriangles(nbTris, force32, serialFlags & IMSF_GRB_DATA);
stream.read(verts, sizeof(PxVec3)*data->mNbVertices);
if(mismatch)
{
for(PxU32 i=0;i<data->mNbVertices;i++)
{
flip(verts[i].x);
flip(verts[i].y);
flip(verts[i].z);
}
}
//TODO: stop support for format conversion on load!!
const PxU32 nbIndices = 3*data->mNbTriangles;
if(serialFlags & IMSF_8BIT_INDICES)
read8BitIndices(stream, tris, nbIndices, data->has16BitIndices());
else if(serialFlags & IMSF_16BIT_INDICES)
read16BitIndices(stream, tris, nbIndices, data->has16BitIndices(), mismatch);
else
read32BitIndices(stream, tris, nbIndices, data->has16BitIndices(), mismatch);
if(serialFlags & IMSF_MATERIALS)
{
PxU16* materials = data->allocateMaterials();
stream.read(materials, sizeof(PxU16)*data->mNbTriangles);
if(mismatch)
{
for(PxU32 i=0;i<data->mNbTriangles;i++)
flip(materials[i]);
}
}
if(serialFlags & IMSF_FACE_REMAP)
{
PxU32* remap = data->allocateFaceRemap();
readIndices(readDword(mismatch, stream), data->mNbTriangles, remap, stream, mismatch);
}
if(serialFlags & IMSF_ADJACENCIES)
{
PxU32* adj = data->allocateAdjacencies();
stream.read(adj, sizeof(PxU32)*data->mNbTriangles*3);
if(mismatch)
{
for(PxU32 i=0;i<data->mNbTriangles*3;i++)
flip(adj[i]);
}
}
// PT: TODO better
if(midphaseID==PxMeshMidPhase::eBVH33)
{
if(!static_cast<RTreeTriangleData*>(data)->mRTree.load(stream, version, mismatch))
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "RTree binary image load error.");
PX_DELETE(data);
return NULL;
}
}
else if(midphaseID==PxMeshMidPhase::eBVH34)
{
BV4TriangleData* bv4data = static_cast<BV4TriangleData*>(data);
if(!bv4data->mBV4Tree.load(stream, mismatch))
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "BV4 binary image load error.");
PX_DELETE(data);
return NULL;
}
bv4data->mMeshInterface.setNbTriangles(nbTris);
bv4data->mMeshInterface.setNbVertices(data->mNbVertices);
if(data->has16BitIndices())
bv4data->mMeshInterface.setPointers(NULL, reinterpret_cast<IndTri16*>(tris), verts);
else
bv4data->mMeshInterface.setPointers(reinterpret_cast<IndTri32*>(tris), NULL, verts);
bv4data->mBV4Tree.mMeshInterface = &bv4data->mMeshInterface;
}
else PX_ASSERT(0);
// Import local bounds
data->mGeomEpsilon = readFloat(mismatch, stream);
readFloatBuffer(&data->mAABB.minimum.x, 6, mismatch, stream);
PxU32 nb = readDword(mismatch, stream);
if(nb)
{
PX_ASSERT(nb==data->mNbTriangles);
data->allocateExtraTrigData();
// No need to convert those bytes
stream.read(data->mExtraTrigData, nb*sizeof(PxU8));
}
if(serialFlags & IMSF_GRB_DATA)
{
PxU32 GRB_meshAdjVerticiesTotal = 0;
if(version < 15)
GRB_meshAdjVerticiesTotal = readDword(mismatch, stream);
//read grb triangle indices
PX_ASSERT(data->mGRB_primIndices);
if(serialFlags & IMSF_8BIT_INDICES)
read8BitIndices(stream, data->mGRB_primIndices, nbIndices, data->has16BitIndices());
else if(serialFlags & IMSF_16BIT_INDICES)
read16BitIndices(stream, data->mGRB_primIndices, nbIndices, data->has16BitIndices(), mismatch);
else
read32BitIndices(stream, data->mGRB_primIndices, nbIndices, data->has16BitIndices(), mismatch);
data->mGRB_primAdjacencies = PX_ALLOCATE(PxU32, data->mNbTriangles*4, "mGRB_primAdjacencies");
data->mGRB_faceRemap = PX_ALLOCATE(PxU32, data->mNbTriangles, "mGRB_faceRemap");
if(serialFlags & IMSF_GRB_INV_REMAP)
data->mGRB_faceRemapInverse = PX_ALLOCATE(PxU32, data->mNbTriangles, "mGRB_faceRemapInverse");
stream.read(data->mGRB_primAdjacencies, sizeof(PxU32)*data->mNbTriangles*4);
if (version < 15)
{
//stream.read(data->mGRB_vertValency, sizeof(PxU32)*data->mNbVertices);
for (PxU32 i = 0; i < data->mNbVertices; ++i)
readDword(mismatch, stream);
//stream.read(data->mGRB_adjVertStart, sizeof(PxU32)*data->mNbVertices);
for (PxU32 i = 0; i < data->mNbVertices; ++i)
readDword(mismatch, stream);
//stream.read(data->mGRB_adjVertices, sizeof(PxU32)*GRB_meshAdjVerticiesTotal);
for (PxU32 i = 0; i < GRB_meshAdjVerticiesTotal; ++i)
readDword(mismatch, stream);
}
stream.read(data->mGRB_faceRemap, sizeof(PxU32)*data->mNbTriangles);
if(data->mGRB_faceRemapInverse)
stream.read(data->mGRB_faceRemapInverse, sizeof(PxU32)*data->mNbTriangles);
if(mismatch)
{
for(PxU32 i=0;i<data->mNbTriangles*4;i++)
flip(reinterpret_cast<PxU32 *>(data->mGRB_primIndices)[i]);
for(PxU32 i=0;i<data->mNbTriangles*4;i++)
flip(reinterpret_cast<PxU32 *>(data->mGRB_primAdjacencies)[i]);
}
//read BV32
data->mGRB_BV32Tree = PX_NEW(BV32Tree);
if (!data->mGRB_BV32Tree->load(stream, mismatch))
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "BV32 binary image load error.");
PX_DELETE(data);
return NULL;
}
if (serialFlags & IMSF_VERT_MAPPING)
{
//import vertex mapping data
data->mNbTrianglesReferences = readDword(mismatch, stream);
data->mAccumulatedTrianglesRef = PX_ALLOCATE(PxU32, data->mNbVertices, "mAccumulatedTrianglesRef");
data->mTrianglesReferences = PX_ALLOCATE(PxU32, data->mNbTrianglesReferences, "mTrianglesReferences");
stream.read(data->mAccumulatedTrianglesRef, data->mNbVertices * sizeof(PxU32));
stream.read(data->mTrianglesReferences, data->mNbTrianglesReferences * sizeof(PxU32));
}
}
if (serialFlags & IMSF_SDF)
{
// Import sdf
SDF& sdfData = data->mSdfData;
sdfData.mMeshLower.x = readFloat(mismatch, stream);
sdfData.mMeshLower.y = readFloat(mismatch, stream);
sdfData.mMeshLower.z = readFloat(mismatch, stream);
sdfData.mSpacing = readFloat(mismatch, stream);
sdfData.mDims.x = readDword(mismatch, stream);
sdfData.mDims.y = readDword(mismatch, stream);
sdfData.mDims.z = readDword(mismatch, stream);
sdfData.mNumSdfs = readDword(mismatch, stream);
sdfData.mNumSubgridSdfs = readDword(mismatch, stream);
sdfData.mNumStartSlots = readDword(mismatch, stream);
sdfData.mSubgridSize = readDword(mismatch, stream);
sdfData.mSdfSubgrids3DTexBlockDim.x = readDword(mismatch, stream);
sdfData.mSdfSubgrids3DTexBlockDim.y = readDword(mismatch, stream);
sdfData.mSdfSubgrids3DTexBlockDim.z = readDword(mismatch, stream);
sdfData.mSubgridsMinSdfValue = readFloat(mismatch, stream);
sdfData.mSubgridsMaxSdfValue = readFloat(mismatch, stream);
sdfData.mBytesPerSparsePixel = readDword(mismatch, stream);
PxReal* sdf = sdfData.allocateSdfs(sdfData.mMeshLower, sdfData.mSpacing, sdfData.mDims.x, sdfData.mDims.y, sdfData.mDims.z,
sdfData.mSubgridSize, sdfData.mSdfSubgrids3DTexBlockDim.x, sdfData.mSdfSubgrids3DTexBlockDim.y, sdfData.mSdfSubgrids3DTexBlockDim.z,
sdfData.mSubgridsMinSdfValue, sdfData.mSubgridsMaxSdfValue, sdfData.mBytesPerSparsePixel);
stream.read(sdf, sizeof(PxReal) * sdfData.mNumSdfs);
readByteBuffer(sdfData.mSubgridSdf, sdfData.mNumSubgridSdfs, stream);
readIntBuffer(sdfData.mSubgridStartSlots, sdfData.mNumStartSlots, mismatch, stream);
}
if (serialFlags & IMSF_INERTIA)
{
// Import inertia
stream.read(&data->mMass, sizeof(PxReal));
readFloatBuffer(&data->mInertia(0, 0), 9, mismatch, stream);
readFloatBuffer(&data->mLocalCenterOfMass.x, 3, mismatch, stream);
}
return data;
}
static void readIndices(const PxU32 serialFlags, void* indices, const PxU32 nbIndices,
const bool has16BitIndices, const bool mismatch, PxInputStream& stream)
{
if(serialFlags & IMSF_8BIT_INDICES)
read8BitIndices(stream, indices, nbIndices, has16BitIndices);
else if(serialFlags & IMSF_16BIT_INDICES)
read16BitIndices(stream, indices, nbIndices, has16BitIndices, mismatch);
else
read32BitIndices(stream, indices, nbIndices, has16BitIndices, mismatch);
}
void MeshFactory::addTriangleMesh(TriangleMesh* np, bool lock)
{
addToHash(mTriangleMeshes, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
PxTriangleMesh* MeshFactory::createTriangleMesh(TriangleMeshData& data)
{
TriangleMesh* np;
if(data.mType==PxMeshMidPhase::eBVH33)
{
PX_NEW_SERIALIZED(np, RTreeTriangleMesh)(this, data);
}
else if(data.mType==PxMeshMidPhase::eBVH34)
{
PX_NEW_SERIALIZED(np, BV4TriangleMesh)(this, data);
}
else return NULL;
if(np)
addTriangleMesh(np);
return np;
}
// data injected by cooking lib for runtime cooking
PxTriangleMesh* MeshFactory::createTriangleMesh(void* data)
{
return createTriangleMesh(*reinterpret_cast<TriangleMeshData*>(data));
}
PxTriangleMesh* MeshFactory::createTriangleMesh(PxInputStream& desc)
{
TriangleMeshData* data = ::loadMeshData(desc);
if(!data)
return NULL;
PxTriangleMesh* m = createTriangleMesh(*data);
PX_DELETE(data);
return m;
}
bool MeshFactory::removeTriangleMesh(PxTriangleMesh& m)
{
TriangleMesh* gu = static_cast<TriangleMesh*>(&m);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mTriangleMeshes.erase(gu);
return found;
}
PxU32 MeshFactory::getNbTriangleMeshes() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mTriangleMeshes.size();
}
PxU32 MeshFactory::getTriangleMeshes(PxTriangleMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mTriangleMeshes.getEntries(), mTriangleMeshes.size());
}
///////////////////////////////////////////////////////////////////////////////
static TetrahedronMeshData* loadTetrahedronMeshData(PxInputStream& stream)
{
// Import header
PxU32 version;
bool mismatch;
if (!readHeader('T', 'E', 'M', 'E', version, mismatch, stream))
return NULL;
// Import serialization flags
const PxU32 serialFlags = readDword(mismatch, stream);
TetrahedronMeshData* data = PX_NEW(TetrahedronMeshData);
// Import mesh
const PxU32 nbVerts = readDword(mismatch, stream);
PxVec3* verts = data->allocateVertices(nbVerts);
//const PxU32 nbSurfaceTriangles = readDword(mismatch, stream);
const PxU32 nbTetrahedrons = readDword(mismatch, stream);
//ML: this will allocate CPU tetrahedron indices and GPU tetrahedron indices and other GPU data if we have GRB data built
//void* tets = data->allocateTetrahedrons(nbTetrahedrons, serialFlags & IMSF_GRB_DATA);
data->allocateTetrahedrons(nbTetrahedrons, 1);
void* tets = data->mTetrahedrons;
stream.read(verts, sizeof(PxVec3)*data->mNbVertices);
//stream.read(restPoses, sizeof(PxMat33) * data->mNbTetrahedrons);
if (mismatch)
{
for (PxU32 i = 0; i < data->mNbVertices; i++)
{
flip(verts[i].x);
flip(verts[i].y);
flip(verts[i].z);
}
}
//TODO: stop support for format conversion on load!!
const PxU32 nbTetIndices = 4 * data->mNbTetrahedrons;
readIndices(serialFlags, tets, nbTetIndices, data->has16BitIndices(), mismatch, stream);
// Import local bounds
data->mGeomEpsilon = readFloat(mismatch, stream);
readFloatBuffer(&data->mAABB.minimum.x, 6, mismatch, stream);
return data;
}
static bool loadDeformableVolumeMeshData(PxInputStream& stream, DeformableVolumeMeshData& data)
{
// Import header
PxU32 version;
bool mismatch;
if (!readHeader('D', 'V', 'M', 'E', version, mismatch, stream))
return false;
// Import serialization flags
const PxU32 serialFlags = readDword(mismatch, stream);
// Import mesh
const PxU32 nbVerts = readDword(mismatch, stream);
PxVec3* verts = data.mCollisionMesh.allocateVertices(nbVerts);
//const PxU32 nbSurfaceTriangles = readDword(mismatch, stream);
const PxU32 nbTetrahedrons = readDword(mismatch, stream);
//ML: this will allocate CPU tetrahedron indices and GPU tetrahedron indices and other GPU data if we have GRB data built
//void* tets = data.allocateTetrahedrons(nbTetrahedrons, serialFlags & IMSF_GRB_DATA);
data.mCollisionMesh.allocateTetrahedrons(nbTetrahedrons, 1);
if (serialFlags & IMSF_GRB_DATA)
data.mCollisionData.allocateCollisionData(nbTetrahedrons);
void* tets = data.mCollisionMesh.mTetrahedrons;
//void* surfaceTriangles = data.mCollisionData.allocateSurfaceTriangles(nbSurfaceTriangles);
//void* restPoses = data.mTetraRestPoses;
stream.read(verts, sizeof(PxVec3)*nbVerts);
//stream.read(restPoses, sizeof(PxMat33) * data.mNbTetrahedrons);
if (mismatch)
{
for (PxU32 i = 0; i< nbVerts; i++)
{
flip(verts[i].x);
flip(verts[i].y);
flip(verts[i].z);
}
}
//TODO: stop support for format conversion on load!!
const PxU32 nbTetIndices = 4 * nbTetrahedrons;
readIndices(serialFlags, tets, nbTetIndices, data.mCollisionMesh.has16BitIndices(), mismatch, stream);
//const PxU32 nbSurfaceTriangleIndices = 3 * nbSurfaceTriangles;
//readIndices(serialFlags, surfaceTriangles, nbSurfaceTriangleIndices, data.mCollisionMesh.has16BitIndices(), mismatch, stream);
////using IMSF_ADJACENCIES for tetMesh tetrahedron surface hint
//if (serialFlags & IMSF_ADJACENCIES)
//{
// PxU8* surfaceHints = reinterpret_cast<PxU8*>(data.mTetraSurfaceHint);
// stream.read(surfaceHints, sizeof(PxU8)*data.mNbTetrahedrons);
//}
if (serialFlags & IMSF_MATERIALS)
{
PxU16* materials = data.mCollisionMesh.allocateMaterials();
stream.read(materials, sizeof(PxU16)*nbTetrahedrons);
if (mismatch)
{
for (PxU32 i = 0; i < nbTetrahedrons; i++)
flip(materials[i]);
}
}
if (serialFlags & IMSF_FACE_REMAP)
{
PxU32* remap = data.mCollisionData.allocateFaceRemap(nbTetrahedrons);
readIndices(readDword(mismatch, stream), nbTetrahedrons, remap, stream, mismatch);
}
/*if (serialFlags & IMSF_ADJACENCIES)
{
PxU32* adj = data.allocateAdjacencies();
stream.read(adj, sizeof(PxU32)*data.mNbTetrahedrons * 4);
if (mismatch)
{
for (PxU32 i = 0; i<data.mNbTetrahedrons * 4; i++)
flip(adj[i]);
}
}*/
DeformableVolumeMeshData* bv4data = &data;
if (!bv4data->mCollisionData.mBV4Tree.load(stream, mismatch))
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "BV4 binary image load error.");
//PX_DELETE(data);
return false;
}
bv4data->mCollisionData.mMeshInterface.setNbTetrahedrons(nbTetrahedrons);
bv4data->mCollisionData.mMeshInterface.setNbVertices(nbVerts);
if (data.mCollisionMesh.has16BitIndices())
bv4data->mCollisionData.mMeshInterface.setPointers(NULL, reinterpret_cast<IndTetrahedron16*>(tets), verts);
else
bv4data->mCollisionData.mMeshInterface.setPointers(reinterpret_cast<IndTetrahedron32*>(tets), NULL, verts);
bv4data->mCollisionData.mBV4Tree.mMeshInterface = &bv4data->mCollisionData.mMeshInterface;
// Import local bounds
data.mCollisionMesh.mGeomEpsilon = readFloat(mismatch, stream);
readFloatBuffer(&data.mCollisionMesh.mAABB.minimum.x, 6, mismatch, stream);
if (serialFlags & IMSF_GRB_DATA)
{
/*PxU32 GRB_meshAdjVerticiesTotal = 0;
if (version < 15)
GRB_meshAdjVerticiesTotal = readDword(mismatch, stream);*/
//read grb tetrahedron indices
PX_ASSERT(data.mCollisionData.mGRB_primIndices);
//read tetrahedron indices
readIndices(serialFlags, data.mCollisionData.mGRB_primIndices, nbTetIndices, data.mCollisionMesh.has16BitIndices(), mismatch, stream);
//data.mGRB_primAdjacencies = static_cast<void *>(PX_NEW(PxU32)[data.mNbTetrahedrons * 4]);
//data.mGRB_surfaceTriIndices = static_cast<void *>(PX_NEW(PxU32)[data.mNbTriangles * 3]);
data.mCollisionData.mGRB_faceRemap = PX_ALLOCATE(PxU32, data.mCollisionMesh.mNbTetrahedrons, "mGRB_faceRemap");
data.mCollisionData.mGRB_faceRemapInverse = PX_ALLOCATE(PxU32, data.mCollisionMesh.mNbTetrahedrons, "mGRB_faceRemapInverse");
//data.mGRB_surfaceTriangleIndice = PX_NEW(PxU32)[data.mNbSurfaceTriangles * 3];
//stream.read(data.mGRB_primAdjacencies, sizeof(PxU32)*data.mNbTetrahedrons * 4);
stream.read(data.mCollisionData.mGRB_tetraSurfaceHint, sizeof(PxU8) * data.mCollisionMesh.mNbTetrahedrons);
stream.read(data.mCollisionData.mGRB_faceRemap, sizeof(PxU32) * data.mCollisionMesh.mNbTetrahedrons);
stream.read(data.mCollisionData.mGRB_faceRemapInverse, sizeof(PxU32) * data.mCollisionMesh.mNbTetrahedrons);
//stream.read(data.mGRB_surfaceTriangleIndice, sizeof(PxU32) * data.mNbSurfaceTriangles * 3);
stream.read(data.mCollisionData.mTetraRestPoses, sizeof(PxMat33) * nbTetrahedrons);
if (mismatch)
{
for (PxU32 i = 0; i<data.mCollisionMesh.mNbTetrahedrons * 4; i++)
flip(reinterpret_cast<PxU32 *>(data.mCollisionData.mGRB_primIndices)[i]);
}
//read BV32
data.mCollisionData.mGRB_BV32Tree = PX_NEW(BV32Tree);
if (!data.mCollisionData.mGRB_BV32Tree->load(stream, mismatch))
{
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "BV32 binary image load error.");
//PX_DELETE(data);
return false;
}
const PxU32 nbGridModelTetrahedrons = readDword(mismatch, stream);
const PxU32 nbGridModelVertices = readDword(mismatch, stream);
const PxU32 nbGridModelPartitions = readDword(mismatch, stream);
const PxU32 nbGMMaxTetsPerPartition = readDword(mismatch, stream);
const PxU32 nbGMRemapOutputSize = readDword(mismatch, stream);
PxU32 numTetsPerElement = 1;
if(version >= 2)
numTetsPerElement = readDword(mismatch, stream);
const PxU32 nbGMTotalTetReferenceCount = readDword(mismatch, stream);
const PxU32 nbTetRemapSize = readDword(mismatch, stream);
const PxU32 numVertsPerElement = (numTetsPerElement == 5 || numTetsPerElement == 6) ? 8 : 4;
const PxU32 numElements = nbGridModelTetrahedrons / numTetsPerElement;
data.mSimulationData.mGridModelMaxTetsPerPartitions = nbGMMaxTetsPerPartition;
data.mSimulationData.mNumTetsPerElement = numTetsPerElement;
data.mMappingData.mTetsRemapSize = nbTetRemapSize;
data.mSimulationMesh.allocateTetrahedrons(nbGridModelTetrahedrons, serialFlags & IMSF_GRB_DATA);
data.mSimulationMesh.allocateVertices(nbGridModelVertices, serialFlags & IMSF_GRB_DATA);
data.mSimulationData.allocateGridModelData(nbGridModelTetrahedrons, nbGridModelVertices,
data.mCollisionMesh.mNbVertices, nbGridModelPartitions, nbGMRemapOutputSize, numTetsPerElement, serialFlags & IMSF_GRB_DATA);
data.mMappingData.allocatemappingData(data.mCollisionMesh.mNbVertices, nbTetRemapSize, data.mCollisionMesh.mNbTetrahedrons, serialFlags & IMSF_GRB_DATA);
data.mMappingData.allocateTetRefData(nbGMTotalTetReferenceCount, data.mCollisionMesh.mNbVertices, serialFlags & IMSF_GRB_DATA);
const PxU32 nbGridModelIndices = 4 * nbGridModelTetrahedrons;
readIndices(serialFlags, data.mSimulationMesh.mTetrahedrons, nbGridModelIndices, data.mSimulationMesh.has16BitIndices(), mismatch, stream);
//stream.read(data.mGridModelVerticesInvMass, sizeof(PxVec4) * nbGridModelVertices);
stream.read(data.mSimulationMesh.mVertices, sizeof(PxVec3) * nbGridModelVertices);
if (serialFlags & IMSF_MATERIALS)
{
PxU16* materials = data.mSimulationMesh.allocateMaterials();
stream.read(materials, sizeof(PxU16)*nbGridModelTetrahedrons);
if (mismatch)
{
for (PxU32 i = 0; i < nbTetrahedrons; i++)
flip(materials[i]);
}
}
stream.read(data.mSimulationData.mGridModelInvMass, sizeof(PxReal) * nbGridModelVertices);
stream.read(data.mSimulationData.mGridModelTetraRestPoses, sizeof(PxMat33) * nbGridModelTetrahedrons);
stream.read(data.mSimulationData.mGridModelOrderedTetrahedrons, sizeof(PxU32) * numElements);
if (data.mSimulationData.mGMRemapOutputSize) // tet mesh only (or old hex mesh)
{
stream.read(data.mSimulationData.mGMRemapOutputCP, sizeof(PxU32) * numElements * numVertsPerElement);
}
stream.read(data.mSimulationData.mGMAccumulatedPartitionsCP, sizeof(PxU32) * nbGridModelPartitions);
if (data.mSimulationData.mGMRemapOutputSize) // tet mesh only (or old hex mesh)
{
stream.read(data.mSimulationData.mGMAccumulatedCopiesCP, sizeof(PxU32) * data.mSimulationMesh.mNbVertices);
}
stream.read(data.mMappingData.mCollisionAccumulatedTetrahedronsRef, sizeof(PxU32) * data.mCollisionMesh.mNbVertices);
stream.read(data.mMappingData.mCollisionTetrahedronsReferences, sizeof(PxU32) * data.mMappingData.mCollisionNbTetrahedronsReferences);
stream.read(data.mMappingData.mCollisionSurfaceVertsHint, sizeof(PxU8) * data.mCollisionMesh.mNbVertices);
stream.read(data.mMappingData.mCollisionSurfaceVertToTetRemap, sizeof(PxU32) * data.mCollisionMesh.mNbVertices);
//stream.read(data->mVertsBarycentricInGridModel, sizeof(PxReal) * 4 * data->mNbVertices);
stream.read(data.mSimulationData.mGMPullIndices, sizeof(PxU32) * numElements * numVertsPerElement);
//stream.read(data->mVertsBarycentricInGridModel, sizeof(PxReal) * 4 * data->mNbVertices);
stream.read(data.mMappingData.mVertsBarycentricInGridModel, sizeof(PxReal) * 4 * data.mCollisionMesh.mNbVertices);
stream.read(data.mMappingData.mVertsRemapInGridModel, sizeof(PxU32) * data.mCollisionMesh.mNbVertices);
stream.read(data.mMappingData.mTetsRemapColToSim, sizeof(PxU32) *nbTetRemapSize);
stream.read(data.mMappingData.mTetsAccumulatedRemapColToSim, sizeof(PxU32) * data.mCollisionMesh.mNbTetrahedrons);
}
return true;
}
void MeshFactory::addTetrahedronMesh(TetrahedronMesh* np, bool lock)
{
addToHash(mTetrahedronMeshes, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
void MeshFactory::addDeformableVolumeMesh(DeformableVolumeMesh* np, bool lock)
{
addToHash(mDeformableVolumeMeshes, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
PxDeformableVolumeMesh* MeshFactory::createDeformableVolumeMesh(PxInputStream& desc)
{
TetrahedronMeshData mSimulationMesh;
DeformableVolumeSimulationData mSimulationData;
TetrahedronMeshData mCollisionMesh;
DeformableVolumeCollisionData mCollisionData;
CollisionMeshMappingData mMappingData;
DeformableVolumeMeshData data(mSimulationMesh, mSimulationData, mCollisionMesh, mCollisionData, mMappingData);
if (!::loadDeformableVolumeMeshData(desc, data))
return NULL;
PxDeformableVolumeMesh* m = createDeformableVolumeMesh(data);
return m;
}
PxTetrahedronMesh* MeshFactory::createTetrahedronMesh(PxInputStream& desc)
{
TetrahedronMeshData* data = ::loadTetrahedronMeshData(desc);
if (!data)
return NULL;
PxTetrahedronMesh* m = createTetrahedronMesh(*data);
PX_DELETE(data);
return m;
}
PxTetrahedronMesh* MeshFactory::createTetrahedronMesh(TetrahedronMeshData& data)
{
TetrahedronMesh* np = NULL;
PX_NEW_SERIALIZED(np, TetrahedronMesh)(this, data);
if (np)
addTetrahedronMesh(np);
return np;
}
// data injected by cooking lib for runtime cooking
PxTetrahedronMesh* MeshFactory::createTetrahedronMesh(void* data)
{
return createTetrahedronMesh(*reinterpret_cast<TetrahedronMeshData*>(data));
}
PxDeformableVolumeMesh* MeshFactory::createDeformableVolumeMesh(Gu::DeformableVolumeMeshData& data)
{
DeformableVolumeMesh* np = NULL;
PX_NEW_SERIALIZED(np, DeformableVolumeMesh)(this, data);
if (np)
addDeformableVolumeMesh(np);
return np;
}
// data injected by cooking lib for runtime cooking
PxDeformableVolumeMesh* MeshFactory::createDeformableVolumeMesh(void* data)
{
return createDeformableVolumeMesh(*reinterpret_cast<DeformableVolumeMeshData*>(data));
}
bool MeshFactory::removeDeformableVolumeMesh(PxDeformableVolumeMesh& tetMesh)
{
DeformableVolumeMesh* gu = static_cast<DeformableVolumeMesh*>(&tetMesh);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mDeformableVolumeMeshes.erase(gu);
return found;
}
bool MeshFactory::removeTetrahedronMesh(PxTetrahedronMesh& tetMesh)
{
TetrahedronMesh* gu = static_cast<TetrahedronMesh*>(&tetMesh);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mTetrahedronMeshes.erase(gu);
return found;
}
PxU32 MeshFactory::getNbDeformableVolumeMeshes() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mDeformableVolumeMeshes.size();
}
PxU32 MeshFactory::getNbTetrahedronMeshes() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mTetrahedronMeshes.size();
}
PxU32 MeshFactory::getTetrahedronMeshes(PxTetrahedronMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mTetrahedronMeshes.getEntries(), mTetrahedronMeshes.size());
}
PxU32 MeshFactory::getDeformableVolumeMeshes(PxDeformableVolumeMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mDeformableVolumeMeshes.getEntries(), mDeformableVolumeMeshes.size());
}
///////////////////////////////////////////////////////////////////////////////
void MeshFactory::addConvexMesh(ConvexMesh* np, bool lock)
{
addToHash(mConvexMeshes, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
// data injected by cooking lib for runtime cooking
PxConvexMesh* MeshFactory::createConvexMesh(void* data)
{
return createConvexMesh(*reinterpret_cast<ConvexHullInitData*>(data));
}
PxConvexMesh* MeshFactory::createConvexMesh(ConvexHullInitData& data)
{
ConvexMesh* np;
PX_NEW_SERIALIZED(np, ConvexMesh)(this, data);
if (np)
addConvexMesh(np);
return np;
}
PxConvexMesh* MeshFactory::createConvexMesh(PxInputStream& desc)
{
ConvexMesh* np;
PX_NEW_SERIALIZED(np, ConvexMesh)(this);
if(!np)
return NULL;
if(!np->load(desc))
{
Cm::deletePxBase(np);
return NULL;
}
addConvexMesh(np);
return np;
}
bool MeshFactory::removeConvexMesh(PxConvexMesh& m)
{
ConvexMesh* gu = static_cast<ConvexMesh*>(&m);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mConvexMeshes.erase(gu);
return found;
}
PxU32 MeshFactory::getNbConvexMeshes() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mConvexMeshes.size();
}
PxU32 MeshFactory::getConvexMeshes(PxConvexMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mConvexMeshes.getEntries(), mConvexMeshes.size());
}
///////////////////////////////////////////////////////////////////////////////
void MeshFactory::addHeightField(HeightField* np, bool lock)
{
addToHash(mHeightFields, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
PxHeightField* MeshFactory::createHeightField(void* heightFieldMeshData)
{
HeightField* np;
PX_NEW_SERIALIZED(np, HeightField)(this, *reinterpret_cast<HeightFieldData*>(heightFieldMeshData));
if(np)
addHeightField(np);
return np;
}
PxHeightField* MeshFactory::createHeightField(PxInputStream& stream)
{
HeightField* np;
PX_NEW_SERIALIZED(np, HeightField)(this);
if(!np)
return NULL;
if(!np->load(stream))
{
Cm::deletePxBase(np);
return NULL;
}
addHeightField(np);
return np;
}
bool MeshFactory::removeHeightField(PxHeightField& hf)
{
HeightField* gu = static_cast<HeightField*>(&hf);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mHeightFields.erase(gu);
return found;
}
PxU32 MeshFactory::getNbHeightFields() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mHeightFields.size();
}
PxU32 MeshFactory::getHeightFields(PxHeightField** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mHeightFields.getEntries(), mHeightFields.size());
}
///////////////////////////////////////////////////////////////////////////////
void MeshFactory::addFactoryListener(Gu::MeshFactoryListener& listener )
{
PxMutex::ScopedLock lock(mTrackingMutex);
mFactoryListeners.pushBack( &listener );
}
void MeshFactory::removeFactoryListener(Gu::MeshFactoryListener& listener )
{
PxMutex::ScopedLock lock(mTrackingMutex);
for ( PxU32 idx = 0; idx < mFactoryListeners.size(); ++idx )
{
if ( mFactoryListeners[idx] == &listener )
{
mFactoryListeners.replaceWithLast( idx );
--idx;
}
}
}
void MeshFactory::notifyFactoryListener(const PxBase* base, PxType typeID)
{
const PxU32 nbListeners = mFactoryListeners.size();
for(PxU32 i=0; i<nbListeners; i++)
mFactoryListeners[i]->onMeshFactoryBufferRelease(base, typeID);
}
#if PX_SUPPORT_OMNI_PVD
void MeshFactory::notifyListenersAdd(const PxBase* base)
{
for (PxU32 i = 0; i < mFactoryListeners.size(); i++)
mFactoryListeners[i]->onObjectAdd(base);
}
void MeshFactory::notifyListenersRemove(const PxBase* base)
{
for (PxU32 i = 0; i < mFactoryListeners.size(); i++)
mFactoryListeners[i]->onObjectRemove(base);
}
#endif
///////////////////////////////////////////////////////////////////////////////
void MeshFactory::addBVH(BVH* np, bool lock)
{
addToHash(mBVHs, np, lock ? &mTrackingMutex : NULL);
OMNI_PVD_NOTIFY_ADD(np);
}
// data injected by cooking lib for runtime cooking
PxBVH* MeshFactory::createBVH(void* data)
{
return createBVH(*reinterpret_cast<BVHData*>(data));
}
PxBVH* MeshFactory::createBVH(BVHData& data)
{
BVH* np;
PX_NEW_SERIALIZED(np, BVH)(this, data);
if (np)
addBVH(np);
return np;
}
PxBVH* MeshFactory::createBVH(PxInputStream& desc)
{
BVH* np;
PX_NEW_SERIALIZED(np, BVH)(this);
if(!np)
return NULL;
if(!np->load(desc))
{
Cm::deletePxBase(np);
return NULL;
}
addBVH(np);
return np;
}
bool MeshFactory::removeBVH(PxBVH& m)
{
BVH* gu = static_cast<BVH*>(&m);
OMNI_PVD_NOTIFY_REMOVE(gu);
PxMutex::ScopedLock lock(mTrackingMutex);
bool found = mBVHs.erase(gu);
return found;
}
PxU32 MeshFactory::getNbBVHs() const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return mBVHs.size();
}
PxU32 MeshFactory::getBVHs(PxBVH** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
{
PxMutex::ScopedLock lock(mTrackingMutex);
return getArrayOfPointers(userBuffer, bufferSize, startIndex, mBVHs.getEntries(), mBVHs.size());
}
///////////////////////////////////////////////////////////////////////////////
bool MeshFactory::remove(PxBase& obj)
{
const PxType type = obj.getConcreteType();
if(type==PxConcreteType::eHEIGHTFIELD)
return removeHeightField(static_cast<PxHeightField&>(obj));
else if(type==PxConcreteType::eCONVEX_MESH)
return removeConvexMesh(static_cast<PxConvexMesh&>(obj));
else if(type==PxConcreteType::eTRIANGLE_MESH_BVH33 || type==PxConcreteType::eTRIANGLE_MESH_BVH34)
return removeTriangleMesh(static_cast<PxTriangleMesh&>(obj));
else if(type==PxConcreteType::eTETRAHEDRON_MESH)
return removeTetrahedronMesh(static_cast<PxTetrahedronMesh&>(obj));
else if (type == PxConcreteType::eDEFORMABLE_VOLUME_MESH)
return removeDeformableVolumeMesh(static_cast<PxDeformableVolumeMesh&>(obj));
else if(type==PxConcreteType::eBVH)
return removeBVH(static_cast<PxBVH&>(obj));
return false;
}
///////////////////////////////////////////////////////////////////////////////
namespace
{
class StandaloneInsertionCallback : public PxInsertionCallback
{
public:
StandaloneInsertionCallback() {}
virtual PxBase* buildObjectFromData(PxConcreteType::Enum type, void* data)
{
if(type == PxConcreteType::eTRIANGLE_MESH_BVH33)
{
TriangleMesh* np;
PX_NEW_SERIALIZED(np, RTreeTriangleMesh)(NULL, *reinterpret_cast<TriangleMeshData*>(data));
return np;
}
if(type == PxConcreteType::eTRIANGLE_MESH_BVH34)
{
TriangleMesh* np;
PX_NEW_SERIALIZED(np, BV4TriangleMesh)(NULL, *reinterpret_cast<TriangleMeshData*>(data));
return np;
}
if(type == PxConcreteType::eCONVEX_MESH)
{
ConvexMesh* np;
PX_NEW_SERIALIZED(np, ConvexMesh)(NULL, *reinterpret_cast<ConvexHullInitData*>(data));
return np;
}
if(type == PxConcreteType::eHEIGHTFIELD)
{
HeightField* np;
PX_NEW_SERIALIZED(np, HeightField)(NULL, *reinterpret_cast<HeightFieldData*>(data));
return np;
}
if(type == PxConcreteType::eBVH)
{
BVH* np;
PX_NEW_SERIALIZED(np, BVH)(NULL, *reinterpret_cast<BVHData*>(data));
return np;
}
if (type == PxConcreteType::eTETRAHEDRON_MESH)
{
TetrahedronMesh* np;
PX_NEW_SERIALIZED(np, TetrahedronMesh)(NULL, *reinterpret_cast<TetrahedronMeshData*>(data));
return np;
}
if (type == PxConcreteType::eDEFORMABLE_VOLUME_MESH)
{
DeformableVolumeMesh* np;
PX_NEW_SERIALIZED(np, DeformableVolumeMesh)(NULL, *reinterpret_cast<DeformableVolumeMeshData*>(data));
return np;
}
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "Inserting object failed: "
"Object type not supported for buildObjectFromData.");
return NULL;
}
}gSAIC;
}
PxInsertionCallback* physx::immediateCooking::getInsertionCallback()
{
return &gSAIC;
}