Skip to content

Commit

Permalink
collide: Allow saving of Jolt collide binary state with base ivp coll…
Browse files Browse the repository at this point in the history
…ide header

Also restore CollideIndex method, saverestore system uses it
  • Loading branch information
SCell555 committed Aug 8, 2023
1 parent 50cef39 commit 59ad757
Showing 1 changed file with 169 additions and 70 deletions.
239 changes: 169 additions & 70 deletions vphysics_jolt/vjolt_collide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ float JoltPhysicsCollision::ConvexSurfaceArea( CPhysConvex *pConvex )

void JoltPhysicsCollision::SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData )
{
pConvex->ToConvexShape()->SetUserData( gameData );
JPH::Shape *shape = pConvex->ToConvexShape();
const uint64 upper = shape->GetUserData() & 0xFFFFFFFF00000000;
shape->SetUserData( gameData | upper );
}

void JoltPhysicsCollision::ConvexFree( CPhysConvex *pConvex )
Expand Down Expand Up @@ -203,26 +205,6 @@ void JoltPhysicsCollision::DestroyCollide( CPhysCollide *pCollide )

//-------------------------------------------------------------------------------------------------

int JoltPhysicsCollision::CollideSize( CPhysCollide *pCollide )
{
Log_Stub( LOG_VJolt );
return 0;
}

int JoltPhysicsCollision::CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap /*= false*/ )
{
Log_Stub( LOG_VJolt );
return 0;
}

CPhysCollide *JoltPhysicsCollision::UnserializeCollide( char *pBuffer, int size, int index )
{
Log_Stub( LOG_VJolt );
return nullptr;
}

//-------------------------------------------------------------------------------------------------

float JoltPhysicsCollision::CollideVolume( CPhysCollide *pCollide )
{
return JoltToSource::Volume( pCollide->ToShape()->GetVolume() );
Expand Down Expand Up @@ -315,9 +297,9 @@ void JoltPhysicsCollision::CollideSetOrthographicAreas( CPhysCollide *pCollide,

int JoltPhysicsCollision::CollideIndex( const CPhysCollide *pCollide )
{
// Slart: Only used by code behind #ifdef _DEBUG
Log_Stub( LOG_VJolt );
return 0;
const JPH::Shape *shape = pCollide->ToShape();
VJoltAssert( ( shape->GetType() == JPH::EShapeType::Convex && shape->GetSubType() == JPH::EShapeSubType::ConvexHull ) || ( shape->GetType() == JPH::EShapeType::Compound && shape->GetSubType() == JPH::EShapeSubType::StaticCompound ) );
return static_cast<int>( shape->GetUserData() >> 32 );
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -494,6 +476,7 @@ namespace ivp_compat
static constexpr int IVP_COMPACT_SURFACE_ID_SWAPPED = MAKEID('S','P','V','I');
static constexpr int IVP_COMPACT_MOPP_ID = MAKEID('M','O','P','P');
static constexpr int VPHYSICS_COLLISION_ID = MAKEID('V','P','H','Y');
static constexpr int JOLT_COLLISION_ID = MAKEID('J','P','H','Y');
static constexpr short VPHYSICS_COLLISION_VERSION = 0x0100;

enum
Expand All @@ -504,7 +487,7 @@ namespace ivp_compat
COLLIDE_VIRTUAL = 3,
};

JPH::ConvexShape *IVPLedgeToConvexShape( const compactledge_t *pLedge )
JPH::ConvexShape *IVPLedgeToConvexShape( const compactledge_t *pLedge, uint64 userData )
{
if ( !pLedge->n_triangles )
return nullptr;
Expand Down Expand Up @@ -550,7 +533,7 @@ namespace ivp_compat
}
}

pConvexShape->SetUserData( pLedge->client_data );
pConvexShape->SetUserData( pLedge->client_data | userData );
return pConvexShape;
}

Expand All @@ -568,7 +551,7 @@ namespace ivp_compat
vecOut.AddToTail( pNode->GetCompactLedge() );
}

CPhysCollide *DeserializeIVP_Poly( const compactsurface_t* pSurface )
CPhysCollide *DeserializeIVP_Poly( const compactsurface_t* pSurface, uint64 userData )
{
const compactledgenode_t *pFirstLedgeNode = reinterpret_cast< const compactledgenode_t * >(
reinterpret_cast< const char * >( pSurface ) + pSurface->offset_ledgetree_root );
Expand All @@ -584,78 +567,60 @@ namespace ivp_compat
// One compound convex per ledge.
for ( int i = 0; i < ledges.Count(); i++ )
{
const JPH::Shape* pShape = IVPLedgeToConvexShape( ledges[i] );
const JPH::Shape* pShape = IVPLedgeToConvexShape( ledges[i], userData );
// Josh:
// Some models have degenerate convexes which fails to make
// a subshape in Jolt, so we need to ignore those ledges.
if ( pShape )
settings.AddShape( JPH::Vec3::sZero(), JPH::Quat::sIdentity(), pShape );
}
CPhysCollide* pCollide = ShapeSettingsToPhysCollide( settings );
return pCollide;
JPH::Shape *shape = ShapeSettingsToShape<JPH::Shape>( settings );
shape->SetUserData( userData );
return CPhysCollide::FromShape( shape );
}
else
{
JPH::ConvexShape *pShape = IVPLedgeToConvexShape( ledges[ 0 ] );
return CPhysConvex::FromConvexShape( pShape )->ToPhysCollide();
JPH::ConvexShape *pShape = IVPLedgeToConvexShape( ledges[ 0 ], userData );
return CPhysCollide::FromShape( pShape );
}
}

