Browse Source

Backport of H'Uru/Plasma PR533 - Implement a generic hull/trimesh collider format.

PhysX requires all of its actors to have cooked mesh data. This cooked
data is unfortunately not compatible with other versions of PhysX outside
of the minor branch. The format is also largely unknown. Therefore, it is
relevant to allow CWE prps to include an engine agnostic physical format
to reduce our dependencies on proprietary libraries.

All PhysX blobs thankfully begin with the magic string NXS\x01, so we now
abuse that by adding our own format that begins with the magic string
HSP\x01. These blobs are cooked on the fly while already cooked blobs are
passed directly on to PhysX.


Original commit: 392c5f5cad
author = "Adam Johnson <AdamJohnso@gmail.com>
H'uru/Plasma_PR533
cjkelly1 5 years ago
parent
commit
a49cb6eb1f
  1. 105
      MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp
  2. 3
      MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h
  3. 17
      MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp

105
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<hsPoint3> 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<hsPoint3> verts;
verts.resize(s->ReadSwap32());
for (size_t i = 0; i < verts.size(); ++i)
verts[i].Read(s);
std::vector<UInt32> 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];

3
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);

17
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;

Loading…
Cancel
Save