diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp index 654e6184..a5793e53 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp @@ -42,6 +42,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plPXPhysical.h" #include "NxPhysics.h" +#include "NxCooking.h" #include "hsResMgr.h" #include "hsStream.h" @@ -1060,12 +1061,10 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr) } else { - // Read in the cooked mesh - plPXStream pxs(stream); if (recipe.bounds == plSimDefs::kHullBounds) - recipe.convexMesh = plSimulationMgr::GetInstance()->GetSDK()->createConvexMesh(pxs); + recipe.convexMesh = IReadHull(stream); else - recipe.triMesh = plSimulationMgr::GetInstance()->GetSDK()->createTriangleMesh(pxs); + recipe.triMesh = IReadTriMesh(stream); } Init(recipe); @@ -1123,11 +1122,107 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr) fProxyGen->Init(this); } +static bool IIsNxStream(hsStream* s) +{ + char tag[4]; + s->Read(sizeof(tag), tag); + + // PhysX streams begin with the magic string "NXS\x01" + // Our hacked streams begin with the magic string "HSP\x01" + if (memcmp("HSP\x01", tag, sizeof(tag)) == 0) + return false; + + // We're not going to compare to see if it says NXS. We will let the PhysX SDK + // worry about garbage data. Just rewind the stream back so PhysX can deal with it. + s->SetPosition(s->GetPosition() - sizeof(tag)); + return true; +} + +NxConvexMesh* plPXPhysical::IReadHull(hsStream* s) +{ + if (IIsNxStream(s)) + { + plPXStream pxs(s); + return plSimulationMgr::GetInstance()->GetSDK()->createConvexMesh(pxs); + } + else + { + std::vector verts; + verts.resize(s->ReadSwap32()); + for (size_t i = 0; i < verts.size(); ++i) + verts[i].Read(s); + + // Unfortunately, the only way I know of to accomplish this is to cook to a RAM stream, + // then have PhysX read the cooked data from the RAM stream. Yes, this is very sad. + // I blame PhysX. It needs to die in a fiaaaaaaaaaaah + hsRAMStream ram; + plPXStream pxs(&ram); + + NxConvexMeshDesc desc; + desc.numVertices = verts.size(); + desc.pointStrideBytes = sizeof(hsPoint3); + desc.points = &verts[0]; + desc.flags = NX_CF_COMPUTE_CONVEX | NX_CF_USE_UNCOMPRESSED_NORMALS; + if (!NxCookConvexMesh(desc, pxs)) + { + SimLog("Failed to cook hull for '%s'", GetKeyName()); + return NULL; + } + + ram.Rewind(); + return plSimulationMgr::GetInstance()->GetSDK()->createConvexMesh(pxs); + } +} + +NxTriangleMesh* plPXPhysical::IReadTriMesh(hsStream* s) +{ + if (IIsNxStream(s)) + { + plPXStream pxs(s); + return plSimulationMgr::GetInstance()->GetSDK()->createTriangleMesh(pxs); + } + else + { + std::vector verts; + verts.resize(s->ReadSwap32()); + for (size_t i = 0; i < verts.size(); ++i) + verts[i].Read(s); + std::vector indices; + UInt32 numTriangles = s->ReadSwap32(); + indices.resize(numTriangles * 3); + for (size_t i = 0; i < indices.size(); ++i) + indices[i] = s->ReadSwap32(); + + // Unfortunately, the only way I know of to accomplish this is to cook to a RAM stream, + // then have PhysX read the cooked data from the RAM stream. Yes, this is very sad. + // I blame PhysX. It needs to die in a fiaaaaaaaaaaah + hsRAMStream ram; + plPXStream pxs(&ram); + + NxTriangleMeshDesc desc; + desc.numVertices = verts.size(); + desc.pointStrideBytes = sizeof(hsPoint3); + desc.points = &verts[0]; + desc.numTriangles = numTriangles; + desc.triangleStrideBytes = sizeof(UInt32) * 3; + desc.triangles = &indices[0]; + desc.flags = 0; + if (!NxCookTriangleMesh(desc, pxs)) + { + SimLog("Failed to cook trimesh for '%s'", GetKeyName()); + return NULL; + } + + ram.Rewind(); + return plSimulationMgr::GetInstance()->GetSDK()->createTriangleMesh(pxs); + } +} + void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr) { plPhysical::Write(stream, mgr); - hsAssert(fActor, "nil actor"); + hsAssert(fActor, "nil actor"); hsAssert(fActor->getNbShapes() == 1, "Can only write actors with one shape. Writing first only."); NxShape* shape = fActor->getShapes()[0]; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h index 5dc56c79..7ae2ef2d 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h @@ -193,6 +193,9 @@ public: virtual hsScalar GetMass() {return fMass;} protected: + class NxConvexMesh* IReadHull(hsStream* s); + class NxTriangleMesh* IReadTriMesh(hsStream* s); + void IGetPositionSim(hsPoint3& pos) const; void IGetRotationSim(hsQuat& rot) const; void ISetPositionSim(const hsPoint3& pos); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index 797f15b0..305f9381 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -42,6 +42,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plSimulationMgr.h" #include "NxPhysics.h" +#include "NxCooking.h" #include "hsTimer.h" #include "plProfile.h" @@ -367,10 +368,21 @@ bool plSimulationMgr::InitSimulation() { fSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION, &gHeapAllocator, &gErrorStream); if (!fSDK) + { + fLog->AddLine("Phailed to init PhysX SDL"); return false; // client will handle this and ask user to install + } fLog = plStatusLogMgr::GetInstance().CreateStatusLog(40, "Simulation.log", plStatusLog::kFilledBackground | plStatusLog::kAlignToTop); - fLog->AddLine("Initialized simulation mgr"); + fLog->AddLine("Initialized PhysX SDK"); + + if (!NxInitCooking(NULL, &gErrorStream)) + { + fLog->AddLine("Phailed to init NxCooking"); + fSDK->release(); + fSDK = NULL; + return false; + } #ifndef PLASMA_EXTERNAL_RELEASE // If this is an internal build, enable the PhysX debugger @@ -399,7 +411,10 @@ plSimulationMgr::~plSimulationMgr() hsAssert(fScenes.empty(), "Unreleased scenes at shutdown"); if (fSDK) + { + NxCloseCooking(); fSDK->release(); + } delete fLog; fLog = nil;