CPhysCollide *DeserializeIVP_Poly( const collideheader_t *pCollideHeader )
CPhysCollide *DeserializeIVP_Poly( const collideheader_t *pCollideHeader, uint64 userData )
{
const compactsurfaceheader_t *pSurfaceHeader = reinterpret_cast< const compactsurfaceheader_t* >( pCollideHeader + 1 );
const compactsurface_t *pSurface = reinterpret_cast< const compactsurface_t* >( pSurfaceHeader + 1 );

return DeserializeIVP_Poly( pSurface );
}
}

void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap /*= false*/ )
{
if ( swap )
{
Log_Error( LOG_VJolt, "If you got here. Tell me what you did!\n" );
return;
return DeserializeIVP_Poly( pSurface, userData );
}

pOutput->solidCount = solidCount;
pOutput->solids = new CPhysCollide*[ solidCount ];

const char *pCursor = pBuffer;
for ( int i = 0; i < solidCount; i++ )
CPhysCollide *Deserialize( const char *pCursor, int solidSize, unsigned int i )
{
// Be safe ahead of time as so much can go wrong with
// this mess! :p
pOutput->solids[ i ] = nullptr;

const int solidSize = *reinterpret_cast<const int *>( pCursor );
pCursor += sizeof( int );
const collideheader_t *pCollideHeader = reinterpret_cast<const collideheader_t *>( pCursor );
uint64 userData = static_cast<uint64>( i ) << 32ULL;

const ivp_compat::collideheader_t *pCollideHeader = reinterpret_cast<const ivp_compat::collideheader_t *>( pCursor );

if ( pCollideHeader->vphysicsID == ivp_compat::VPHYSICS_COLLISION_ID )
if ( pCollideHeader->vphysicsID == VPHYSICS_COLLISION_ID )
{
// This is the main path that everything falls down for a modern
// .phy file with the collide header.

if ( pCollideHeader->version != ivp_compat::VPHYSICS_COLLISION_VERSION )
if ( pCollideHeader->version != VPHYSICS_COLLISION_VERSION )
Log_Warning( LOG_VJolt, "Solid with unknown version: 0x%x, may crash!\n", pCollideHeader->version );

switch ( pCollideHeader->modelType )
{
case ivp_compat::COLLIDE_POLY:
pOutput->solids[ i ] = DeserializeIVP_Poly( pCollideHeader );
case COLLIDE_POLY:
return DeserializeIVP_Poly( pCollideHeader, userData );
break;

case ivp_compat::COLLIDE_MOPP:
case COLLIDE_MOPP:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_MOPP on solid %d. Skipping...\n", i );
break;

case ivp_compat::COLLIDE_BALL:
case COLLIDE_BALL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_BALL on solid %d. Skipping...\n", i );
break;

case ivp_compat::COLLIDE_VIRTUAL:
case COLLIDE_VIRTUAL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_VIRTUAL on solid %d. Skipping...\n", i );
break;

Expand All @@ -664,23 +629,67 @@ void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, co
break;
}
}
else if ( pCollideHeader->vphysicsID == JOLT_COLLISION_ID )
{
VJoltAssert( pCollideHeader->version == 1 );
struct Reader : JPH::StreamIn, CUtlBuffer
{
using CUtlBuffer::CUtlBuffer;

void ReadBytes( void *outData, size_t inNumBytes ) override
{
Get( outData, inNumBytes );
}

bool IsEOF() const override
{
return TellGet() == TellMaxPut();
}

bool IsFailed() const override
{
return !IsValid();
}
} reader( pCollideHeader + 1, solidSize - sizeof( collideheader_t ), CUtlBuffer::READ_ONLY );

JPH::Shape::ShapeResult shape = JPH::Shape::sRestoreFromBinaryState( reader );
if ( shape.HasError() )
{
Log_Warning( LOG_VJolt, "Jolt collide deserialize error: %s\n", shape.GetError().c_str() );
return nullptr;
}
const int subShapeCount = reader.GetInt();
JPH::ShapeList subShapes;
for ( int j = 0; j < subShapeCount; ++j )
{
JPH::Shape::ShapeResult subShape = JPH::Shape::sRestoreFromBinaryState( reader );
if ( subShape.HasError() )
{
Log_Warning( LOG_VJolt, "Jolt collide deserialize error: %s\n", shape.GetError().c_str() );
return nullptr;
}
subShapes.emplace_back( subShape.Get() );
}
shape.Get()->RestoreSubShapeState( subShapes.data(), subShapeCount );
return CPhysCollide::FromShape( ToDanglingRef( shape.Get() ) );
}
else
{
// This must be a legacy style .phy where it is just a dumped compact surface.
// Some props in shipping HL2 still use this format, as they have a .phy, even after their
// .qc had the $collisionmodel removed, as they didn't get the stale .phy in the game files deleted.

const ivp_compat::compactsurface_t *pCompactSurface = reinterpret_cast<const ivp_compat::compactsurface_t *>( pCursor );
const compactsurface_t *pCompactSurface = reinterpret_cast<const compactsurface_t *>( pCursor );
const int legacyModelType = pCompactSurface->dummy[2];
switch ( legacyModelType )
{
case ivp_compat::IVP_COMPACT_SURFACE_SUPER_LEGACY:
case ivp_compat::IVP_COMPACT_SURFACE_ID:
case ivp_compat::IVP_COMPACT_SURFACE_ID_SWAPPED:
pOutput->solids[i] = DeserializeIVP_Poly( pCompactSurface );
case IVP_COMPACT_SURFACE_SUPER_LEGACY:
case IVP_COMPACT_SURFACE_ID:
case IVP_COMPACT_SURFACE_ID_SWAPPED:
return DeserializeIVP_Poly( pCompactSurface, userData );
break;

case ivp_compat::IVP_COMPACT_MOPP_ID:
case IVP_COMPACT_MOPP_ID:
Log_Warning( LOG_VJolt, "Unsupported legacy solid type IVP_COMPACT_MOPP_ID on solid %d. Skipping...\n", i );
break;

Expand All @@ -689,6 +698,28 @@ void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, co
break;
}
}
return nullptr;
}
}

