mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
1
This commit is contained in:
@@ -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 ¶ms )
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -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\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe
|
||||
if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 ¶ms, 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;
|
||||
}
|
||||
@@ -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 ¶ms, int *pSize, bool bStoreSurfaceprops, bool bStoreSolidNames );
|
||||
void DestroyPHX( vcollide_t *pCollide );
|
||||
|
||||
#endif // PHXFILE_H
|
||||
@@ -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 ¶ms )
|
||||
{
|
||||
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 ¶ms )
|
||||
{
|
||||
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 ¶ms )
|
||||
{
|
||||
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 ¶ms )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 ¶ms );
|
||||
|
||||
#endif // SIMPLIFY_H
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user