mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,619 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1998, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
****/
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "vphysics/constraints.h"
|
||||
#include "phyfile.h"
|
||||
#include "physdll.h"
|
||||
#include "physmesh.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include <stddef.h>
|
||||
#include "utlvector.h"
|
||||
#include "commonmacros.h"
|
||||
#include "studiomodel.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "bone_setup.h"
|
||||
#include "fmtstr.h"
|
||||
#include "vcollide_parse.h"
|
||||
|
||||
int FindPhysprop( const char *pPropname );
|
||||
|
||||
bool LoadPhysicsProperties( void );
|
||||
extern int FindBoneIndex( CStudioHdr *pstudiohdr, const char *pName );
|
||||
|
||||
|
||||
struct collisionpair_t
|
||||
{
|
||||
int object0;
|
||||
int object1;
|
||||
collisionpair_t *pNext;
|
||||
};
|
||||
|
||||
class CStudioPhysics : public IStudioPhysics
|
||||
{
|
||||
public:
|
||||
CStudioPhysics( void )
|
||||
{
|
||||
m_pList = NULL;
|
||||
m_listCount = 0;
|
||||
m_mass = 0;
|
||||
m_noselfCollisions = false;
|
||||
m_pCollisionPairs = NULL;
|
||||
memset( &m_edit, 0, sizeof(editparams_t) );
|
||||
}
|
||||
|
||||
~CStudioPhysics( void )
|
||||
{
|
||||
if ( physcollision )
|
||||
{
|
||||
for ( int i = 0; i < m_listCount; i++ )
|
||||
{
|
||||
physcollision->DestroyDebugMesh( m_pList[i].m_vertCount, m_pList[i].m_pVerts );
|
||||
physcollision->DestroyQueryModel( m_pList[i].m_pCollisionModel );
|
||||
}
|
||||
}
|
||||
delete[] m_pList;
|
||||
}
|
||||
|
||||
int Count( void )
|
||||
{
|
||||
return m_listCount;
|
||||
}
|
||||
|
||||
CPhysmesh *GetMesh( int index )
|
||||
{
|
||||
if ( index < m_listCount )
|
||||
return m_pList + index;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float GetMass( void ) { return m_mass; }
|
||||
|
||||
void AddCollisionPair( int index0, int index1 )
|
||||
{
|
||||
collisionpair_t *pPair = new collisionpair_t;
|
||||
pPair->object0 = index0;
|
||||
pPair->object1 = index1;
|
||||
pPair->pNext = m_pCollisionPairs;
|
||||
m_pCollisionPairs = pPair;
|
||||
|
||||
}
|
||||
|
||||
void Load( MDLHandle_t handle );
|
||||
char *DumpQC( void );
|
||||
void ParseKeydata( void );
|
||||
|
||||
vcollide_t *GetVCollide()
|
||||
{
|
||||
return g_pMDLCache->GetVCollide( m_MDLHandle );
|
||||
}
|
||||
|
||||
CPhysmesh *m_pList;
|
||||
MDLHandle_t m_MDLHandle;
|
||||
int m_listCount;
|
||||
|
||||
float m_mass;
|
||||
editparams_t m_edit;
|
||||
bool m_noselfCollisions;
|
||||
collisionpair_t *m_pCollisionPairs;
|
||||
};
|
||||
|
||||
|
||||
void CPhysmesh::Clear( void )
|
||||
{
|
||||
memset( this, 0, sizeof(*this) );
|
||||
memset( &m_constraint, 0, sizeof(m_constraint) );
|
||||
m_constraint.parentIndex = -1;
|
||||
m_constraint.childIndex = -1;
|
||||
}
|
||||
|
||||
|
||||
IStudioPhysics *LoadPhysics( MDLHandle_t mdlHandle )
|
||||
{
|
||||
CStudioPhysics *pPhysics = new CStudioPhysics;
|
||||
pPhysics->Load( mdlHandle );
|
||||
return pPhysics;
|
||||
}
|
||||
|
||||
void DestroyPhysics( IStudioPhysics *pStudioPhysics )
|
||||
{
|
||||
CStudioPhysics *pPhysics = static_cast<CStudioPhysics*>( pStudioPhysics );
|
||||
if ( pPhysics )
|
||||
{
|
||||
delete pPhysics;
|
||||
}
|
||||
}
|
||||
|
||||
void CStudioPhysics::Load( MDLHandle_t mdlHandle )
|
||||
{
|
||||
m_MDLHandle = mdlHandle;
|
||||
|
||||
LoadPhysicsProperties();
|
||||
|
||||
vcollide_t *pVCollide = GetVCollide( );
|
||||
if ( !pVCollide )
|
||||
{
|
||||
m_pList = NULL;
|
||||
m_listCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_pList = new CPhysmesh[pVCollide->solidCount];
|
||||
m_listCount = pVCollide->solidCount;
|
||||
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < pVCollide->solidCount; i++ )
|
||||
{
|
||||
m_pList[i].Clear();
|
||||
m_pList[i].m_vertCount = physcollision->CreateDebugMesh( pVCollide->solids[i], &m_pList[i].m_pVerts );
|
||||
m_pList[i].m_pCollisionModel = physcollision->CreateQueryModel( pVCollide->solids[i] );
|
||||
}
|
||||
|
||||
ParseKeydata();
|
||||
|
||||
CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( mdlHandle ), g_pMDLCache );
|
||||
for ( i = 0; i < pVCollide->solidCount; i++ )
|
||||
{
|
||||
CPhysmesh *pmesh = m_pList + i;
|
||||
int boneIndex = FindBoneIndex( &studioHdr, pmesh->m_boneName );
|
||||
if ( boneIndex < 0 )
|
||||
continue;
|
||||
|
||||
if ( pmesh->m_constraint.parentIndex >= 0 )
|
||||
{
|
||||
CPhysmesh *pparent = m_pList + pmesh->m_constraint.parentIndex;
|
||||
int parentIndex = FindBoneIndex( &studioHdr, pparent->m_boneName );
|
||||
Studio_CalcBoneToBoneTransform( &studioHdr, boneIndex, parentIndex, pmesh->m_matrix );
|
||||
}
|
||||
else
|
||||
{
|
||||
MatrixInvert( studioHdr.pBone(boneIndex)->poseToBone, pmesh->m_matrix );
|
||||
}
|
||||
}
|
||||
|
||||
// doesn't have a root bone? Make it the first bone
|
||||
if ( !m_edit.rootName[0] )
|
||||
{
|
||||
strcpy( m_edit.rootName, m_pList[0].m_boneName );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CEditParse : public IVPhysicsKeyHandler
|
||||
{
|
||||
public:
|
||||
virtual void ParseKeyValue( void *pCustom, const char *pKey, const char *pValue )
|
||||
{
|
||||
editparams_t *pEdit = (editparams_t *)pCustom;
|
||||
if ( !strcmpi( pKey, "rootname" ) )
|
||||
{
|
||||
strncpy( pEdit->rootName, pValue, sizeof(pEdit->rootName) );
|
||||
}
|
||||
else if ( !strcmpi( pKey, "totalmass" ) )
|
||||
{
|
||||
pEdit->totalMass = atof( pValue );
|
||||
}
|
||||
else if ( !strcmpi( pKey, "concave" ) )
|
||||
{
|
||||
pEdit->concave = atoi( pValue );
|
||||
}
|
||||
else if ( !strcmpi( pKey, "jointmerge" ) )
|
||||
{
|
||||
char tmp[1024];
|
||||
char parentName[512], childName[512];
|
||||
Q_strncpy( tmp, pValue, 1024 );
|
||||
char *pWord = strtok( tmp, "," );
|
||||
Q_strncpy( parentName, pWord, sizeof(parentName) );
|
||||
pWord = strtok( NULL, "," );
|
||||
Q_strncpy( childName, pWord, sizeof(childName) );
|
||||
if ( pEdit->mergeCount < ARRAYSIZE(pEdit->mergeList) )
|
||||
{
|
||||
merge_t *pMerge = &pEdit->mergeList[pEdit->mergeCount];
|
||||
pEdit->mergeCount++;
|
||||
pMerge->parent = g_pStudioModel->FindBone(parentName);
|
||||
pMerge->child = g_pStudioModel->FindBone(childName);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void SetDefaults( void *pCustom )
|
||||
{
|
||||
editparams_t *pEdit = (editparams_t *)pCustom;
|
||||
memset( pEdit, 0, sizeof(*pEdit) );
|
||||
}
|
||||
};
|
||||
|
||||
class CRagdollCollisionRulesParse : public IVPhysicsKeyHandler
|
||||
{
|
||||
public:
|
||||
CRagdollCollisionRulesParse( CStudioPhysics *pStudio ) : m_pStudio(pStudio)
|
||||
{
|
||||
pStudio->m_noselfCollisions = false;
|
||||
}
|
||||
|
||||
virtual void ParseKeyValue( void *pData, const char *pKey, const char *pValue )
|
||||
{
|
||||
if ( !strcmpi( pKey, "selfcollisions" ) )
|
||||
{
|
||||
// keys disabled by default
|
||||
Assert( atoi(pValue) == 0 );
|
||||
m_pStudio->m_noselfCollisions = true;
|
||||
}
|
||||
else if ( !strcmpi( pKey, "collisionpair" ) )
|
||||
{
|
||||
if ( !m_pStudio->m_noselfCollisions )
|
||||
{
|
||||
char tmp[1024];
|
||||
Q_strncpy( tmp, pValue, 1024 );
|
||||
char *pWord = strtok( tmp, "," );
|
||||
int index0 = atoi(pWord);
|
||||
pWord = strtok( NULL, "," );
|
||||
int index1 = atoi(pWord);
|
||||
m_pStudio->AddCollisionPair( index0, index1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void SetDefaults( void *pData ) {}
|
||||
|
||||
private:
|
||||
CStudioPhysics *m_pStudio;
|
||||
};
|
||||
|
||||
class CSolidParse : public IVPhysicsKeyHandler
|
||||
{
|
||||
public:
|
||||
virtual void ParseKeyValue( void *pCustom, const char *pKey, const char *pValue )
|
||||
{
|
||||
hlmvsolid_t *pSolid = (hlmvsolid_t *)pCustom;
|
||||
if ( !strcmpi( pKey, "massbias" ) )
|
||||
{
|
||||
pSolid->massBias = atof( pValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Bad key %s!!\n", pKey);
|
||||
}
|
||||
}
|
||||
virtual void SetDefaults( void *pCustom )
|
||||
{
|
||||
hlmvsolid_t *pSolid = (hlmvsolid_t *)pCustom;
|
||||
pSolid->massBias = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
void CStudioPhysics::ParseKeydata( void )
|
||||
{
|
||||
IVPhysicsKeyParser *pParser = physcollision->VPhysicsKeyParserCreate( GetVCollide()->pKeyValues );
|
||||
|
||||
while ( !pParser->Finished() )
|
||||
{
|
||||
const char *pBlock = pParser->GetCurrentBlockName();
|
||||
if ( !stricmp( pBlock, "solid" ) )
|
||||
{
|
||||
hlmvsolid_t solid;
|
||||
CSolidParse solidParse;
|
||||
|
||||
pParser->ParseSolid( &solid, &solidParse );
|
||||
solid.surfacePropIndex = FindPhysprop( solid.surfaceprop );
|
||||
|
||||
if ( solid.index >= 0 && solid.index < m_listCount )
|
||||
{
|
||||
strcpy( m_pList[solid.index].m_boneName, solid.name );
|
||||
memcpy( &m_pList[solid.index].m_solid, &solid, sizeof(solid) );
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( pBlock, "ragdollconstraint" ) )
|
||||
{
|
||||
constraint_ragdollparams_t constraint;
|
||||
pParser->ParseRagdollConstraint( &constraint, NULL );
|
||||
if ( constraint.childIndex >= 0 && constraint.childIndex < m_listCount )
|
||||
{
|
||||
// In the editor / qc these show up as 5X so that 1.0 is the default
|
||||
constraint.axes[0].torque *= 5;
|
||||
constraint.axes[1].torque *= 5;
|
||||
constraint.axes[2].torque *= 5;
|
||||
m_pList[constraint.childIndex].m_constraint = constraint;
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( pBlock, "editparams" ) )
|
||||
{
|
||||
CEditParse editParse;
|
||||
pParser->ParseCustom( &m_edit, &editParse );
|
||||
m_mass = m_edit.totalMass;
|
||||
}
|
||||
else if ( !strcmpi( pBlock, "collisionrules" ) )
|
||||
{
|
||||
CRagdollCollisionRulesParse rules(this);
|
||||
pParser->ParseCustom( NULL, &rules );
|
||||
}
|
||||
else
|
||||
{
|
||||
pParser->SkipBlock();
|
||||
}
|
||||
}
|
||||
physcollision->VPhysicsKeyParserDestroy( pParser );
|
||||
}
|
||||
|
||||
|
||||
int FindPhysprop( const char *pPropname )
|
||||
{
|
||||
if ( physprop )
|
||||
{
|
||||
int count = physprop->SurfacePropCount();
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
if ( !strcmpi( pPropname, physprop->GetPropName(i) ) )
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CTextBuffer
|
||||
{
|
||||
public:
|
||||
CTextBuffer( void ) {}
|
||||
~CTextBuffer( void ) {}
|
||||
|
||||
inline int GetSize( void ) { return m_buffer.Size(); }
|
||||
inline char *GetData( void ) { return m_buffer.Base(); }
|
||||
|
||||
void WriteText( const char *pText )
|
||||
{
|
||||
int len = strlen( pText );
|
||||
CopyData( pText, len );
|
||||
}
|
||||
|
||||
void Terminate( void ) { CopyData( "\0", 1 ); }
|
||||
|
||||
void CopyData( const char *pData, int len )
|
||||
{
|
||||
int offset = m_buffer.AddMultipleToTail( len );
|
||||
memcpy( m_buffer.Base() + offset, pData, len );
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlVector<char> m_buffer;
|
||||
};
|
||||
|
||||
|
||||
struct physdefaults_t
|
||||
{
|
||||
int surfacePropIndex;
|
||||
float inertia;
|
||||
float damping;
|
||||
float rotdamping;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Nasty little routine (that was easy to code) to find the most common
|
||||
// value in an array of structs containing that as a member
|
||||
// Input : *pStructArray - pointer to head of struct array
|
||||
// arrayCount - number of elements in the array
|
||||
// structSize - size of each element
|
||||
// fieldOffset - offset to the float we're finding
|
||||
// Output : static T - most common value
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
static T FindCommonValue( void *pStructArray, int arrayCount, int structSize, int fieldOffset )
|
||||
{
|
||||
int maxCount = 0;
|
||||
T maxVal = 0;
|
||||
|
||||
// BUGBUG: This is O(n^2), but n is really small
|
||||
for ( int i = 0; i < arrayCount; i++ )
|
||||
{
|
||||
// current = struct[i].offset
|
||||
T current = *(T *)((char *)pStructArray + (i*structSize) + fieldOffset);
|
||||
int currentCount = 0;
|
||||
|
||||
// if everything is set to the default, this is almost O(n)
|
||||
if ( current == maxVal )
|
||||
continue;
|
||||
|
||||
for ( int j = 0; j < arrayCount; j++ )
|
||||
{
|
||||
// value = struct[j].offset
|
||||
T value = *(T *)((char *)pStructArray + (j*structSize) + fieldOffset);
|
||||
if ( value == current )
|
||||
currentCount++;
|
||||
}
|
||||
|
||||
if ( currentCount > maxCount )
|
||||
{
|
||||
maxVal = current;
|
||||
maxCount = currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
return maxVal;
|
||||
}
|
||||
|
||||
static void CalcDefaultProperties( CPhysmesh *pList, int listCount, physdefaults_t &defs )
|
||||
{
|
||||
defs.surfacePropIndex = FindCommonValue<int>( pList, listCount, sizeof(CPhysmesh), offsetof(CPhysmesh, m_solid.surfacePropIndex) );
|
||||
defs.inertia = FindCommonValue<float>( pList, listCount, sizeof(CPhysmesh), offsetof(CPhysmesh, m_solid.params.inertia) );
|
||||
defs.damping = FindCommonValue<float>( pList, listCount, sizeof(CPhysmesh), offsetof(CPhysmesh, m_solid.params.damping) );
|
||||
defs.rotdamping = FindCommonValue<float>( pList, listCount, sizeof(CPhysmesh), offsetof(CPhysmesh, m_solid.params.rotdamping) );
|
||||
}
|
||||
|
||||
static void DumpModelProperties( CTextBuffer &out, float mass, physdefaults_t &defs )
|
||||
{
|
||||
char tmpbuf[1024];
|
||||
sprintf( tmpbuf, "\t$mass %.1f\r\n", mass );
|
||||
out.WriteText( tmpbuf );
|
||||
sprintf( tmpbuf, "\t$inertia %.2f\r\n", defs.inertia );
|
||||
out.WriteText( tmpbuf );
|
||||
sprintf( tmpbuf, "\t$damping %.2f\r\n", defs.damping );
|
||||
out.WriteText( tmpbuf );
|
||||
sprintf( tmpbuf, "\t$rotdamping %.2f\r\n", defs.rotdamping );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
|
||||
char *CStudioPhysics::DumpQC( void )
|
||||
{
|
||||
if ( !m_listCount )
|
||||
return NULL;
|
||||
|
||||
CTextBuffer out;
|
||||
physdefaults_t defs;
|
||||
|
||||
CalcDefaultProperties( m_pList, m_listCount, defs );
|
||||
|
||||
if ( m_listCount == 1 )
|
||||
{
|
||||
out.WriteText( "$collisionmodel ragdoll {\r\n\r\n" );
|
||||
if ( m_edit.concave )
|
||||
{
|
||||
out.WriteText( "\t$concave\r\n" );
|
||||
}
|
||||
DumpModelProperties( out, m_mass, defs );
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
out.WriteText( "$collisionjoints ragdoll {\r\n\r\n" );
|
||||
DumpModelProperties( out, m_mass, defs );
|
||||
|
||||
// write out the root bone
|
||||
if ( m_edit.rootName[0] )
|
||||
{
|
||||
char tmp[128];
|
||||
sprintf( tmp, "\t$rootbone \"%s\"\r\n", m_edit.rootName );
|
||||
out.WriteText( tmp );
|
||||
}
|
||||
|
||||
for ( i = 0; i < m_edit.mergeCount; i++ )
|
||||
{
|
||||
char tmp[1024];
|
||||
if ( m_edit.mergeList[i].parent >= 0 && m_edit.mergeList[i].child >= 0 )
|
||||
{
|
||||
char const *pParentName = g_pStudioModel->GetStudioHdr()->pBone(m_edit.mergeList[i].parent)->pszName();
|
||||
char const *pChildName = g_pStudioModel->GetStudioHdr()->pBone(m_edit.mergeList[i].child)->pszName();
|
||||
Q_snprintf( tmp, sizeof(tmp), "\t$jointmerge \"%s\" \"%s\"\r\n", pParentName, pChildName );
|
||||
out.WriteText( tmp );
|
||||
}
|
||||
}
|
||||
char tmpbuf[1024];
|
||||
for ( i = 0; i < m_listCount; i++ )
|
||||
{
|
||||
CPhysmesh *pmesh = m_pList + i;
|
||||
char jointname[256];
|
||||
sprintf( jointname, "\"%s\"", pmesh->m_boneName );
|
||||
if ( pmesh->m_solid.massBias != 1.0 )
|
||||
{
|
||||
sprintf( tmpbuf, "\t$jointmassbias %s %.2f\r\n", jointname, pmesh->m_solid.massBias );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
if ( pmesh->m_solid.params.inertia != defs.inertia )
|
||||
{
|
||||
sprintf( tmpbuf, "\t$jointinertia %s %.2f\r\n", jointname, pmesh->m_solid.params.inertia );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
if ( pmesh->m_solid.params.damping != defs.damping )
|
||||
{
|
||||
sprintf( tmpbuf, "\t$jointdamping %s %.2f\r\n", jointname, pmesh->m_solid.params.damping );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
if ( pmesh->m_solid.params.rotdamping != defs.rotdamping )
|
||||
{
|
||||
sprintf( tmpbuf, "\t$jointrotdamping %s %.2f\r\n", jointname, pmesh->m_solid.params.rotdamping );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
|
||||
if ( pmesh->m_constraint.parentIndex >= 0 )
|
||||
{
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
char *pAxis[] = { "x", "y", "z" };
|
||||
sprintf( tmpbuf, "\t$jointconstrain %s %s limit %.2f %.2f %.2f\r\n", jointname, pAxis[j], pmesh->m_constraint.axes[j].minRotation, pmesh->m_constraint.axes[j].maxRotation, pmesh->m_constraint.axes[j].torque );
|
||||
out.WriteText( tmpbuf );
|
||||
}
|
||||
}
|
||||
if ( i != m_listCount-1 )
|
||||
{
|
||||
out.WriteText( "\r\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_noselfCollisions )
|
||||
{
|
||||
out.WriteText( "\t$noselfcollisions\r\n" );
|
||||
}
|
||||
else if ( m_pCollisionPairs )
|
||||
{
|
||||
collisionpair_t *pPair = m_pCollisionPairs;
|
||||
out.WriteText("\r\n");
|
||||
while ( pPair )
|
||||
{
|
||||
out.WriteText( CFmtStr( "\t$jointcollide %s %s\r\n", m_pList[pPair->object0].m_boneName, m_pList[pPair->object1].m_boneName ) );
|
||||
pPair = pPair->pNext;
|
||||
}
|
||||
}
|
||||
out.WriteText( "}\r\n" );
|
||||
|
||||
// only need the pose for ragdolls
|
||||
if ( m_listCount != 1 )
|
||||
{
|
||||
out.WriteText( "$sequence ragdoll \t\t\"ragdoll_pose\" \t\tFPS 30 \t\tactivity ACT_DIERAGDOLL 1\r\n" );
|
||||
}
|
||||
|
||||
out.Terminate();
|
||||
|
||||
if ( out.GetSize() )
|
||||
{
|
||||
char *pOutput = new char[out.GetSize()];
|
||||
memcpy( pOutput, out.GetData(), out.GetSize() );
|
||||
return pOutput;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *pMaterialFilename = "scripts/surfaceproperties.txt";
|
||||
|
||||
bool LoadPhysicsProperties( void )
|
||||
{
|
||||
// already loaded
|
||||
if ( physprop->SurfacePropCount() )
|
||||
return false;
|
||||
|
||||
FileHandle_t fp = g_pFileSystem->Open( pMaterialFilename, "rb" );
|
||||
if ( fp == FILESYSTEM_INVALID_HANDLE )
|
||||
return false;
|
||||
|
||||
int len = g_pFileSystem->Size( fp );
|
||||
|
||||
char *pText = new char[len+1];
|
||||
g_pFileSystem->Read( pText, len, fp );
|
||||
g_pFileSystem->Close( fp );
|
||||
pText[len]=0;
|
||||
|
||||
physprop->ParseSurfaceData( pMaterialFilename, pText );
|
||||
|
||||
delete[] pText;
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user