void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap /*= false*/ )
{
if ( swap )
{
Log_Error( LOG_VJolt, "If you got here. Tell me what you did!\n" );
return 0;
}

pOutput->solidCount = solidCount;
pOutput->solids = new CPhysCollide*[ solidCount ];

const char *pCursor = pBuffer;
for ( int i = 0; i < solidCount; i++ )
{
const int solidSize = *reinterpret_cast<const int *>( pCursor );
pCursor += sizeof( int );

pOutput->solids[ i ] = ivp_compat::Deserialize( pCursor, solidSize, i );

pCursor += solidSize;
}
Expand All @@ -705,7 +736,6 @@ void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, co
#ifdef GAME_ASW_OR_NEWER
pOutput->pUserData = nullptr;
#endif

}

void JoltPhysicsCollision::VCollideUnload( vcollide_t *pVCollide )
Expand All @@ -719,6 +749,75 @@ void JoltPhysicsCollision::VCollideUnload( vcollide_t *pVCollide )
V_memset( pVCollide, 0, sizeof( *pVCollide ) );
}

int JoltPhysicsCollision::CollideSize( CPhysCollide *pCollide )
{
struct SizeCounter : JPH::StreamOut
{
void WriteBytes( const void *, size_t inNumBytes ) override
{
bytes += inNumBytes;
}

bool IsFailed() const override
{
return false;
}

size_t bytes = 0;
} counter;

counter.bytes += sizeof( ivp_compat::collideheader_t );
pCollide->ToShape()->SaveBinaryState( counter );
counter.bytes += sizeof( int );
JPH::ShapeList subShapes;
pCollide->ToShape()->SaveSubShapeState( subShapes );
for ( const auto &s : subShapes )
s->SaveBinaryState( counter );

return static_cast<int>( counter.bytes );
}

int JoltPhysicsCollision::CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap /*= false*/ )
{
if ( bSwap )
{
Log_Error( LOG_VJolt, "If you got here. Tell me what you did!\n" );
return;
}

struct Writer : JPH::StreamOut, CUtlBuffer
{
using CUtlBuffer::CUtlBuffer;

void WriteBytes( const void *inData, size_t inNumBytes ) override
{
Put( inData, inNumBytes );
}

bool IsFailed() const override
{
return !IsValid();
}
} writer;

constexpr ivp_compat::collideheader_t header { ivp_compat::JOLT_COLLISION_ID, 1, 0 };
writer.Put( &header, sizeof( header ) );
pCollide->ToShape()->SaveBinaryState( writer );
JPH::ShapeList subShapes;
writer.PutInt( static_cast<int>( subShapes.size() ) );
pCollide->ToShape()->SaveSubShapeState( subShapes );
for ( const auto &s : subShapes )
s->SaveBinaryState( writer );

memcpy( pDest, writer.Base(), writer.TellMaxPut() );
return writer.TellMaxPut();
}

CPhysCollide *JoltPhysicsCollision::UnserializeCollide( const char *pBuffer, int size, int index )
{
return ivp_compat::Deserialize( pBuffer, size, index );
}

//-------------------------------------------------------------------------------------------------

IVPhysicsKeyParser *JoltPhysicsCollision::VPhysicsKeyParserCreate( const char *pKeyData )
Expand Down

0 comments on commit 59ad757

Please sign in to comment.