diff options
Diffstat (limited to 'utils/xbox/makephx')
| -rw-r--r-- | utils/xbox/makephx/makephx.cpp | 359 | ||||
| -rw-r--r-- | utils/xbox/makephx/makephx.vcproj | 300 | ||||
| -rw-r--r-- | utils/xbox/makephx/phx.cpp | 215 | ||||
| -rw-r--r-- | utils/xbox/makephx/phxfile.cpp | 42 | ||||
| -rw-r--r-- | utils/xbox/makephx/phxfile.h | 18 | ||||
| -rw-r--r-- | utils/xbox/makephx/simplify.cpp | 453 | ||||
| -rw-r--r-- | utils/xbox/makephx/simplify.h | 38 | ||||
| -rw-r--r-- | utils/xbox/makephx/stdafx.cpp | 9 | ||||
| -rw-r--r-- | utils/xbox/makephx/stdafx.h | 20 | ||||
| -rw-r--r-- | utils/xbox/makephx/util.cpp | 41 | ||||
| -rw-r--r-- | utils/xbox/makephx/util.h | 16 |
11 files changed, 1511 insertions, 0 deletions
diff --git a/utils/xbox/makephx/makephx.cpp b/utils/xbox/makephx/makephx.cpp new file mode 100644 index 0000000..8473005 --- /dev/null +++ b/utils/xbox/makephx/makephx.cpp @@ -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; +} diff --git a/utils/xbox/makephx/makephx.vcproj b/utils/xbox/makephx/makephx.vcproj new file mode 100644 index 0000000..90df4a1 --- /dev/null +++ b/utils/xbox/makephx/makephx.vcproj @@ -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> diff --git a/utils/xbox/makephx/phx.cpp b/utils/xbox/makephx/phx.cpp new file mode 100644 index 0000000..5a292b2 --- /dev/null +++ b/utils/xbox/makephx/phx.cpp @@ -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; +} diff --git a/utils/xbox/makephx/phxfile.cpp b/utils/xbox/makephx/phxfile.cpp new file mode 100644 index 0000000..304e87e --- /dev/null +++ b/utils/xbox/makephx/phxfile.cpp @@ -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; +} diff --git a/utils/xbox/makephx/phxfile.h b/utils/xbox/makephx/phxfile.h new file mode 100644 index 0000000..cb4f2dc --- /dev/null +++ b/utils/xbox/makephx/phxfile.h @@ -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 diff --git a/utils/xbox/makephx/simplify.cpp b/utils/xbox/makephx/simplify.cpp new file mode 100644 index 0000000..897fccf --- /dev/null +++ b/utils/xbox/makephx/simplify.cpp @@ -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; +} + diff --git a/utils/xbox/makephx/simplify.h b/utils/xbox/makephx/simplify.h new file mode 100644 index 0000000..acf2625 --- /dev/null +++ b/utils/xbox/makephx/simplify.h @@ -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 diff --git a/utils/xbox/makephx/stdafx.cpp b/utils/xbox/makephx/stdafx.cpp new file mode 100644 index 0000000..c4c1f62 --- /dev/null +++ b/utils/xbox/makephx/stdafx.cpp @@ -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 diff --git a/utils/xbox/makephx/stdafx.h b/utils/xbox/makephx/stdafx.h new file mode 100644 index 0000000..db4423e --- /dev/null +++ b/utils/xbox/makephx/stdafx.h @@ -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 diff --git a/utils/xbox/makephx/util.cpp b/utils/xbox/makephx/util.cpp new file mode 100644 index 0000000..cb5e879 --- /dev/null +++ b/utils/xbox/makephx/util.cpp @@ -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 ); +} diff --git a/utils/xbox/makephx/util.h b/utils/xbox/makephx/util.h new file mode 100644 index 0000000..8d389a3 --- /dev/null +++ b/utils/xbox/makephx/util.h @@ -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 |