This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+359
View File
@@ -0,0 +1,359 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "stdafx.h"
#include "physdll.h"
#include "vphysics/constraints.h"
#include "tier0/icommandline.h"
#include "filesystem_tools.h"
#include "simplify.h"
#include "keyvalues.h"
#include "studio.h"
IPhysicsCollision *physcollision = NULL;
IPhysicsSurfaceProps *physprops = NULL;
int g_TotalOut = 0;
int g_TotalCompress = 0;
bool g_bRecursive = false;
bool g_bQuiet = false;
KeyValues *g_pModelConfig = NULL;
void InitFilesystem( const char *pPath )
{
CmdLib_InitFileSystem( pPath );
// This bit of hackery allows us to access files on the harddrive
g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD );
}
static bool LoadSurfaceProps( const char *pMaterialFilename )
{
if ( !physprops )
return false;
FileHandle_t fp = g_pFileSystem->Open( pMaterialFilename, "rb", TOOLS_READ_PATH_ID );
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;
physprops->ParseSurfaceData( pMaterialFilename, pText );
delete[] pText;
return true;
}
void LoadSurfacePropsAll()
{
// already loaded
if ( physprops->SurfacePropCount() )
return;
const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt";
KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE );
if ( manifest->LoadFromFile( g_pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) )
{
for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
{
if ( !Q_stricmp( sub->GetName(), "file" ) )
{
// Add
LoadSurfaceProps( sub->GetString() );
continue;
}
}
}
manifest->deleteThis();
}
void InitVPhysics()
{
CreateInterfaceFn physicsFactory = GetPhysicsFactory();
physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL );
LoadSurfacePropsAll();
}
struct phyfile_t
{
phyheader_t header;
vcollide_t collide;
int fileSize;
};
void LoadPHYFile(phyfile_t *pOut, const char *name)
{
memset( pOut, 0, sizeof(*pOut) );
FileHandle_t file = g_pFullFileSystem->Open( name, "rb" );
if ( !file )
return;
g_pFullFileSystem->Read( &pOut->header, sizeof(pOut->header), file );
if ( pOut->header.size != sizeof(pOut->header) || pOut->header.solidCount <= 0 )
return;
pOut->fileSize = g_pFullFileSystem->Size( file );
char *buf = (char *)_alloca( pOut->fileSize );
g_pFullFileSystem->Read( buf, pOut->fileSize, file );
g_pFullFileSystem->Close( file );
physcollision->VCollideLoad( &pOut->collide, pOut->header.solidCount, (const char *)buf, pOut->fileSize );
}
void OverrideDefaultsForModel( const char *keyname, simplifyparams_t &params )
{
KeyValues *pKeys = g_pModelConfig;
while ( pKeys )
{
if ( !Q_stricmp( pKeys->GetName(), keyname ) )
{
for ( KeyValues *pData = pKeys->GetFirstSubKey(); pData; pData = pData->GetNextKey() )
{
if ( !Q_stricmp( pData->GetName(), "tolerance" ) )
{
params.tolerance = pData->GetFloat();
if (!g_bQuiet)
{
Msg("%s: tolerance set to %.2f\n", keyname, params.tolerance );
}
}
else if ( !Q_stricmp( pData->GetName(), "addAABB" ) )
{
params.addAABBToSimplifiedHull = pData->GetInt() ? true : false;
if (!g_bQuiet)
{
Msg("%s: AABB %s\n", keyname, params.addAABBToSimplifiedHull ? "on" : "off" );
}
}
else if ( !Q_stricmp( pData->GetName(), "singleconvex" ) )
{
params.forceSingleConvex = pData->GetInt() ? true : false;
if (!g_bQuiet)
{
Msg("%s: Forced to single convex\n", keyname );
}
}
else if ( !Q_stricmp( pData->GetName(), "mergeconvex" ) )
{
params.mergeConvexTolerance = pData->GetFloat();
params.mergeConvexElements = params.mergeConvexTolerance > 0 ? true : false;
if (!g_bQuiet)
{
Msg("%s: Merge convex %.2f\n", keyname, params.mergeConvexTolerance );
}
}
}
return;
}
pKeys = pKeys->GetNextKey();
}
}
bool HasMultipleBones( const char *pFilename )
{
char outName[1024];
studiohdr_t hdr;
Q_strncpy( outName, pFilename, sizeof(outName) );
Q_SetExtension( outName, ".mdl", sizeof(outName) );
FileHandle_t fp = g_pFileSystem->Open( outName, "rb", TOOLS_READ_PATH_ID );
if ( fp == FILESYSTEM_INVALID_HANDLE )
return false;
g_pFileSystem->Read( &hdr, sizeof(hdr), fp );
g_pFileSystem->Close( fp );
if ( hdr.numbones > 1 )
return true;
return false;
}
void WritePHXFile( const char *pName, const phyfile_t &file )
{
if ( file.header.size != sizeof(file.header) || file.collide.solidCount <= 0 )
return;
CUtlBuffer out;
char outName[1024];
Q_snprintf( outName, sizeof(outName), "%s", pName );
Q_SetExtension( outName, ".phx", sizeof(outName) );
simplifyparams_t params;
params.Defaults();
params.tolerance = (file.collide.solidCount > 1) ? 4.0f : 2.0f;
// single solids constraint to AABB for placement help
params.addAABBToSimplifiedHull = (file.collide.solidCount == 1) ? true : false;
params.mergeConvexElements = true;
params.mergeConvexTolerance = 0.025f;
Q_FixSlashes(outName);
Q_strlower(outName);
char *pSearch = Q_strstr( outName,"models\\" );
if ( pSearch )
{
char keyname[1024];
pSearch += strlen("models\\");
Q_StripExtension( pSearch, keyname, sizeof(keyname) );
OverrideDefaultsForModel( keyname, params );
}
out.Put( &file.header, sizeof(file.header) );
int outSize = 0;
bool bStoreSolidNames = file.collide.solidCount > 1 ? true : false;
bStoreSolidNames = bStoreSolidNames || HasMultipleBones(outName);
vcollide_t *pNewCollide = ConvertVCollideToPHX( &file.collide, params, &outSize, false, bStoreSolidNames);
g_TotalOut += file.fileSize;
for ( int i = 0; i < pNewCollide->solidCount; i++ )
{
int collideSize = physcollision->CollideSize( pNewCollide->solids[i] );
out.PutInt( collideSize );
char *pMem = new char[collideSize];
physcollision->CollideWrite( pMem, pNewCollide->solids[i] );
out.Put( pMem, collideSize );
delete[] pMem;
}
if (!g_bQuiet)
{
Msg("%s Compressed %d (%d text) to %d (%d text)\n", outName, file.fileSize, file.collide.descSize, out.TellPut(), pNewCollide->descSize );
}
out.Put( pNewCollide->pKeyValues, pNewCollide->descSize );
g_TotalCompress += out.TellPut();
#if 0
//Msg("OLD:\n-----------------------------------\n%s\n", file.collide.pKeyValues );
CPackedPhysicsDescription *pPacked = physcollision->CreatePackedDesc( pNewCollide->pKeyValues, pNewCollide->descSize );
Msg("NEW:\n-----------------------------------\n" );
for ( int i = 0; i < pPacked->m_solidCount; i++ )
{
solid_t solid;
pPacked->GetSolid( &solid, i );
Msg("index %d\n", solid.index );
Msg("name %s\n", solid.name );
Msg("mass %.2f\n", solid.params.mass );
Msg("surfaceprop %s\n", solid.surfaceprop);
Msg("damping %.2f\n", solid.params.damping );
Msg("rotdamping %.2f\n", solid.params.rotdamping );
Msg("drag %.2f\n", solid.params.dragCoefficient );
Msg("inertia %.2f\n", solid.params.inertia );
Msg("volume %.2f\n", solid.params.volume );
}
#endif
DestroyPHX( pNewCollide );
if ( !g_pFullFileSystem->WriteFile( outName, NULL, out ) )
Warning("Can't write file: %s\n", outName );
}
void UnloadPHYFile( phyfile_t *pFile )
{
physcollision->VCollideUnload( &pFile->collide );
pFile->header.size = 0;
}
void MakeFilename( char *pDest, int destSize, const char *pPathname, const char *pFilenameExt )
{
Q_strncpy(pDest, pPathname, destSize);
Q_AppendSlash(pDest, destSize);
Q_strncat(pDest, pFilenameExt, destSize);
}
void MakeDirname( char *pDest, int destSize, const char *pPathname, const char *pSubdir )
{
MakeFilename(pDest, destSize , pPathname, pSubdir);
}
int main( int argc, char *argv[] )
{
if ( argc < 2 )
{
Msg("Usage:\nmakephx [options] <FILESPEC>\ne.g. makephx [-r] *.phy\n");
return 0;
}
CommandLine()->CreateCmdLine( argc, argv );
g_bRecursive = CommandLine()->FindParm("-r") > 0 ? true : false;
g_bQuiet = CommandLine()->FindParm("-quiet") > 0 ? true : false;
InitFilesystem( "*.*" );
InitVPhysics();
// disable automatic packing, we want to do this ourselves.
physcollision->SetPackOnLoad( false );
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
InstallSpewFunction();
g_pModelConfig = new KeyValues("config");
g_pModelConfig->LoadFromFile( g_pFullFileSystem, "phx.cfg", "GAME" );
g_TotalOut = 0;
g_TotalCompress = 0;
FileFindHandle_t handle;
char fullpath[1024], currentFile[1024], dirName[1024], nameext[256];
strcpy( fullpath, argv[argc-1] );
strcpy( fullpath, ExpandPath( fullpath ) );
strcpy( fullpath, ExpandArg( fullpath ) );
Q_strncpy(dirName, fullpath, sizeof(dirName));
Q_StripFilename(dirName);
Q_strncpy(nameext, fullpath + strlen(dirName)+1, sizeof(nameext));
CUtlVector< const char * > directoryList;
directoryList.AddToTail( strdup(dirName) );
int current = 0;
int count = 0;
do
{
if ( g_bRecursive )
{
MakeFilename( currentFile, sizeof(currentFile), directoryList[current], "*.*" );
const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle );
while ( pFilename )
{
if ( pFilename[0] != '.' && g_pFullFileSystem->FindIsDirectory( handle ) )
{
MakeDirname( currentFile, sizeof(currentFile), directoryList[current], pFilename );
directoryList.AddToTail(strdup(currentFile));
}
pFilename = g_pFullFileSystem->FindNext( handle );
}
g_pFullFileSystem->FindClose( handle );
}
MakeFilename(currentFile, sizeof(currentFile), directoryList[current], nameext);
const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle );
while ( pFilename )
{
phyfile_t phy;
MakeFilename(currentFile, sizeof(currentFile), directoryList[current], pFilename);
LoadPHYFile( &phy, currentFile );
if ( phy.collide.isPacked || phy.collide.solidCount < 1 )
{
Msg("%s is not a valid PHY file\n", currentFile );
}
else
{
WritePHXFile( currentFile, phy );
count++;
}
UnloadPHYFile( &phy );
pFilename = g_pFullFileSystem->FindNext( handle );
}
g_pFullFileSystem->FindClose( handle );
current++;
} while( current < directoryList.Count() );
if ( count )
{
if (!g_bQuiet)
{
Msg("\n------\nTotal %s, %s\nSaved %s\n", Q_pretifymem( g_TotalOut ), Q_pretifymem( g_TotalCompress ), Q_pretifymem( g_TotalOut - g_TotalCompress ) );
Msg("%.2f%% savings\n", ((float)(g_TotalOut-g_TotalCompress) / (float)g_TotalOut) * 100.0f );
}
}
else
{
Msg("No files found in %s!\n", directoryList[current] );
}
return 0;
}
+300
View File
@@ -0,0 +1,300 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="makephx"
ProjectGUID="{FD9038D2-A941-4B5E-8E35-4205E650F120}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="..\..\..\..\game\bin\"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\public;..\..\common;..\..\..\public\tier1"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/makephx.exe"
LinkIncremental="2"
IgnoreDefaultLibraryNames="LIBC,LIBCD"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/makephx.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"
Description="Write enable target file"
CommandLine="attrib -r ..\..\..\..\game\bin\makephx.exe"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\..\public;..\..\common;..\..\..\public\tier1"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="4"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"
CommandLine="if exist ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\game\bin"
Outputs="..\..\..\..\game\bin\$(TargetName).exe"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/makephx.exe"
LinkIncremental="1"
IgnoreDefaultLibraryNames="LIBC,LIBCD"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"
Description="Write enable target file"
CommandLine="attrib -r ..\..\..\..\game\bin\makephx.exe"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\makephx.cpp">
</File>
<File
RelativePath=".\phxfile.cpp">
</File>
<File
RelativePath=".\simplify.cpp">
</File>
<File
RelativePath=".\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath="..\..\..\public\vphysics\constraints.h">
</File>
<File
RelativePath="..\..\..\public\filesystem.h">
</File>
<File
RelativePath="..\..\..\public\filesystem_helpers.h">
</File>
<File
RelativePath="..\..\..\public\filesystem_init.h">
</File>
<File
RelativePath="..\..\..\public\vstdlib\ICommandLine.h">
</File>
<File
RelativePath="..\..\..\public\tier1\KeyValues.h">
</File>
<File
RelativePath="..\..\..\public\mathlib\mathlib.h">
</File>
<File
RelativePath=".\phxfile.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
<File
RelativePath="..\..\..\public\vstdlib\strtools.h">
</File>
<File
RelativePath="..\..\..\public\vcollide.h">
</File>
<File
RelativePath="..\..\..\public\vcollide_parse.h">
</File>
<File
RelativePath="..\..\..\public\vphysics_interface.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<Filter
Name="common"
Filter="">
<File
RelativePath="..\..\common\cmdlib.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\..\public\filesystem_helpers.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\..\public\filesystem_init.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\common\filesystem_tools.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\common\physdll.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
</Filter>
<File
RelativePath="..\..\..\lib\public\mathlib.lib">
</File>
<File
RelativePath=".\ReadMe.txt">
</File>
<File
RelativePath="..\..\..\lib\public\tier0.lib">
</File>
<File
RelativePath="..\..\..\lib\public\tier1.lib">
</File>
<File
RelativePath="..\..\..\lib\public\tier2.lib">
</File>
<File
RelativePath="..\..\..\lib\public\vstdlib.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+215
View File
@@ -0,0 +1,215 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "cmdlib.h"
#include "mathlib/mathlib.h"
#include "tier1/strtools.h"
#include "physdll.h"
#include "phyfile.h"
#include "phxfile.h"
#include "utlvector.h"
#include "utlbuffer.h"
#include "vphysics_interface.h"
#include "vcollide_parse.h"
#include "vphysics/constraints.h"
#include "tier0/icommandline.h"
#include "filesystem_tools.h"
#include "simplify.h"
#include "mathlib/compressed_vector.h"
#include "keyvalues.h"
IPhysicsCollision *physcollision = NULL;
IPhysicsSurfaceProps *physprops = NULL;
int g_TotalOut = 0;
int g_TotalCompress = 0;
void InitFilesystem( const char *pPath )
{
CmdLib_InitFileSystem( pPath );
//FileSystem_Init( ".", 0, FS_INIT_COMPATIBILITY_MODE );
// This bit of hackery allows us to access files on the harddrive
g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD );
}
static bool LoadSurfaceProps( const char *pMaterialFilename )
{
if ( !physprops )
return false;
// already loaded
if ( physprops->SurfacePropCount() )
return false;
FileHandle_t fp = g_pFileSystem->Open( pMaterialFilename, "rb", TOOLS_READ_PATH_ID );
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;
physprops->ParseSurfaceData( pMaterialFilename, pText );
delete[] pText;
return true;
}
void LoadSurfacePropsAll()
{
const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt";
KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE );
if ( manifest->LoadFromFile( g_pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) )
{
for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
{
if ( !Q_stricmp( sub->GetName(), "file" ) )
{
// Add
LoadSurfaceProps( sub->GetString() );
continue;
}
}
}
manifest->deleteThis();
}
void InitVPhysics()
{
CreateInterfaceFn physicsFactory = GetPhysicsFactory();
physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL );
LoadSurfacePropsAll();
}
struct phyfile_t
{
phyheader_t header;
vcollide_t collide;
int fileSize;
};
void LoadPHYFile(phyfile_t *pOut, const char *name)
{
memset( pOut, 0, sizeof(*pOut) );
FileHandle_t file = g_pFullFileSystem->Open( name, "rb" );
if ( !file )
return;
g_pFullFileSystem->Read( &pOut->header, sizeof(pOut->header), file );
if ( pOut->header.size != sizeof(pOut->header) || pOut->header.solidCount <= 0 )
return;
pOut->fileSize = g_pFullFileSystem->Size( file );
char *buf = (char *)_alloca( pOut->fileSize );
g_pFullFileSystem->Read( buf, pOut->fileSize, file );
g_pFullFileSystem->Close( file );
physcollision->VCollideLoad( &pOut->collide, pOut->header.solidCount, (const char *)buf, pOut->fileSize );
}
void WritePHXFile( const char *pName, const phyfile_t &file )
{
if ( file.header.size != sizeof(file.header) || file.collide.solidCount <= 0 )
return;
CUtlBuffer out;
char outName[1024];
Q_snprintf( outName, sizeof(outName), "%s", pName );
Q_SetExtension( outName, ".phx", sizeof(outName) );
out.Put( &file.header, sizeof(file.header) );
int outSize = 0;
float tolerance = (file.collide.solidCount > 1) ? 3.0f : 7.0f;
vcollide_t *pNewCollide = ConvertVCollideToPHX( &file.collide, tolerance, &outSize, false );
g_TotalOut += file.fileSize;
for ( int i = 0; i < pNewCollide->solidCount; i++ )
{
int collideSize = physcollision->CollideSize( pNewCollide->solids[i] );
out.PutInt( collideSize );
char *pMem = new char[collideSize];
physcollision->CollideWrite( pMem, pNewCollide->solids[i] );
out.Put( pMem, collideSize );
delete[] pMem;
}
Msg("%s Compressed %d (%d text) to %d (%d text)\n", outName, file.fileSize, file.collide.descSize, out.TellPut(), pNewCollide->descSize );
out.Put( pNewCollide->pKeyValues, pNewCollide->descSize );
g_TotalCompress += out.TellPut();
Msg("OLD:\n-----------------------------------\n%s\n", file.collide.pKeyValues );
CPackedPhysicsDescription *pPacked = physcollision->CreatePackedDesc( pNewCollide->pKeyValues, pNewCollide->descSize );
Msg("NEW:\n-----------------------------------\n" );
for ( int i = 0; i < pPacked->m_solidCount; i++ )
{
solid_t solid;
pPacked->GetSolid( &solid, i );
Msg("index %d\n", solid.index );
Msg("name %s\n", solid.name );
Msg("mass %.2f\n", solid.params.mass );
Msg("surfaceprop %s\n", solid.surfaceprop);
Msg("damping %.2f\n", solid.params.damping );
Msg("rotdamping %.2f\n", solid.params.rotdamping );
Msg("drag %.2f\n", solid.params.dragCoefficient );
Msg("inertia %.2f\n", solid.params.inertia );
Msg("volume %.2f\n", solid.params.volume );
}
if ( !g_pFullFileSystem->WriteFile( outName, NULL, out ) )
Error("Error writing %s\n", outName );
}
void UnloadPHYFile( phyfile_t *pFile )
{
physcollision->VCollideUnload( &pFile->collide );
pFile->header.size = 0;
}
int main( int argc, char *argv[] )
{
CommandLine()->CreateCmdLine( argc, argv );
InstallSpewFunction();
InitFilesystem( argv[argc-1] );
InitVPhysics();
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
g_TotalOut = 0;
g_TotalCompress = 0;
FileFindHandle_t handle;
char fullpath[1024], filebase[1024];
strcpy( fullpath, argv[argc-1] );
strcpy( fullpath, ExpandPath( fullpath ) );
strcpy( fullpath, ExpandArg( fullpath ) );
Q_FileBase(fullpath, filebase, sizeof(filebase));
const char *pFilename = g_pFullFileSystem->FindFirst( argv[argc-1], &handle );
while ( pFilename )
{
#if 0
if ( g_pFullFileSystem->FindIsDirectory( handle ) )
{
}
#endif
g_pFullFileSystem->RelativePathToFullPath( pFilename, NULL, filebase, sizeof( filebase ) );
phyfile_t phy;
strcpy( filebase, ExpandPath( filebase ) );
strcpy( filebase, ExpandArg( filebase ) );
LoadPHYFile( &phy, filebase );
WritePHXFile( filebase, phy );
UnloadPHYFile( &phy );
pFilename = g_pFullFileSystem->FindNext( handle );
}
g_pFullFileSystem->FindClose( handle );
Msg("Total %s, %s\nSaved %s\n", Q_pretifymem( g_TotalOut ), Q_pretifymem( g_TotalCompress ), Q_pretifymem( g_TotalOut - g_TotalCompress ) );
Msg("%.2f%% savings\n", ((float)(g_TotalOut-g_TotalCompress) / (float)g_TotalOut) * 100.0f );
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "stdafx.h"
#include "simplify.h"
extern IPhysicsCollision *physcollision;
vcollide_t *ConvertVCollideToPHX( const vcollide_t *pCollideIn, const simplifyparams_t &params, int *pSize, bool bStoreSurfaceprops, bool bStoreSolidNames )
{
Assert( !pCollideIn->isPacked );
vcollide_t *pCollideOut = new vcollide_t;
pCollideOut->solids = new CPhysCollide *[pCollideIn->solidCount];
pCollideOut->solidCount = pCollideIn->solidCount;
*pSize = 0;
for ( int i = 0; i < pCollideIn->solidCount; i++ )
{
Assert( pCollideIn->solids[i] );
pCollideOut->solids[i] = SimplifyCollide( pCollideIn->solids[i], i, params );
Assert( pCollideOut->solids[i] );
int collideSize = physcollision->CollideSize( pCollideOut->solids[i] );
*pSize += collideSize;
}
int packedTextSize;
pCollideOut->pKeyValues = (char *)physcollision->PackVCollideText( pCollideIn->pKeyValues, &packedTextSize, bStoreSolidNames, bStoreSurfaceprops );
pCollideOut->isPacked = true;
pCollideOut->descSize = packedTextSize;
*pSize += packedTextSize;
return pCollideOut;
}
void DestroyPHX( vcollide_t *pCollide )
{
for ( int i = 0; i < pCollide->solidCount; i++ )
{
physcollision->DestroyCollide( pCollide->solids[i] );
}
delete[] pCollide->solids;
physcollision->DestroyVCollideText( pCollide->pKeyValues );
delete pCollide;
}
+18
View File
@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef PHXFILE_H
#define PHXFILE_H
#ifdef _WIN32
#pragma once
#endif
#include "simplify.h"
// convert a vcollide to packed/simplified format
vcollide_t *ConvertVCollideToPHX( const vcollide_t *pCollideIn, const simplifyparams_t &params, int *pSize, bool bStoreSurfaceprops, bool bStoreSolidNames );
void DestroyPHX( vcollide_t *pCollide );
#endif // PHXFILE_H
+453
View File
@@ -0,0 +1,453 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "stdafx.h"
#include "simplify.h"
extern IPhysicsCollision *physcollision;
extern bool g_bQuiet;
const float DIST_EPSILON = 1.0f / 32.0f;
// this is the list of candidate planes that will be added one by one to the convex hull
// until none of the surface lies outside the tolerance
struct planetest_t
{
Vector normal;
float dist;
int inUse;
float bestDist;
void Init( int axis, float sign, float _dist, bool _inUse = false )
{
memset( this, 0, sizeof(*this) );
normal[axis] = sign;
dist = sign*_dist;
inUse = _inUse;
bestDist = -1;
}
void Init( const Vector &a, const Vector &b, const Vector &c, bool _inUse = false )
{
Vector e0 = b-a;
Vector e1 = c-a;
normal = CrossProduct( e1, e0 );
VectorNormalize( normal );
dist = DotProduct( normal, a );
inUse = _inUse;
bestDist = -1;
}
};
CPhysConvex *ConvertPlaneListToConvex( CUtlVector<planetest_t> &list )
{
float temp[4 * 2048];
struct listplane_t
{
float plane[4];
};
int planeCount = 0;
listplane_t *pList = (listplane_t *)temp;
for ( int i = 0; i < list.Count(); i++ )
{
if ( list[i].inUse )
{
list[i].normal.CopyToArray( pList[planeCount].plane );
pList[planeCount].plane[3] = list[i].dist;
planeCount++;
}
}
return physcollision->ConvexFromPlanes( temp, planeCount, 0.25f );
}
Vector BoxSupport( const Vector &dir, const Vector &mins, const Vector &maxs )
{
Vector out;
for ( int i = 0; i < 3; i++ )
{
out[i] = (dir[i] >= 0) ? maxs[i] : mins[i];
}
return out;
}
struct convexoptimize_t
{
CUtlVector<planetest_t> list;
float targetTolerance;
void InitPlanes( CPhysCollide *pCollide, bool addAABBToSimplifiedHull )
{
Vector mins, maxs;
physcollision->CollideGetAABB( &mins, &maxs, pCollide, vec3_origin, vec3_angle );
if ( !addAABBToSimplifiedHull )
{
mins -= Vector(targetTolerance,targetTolerance,targetTolerance);
maxs += Vector(targetTolerance,targetTolerance,targetTolerance);
}
int i;
for ( i = 0; i < 3; i++ )
{
planetest_t &elem = list[list.AddToTail()];
elem.Init( i, 1.0f, maxs[i], true );
planetest_t &elem2 = list[list.AddToTail()];
elem2.Init( i, -1.0f, mins[i], true );
}
ICollisionQuery *pQuery = physcollision->CreateQueryModel( pCollide );
Vector triVerts[3];
for ( i = 0; i < pQuery->TriangleCount(0); i++ )
{
pQuery->GetTriangleVerts( 0, i, triVerts );
planetest_t &elem = list[list.AddToTail()];
elem.Init( triVerts[0], triVerts[1], triVerts[2], false );
elem.bestDist = DotProduct( elem.normal, BoxSupport(elem.normal, mins, maxs) ) - elem.dist;
}
physcollision->DestroyQueryModel( pQuery );
}
CPhysConvex *ConvertToConvex()
{
return ::ConvertPlaneListToConvex( list );
}
int FindBestPlane( float dist )
{
int best = -1;
for ( int i = 6; i < list.Count(); i++ )
{
if ( list[i].inUse )
continue;
if ( dist >= list[i].bestDist )
continue;
dist = list[i].bestDist;
best = i;
}
return best;
}
bool AddBestPlane()
{
convertconvexparams_t params;
params.Defaults();
CPhysConvex *pConvex = ConvertPlaneListToConvex( list );
CPhysCollide *pCurrentCollide = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params );
int bestIndex = -1;
float bestDist = 0;
while ( true )
{
if ( bestIndex >= 0 )
{
list[bestIndex].inUse = true;
}
int test = FindBestPlane( bestDist );
if ( test < 0 )
break;
if ( bestIndex >= 0 )
{
list[bestIndex].inUse = false;
}
Vector dir = list[test].normal;
Vector point = physcollision->CollideGetExtent( pCurrentCollide, vec3_origin, vec3_angle, dir );
float before = DotProduct( dir, point );
list[test].inUse = true;
pConvex = ConvertToConvex();
list[test].inUse = false;
CPhysCollide *pCollide = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params );
Vector p2 = physcollision->CollideGetExtent( pCollide, vec3_origin, vec3_angle, dir );
physcollision->DestroyCollide( pCollide );
float after = DotProduct( dir, p2 );
list[test].bestDist = fabs(before-after);
if ( list[test].bestDist > bestDist )
{
bestDist = list[test].bestDist;
bestIndex = test;
}
}
physcollision->DestroyCollide( pCurrentCollide );
if ( bestIndex >= 0 && bestDist >= targetTolerance )
{
list[bestIndex].inUse = true;
return true;
}
return false;
}
};
CPhysConvex *SimplifyConvexFromVerts( Vector **verts, int vertCount, bool addAABBToSimplifiedHull, float tolerance, int index )
{
CPhysConvex *pConvex = physcollision->ConvexFromVerts( verts, vertCount );
float targetVolume = physcollision->ConvexVolume( pConvex );
// can't simplify this polyhedron
if ( vertCount <= 8 )
return pConvex;
convexoptimize_t opt;
memset( &opt, 0, sizeof(opt));
opt.targetTolerance = tolerance;
convertconvexparams_t params;
params.Defaults();
CPhysCollide *pRef = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params );
opt.InitPlanes( pRef, addAABBToSimplifiedHull );
physcollision->DestroyCollide( pRef );
// Simplify until you hit the tolerance
int i;
for ( i = 0; i < vertCount; i++ )
{
if ( !opt.AddBestPlane() )
break;
}
// Create the output shape
pConvex = opt.ConvertToConvex();
float currentVolume = physcollision->ConvexVolume( pConvex );
//Msg("%d iterations, for convex %d\n", i, index );
return pConvex;
}
inline int AddVert( Vector **ppVerts, int vertCount, const Vector &newVert )
{
for ( int i = 0; i < vertCount; i++ )
{
if ( fabs(ppVerts[i]->x - newVert.x) < DIST_EPSILON &&
fabs(ppVerts[i]->y - newVert.y) < DIST_EPSILON &&
fabs(ppVerts[i]->z - newVert.z) < DIST_EPSILON )
return vertCount;
}
*ppVerts[vertCount] = newVert;
return vertCount+1;
}
void BuildSingleConvex( CPhysConvex **convexListOut, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t &params )
{
int vertCount = 0;
for ( int i = 0; i < pQuery->ConvexCount(); i++ )
{
Vector v[3];
for ( int j = 0; j < pQuery->TriangleCount(i); j++ )
{
pQuery->GetTriangleVerts( i, j, v );
vertCount = AddVert( ppVerts, vertCount, v[0] );
vertCount = AddVert( ppVerts, vertCount, v[1] );
vertCount = AddVert( ppVerts, vertCount, v[2] );
}
}
convexListOut[0] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, 0 );
physcollision->SetConvexGameData( convexListOut[0], pQuery->GetGameData( 0 ) );
}
void SimplifyConvexElements( CPhysConvex **convexListOut, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t &params )
{
for ( int i = 0; i < pQuery->ConvexCount(); i++ )
{
int vertCount = 0;
Vector v[3];
for ( int j = 0; j < pQuery->TriangleCount(i); j++ )
{
pQuery->GetTriangleVerts( i, j, v );
vertCount = AddVert( ppVerts, vertCount, v[0] );
vertCount = AddVert( ppVerts, vertCount, v[1] );
vertCount = AddVert( ppVerts, vertCount, v[2] );
}
convexListOut[i] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, i );
physcollision->SetConvexGameData( convexListOut[i], pQuery->GetGameData( i ) );
}
}
struct mergeconvex_t
{
byte mergeCount;
byte list[255];
};
void MergeElems( CUtlVector<mergeconvex_t> &elems, int index0, int index1 )
{
Assert( index0 < index1 );
for (int i = 0; i < elems[index1].mergeCount; i++)
{
elems[index0].list[i+elems[index0].mergeCount] = elems[index1].list[i];
}
elems[index0].mergeCount += elems[index1].mergeCount;
elems.FastRemove(index1);
}
int VertsForElem( ICollisionQuery *pQuery, Vector **ppVerts, const mergeconvex_t &elems0, int vertCount )
{
for ( int i = 0; i < elems0.mergeCount; i++ )
{
int convexId = elems0.list[i];
Vector v[3];
for ( int j = 0; j < pQuery->TriangleCount(convexId); j++ )
{
pQuery->GetTriangleVerts( convexId, j, v );
vertCount = AddVert( ppVerts, vertCount, v[0] );
vertCount = AddVert( ppVerts, vertCount, v[1] );
vertCount = AddVert( ppVerts, vertCount, v[2] );
}
}
return vertCount;
}
void PlanesForElem( ICollisionQuery *pQuery, CUtlVector<float> &planes, const mergeconvex_t &elem0 )
{
for ( int i = 0; i < elem0.mergeCount; i++ )
{
int convexId = elem0.list[i];
Vector v[3];
for ( int j = 0; j < pQuery->TriangleCount(convexId); j++ )
{
pQuery->GetTriangleVerts( convexId, j, v );
Vector e0 = v[1]-v[0];
Vector e1 = v[2]-v[0];
Vector normal = CrossProduct( e1, e0 );
VectorNormalize( normal );
float dist = DotProduct( normal, v[0] );
planes.AddToTail( normal.x );
planes.AddToTail( normal.y );
planes.AddToTail( normal.z );
planes.AddToTail( dist );
}
}
}
float ConvexVolumeFromPlanes( CUtlVector<float> &planes )
{
CPhysConvex *pConvex = planes.Count() ? physcollision->ConvexFromPlanes( planes.Base(), planes.Count()/4, DIST_EPSILON ) : NULL;
float volume = 0;
if ( pConvex )
{
volume = physcollision->ConvexVolume(pConvex);
physcollision->ConvexFree(pConvex);
}
return volume;
}
float MergedDeltaVolume( ICollisionQuery *pQuery, Vector **ppVerts, const mergeconvex_t &elem0, const mergeconvex_t &elem1 )
{
// build vert list
int vertCount = VertsForElem( pQuery, ppVerts, elem0, 0 );
// merge in next element
vertCount = VertsForElem( pQuery, ppVerts, elem1, vertCount);
CPhysConvex *pConvex = physcollision->ConvexFromVerts( ppVerts, vertCount );
float finalVolume = physcollision->ConvexVolume(pConvex);
physcollision->ConvexFree(pConvex);
CUtlVector<float> planes;
PlanesForElem( pQuery, planes, elem0 );
float vol0 = ConvexVolumeFromPlanes( planes );
planes.RemoveAll();
PlanesForElem( pQuery, planes, elem1 );
float vol1 = ConvexVolumeFromPlanes( planes );
PlanesForElem( pQuery, planes, elem0 );
float volInt = ConvexVolumeFromPlanes( planes );
return finalVolume - (vol0+vol1-volInt);
}
int MergeAndSimplifyConvexElements( CPhysConvex **convexListOut, const CPhysCollide *pCollideIn, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t &params )
{
Assert( pQuery->ConvexCount() < 256 );
if ( pQuery->ConvexCount() > 256 )
{
SimplifyConvexElements(convexListOut, pQuery, ppVerts, params);
return pQuery->ConvexCount();
}
CUtlVector<mergeconvex_t> elems;
int i;
elems.EnsureCount(pQuery->ConvexCount());
float totalVolume = physcollision->CollideVolume( (CPhysCollide *)pCollideIn );
for ( i = 0; i < pQuery->ConvexCount(); i++ )
{
elems[i].mergeCount = 1;
elems[i].list[0] = i;
}
loop:
for ( i = 0; i < elems.Count(); i++ )
{
for ( int j = i+1; j < elems.Count(); j++ )
{
float volume = fabs(MergedDeltaVolume( pQuery, ppVerts, elems[i], elems[j] ));
volume /= totalVolume;
if ( volume < params.mergeConvexTolerance )
{
MergeElems( elems, i, j );
goto loop;
}
}
}
for ( i = 0; i < elems.Count(); i++ )
{
int vertCount = VertsForElem( pQuery, ppVerts, elems[i], 0 );
convexListOut[i] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, i );
physcollision->SetConvexGameData( convexListOut[i], pQuery->GetGameData( elems[i].list[0] ) );
}
return elems.Count();
}
CPhysCollide *SimplifyCollide( CPhysCollide *pCollideIn, int indexIn, const simplifyparams_t &params )
{
int sizeIn = physcollision->CollideSize( pCollideIn );
ICollisionQuery *pQuery = physcollision->CreateQueryModel( pCollideIn );
int maxVertCount = 0;
int i;
for ( i = pQuery->ConvexCount(); --i >= 0; )
{
int vertCount = pQuery->TriangleCount(i)*3;
maxVertCount += vertCount;
}
Vector **ppVerts = new Vector *[maxVertCount];
Vector *verts = new Vector[maxVertCount];
for ( i = 0; i < maxVertCount; i++ )
{
ppVerts[i] = &verts[i];
}
int outputConvexCount = params.forceSingleConvex ? 1 : pQuery->ConvexCount();
CPhysConvex **convexList = new CPhysConvex *[outputConvexCount];
if ( params.forceSingleConvex )
{
BuildSingleConvex( convexList, pQuery, ppVerts, params );
}
else if ( params.mergeConvexElements && pQuery->ConvexCount() > 1 )
{
outputConvexCount = MergeAndSimplifyConvexElements( convexList, pCollideIn, pQuery, ppVerts, params );
if ( !g_bQuiet && pQuery->ConvexCount() != outputConvexCount)
{
Msg("Simplified %d to %d elements\n", pQuery->ConvexCount(), outputConvexCount );
}
}
else
{
SimplifyConvexElements( convexList, pQuery, ppVerts, params );
}
convertconvexparams_t params;
params.Defaults();
params.buildOuterConvexHull = true;
params.buildDragAxisAreas = false;
CPhysCollide *pCollideOut = physcollision->ConvertConvexToCollideParams( convexList, outputConvexCount, params );
// copy the drag axis areas from the source
Vector dragAxisAreas = physcollision->CollideGetOrthographicAreas( pCollideIn );
physcollision->CollideSetOrthographicAreas( pCollideOut, dragAxisAreas );
physcollision->DestroyQueryModel( pQuery );
delete[] convexList;
delete[] verts;
delete[] ppVerts;
if ( physcollision->CollideSize(pCollideOut) >= sizeIn )
{
// make a copy of the input collide
physcollision->DestroyCollide(pCollideOut);
char *pBuf = new char[sizeIn];
physcollision->CollideWrite( pBuf, pCollideIn );
pCollideOut = physcollision->UnserializeCollide( pBuf, sizeIn, indexIn );
delete[] pBuf;
}
return pCollideOut;
}
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef SIMPLIFY_H
#define SIMPLIFY_H
#pragma once
struct simplifyparams_t
{
float tolerance;
bool addAABBToSimplifiedHull;
bool forceSingleConvex;
bool mergeConvexElements;
float mergeConvexTolerance;
void Defaults()
{
tolerance = 1.0f;
addAABBToSimplifiedHull = false;
forceSingleConvex = false;
mergeConvexElements = false;
mergeConvexTolerance = 0.f;
}
};
extern CPhysCollide *SimplifyCollide( CPhysCollide *pCollideIn, int index, const simplifyparams_t &params );
#endif // SIMPLIFY_H
+9
View File
@@ -0,0 +1,9 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// stdafx.cpp : source file that includes just the standard includes
// makephx.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
+20
View File
@@ -0,0 +1,20 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "cmdlib.h"
#include "mathlib/mathlib.h"
#include "vphysics_interface.h"
#include "tier1/strtools.h"
#include "phyfile.h"
#include "phxfile.h"
#include "utlvector.h"
#include "utlbuffer.h"
#include "vcollide_parse.h"
// TODO: reference additional headers your program requires here
+41
View File
@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include "mathlib/mathlib.h"
#include "util.h"
#include "tier1/strtools.h"
void UTIL_StringToFloatArray( float *pVector, int count, const char *pString )
{
char *pstr, *pfront, tempString[128];
int j;
Q_strncpy( tempString, pString, sizeof(tempString) );
pstr = pfront = tempString;
for ( j = 0; j < count; j++ ) // lifted from pr_edict.c
{
pVector[j] = atof( pfront );
// skip any leading whitespace
while ( *pstr && *pstr <= ' ' )
pstr++;
// skip to next whitespace
while ( *pstr && *pstr > ' ' )
pstr++;
if (!*pstr)
break;
pstr++;
pfront = pstr;
}
for ( j++; j < count; j++ )
{
pVector[j] = 0;
}
}
void UTIL_StringToVector( float *pVector, const char *pString )
{
UTIL_StringToFloatArray( pVector, 3, pString );
}
+16
View File
@@ -0,0 +1,16 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef UTIL_H
#define UTIL_H
#ifdef _WIN32
#pragma once
#endif
extern void UTIL_StringToFloatArray( float *pVector, int count, const char *pString );
extern void UTIL_StringToVector( float *pVector, const char *pString );
#endif // UTIL_H