aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp687
1 files changed, 687 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp b/PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp
new file mode 100644
index 00000000..82cd556f
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/GuMeshFactory.cpp
@@ -0,0 +1,687 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 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 "PsIntrinsics.h"
+#include "GuMeshFactory.h"
+#include "PxHeightFieldDesc.h"
+#include "GuTriangleMesh.h"
+#include "GuTriangleMeshBV4.h"
+#include "GuTriangleMeshRTree.h"
+#include "GuConvexMesh.h"
+#include "GuHeightField.h"
+#include "GuConvexMeshData.h"
+#include "CmUtils.h"
+#include "GuMeshData.h"
+#include "PsFoundation.h"
+
+#if PX_SUPPORT_GPU_PHYSX
+ #define GU_MESH_FACTORY_GPU_NOTIFICATION(notificationMethod, argument) notificationMethod(argument);
+#else
+ #define GU_MESH_FACTORY_GPU_NOTIFICATION(notificationMethod, argument)
+#endif
+
+using namespace physx;
+using namespace Gu;
+
+// PT: TODO: refactor all this with a dedicated container
+
+GuMeshFactory::GuMeshFactory()
+: mTriangleMeshes (PX_DEBUG_EXP("mesh factory triangle mesh hash"))
+, mConvexMeshes (PX_DEBUG_EXP("mesh factory convex mesh hash"))
+, mHeightFields (PX_DEBUG_EXP("mesh factory height field hash"))
+, mFactoryListeners(PX_DEBUG_EXP("FactoryListeners"))
+
+{
+}
+
+GuMeshFactory::~GuMeshFactory()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GuMeshFactory::release()
+{
+ // Release all objects in case the user didn't do it
+
+ while(mTriangleMeshes.size())
+ {
+ Gu::TriangleMesh* mesh = mTriangleMeshes.getEntries()[0];
+ PX_ASSERT(mesh->getRefCount()==1);
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseTriangleMesh, *mesh);
+ mesh->release();
+ }
+
+ while(mConvexMeshes.size())
+ {
+ Gu::ConvexMesh* mesh = mConvexMeshes.getEntries()[0];
+ PX_ASSERT(mesh->getRefCount()==1);
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseConvexMesh, *mesh);
+ mesh->release();
+ }
+
+ while(mHeightFields.size())
+ {
+ Gu::HeightField* mesh = mHeightFields.getEntries()[0];
+ PX_ASSERT(mesh->getRefCount()==1);
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseHeightField, *mesh);
+ mesh->release();
+ }
+
+ PX_DELETE(this);
+}
+
+namespace
+{
+ template<typename TDataType>
+ inline void notifyReleaseFactoryItem( Ps::Array<GuMeshFactoryListener*>& listeners, const TDataType* type, PxType typeID)
+ {
+ PxU32 numListeners = listeners.size();
+ for ( PxU32 idx = 0; idx < numListeners; ++idx )
+ listeners[idx]->onGuMeshFactoryBufferRelease( type, typeID);
+ }
+
+ template <typename T> void addToHash(Ps::CoalescedHashSet<T*>& hash, T* element, Ps::Mutex* mutex)
+ {
+ if(!element)
+ return;
+
+ if(mutex)
+ mutex->lock();
+
+ hash.insert(element);
+
+ if(mutex)
+ mutex->unlock();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GuMeshFactory::addTriangleMesh(TriangleMesh* np, bool lock)
+{
+ addToHash(mTriangleMeshes, np, lock ? &mTrackingMutex : NULL);
+}
+
+PxTriangleMesh* GuMeshFactory::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* GuMeshFactory::createTriangleMesh(void* data)
+{
+ return createTriangleMesh(*reinterpret_cast<TriangleMeshData*>(data));
+}
+
+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
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __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);
+ 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)
+ {
+ PxU8 x;
+ if(data->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;
+ }
+ }
+ }
+ else if(serialFlags & IMSF_16BIT_INDICES)
+ {
+ if(data->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;
+ }
+ }
+
+ }
+ else
+ {
+ if(data->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++ = Ps::to16(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]);
+ }
+ }
+ }
+
+ 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))
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __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, version))
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __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);
+ data->mAABB.minimum.x = readFloat(mismatch, stream);
+ data->mAABB.minimum.y = readFloat(mismatch, stream);
+ data->mAABB.minimum.z = readFloat(mismatch, stream);
+ data->mAABB.maximum.x = readFloat(mismatch, stream);
+ data->mAABB.maximum.y = readFloat(mismatch, stream);
+ data->mAABB.maximum.z = readFloat(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)
+ {
+ data->mGRB_meshAdjVerticiesTotal = readDword(mismatch, stream);
+
+
+ //read grb triangle indices
+ PX_ASSERT(data->mGRB_triIndices);
+
+ if (serialFlags & IMSF_8BIT_INDICES)
+ {
+ PxU8 x;
+ if (data->has16BitIndices())
+ {
+ PxU16* tris16 = reinterpret_cast<PxU16*>(data->mGRB_triIndices);
+ for (PxU32 i = 0; i<nbIndices; i++)
+ {
+ stream.read(&x, sizeof(PxU8));
+ *tris16++ = x;
+ }
+ }
+ else
+ {
+ PxU32* tris32 = reinterpret_cast<PxU32*>(data->mGRB_triIndices);
+ for (PxU32 i = 0; i<nbIndices; i++)
+ {
+ stream.read(&x, sizeof(PxU8));
+ *tris32++ = x;
+ }
+ }
+ }
+ else if (serialFlags & IMSF_16BIT_INDICES)
+ {
+ if (data->has16BitIndices())
+ {
+ PxU16* tris16 = reinterpret_cast<PxU16*>(data->mGRB_triIndices);
+ stream.read(tris16, nbIndices*sizeof(PxU16));
+ if (mismatch)
+ {
+ for (PxU32 i = 0; i<nbIndices; i++)
+ flip(tris16[i]);
+ }
+ }
+ else
+ {
+ PxU32* tris32 = reinterpret_cast<PxU32*>(data->mGRB_triIndices);
+ PxU16 x;
+ for (PxU32 i = 0; i<nbIndices; i++)
+ {
+ stream.read(&x, sizeof(PxU16));
+ if (mismatch)
+ flip(x);
+
+ *tris32++ = x;
+ }
+ }
+
+ }
+ else
+ {
+ if (data->has16BitIndices())
+ {
+ PxU32 x;
+ PxU16* tris16 = reinterpret_cast<PxU16*>(data->mGRB_triIndices);
+ for (PxU32 i = 0; i<nbIndices; i++)
+ {
+ stream.read(&x, sizeof(PxU32));
+ if (mismatch)
+ flip(x);
+ *tris16++ = Ps::to16(x);
+ }
+ }
+ else
+ {
+ PxU32* tris32 = reinterpret_cast<PxU32*>(data->mGRB_triIndices);
+ stream.read(tris32, nbIndices*sizeof(PxU32));
+
+ if (mismatch)
+ {
+ for (PxU32 i = 0; i<nbIndices; i++)
+ flip(tris32[i]);
+ }
+ }
+ }
+
+
+ data->mGRB_triAdjacencies = static_cast<void *>(PX_NEW(PxU32)[data->mNbTriangles*4]);
+ data->mGRB_vertValency = PX_NEW(PxU32)[data->mNbVertices];
+ data->mGRB_adjVertStart = PX_NEW(PxU32)[data->mNbVertices];
+ data->mGRB_adjVertices = PX_NEW(PxU32)[data->mGRB_meshAdjVerticiesTotal];
+ data->mGRB_faceRemap = PX_NEW(PxU32)[data->mNbTriangles];
+
+ stream.read(data->mGRB_triAdjacencies, sizeof(PxU32)*data->mNbTriangles*4);
+ stream.read(data->mGRB_vertValency, sizeof(PxU32)*data->mNbVertices);
+ stream.read(data->mGRB_adjVertStart, sizeof(PxU32)*data->mNbVertices);
+ stream.read(data->mGRB_adjVertices, sizeof(PxU32)*data->mGRB_meshAdjVerticiesTotal);
+ stream.read(data->mGRB_faceRemap, sizeof(PxU32)*data->mNbTriangles);
+
+ if(mismatch)
+ {
+ for(PxU32 i=0;i<data->mNbTriangles*4;i++)
+ flip(reinterpret_cast<PxU32 *>(data->mGRB_triIndices)[i]);
+
+ for(PxU32 i=0;i<data->mNbTriangles*4;i++)
+ flip(reinterpret_cast<PxU32 *>(data->mGRB_triAdjacencies)[i]);
+ for(PxU32 i=0;i<data->mNbVertices;i++)
+ {
+ flip(data->mGRB_vertValency[i]);
+ flip(data->mGRB_adjVertStart[i]);
+ }
+ for(PxU32 i=0;i<data->mGRB_meshAdjVerticiesTotal;i++)
+ flip(data->mGRB_adjVertices[i]);
+
+ }
+
+ //read BV32
+ data->mGRB_BV32Tree = PX_NEW(BV32Tree);
+ BV32Tree* bv32Tree = static_cast<BV32Tree*>(data->mGRB_BV32Tree);
+ if (!bv32Tree->load(stream, version))
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "BV32 binary image load error.");
+ PX_DELETE(data);
+ return NULL;
+ }
+ }
+
+ return data;
+}
+
+PxTriangleMesh* GuMeshFactory::createTriangleMesh(PxInputStream& desc)
+{
+ TriangleMeshData* data = ::loadMeshData(desc);
+ if(!data)
+ return NULL;
+ PxTriangleMesh* m = createTriangleMesh(*data);
+ PX_DELETE(data);
+ return m;
+}
+
+bool GuMeshFactory::removeTriangleMesh(PxTriangleMesh& m)
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ TriangleMesh* gu = static_cast<TriangleMesh*>(&m);
+
+ bool found = mTriangleMeshes.erase(gu);
+
+ if(found)
+ {
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseTriangleMesh, m)
+ }
+
+ return found;
+}
+
+PxU32 GuMeshFactory::getNbTriangleMeshes() const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return mTriangleMeshes.size();
+}
+
+PxU32 GuMeshFactory::getTriangleMeshes(PxTriangleMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mTriangleMeshes.getEntries(), mTriangleMeshes.size());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GuMeshFactory::addConvexMesh(ConvexMesh* np, bool lock)
+{
+ addToHash(mConvexMeshes, np, lock ? &mTrackingMutex : NULL);
+}
+
+// data injected by cooking lib for runtime cooking
+PxConvexMesh* GuMeshFactory::createConvexMesh(void* data)
+{
+ return createConvexMesh(*reinterpret_cast<Gu::ConvexHullData*>(data));
+}
+
+PxConvexMesh* GuMeshFactory::createConvexMesh(Gu::ConvexHullData& data)
+{
+ Gu::ConvexMesh *np;
+ PX_NEW_SERIALIZED(np, Gu::ConvexMesh)(*this, data);
+ if (np)
+ addConvexMesh(np);
+
+ return np;
+}
+
+PxConvexMesh* GuMeshFactory::createConvexMesh(PxInputStream& desc)
+{
+ ConvexMesh* np;
+ PX_NEW_SERIALIZED(np, ConvexMesh);
+ if(!np)
+ return NULL;
+
+ np->setMeshFactory(this);
+
+ if(!np->load(desc))
+ {
+ np->decRefCount();
+ return NULL;
+ }
+
+ addConvexMesh(np);
+ return np;
+}
+
+bool GuMeshFactory::removeConvexMesh(PxConvexMesh& m)
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ ConvexMesh* gu = static_cast<ConvexMesh*>(&m);
+
+ bool found = mConvexMeshes.erase(gu);
+ if(found)
+ {
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseConvexMesh, m)
+ }
+
+ return found;
+}
+
+PxU32 GuMeshFactory::getNbConvexMeshes() const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return mConvexMeshes.size();
+}
+
+PxU32 GuMeshFactory::getConvexMeshes(PxConvexMesh** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mConvexMeshes.getEntries(), mConvexMeshes.size());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GuMeshFactory::addHeightField(HeightField* np, bool lock)
+{
+ addToHash(mHeightFields, np, lock ? &mTrackingMutex : NULL);
+}
+
+PxHeightField* GuMeshFactory::createHeightField(void* heightFieldMeshData)
+{
+ HeightField* np;
+ PX_NEW_SERIALIZED(np, HeightField)(*this, *reinterpret_cast<Gu::HeightFieldData*>(heightFieldMeshData));
+ if(np)
+ addHeightField(np);
+
+ return np;
+}
+
+PxHeightField* GuMeshFactory::createHeightField(PxInputStream& stream)
+{
+ HeightField* np;
+ PX_NEW_SERIALIZED(np, HeightField)(this);
+ if(!np)
+ return NULL;
+
+ if(!np->load(stream))
+ {
+ np->decRefCount();
+ return NULL;
+ }
+
+ addHeightField(np);
+ return np;
+}
+
+bool GuMeshFactory::removeHeightField(PxHeightField& hf)
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ HeightField* gu = static_cast<HeightField*>(&hf);
+
+ bool found = mHeightFields.erase(gu);
+ if(found)
+ {
+ GU_MESH_FACTORY_GPU_NOTIFICATION(notifyReleaseHeightField, hf)
+ }
+
+ return found;
+}
+
+PxU32 GuMeshFactory::getNbHeightFields() const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return mHeightFields.size();
+}
+
+PxU32 GuMeshFactory::getHeightFields(PxHeightField** userBuffer, PxU32 bufferSize, PxU32 startIndex) const
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ return Cm::getArrayOfPointers(userBuffer, bufferSize, startIndex, mHeightFields.getEntries(), mHeightFields.size());
+}
+
+void GuMeshFactory::addFactoryListener( GuMeshFactoryListener& listener )
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ mFactoryListeners.pushBack( &listener );
+}
+
+void GuMeshFactory::removeFactoryListener( GuMeshFactoryListener& listener )
+{
+ Ps::Mutex::ScopedLock lock(mTrackingMutex);
+ for ( PxU32 idx = 0; idx < mFactoryListeners.size(); ++idx )
+ {
+ if ( mFactoryListeners[idx] == &listener )
+ {
+ mFactoryListeners.replaceWithLast( idx );
+ --idx;
+ }
+ }
+}
+
+void GuMeshFactory::notifyFactoryListener(const PxBase* base, PxType typeID)
+{
+ notifyReleaseFactoryItem(mFactoryListeners, base, typeID);
+}
+
+///////////////////////////////////////////////////////////////////////////////