This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+165
View File
@@ -0,0 +1,165 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#pragma once
#include <windows.h>
#include <mmreg.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <io.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utime.h>
#include "tier0/dbg.h"
#include "tier0/icommandline.h"
#include "appframework/appframework.h"
#include "characterset.h"
#include "tier1/strtools.h"
#include "tier1/UtlVector.h"
#include "tier1/UtlBuffer.h"
#include "tier1/UtlString.h"
#include "tier1/UtlRBTree.h"
#include "tier1/UtlDict.h"
#include "tier1/UtlSortVector.h"
#include "tier1/UtlStringMap.h"
#include "tier1/UtlSymbol.h"
#include "tier1/KeyValues.h"
#include "tier1/lzss.h"
#include "lzma/lzma.h"
#include "datamap.h"
#include "XZipTool.h"
#include "../../common/scriplib.h"
#include "../../common/cmdlib.h"
#include "tier2/tier2.h"
#include "dmserializers/idmserializers.h"
#include "datamodel/dmattribute.h"
#include "datamodel/dmelement.h"
#include "studiobyteswap.h"
#include "studio.h"
#include "vphysics_interface.h"
#include "materialsystem/IMaterial.h"
#include "materialsystem/hardwareverts.h"
#include "optimize.h"
#include "soundchars.h"
#include "mdllib/mdllib.h"
enum fileType_e
{
FILETYPE_UNKNOWN = 0,
FILETYPE_WAV,
FILETYPE_VTF,
FILETYPE_MDL,
FILETYPE_ANI,
FILETYPE_VTX,
FILETYPE_VVD,
FILETYPE_PHY,
FILETYPE_BSP,
FILETYPE_AIN,
FILETYPE_CCDAT,
FILETYPE_MP3,
FILETYPE_RESLST,
FILETYPE_PCF,
FILETYPE_SCENEIMAGE
};
typedef struct
{
int result;
CUtlString fileName;
} errorList_t;
//-----------------------------------------------------------------------------
// MakeGameData.cpp
//-----------------------------------------------------------------------------
bool IsLocalizedFile( const char *pFileName );
bool IsLocalizedFileValid( const char *pFileName, const char *pLanguageSuffix = NULL );
bool CompressCallback( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer );
bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning );
bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, bool bWriteToZip, DiskWriteMode_t writeMode );
fileType_e ResolveFileType( const char *pSourceName, char *pTargetName, int targetNameSize );
extern DiskWriteMode_t g_WriteModeForConversions;
extern CXZipTool g_MasterXZip;
extern char g_szGamePath[];
extern char g_szModPath[];
extern bool g_bModPathIsValid;
extern const char *g_GameNames[];
extern bool g_bForce;
extern bool g_bQuiet;
extern bool g_bMakeZip;
extern bool g_bIsPlatformZip;
extern IPhysicsCollision *g_pPhysicsCollision;
extern char g_szSourcePath[];
extern CUtlVector< errorList_t > g_errorList;
//-----------------------------------------------------------------------------
// MakeTextures.cpp
//-----------------------------------------------------------------------------
bool CreateTargetFile_VTF( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool GetPreloadData_VTF( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
//-----------------------------------------------------------------------------
// MakeScenes.cpp
//-----------------------------------------------------------------------------
bool CreateSceneImageFile( char const *pchModPath, bool bWriteToZip, bool bLittleEndian, bool bQuiet, DiskWriteMode_t eWriteModeForConversions );
//-----------------------------------------------------------------------------
// MakeSounds.cpp
//-----------------------------------------------------------------------------
bool CreateTargetFile_WAV( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool CreateTargetFile_MP3( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool GetPreloadData_WAV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
//-----------------------------------------------------------------------------
// MakeMaps.cpp
//-----------------------------------------------------------------------------
bool CreateTargetFile_BSP( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool CreateTargetFile_AIN( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool GetDependants_BSP( const char *pBspName, CUtlVector< CUtlString > *pList );
//-----------------------------------------------------------------------------
// MakeResources.cpp
//-----------------------------------------------------------------------------
bool CreateTargetFile_CCDAT( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool CreateTargetFile_RESLST( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
//-----------------------------------------------------------------------------
// MakeModels.cpp
//-----------------------------------------------------------------------------
bool InitStudioByteSwap( void );
void ShutdownStudioByteSwap( void );
bool CreateTargetFile_Model( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList );
bool GetPreloadData_VHV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
bool GetPreloadData_VTX( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
bool GetPreloadData_VVD( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
bool PreprocessModelFiles( CUtlVector<fileList_t> &fileList );
//-----------------------------------------------------------------------------
// MakeShaders.cpp
//-----------------------------------------------------------------------------
bool GetPreloadData_VCS( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut );
//-----------------------------------------------------------------------------
// MakeMisc.cpp
//-----------------------------------------------------------------------------
bool ProcessDXSupportConfig( bool bWriteToZip );
//-----------------------------------------------------------------------------
// MakeResources.cpp
//-----------------------------------------------------------------------------
bool CreateTargetFile_PCF( const char *pSourceName, const char *pTargetName, bool bWriteToZip );
//-----------------------------------------------------------------------------
// MakeZip.cpp
//-----------------------------------------------------------------------------
void SetupCriticalPreloadScript( const char *pModPath );
+111
View File
@@ -0,0 +1,111 @@
//-----------------------------------------------------------------------------
// MAKEGAMEDATA.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005;$SRCDIR\game\shared"
$PreprocessorDefinitions "$BASE;NO_X360_XDK" [$VS2015]
}
$Linker
{
$AdditionalDependencies "$BASE xgraphics.lib d3d9.lib legacy_stdio_definitions.lib"
$AdditionalDependencies "$BASE xmaencoder.lib" [!$VS2015]
$AdditionalLibraryDirectories "$BASE;$SRCDIR\x360xdk\lib\win32\vs2005"
}
}
$Project "MakeGameData"
{
$Folder "Source Files"
{
$File "MakeGameData.cpp"
$File "MakeMaps.cpp"
$File "MakeMisc.cpp"
$File "MakeModels.cpp"
$File "MakeParticles.cpp"
$File "MakeResources.cpp"
$File "MakeScenes.cpp"
$File "MakeShaders.cpp"
$File "MakeSounds.cpp"
$File "MakeTextures.cpp"
$File "MakeZip.cpp"
$Folder "Audio"
{
$File "imaadpcm.cpp"
$File "sound_io.cpp"
$File "resample.cpp"
}
$Folder "Public Modules"
{
$File "$SRCDIR\common\compiledcaptionswap.cpp"
$file "$SRCDIR\common\studiobyteswap.cpp"
$File "$SRCDIR\utils\common\scriplib.cpp"
$File "$SRCDIR\public\zip_utils.cpp"
$File "$SRCDIR\public\sentence.cpp"
$File "$SRCDIR\utils\common\cmdlib.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "$SRCDIR\utils\common\filesystem_tools.cpp"
$File "$SRCDIR\public\interpolatortypes.cpp"
}
}
$Folder "Header Files"
{
$File "MakeGameData.h"
$File "XZipTool.h"
$File "imaadpcm.h"
$File "resample.h"
$File "$SRCDIR\public\captioncompiler.h"
$File "$SRCDIR\common\studiobyteswap.h"
$File "$SRCDIR\utils\common\scriplib.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\ibsppack.h"
$File "$SRCDIR\public\sentence.h"
$File "$SRCDIR\public\studio.h"
$File "$SRCDIR\public\tier1\utlbuffer.h"
$File "$SRCDIR\public\tier1\strtools.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\vstdlib\vstdlib.h"
$File "$SRCDIR\public\xwvfile.h"
$File "$SRCDIR\public\zip_utils.h"
$File "$SRCDIR\game\shared\choreoscene.h"
$File "$SRCDIR\game\shared\choreoactor.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "$SRCDIR\public\filesystem_init.h"
$File "$SRCDIR\utils\common\filesystem_tools.h"
$File "$SRCDIR\public\interpolatortypes.h"
$File "$SRCDIR\utils\common\cmdlib.h"
$File "$SRCDIR\game\shared\choreochannel.h"
$File "$SRCDIR\game\shared\choreoevent.h"
$File "$SRCDIR\public\tier1\checksum_crc.h"
$File "$SRCDIR\public\tier2\tier2.h"
$File "$SRCDIR\common\lzma\lzma.h"
}
$Folder "Link Libraries"
{
$Lib appframework
$Lib mathlib
$Lib vtf
$Lib tier2
$Lib choreoobjects
$Lib bitmap
$Lib datamodel
$Lib dmserializers
$Lib $LIBCOMMON\lzma
}
}
+383
View File
@@ -0,0 +1,383 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 Creation for all studiomdl generated files (mdl, vvd, vtx, ani, phy)
//
//=====================================================================================//
#include "MakeGameData.h"
#include "filesystem.h"
#include "../../common/bsplib.h"
#include "ibsppack.h"
#include "vtf/vtf.h"
#include "../../game/server/ai_hull.h"
#include "zip_utils.h"
#define AINET_VERSION_NUMBER 37
#define MAX_NODES 1500
bool ReadBSPHeader( const char *pFilename, dheader_t *pHeader )
{
V_memset( pHeader, 0, sizeof( dheader_t ) );
int handle = _open( pFilename, _O_RDONLY|_O_BINARY );
if ( handle == -1 )
{
return false;
}
_read( handle, pHeader, sizeof( dheader_t ) );
close( handle );
return true;
}
//-----------------------------------------------------------------------------
// Run possible lod culling fixup
//-----------------------------------------------------------------------------
bool ConvertVHV( const char *pVhvFilename, const char *pModelName, CUtlBuffer &sourceBuffer, CUtlBuffer &targetBuffer )
{
// find strip info from model
char vsiFilename[MAX_PATH];
V_strncpy( vsiFilename, pModelName, sizeof( vsiFilename ) );
V_SetExtension( vsiFilename, ".vsi", sizeof( vsiFilename ) );
CUtlBuffer vsiBuffer;
if ( !g_pFullFileSystem->ReadFile( vsiFilename, NULL, vsiBuffer ) )
{
// cannot convert bsp's without model converions
Msg( "Error! Missing expected model conversion file '%s'. Cannot perform VHV fixup.\n", vsiFilename );
return false;
}
IMdlStripInfo *pMdlStripInfo = NULL;
if ( !mdllib->CreateNewStripInfo( &pMdlStripInfo ) )
{
Msg( "Error! Failed to allocate strip info object\n" );
return false;
}
if ( !pMdlStripInfo->UnSerialize( vsiBuffer ) )
{
Msg( "Error! Failed to unserialize strip info object '%s'\n", vsiFilename );
pMdlStripInfo->DeleteThis();
return false;
}
long originalChecksum = 0;
long newChecksum = 0;
if ( !pMdlStripInfo->GetCheckSum( &originalChecksum, &newChecksum ) )
{
Msg( "Error! Failed to get checksums from '%s'\n", vsiFilename );
pMdlStripInfo->DeleteThis();
return false;
}
HardwareVerts::FileHeader_t *pVHVhdr = (HardwareVerts::FileHeader_t*)sourceBuffer.Base();
if ( pVHVhdr->m_nChecksum != originalChecksum )
{
// vhv file should have matching original checksums
Msg( "Error! Mismatched checksums from '%s' and '%s'\n", vsiFilename, pVhvFilename );
pMdlStripInfo->DeleteThis();
return false;
}
targetBuffer.EnsureCapacity( sourceBuffer.TellMaxPut() );
targetBuffer.Put( sourceBuffer.Base(), sourceBuffer.TellMaxPut() );
if ( !pMdlStripInfo->StripHardwareVertsBuffer( targetBuffer ) )
{
pMdlStripInfo->DeleteThis();
return false;
}
// success
pMdlStripInfo->DeleteThis();
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Generate .360 bsp
//-----------------------------------------------------------------------------
bool CreateTargetFile_BSP( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
CUtlBuffer targetBuffer;
CUtlBuffer zipBuffer;
CUtlBuffer fileBuffer;
CUtlBuffer tempBuffer;
char tempZipName[MAX_PATH];
char tempSwapName[MAX_PATH];
tempZipName[0] = '\0';
tempSwapName[0] = '\0';
void *pPakData = NULL;
int pakSize = 0;
CXZipTool *pNewXZip = NULL;
if ( !g_bModPathIsValid )
{
Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
return false;
}
// Load bsppack.dll
void *pBSPPack;
CSysModule *pBSPModule;
if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) )
{
Msg( "Failed to load bsppack interface\n" );
return false;
}
scriptlib->MakeTemporaryFilename( g_szModPath, tempSwapName, sizeof( tempSwapName ) );
// Swaps the bsp directly to disk
bool bOK = ((IBSPPack*)pBSPPack)->SwapBSPFile( g_pFullFileSystem, pSourceName, tempSwapName, false, ConvertVTFTo360Format, ConvertVHV, CompressCallback );
if ( !bOK )
{
goto cleanUp;
}
// get the pak file from the swapped bsp
bOK = ((IBSPPack*)pBSPPack)->GetPakFileLump( g_pFullFileSystem, tempSwapName, &pPakData, &pakSize );
if ( !bOK )
{
goto cleanUp;
}
// build an xzip version of the pak file
if ( pPakData && pakSize )
{
// mount current pak file
IZip *pOldZip = IZip::CreateZip( false, true );
pOldZip->ParseFromBuffer( pPakData, pakSize );
// start a new xzip version
scriptlib->MakeTemporaryFilename( g_szModPath, tempZipName, sizeof( tempZipName ) );
pNewXZip = new CXZipTool;
pNewXZip->Begin( tempZipName, XBOX_DVD_SECTORSIZE );
// iterate each file in existing zip, add to new zip
int zipIndex = -1;
for ( ;; )
{
char filename[MAX_PATH];
filename[0] = '\0';
int fileSize = 0;
zipIndex = pOldZip->GetNextFilename( zipIndex, filename, sizeof( filename ), fileSize );
if ( zipIndex == -1 )
{
break;
}
fileBuffer.Purge();
bOK = pOldZip->ReadFileFromZip( filename, false, fileBuffer );
if ( !bOK )
{
goto cleanUp;
}
bOK = pNewXZip->AddBuffer( filename, fileBuffer, true );
if ( !bOK )
{
goto cleanUp;
}
}
IZip::ReleaseZip( pOldZip );
pNewXZip->End();
// read the new zip into memory
bOK = scriptlib->ReadFileToBuffer( tempZipName, zipBuffer );
if ( !bOK )
{
goto cleanUp;
}
// replace old pak lump with new zip
bOK = ((IBSPPack*)pBSPPack)->SetPakFileLump( g_pFullFileSystem, tempSwapName, tempSwapName, zipBuffer.Base(), zipBuffer.TellMaxPut() );
if ( !bOK )
{
goto cleanUp;
}
}
bOK = scriptlib->ReadFileToBuffer( tempSwapName, targetBuffer );
if ( !bOK )
{
goto cleanUp;
}
// never zip, always write local file
bOK = WriteBufferToFile( pTargetName, targetBuffer, false, WRITE_TO_DISK_ALWAYS );
cleanUp:
if ( tempZipName[0] )
{
_unlink( tempZipName );
}
if ( tempSwapName[0] )
{
_unlink( tempSwapName );
}
Sys_UnloadModule( pBSPModule );
if ( pPakData )
{
free( pPakData );
}
delete pNewXZip;
return bOK;
}
//-----------------------------------------------------------------------------
// Purpose: Generate .360 node graphs
//-----------------------------------------------------------------------------
bool CreateTargetFile_AIN( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
CUtlBuffer sourceBuf;
if ( !scriptlib->ReadFileToBuffer( pSourceName, sourceBuf ) )
{
return false;
}
// the pc ain is tied to the pc bsp and should have been generated after the bsp
char szBspName[MAX_PATH];
char szBspPath[MAX_PATH];
V_FileBase( pSourceName, szBspName, sizeof( szBspName ) );
V_ExtractFilePath( pSourceName, szBspPath, sizeof( szBspPath ) );
V_AppendSlash( szBspPath, sizeof( szBspPath ) );
V_strncat( szBspPath, "..\\", sizeof( szBspPath ) );
V_strncat( szBspPath, szBspName, sizeof( szBspPath ) );
V_strncat( szBspPath, ".bsp", sizeof( szBspPath ) );
if ( scriptlib->CompareFileTime( pSourceName, szBspPath ) < 0 )
{
// ain has a smaller filetime, thus older than bsp
Msg( "%s: Need to regenerate PC nodegraph (stale)\n", pSourceName );
if ( !g_bForce )
{
return false;
}
}
// Check the version
if ( sourceBuf.GetChar() == 'V' && sourceBuf.GetChar() == 'e' && sourceBuf.GetChar() == 'r' )
{
Msg( "%s: Need to regenerate PC nodegraph (bad format)\n", pSourceName );
return false;
}
// reset
sourceBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
// Version number
int version = sourceBuf.GetInt();
if ( version != AINET_VERSION_NUMBER )
{
Msg( "%s: Need to regenerate PC nodegraph (got version '%d', expected '%d')\n", pSourceName, version, AINET_VERSION_NUMBER );
return false;
}
// check the map revision
int mapVersion = sourceBuf.GetInt();
dheader_t bspHeader;
if ( ReadBSPHeader( szBspPath, &bspHeader ) )
{
if ( mapVersion != bspHeader.mapRevision )
{
Msg( "%s: Need to regenerate PC nodegraph (ai revision '%d' does not match bsp revision '%d')\n", pSourceName, mapVersion, bspHeader.mapRevision );
return false;
}
}
else
{
Msg( "%s: Could not find expected bsp '%s'\n", pSourceName, szBspPath );
}
// Nodes
int nodeCt = sourceBuf.GetInt();
if ( nodeCt > MAX_NODES || nodeCt < 0 )
{
Msg( "%s: Need to regenerate PC nodegraph (corrupt)\n", pSourceName );
return false;
}
CUtlBuffer targetBuf;
targetBuf.ActivateByteSwapping( true );
CByteswap swap;
swap.ActivateByteSwapping( true );
targetBuf.PutInt( version );
targetBuf.PutInt( mapVersion );
targetBuf.PutInt( nodeCt );
int numFloats = NUM_HULLS + 4;
for ( int node = 0; node < nodeCt; ++node )
{
targetBuf.EnsureCapacity( targetBuf.TellPut() + numFloats * sizeof( float ) );
swap.SwapBufferToTargetEndian<float>( (float*)targetBuf.PeekPut(), (float*)sourceBuf.PeekGet(), numFloats );
sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) );
targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) );
targetBuf.PutChar( sourceBuf.GetChar() );
// Align the remaining data
targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, 3 );
targetBuf.PutUnsignedShort( sourceBuf.GetUnsignedShort() );
targetBuf.PutShort( sourceBuf.GetShort() );
}
// Node links
int totalNumLinks = sourceBuf.GetInt();
targetBuf.PutInt( totalNumLinks );
for ( int link = 0; link < totalNumLinks; ++link )
{
targetBuf.PutShort( sourceBuf.GetShort() );
targetBuf.PutShort( sourceBuf.GetShort() );
targetBuf.Put( sourceBuf.PeekGet(), NUM_HULLS );
sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, NUM_HULLS );
}
// WC lookup table
targetBuf.EnsureCapacity( targetBuf.TellPut() + nodeCt * sizeof( int ) );
swap.SwapBufferToTargetEndian<int>( (int*)targetBuf.PeekPut(), (int*)sourceBuf.PeekGet(), nodeCt );
targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, nodeCt * sizeof( int ) );
// Write the file out
return WriteBufferToFile( pTargetName, targetBuf, bWriteToZip, WRITE_TO_DISK_ALWAYS );
}
bool GetDependants_BSP( const char *pBspName, CUtlVector< CUtlString > *pList )
{
if ( !g_bModPathIsValid )
{
Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
return false;
}
// Load bsppack.dll
void *pBSPPack;
CSysModule *pBSPModule;
if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) )
{
Msg( "Failed to load bsppack interface\n" );
return false;
}
// 360 builds a more complete reslist that includes bsp internal files
// build full path to bsp file
char szBspFilename[MAX_PATH];
V_ComposeFileName( g_szGamePath, pBspName, szBspFilename, sizeof( szBspFilename ) );
bool bOK = ((IBSPPack*)pBSPPack)->GetBSPDependants( g_pFullFileSystem, szBspFilename, pList );
Sys_UnloadModule( pBSPModule );
return bOK;
}
+86
View File
@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Conversion for general wierd files.
//
//=====================================================================================//
#include "MakeGameData.h"
//-----------------------------------------------------------------------------
// The DX Support file is a very fat expensive KV file, causes a run-time startup slowdown.
// Becauase it normally lives in the game\bin directory, it can't be in the zip or preloaded.
// Thus, it gets reprocessed into just the trivial 360 portion and placed into the platform.zip
// Yes, it's evil.
//-----------------------------------------------------------------------------
bool ProcessDXSupportConfig( bool bWriteToZip )
{
if ( !g_bIsPlatformZip )
{
// only relevant when building platform zip, otherwise no-op
return false;
}
const char *pConfigName = "dxsupport.cfg";
char szTempPath[MAX_PATH];
char szSourcePath[MAX_PATH];
V_ComposeFileName( g_szModPath, "../bin", szTempPath, sizeof( szTempPath ) );
V_ComposeFileName( szTempPath, pConfigName, szSourcePath, sizeof( szSourcePath ) );
CUtlBuffer sourceBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
if ( !g_pFullFileSystem->ReadFile( szSourcePath, NULL, sourceBuf ) )
{
Msg( "Error! Couldn't open file '%s'!\n", pConfigName );
return false;
}
KeyValues *pKV = new KeyValues( "" );
if ( !pKV->LoadFromBuffer( "dxsupport.cfg", sourceBuf ) )
{
Msg( "Error! Couldn't parse config file '%s'!\n", pConfigName );
pKV->deleteThis();
return false;
}
// only care about the xbox specific dxlevel 98 block
KeyValues *pXboxSubKey = NULL;
for ( KeyValues *pSubKey = pKV->GetFirstSubKey(); pSubKey != NULL && pXboxSubKey == NULL; pSubKey = pSubKey->GetNextKey() )
{
// descend each sub block
for ( KeyValues *pKey = pSubKey->GetFirstSubKey(); pKey != NULL && pXboxSubKey == NULL; pKey = pKey->GetNextKey() )
{
if ( !V_stricmp( pKey->GetName(), "name" ) && pKey->GetInt( (const char *)NULL ) == 98 )
{
pXboxSubKey = pSubKey;
}
}
}
if ( !pXboxSubKey )
{
Msg( "Error! Couldn't find expected dxlevel 98 in config file '%s'!\n", pConfigName );
pKV->deleteThis();
return false;
}
CUtlBuffer kvBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
kvBuffer.Printf( "\"dxsupport\"\n" );
kvBuffer.Printf( "{\n" );
kvBuffer.Printf( "\t\"0\"\n" );
kvBuffer.Printf( "\t{\n" );
for ( KeyValues *pKey = pXboxSubKey->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey() )
{
kvBuffer.Printf( "\t\t\"%s\" \"%s\"\n", pKey->GetName(), pKey->GetString( (const char *)NULL ) );
}
kvBuffer.Printf( "\t}\n" );
kvBuffer.Printf( "}\n" );
CUtlBuffer targetBuf( 0, 0, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::CONTAINS_CRLF );
kvBuffer.ConvertCRLF( targetBuf );
// only appears in zip file
bool bSuccess = WriteBufferToFile( pConfigName, targetBuf, bWriteToZip, WRITE_TO_DISK_NEVER );
pKV->deleteThis();
return bSuccess;
}
+614
View File
@@ -0,0 +1,614 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 Creation for all studiomdl generated files (mdl, vvd, vtx, ani, phy)
//
//=====================================================================================//
#include "MakeGameData.h"
#include "studiobyteswap.h"
#include "studio.h"
#include "vphysics_interface.h"
#include "materialsystem/IMaterial.h"
#include "materialsystem/hardwareverts.h"
#include "optimize.h"
//-----------------------------------------------------------------------------
// Models are already converted in a pre-pass.
//-----------------------------------------------------------------------------
bool CreateTargetFile_Model( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
// model component should be present
CUtlBuffer targetBuffer;
if ( !scriptlib->ReadFileToBuffer( pTargetName, targetBuffer ) )
{
return false;
}
// no conversion to write, but possibly zipped
bool bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, WRITE_TO_DISK_NEVER );
return bSuccess;
}
//-----------------------------------------------------------------------------
// Load necessary dlls
//-----------------------------------------------------------------------------
bool InitStudioByteSwap( void )
{
StudioByteSwap::SetVerbose( false );
StudioByteSwap::ActivateByteSwapping( true );
StudioByteSwap::SetCollisionInterface( g_pPhysicsCollision );
return true;
}
//----------------------------------------------------------------------
// Get list of files that a model requires.
//----------------------------------------------------------------------
bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList )
{
if ( !g_bModPathIsValid )
{
Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
return false;
}
CUtlBuffer sourceBuf;
if ( !g_pFullFileSystem->ReadFile( pModelName, "GAME", sourceBuf ) )
{
Msg( "Error! Couldn't open file '%s'!\n", pModelName );
return false;
}
studiohdr_t *pStudioHdr = (studiohdr_t *)sourceBuf.Base();
Studio_ConvertStudioHdrToNewVersion( pStudioHdr );
if ( pStudioHdr->version != STUDIO_VERSION )
{
Msg( "Error! Bad Model '%s', Expecting Version (%d), got (%d)\n", pModelName, STUDIO_VERSION, pStudioHdr->version );
return false;
}
char szOutName[MAX_PATH];
if ( pStudioHdr->flags & STUDIOHDR_FLAGS_OBSOLETE )
{
V_strncpy( szOutName, "materials/sprites/obsolete.vmt", sizeof( szOutName ) );
V_FixSlashes( szOutName );
pList->AddToTail( szOutName );
}
else if ( pStudioHdr->textureindex != 0 )
{
// iterate each texture
int i;
int j;
for ( i = 0; i < pStudioHdr->numtextures; i++ )
{
// iterate through all directories until a valid material is found
bool bFound = false;
for ( j = 0; j < pStudioHdr->numcdtextures; j++ )
{
char szPath[MAX_PATH];
V_ComposeFileName( "materials", pStudioHdr->pCdtexture( j ), szPath, sizeof( szPath ) );
// should have been fixed in studiomdl
// some mdls are ending up with double slashes, borking loads
int len = strlen( szPath );
if ( len > 2 && szPath[len-2] == '\\' && szPath[len-1] == '\\' )
{
szPath[len-1] = '\0';
}
V_ComposeFileName( szPath, pStudioHdr->pTexture( i )->pszName(), szOutName, sizeof( szOutName ) );
V_SetExtension( szOutName, ".vmt", sizeof( szOutName ) );
if ( g_pFullFileSystem->FileExists( szOutName, "GAME" ) )
{
bFound = true;
break;
}
}
if ( bFound )
{
pList->AddToTail( szOutName );
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Get the preload data for a vhv file
//-----------------------------------------------------------------------------
bool GetPreloadData_VHV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
HardwareVerts::FileHeader_t *pHeader = (HardwareVerts::FileHeader_t *)fileBufferIn.Base();
unsigned int version = BigLong( pHeader->m_nVersion );
// ensure caller's buffer is clean
// caller determines preload size, via TellMaxPut()
preloadBufferOut.Purge();
if ( version != VHV_VERSION )
{
// bad version
Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, VHV_VERSION, version );
return false;
}
unsigned int nPreloadSize = sizeof( HardwareVerts::FileHeader_t );
preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize );
return true;
}
//-----------------------------------------------------------------------------
// Get the preload data for a vtx file
//-----------------------------------------------------------------------------
bool GetPreloadData_VTX( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
OptimizedModel::FileHeader_t *pHeader = (OptimizedModel::FileHeader_t *)fileBufferIn.Base();
unsigned int version = BigLong( pHeader->version );
// ensure caller's buffer is clean
// caller determines preload size, via TellMaxPut()
preloadBufferOut.Purge();
if ( version != OPTIMIZED_MODEL_FILE_VERSION )
{
// bad version
Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, OPTIMIZED_MODEL_FILE_VERSION, version );
return false;
}
unsigned int nPreloadSize = sizeof( OptimizedModel::FileHeader_t );
preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize );
return true;
}
//-----------------------------------------------------------------------------
// Get the preload data for a vvd file
//-----------------------------------------------------------------------------
bool GetPreloadData_VVD( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
vertexFileHeader_t *pHeader = (vertexFileHeader_t *)fileBufferIn.Base();
unsigned int id = BigLong( pHeader->id );
unsigned int version = BigLong( pHeader->version );
// ensure caller's buffer is clean
// caller determines preload size, via TellMaxPut()
preloadBufferOut.Purge();
if ( id != MODEL_VERTEX_FILE_ID )
{
// bad version
Msg( "Can't preload: '%s', expecting id %d got id %d\n", pFilename, MODEL_VERTEX_FILE_ID, id );
return false;
}
if ( version != MODEL_VERTEX_FILE_VERSION )
{
// bad version
Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, MODEL_VERTEX_FILE_VERSION, version );
return false;
}
unsigned int nPreloadSize = sizeof( vertexFileHeader_t );
preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize );
return true;
}
bool CompressFunc( const void *pInput, int inputSize, void **pOutput, int *pOutputSize )
{
*pOutput = NULL;
*pOutputSize = 0;
if ( !inputSize )
{
// nothing to do
return false;
}
unsigned int compressedSize;
unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)pInput, inputSize, &compressedSize );
if ( pCompressedOutput )
{
*pOutput = pCompressedOutput;
*pOutputSize = compressedSize;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Rebuilds all of a MDL's components.
//-----------------------------------------------------------------------------
static bool GenerateModelFiles( const char *pMdlFilename )
{
CUtlBuffer tempBuffer;
int fileSize;
int paddedSize;
int swappedSize;
// .mdl
CUtlBuffer mdlBuffer;
if ( !scriptlib->ReadFileToBuffer( pMdlFilename, mdlBuffer ) )
{
return false;
}
if ( !Studio_ConvertStudioHdrToNewVersion( (studiohdr_t *)mdlBuffer.Base() ))
{
Msg("%s needs to be recompiled\n", pMdlFilename );
}
// .vtx
char szVtxFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) );
V_strncat( szVtxFilename, ".dx90.vtx", sizeof( szVtxFilename ) );
CUtlBuffer vtxBuffer;
bool bHasVtx = ReadFileToBuffer( szVtxFilename, vtxBuffer, false, true );
// .vvd
char szVvdFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) );
V_strncat( szVvdFilename, ".vvd", sizeof( szVvdFilename ) );
CUtlBuffer vvdBuffer;
bool bHasVvd = ReadFileToBuffer( szVvdFilename, vvdBuffer, false, true );
if ( bHasVtx != bHasVvd )
{
// paired resources, either mandates the other
return false;
}
// a .mdl file that has .vtx/.vvd gets re-processed to cull lod data
if ( bHasVtx && bHasVvd )
{
// cull lod if needed
IMdlStripInfo *pStripInfo = NULL;
bool bResult = mdllib->StripModelBuffers( mdlBuffer, vvdBuffer, vtxBuffer, &pStripInfo );
if ( !bResult )
{
return false;
}
if ( pStripInfo )
{
// .vsi
CUtlBuffer vsiBuffer;
pStripInfo->Serialize( vsiBuffer );
pStripInfo->DeleteThis();
// save strip info for later processing
char szVsiFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szVsiFilename, sizeof( szVsiFilename ) );
V_strncat( szVsiFilename, ".vsi", sizeof( szVsiFilename ) );
WriteBufferToFile( szVsiFilename, vsiBuffer, false, WRITE_TO_DISK_ALWAYS );
}
}
// .ani processing may further update .mdl buffer
char szAniFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) );
V_strncat( szAniFilename, ".ani", sizeof( szAniFilename ) );
CUtlBuffer aniBuffer;
bool bHasAni = ReadFileToBuffer( szAniFilename, aniBuffer, false, true );
if ( bHasAni )
{
// Some vestigal .ani files exist in the tree, only process valid .ani
if ( ((studiohdr_t*)mdlBuffer.Base())->numanimblocks != 0 )
{
// .ani processing modifies .mdl buffer
fileSize = aniBuffer.TellPut();
paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
aniBuffer.EnsureCapacity( paddedSize );
tempBuffer.EnsureCapacity( paddedSize );
V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) );
V_strncat( szAniFilename, ".360.ani", sizeof( szAniFilename ) );
swappedSize = StudioByteSwap::ByteswapStudioFile( szAniFilename, tempBuffer.Base(), aniBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
if ( swappedSize > 0 )
{
// .ani buffer is replaced with swapped data
aniBuffer.Purge();
aniBuffer.Put( tempBuffer.Base(), swappedSize );
WriteBufferToFile( szAniFilename, aniBuffer, false, WRITE_TO_DISK_ALWAYS );
}
else
{
return false;
}
}
}
// .phy
char szPhyFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) );
V_strncat( szPhyFilename, ".phy", sizeof( szPhyFilename ) );
CUtlBuffer phyBuffer;
bool bHasPhy = ReadFileToBuffer( szPhyFilename, phyBuffer, false, true );
if ( bHasPhy )
{
fileSize = phyBuffer.TellPut();
paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
phyBuffer.EnsureCapacity( paddedSize );
tempBuffer.EnsureCapacity( paddedSize );
V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) );
V_strncat( szPhyFilename, ".360.phy", sizeof( szPhyFilename ) );
swappedSize = StudioByteSwap::ByteswapStudioFile( szPhyFilename, tempBuffer.Base(), phyBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
if ( swappedSize > 0 )
{
// .phy buffer is replaced with swapped data
phyBuffer.Purge();
phyBuffer.Put( tempBuffer.Base(), swappedSize );
WriteBufferToFile( szPhyFilename, phyBuffer, false, WRITE_TO_DISK_ALWAYS );
}
else
{
return false;
}
}
if ( bHasVtx )
{
fileSize = vtxBuffer.TellPut();
paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
vtxBuffer.EnsureCapacity( paddedSize );
tempBuffer.EnsureCapacity( paddedSize );
V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) );
V_strncat( szVtxFilename, ".dx90.360.vtx", sizeof( szVtxFilename ) );
swappedSize = StudioByteSwap::ByteswapStudioFile( szVtxFilename, tempBuffer.Base(), vtxBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
if ( swappedSize > 0 )
{
// .vtx buffer is replaced with swapped data
vtxBuffer.Purge();
vtxBuffer.Put( tempBuffer.Base(), swappedSize );
WriteBufferToFile( szVtxFilename, vtxBuffer, false, WRITE_TO_DISK_ALWAYS );
}
else
{
return false;
}
}
if ( bHasVvd )
{
fileSize = vvdBuffer.TellPut();
paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
vvdBuffer.EnsureCapacity( paddedSize );
tempBuffer.EnsureCapacity( paddedSize );
V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) );
V_strncat( szVvdFilename, ".360.vvd", sizeof( szVvdFilename ) );
swappedSize = StudioByteSwap::ByteswapStudioFile( szVvdFilename, tempBuffer.Base(), vvdBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
if ( swappedSize > 0 )
{
// .vvd buffer is replaced with swapped data
vvdBuffer.Purge();
vvdBuffer.Put( tempBuffer.Base(), swappedSize );
WriteBufferToFile( szVvdFilename, vvdBuffer, false, WRITE_TO_DISK_ALWAYS );
}
else
{
return false;
}
}
// swap and write final .mdl
fileSize = mdlBuffer.TellPut();
paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
mdlBuffer.EnsureCapacity( paddedSize );
tempBuffer.EnsureCapacity( paddedSize );
char szMdlFilename[MAX_PATH];
V_StripExtension( pMdlFilename, szMdlFilename, sizeof( szMdlFilename ) );
V_strncat( szMdlFilename, ".360.mdl", sizeof( szMdlFilename ) );
swappedSize = StudioByteSwap::ByteswapStudioFile( szMdlFilename, tempBuffer.Base(), mdlBuffer.PeekGet(), fileSize, NULL, CompressFunc );
if ( swappedSize > 0 )
{
// .mdl buffer is replaced with swapped data
mdlBuffer.Purge();
mdlBuffer.Put( tempBuffer.Base(), swappedSize );
WriteBufferToFile( szMdlFilename, mdlBuffer, false, WRITE_TO_DISK_ALWAYS );
}
else
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Returns true if specified model path has a dirty sub-component, and requires
// update.
//-----------------------------------------------------------------------------
static bool ModelNeedsUpdate( const char *pMdlSourcePath )
{
struct ModelExtensions_t
{
const char *pSourceExtension;
const char *pTargetExtension;
bool bSourceMustExist; // if source exists, so must target
};
ModelExtensions_t pExtensions[] =
{
{ ".mdl", ".360.mdl", true },
{ ".dx90.vtx", ".dx90.360.vtx", false },
{ ".vvd", ".360.vvd", false },
{ ".phy", ".360.phy", false },
{ ".ani", ".360.ani", false },
// vtx/vvd generate a vsi, vsi must be fresher to be valid
{ ".dx90.vtx", ".vsi", false },
{ ".vvd", ".vsi", false },
};
if ( g_bForce )
{
return true;
}
for ( int i = 0; i < ARRAYSIZE( pExtensions ); i++ )
{
char szSourcePath[MAX_PATH];
struct _stat sourceStatBuf;
V_strncpy( szSourcePath, pMdlSourcePath, sizeof( szSourcePath ) );
V_SetExtension( szSourcePath, pExtensions[i].pSourceExtension, sizeof( szSourcePath ) );
int retVal = _stat( szSourcePath, &sourceStatBuf );
if ( retVal != 0 )
{
// couldn't get source
if ( pExtensions[i].bSourceMustExist )
{
return true;
}
else
{
// source is optional
continue;
}
}
char szTargetPath[MAX_PATH];
struct _stat targetStatBuf;
V_strncpy( szTargetPath, pMdlSourcePath, sizeof( szTargetPath ) );
V_SetExtension( szTargetPath, pExtensions[i].pTargetExtension, sizeof( szTargetPath ) );
if ( _stat( szTargetPath, &targetStatBuf ) != 0 )
{
// target doesn't exist
return true;
}
if ( difftime( sourceStatBuf.st_mtime, targetStatBuf.st_mtime ) > 0 )
{
// source is older (thus newer), update required
return true;
}
}
return false;
}
static bool ModelNamesLessFunc( CUtlString const &pLHS, CUtlString const &pRHS )
{
return CaselessStringLessThan( pLHS.Get(), pRHS.Get() );
}
//-----------------------------------------------------------------------------
// Models require specialized group handling to generate intermediate lod culled
// versions that are then used as the the source for target conversion.
//-----------------------------------------------------------------------------
bool PreprocessModelFiles( CUtlVector<fileList_t> &fileList )
{
if ( !InitStudioByteSwap() )
{
return false;
}
CUtlVector< CUtlString > updateList;
CUtlRBTree< CUtlString, int > visitedModels( 0, 0, ModelNamesLessFunc );
char szSourcePath[MAX_PATH];
strcpy( szSourcePath, g_szSourcePath );
V_StripFilename( szSourcePath );
if ( !szSourcePath[0] )
strcpy( szSourcePath, "." );
V_AppendSlash( szSourcePath, sizeof( szSourcePath ) );
char szModelName[MAX_PATH];
for ( int i=0; i<fileList.Count(); i++ )
{
V_strncpy( szModelName, fileList[i].fileName.String(), sizeof( szModelName ) );
if ( V_stristr( szModelName, ".360." ) )
{
// must ignore any target files
continue;
}
// want only model related files
char *pExtension = V_stristr( szModelName, ".mdl" );
if ( !pExtension )
{
pExtension = V_stristr( szModelName, ".dx90.vtx" );
if ( !pExtension )
{
pExtension = V_stristr( szModelName, ".vvd" );
if ( !pExtension )
{
pExtension = V_stristr( szModelName, ".ani" );
if ( !pExtension )
{
pExtension = V_stristr( szModelName, ".phy" );
if ( !pExtension )
{
pExtension = V_stristr( szModelName, ".vsi" );
if ( !pExtension )
{
continue;
}
}
}
}
}
}
*pExtension = '\0';
V_strncat( szModelName, ".mdl", sizeof( szModelName ) );
if ( visitedModels.Find( szModelName ) != visitedModels.InvalidIndex() )
{
// already processed
continue;
}
visitedModels.Insert( szModelName );
// resolve to full source path
const char *ptr = szModelName;
if ( !strnicmp( ptr, ".\\", 2 ) )
ptr += 2;
else if ( !strnicmp( ptr, szSourcePath, strlen( szSourcePath ) ) )
ptr += strlen( szSourcePath );
char szCleanName[MAX_PATH];
strcpy( szCleanName, szSourcePath );
strcat( szCleanName, ptr );
char szFullSourcePath[MAX_PATH];
_fullpath( szFullSourcePath, szCleanName, sizeof( szFullSourcePath ) );
// any one dirty component generates the set of all expected files
if ( ModelNeedsUpdate( szFullSourcePath ) )
{
int index = updateList.AddToTail();
updateList[index].Set( szFullSourcePath );
}
}
Msg( "\n" );
Msg( "Model Pre Pass: Updating %d Models.\n", updateList.Count() );
for ( int i = 0; i < updateList.Count(); i++ )
{
if ( !GenerateModelFiles( updateList[i].String() ) )
{
int error = g_errorList.AddToTail();
g_errorList[error].result = false;
g_errorList[error].fileName.Set( updateList[i].String() );
}
}
// iterate error list
if ( g_errorList.Count() )
{
Msg( "\n" );
for ( int i = 0; i < g_errorList.Count(); i++ )
{
Msg( "ERROR: could not pre-process model: %s\n", g_errorList[i].fileName.String() );
}
}
return true;
}
+37
View File
@@ -0,0 +1,37 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 file creation of PCF files
//
//=====================================================================================//
#include "MakeGameData.h"
bool CreateTargetFile_PCF( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
DmxHeader_t header;
CDmElement *pRoot;
if ( g_pDataModel->RestoreFromFile( pSourceName, NULL, NULL, &pRoot, CR_DELETE_NEW, &header ) == DMFILEID_INVALID )
{
Msg( "CreateTargetFile_PCF: Error reading file \"%s\"!\n", pSourceName );
return false;
}
const char *pOutFormat = header.formatName;
if ( !g_pDataModel->FindFormatUpdater( pOutFormat ) )
{
pOutFormat = "dmx";
}
CUtlBuffer binaryBuffer;
if ( !g_pDataModel->Serialize( binaryBuffer, "binary", pOutFormat, pRoot->GetHandle() ) )
{
Msg( "CreateTargetFile_PCF: Error writing buffer\n" );
return false;
}
g_pDataModel->RemoveFileId( pRoot->GetFileId() );
WriteBufferToFile( pTargetName, binaryBuffer, bWriteToZip, g_WriteModeForConversions );
return true;
}
+343
View File
@@ -0,0 +1,343 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 file creation of miscellaneous resource and data files
//
//=====================================================================================//
#include "MakeGameData.h"
#include "captioncompiler.h"
//-----------------------------------------------------------------------------
// Purpose: Generate .360 compiled caption files
//-----------------------------------------------------------------------------
bool CreateTargetFile_CCDAT( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
CUtlBuffer targetBuffer;
bool bOk = false;
if ( !scriptlib->ReadFileToBuffer( pSourceName, targetBuffer ) )
{
return false;
}
if ( SwapClosecaptionFile( targetBuffer.Base() ) )
{
bOk = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions );
}
return bOk;
}
static bool ReslistLessFunc( CUtlString const &pLHS, CUtlString const &pRHS )
{
return CaselessStringLessThan( pLHS.Get(), pRHS.Get() );
}
//-----------------------------------------------------------------------------
// Find or Add, prevents duplicates. Returns TRUE if found.
//-----------------------------------------------------------------------------
bool FindOrAddFileToResourceList( const char *pFilename, CUtlRBTree< CUtlString, int > *pTree, bool bAdd = true )
{
char szOutName[MAX_PATH];
char *pOutName;
V_strncpy( szOutName, pFilename, sizeof( szOutName ) );
V_FixSlashes( szOutName );
V_RemoveDotSlashes( szOutName );
V_strlower( szOutName );
pOutName = szOutName;
// strip any prefixed game name
for ( int i = 0; g_GameNames[i] != NULL; i++ )
{
size_t len = strlen( g_GameNames[i] );
if ( !V_strnicmp( pOutName, g_GameNames[i], len ) && pOutName[len] == '\\' )
{
// skip past game name and slash
pOutName += len+1;
break;
}
}
if ( pTree->Find( pOutName ) != pTree->InvalidIndex() )
{
// found
return true;
}
if ( bAdd )
{
pTree->Insert( pOutName );
}
return false;
}
//-----------------------------------------------------------------------------
// Remove entry from dictionary, Returns TRUE if removed.
//-----------------------------------------------------------------------------
bool RemoveFileFromResourceList( const char *pFilename, CUtlRBTree< CUtlString, int > *pTree )
{
char szOutName[MAX_PATH];
char *pOutName;
V_strncpy( szOutName, pFilename, sizeof( szOutName ) );
V_FixSlashes( szOutName );
V_RemoveDotSlashes( szOutName );
V_strlower( szOutName );
pOutName = szOutName;
// strip any prefixed game name
for ( int i = 0; g_GameNames[i] != NULL; i++ )
{
size_t len = strlen( g_GameNames[i] );
if ( !V_strnicmp( pOutName, g_GameNames[i], len ) && pOutName[len] == '\\' )
{
// skip past game name and slash
pOutName += len+1;
break;
}
}
if ( pTree->Find( pOutName ) != pTree->InvalidIndex() )
{
pTree->Remove( pOutName );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Generate a tree containing files from a reslist. Returns TRUE if successful.
//-----------------------------------------------------------------------------
bool LoadReslist( const char *pReslistName, CUtlRBTree< CUtlString, int > *pTree )
{
CUtlBuffer buffer;
if ( !scriptlib->ReadFileToBuffer( pReslistName, buffer, true ) )
{
return false;
}
char szBasename[MAX_PATH];
V_FileBase( pReslistName, szBasename, sizeof( szBasename ) );
characterset_t breakSet;
CharacterSetBuild( &breakSet, "" );
// parse reslist
char szToken[MAX_PATH];
char szBspName[MAX_PATH];
szBspName[0] = '\0';
for ( ;; )
{
int nTokenSize = buffer.ParseToken( &breakSet, szToken, sizeof( szToken ) );
if ( nTokenSize <= 0 )
{
break;
}
// reslists are pc built, filenames can be sloppy
V_strlower( szToken );
V_FixSlashes( szToken );
V_RemoveDotSlashes( szToken );
// can safely cull filetypes that are ignored by queued loader at runtime
bool bKeep = false;
const char *pExt = V_GetFileExtension( szToken );
if ( !pExt )
{
// unknown
continue;
}
else if ( !V_stricmp( pExt, "vmt" ) ||
!V_stricmp( pExt, "vhv" ) ||
!V_stricmp( pExt, "mdl" ) ||
!V_stricmp( pExt, "raw" ) ||
!V_stricmp( pExt, "wav" ) )
{
bKeep = true;
}
else if ( !V_stricmp( pExt, "mp3" ) )
{
// change to .wav
V_SetExtension( szToken, ".wav", sizeof( szToken ) );
bKeep = true;
}
else if ( !V_stricmp( pExt, "bsp" ) )
{
// reslists erroneously have multiple bsps
if ( !V_stristr( szToken, szBasename ) )
{
// wrong one, cull it
continue;
}
else
{
// right one, save it
strcpy( szBspName, szToken );
bKeep = true;
}
}
if ( bKeep )
{
FindOrAddFileToResourceList( szToken, pTree );
}
}
if ( !szBspName[0] )
{
// reslist is not bsp derived, nothing more to do
return true;
}
CUtlVector< CUtlString > bspList;
bool bOK = GetDependants_BSP( szBspName, &bspList );
if ( !bOK )
{
return false;
}
// add all the bsp dependants to the resource list
for ( int i=0; i<bspList.Count(); i++ )
{
FindOrAddFileToResourceList( bspList[i].String(), pTree );
}
// iterate all the models in the resource list, get all their dependents
CUtlVector< CUtlString > modelList;
for ( int i = pTree->FirstInorder(); i != pTree->InvalidIndex(); i = pTree->NextInorder( i ) )
{
const char *pExt = V_GetFileExtension( pTree->Element( i ).String() );
if ( !pExt || V_stricmp( pExt, "mdl" ) )
{
continue;
}
if ( !GetDependants_MDL( pTree->Element( i ).String(), &modelList ) )
{
return false;
}
}
// add all the model dependents to the resource list
for ( int i=0; i<modelList.Count(); i++ )
{
FindOrAddFileToResourceList( modelList[i].String(), pTree );
}
// check for optional commentary, include wav dependencies
char szCommentaryName[MAX_PATH];
V_ComposeFileName( g_szGamePath, szBspName, szCommentaryName, sizeof( szCommentaryName ) );
V_StripExtension( szCommentaryName, szCommentaryName, sizeof( szCommentaryName ) );
V_strncat( szCommentaryName, "_commentary.txt", sizeof( szCommentaryName ) );
CUtlBuffer commentaryBuffer;
if ( ReadFileToBuffer( szCommentaryName, commentaryBuffer, true, true ) )
{
// any single token may be quite large to due to text
char szCommentaryToken[8192];
for ( ;; )
{
int nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) );
if ( nTokenSize < 0 )
{
break;
}
if ( nTokenSize > 0 && !V_stricmp( szCommentaryToken, "commentaryfile" ) )
{
// get the commentary file
nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) );
if ( nTokenSize > 0 )
{
// skip past sound chars
char *pName = szCommentaryToken;
while ( *pName && IsSoundChar( *pName ) )
{
pName++;
}
char szWavFile[MAX_PATH];
V_snprintf( szWavFile, sizeof( szWavFile ), "sound/%s", pName );
FindOrAddFileToResourceList( szWavFile, pTree );
}
}
}
}
// check for optional blacklist
char szBlacklist[MAX_PATH];
V_ComposeFileName( g_szGamePath, "reslistfixes_xbox.xsc", szBlacklist, sizeof( szBlacklist ) );
CUtlBuffer blacklistBuffer;
if ( ReadFileToBuffer( szBlacklist, blacklistBuffer, true, true ) )
{
for ( ;; )
{
int nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) );
if ( nTokenSize <= 0 )
{
break;
}
bool bAdd;
if ( !V_stricmp( szToken, "-" ) )
{
bAdd = false;
}
else if ( !V_stricmp( szToken, "+" ) )
{
bAdd = true;
}
else
{
// bad syntax, skip line
Msg( "Bad Syntax, expecting '+' or '-' as first token in reslist fixup file '%s'.\n", szBlacklist );
continue;
}
// get entry
nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) );
if ( nTokenSize <= 0 )
{
break;
}
if ( bAdd )
{
FindOrAddFileToResourceList( szToken, pTree );
}
else
{
RemoveFileFromResourceList( szToken, pTree );
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Generate .360 compiled reslist files
// Reslist files are processed for the unique consumption of Queued Loading.
//-----------------------------------------------------------------------------
bool CreateTargetFile_RESLST( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
bool bOK = false;
// parse reslist
CUtlRBTree< CUtlString, int > rbTree( 0, 0, ReslistLessFunc );
if ( !LoadReslist( pSourceName, &rbTree ) )
{
return false;
}
CUtlBuffer targetBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
for ( int iIndex = rbTree.FirstInorder(); iIndex != rbTree.InvalidIndex(); iIndex = rbTree.NextInorder( iIndex ) )
{
targetBuffer.PutChar( '\"' );
targetBuffer.PutString( rbTree[iIndex].String() );
targetBuffer.PutChar( '\"' );
targetBuffer.PutString( "\n" );
}
bOK = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions );
return bOK;
}
+40
View File
@@ -0,0 +1,40 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 file creation of Choreo VCD files
//
//=====================================================================================//
#include "MakeGameData.h"
#include "sceneimage.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CDefaultStatus : public ISceneCompileStatus
{
public:
virtual void UpdateStatus( char const *pchSceneName, bool bQuiet, int nIndex, int nCount )
{
if ( !bQuiet )
{
Msg( "Scenes: Compiling: %s\n", pchSceneName );
}
}
};
bool CreateSceneImageFile( char const *pchModPath, bool bWriteToZip, bool bLittleEndian, bool bQuiet, DiskWriteMode_t eWriteModeForConversions )
{
CUtlBuffer targetBuffer;
const char *pFilename = bLittleEndian ? "scenes/scenes.image" : "scenes/scenes.360.image";
CDefaultStatus statusHelper;
bool bSuccess = g_pSceneImage->CreateSceneImageFile( targetBuffer, pchModPath, bLittleEndian, bQuiet, &statusHelper );
if ( bSuccess )
{
bSuccess = WriteBufferToFile( pFilename, targetBuffer, bWriteToZip, eWriteModeForConversions );
}
return bSuccess;
}
+133
View File
@@ -0,0 +1,133 @@
//-----------------------------------------------------------------------------
// MAKESCENESIMAGE.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Macro GAMENAME "MakeScenesImage"
$Configuration "Debug"
{
$General
{
$OutputDirectory ".\Debug_$GAMENAME"
$IntermediateDirectory ".\Debug_$GAMENAME"
}
}
$Configuration "Release"
{
$General
{
$OutputDirectory ".\Release_$GAMENAME"
$IntermediateDirectory ".\Release_$GAMENAME"
}
}
$Configuration
{
$Compiler
{
$PreprocessorDefinitions "$BASE;MAKESCENESIMAGE"
$PreprocessorDefinitions "$BASE;NO_X360_XDK" [$VS2015]
$AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005;$SRCDIR\game\shared"
}
$Linker
{
$AdditionalDependencies "$BASE xgraphics.lib d3d9.lib legacy_stdio_definitions.lib"
$AdditionalDependencies "$BASE xmaencoder.lib" [!$VS2015]
$AdditionalLibraryDirectories "$BASE;$SRCDIR\x360xdk\lib\win32\vs2005"
}
}
$Project "MakeScenesImage"
{
$Folder "Source Files"
{
-$File "$SRCDIR\public\tier0\memoverride.cpp"
$File "MakeGameData.cpp"
$File "MakeMaps.cpp"
$File "MakeMisc.cpp"
$File "MakeModels.cpp"
$File "MakeParticles.cpp"
$File "MakeResources.cpp"
$File "MakeScenes.cpp"
$File "MakeShaders.cpp"
$File "MakeSounds.cpp"
$File "MakeTextures.cpp"
$File "MakeZip.cpp"
$Folder "Audio"
{
$File "imaadpcm.cpp"
$File "sound_io.cpp"
$File "resample.cpp"
}
$Folder "Public Modules"
{
$File "$SRCDIR\common\compiledcaptionswap.cpp"
$file "$SRCDIR\common\studiobyteswap.cpp"
$File "$SRCDIR\utils\common\scriplib.cpp"
$File "$SRCDIR\public\zip_utils.cpp"
$File "$SRCDIR\public\sentence.cpp"
$File "$SRCDIR\utils\common\cmdlib.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "$SRCDIR\utils\common\filesystem_tools.cpp"
$File "$SRCDIR\public\interpolatortypes.cpp"
}
}
$Folder "Header Files"
{
$File "MakeGameData.h"
$File "XZipTool.h"
$File "imaadpcm.h"
$File "resample.h"
$File "$SRCDIR\public\captioncompiler.h"
$File "$SRCDIR\common\studiobyteswap.h"
$File "$SRCDIR\utils\common\scriplib.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\ibsppack.h"
$File "$SRCDIR\public\sentence.h"
$File "$SRCDIR\public\studio.h"
$File "$SRCDIR\public\tier1\utlbuffer.h"
$File "$SRCDIR\public\tier1\strtools.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\vstdlib\vstdlib.h"
$File "$SRCDIR\public\xwvfile.h"
$File "$SRCDIR\public\zip_utils.h"
$File "$SRCDIR\game\shared\choreoscene.h"
$File "$SRCDIR\game\shared\choreoactor.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "$SRCDIR\public\filesystem_init.h"
$File "$SRCDIR\utils\common\filesystem_tools.h"
$File "$SRCDIR\public\interpolatortypes.h"
$File "$SRCDIR\utils\common\cmdlib.h"
$File "$SRCDIR\game\shared\choreochannel.h"
$File "$SRCDIR\game\shared\choreoevent.h"
$File "$SRCDIR\public\tier1\checksum_crc.h"
$File "$SRCDIR\public\tier2\tier2.h"
$File "$SRCDIR\common\lzma\lzma.h"
}
$Folder "Link Libraries"
{
$Lib appframework
$Lib mathlib
$Lib vtf
$Lib tier2
$Lib choreoobjects
$Lib bitmap
$Lib datamodel
$Lib dmserializers
$Lib $LIBCOMMON\lzma
}
}
+52
View File
@@ -0,0 +1,52 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360 file creation of shaders
//
//=====================================================================================//
#include "MakeGameData.h"
#include "materialsystem/shader_vcs_version.h"
#define SHADER_FILE_THRESHOLD 32*1024
//-----------------------------------------------------------------------------
// Get the preload data for a vcs file
//-----------------------------------------------------------------------------
bool GetPreloadData_VCS( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
ShaderHeader_t *pHeader = (ShaderHeader_t *)fileBufferIn.Base();
unsigned int version = BigLong( pHeader->m_nVersion );
// ensure caller's buffer is clean
// caller determines preload size, via TellMaxPut()
preloadBufferOut.Purge();
unsigned int nPreloadSize;
if ( fileBufferIn.TellMaxPut() <= SHADER_FILE_THRESHOLD )
{
// include the whole file
nPreloadSize = fileBufferIn.TellMaxPut();
}
else
{
if ( version < SHADER_VCS_VERSION_NUMBER )
{
// not supporting old versions
return false;
}
if ( version != SHADER_VCS_VERSION_NUMBER )
{
// bad version
Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, SHADER_VCS_VERSION_NUMBER, version );
return false;
}
nPreloadSize = sizeof( ShaderHeader_t ) + BigLong( pHeader->m_nNumStaticCombos ) * sizeof( StaticComboRecord_t );
}
preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize );
return true;
}
+968
View File
@@ -0,0 +1,968 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360.WAV Creation
//
//=====================================================================================//
#include "MakeGameData.h"
#ifndef NO_X360_XDK
#include <XMAEncoder.h>
#endif
#include "datamap.h"
#include "sentence.h"
#include "tier2/riff.h"
#include "resample.h"
#include "xwvfile.h"
// all files are built for streaming compliance
// allows for fastest runtime loading path
// actual streaming or static state is determined by engine
#define XBOX_DVD_SECTORSIZE 2048
#define XMA_BLOCK_SIZE 2048 // must be aligned to 1024
#define MAX_CHUNKS 256
// [0,100]
#define XMA_HIGH_QUALITY 90
#define XMA_DEFAULT_QUALITY 75
#define XMA_MEDIUM_QUALITY 50
#define XMA_LOW_QUALITY 25
typedef struct
{
unsigned int id;
int size;
byte *pData;
} chunk_t;
struct conversion_t
{
const char *pSubDir;
int quality;
bool bForceTo22K;
};
// default conversion rules
conversion_t g_defaultConversionRules[] =
{
// subdir quality 22Khz
{ "", XMA_DEFAULT_QUALITY, false }, // default settings
{ "weapons", XMA_DEFAULT_QUALITY, false },
{ "music", XMA_DEFAULT_QUALITY, false },
{ "vo", XMA_MEDIUM_QUALITY, false },
{ "npc", XMA_MEDIUM_QUALITY, false },
{ "ambient", XMA_DEFAULT_QUALITY, false },
{ "commentary", XMA_LOW_QUALITY, true },
{ NULL },
};
// portal conversion rules
conversion_t g_portalConversionRules[] =
{
// subdir quality 22Khz
{ "", XMA_DEFAULT_QUALITY, false }, // default settings
{ "commentary", XMA_LOW_QUALITY, true },
{ NULL },
};
chunk_t g_chunks[MAX_CHUNKS];
int g_numChunks;
extern IFileReadBinary *g_pSndIO;
//-----------------------------------------------------------------------------
// Purpose: chunk printer
//-----------------------------------------------------------------------------
void PrintChunk( unsigned int chunkName, int size )
{
char c[4];
for ( int i=0; i<4; i++ )
{
c[i] = ( chunkName >> i*8 ) & 0xFF;
if ( !c[i] )
c[i] = ' ';
}
Msg( "%c%c%c%c: %d bytes\n", c[0], c[1], c[2], c[3], size );
}
//-----------------------------------------------------------------------------
// Purpose: which chunks are supported, false to ignore
//-----------------------------------------------------------------------------
bool IsValidChunk( unsigned int chunkName )
{
switch ( chunkName )
{
case WAVE_DATA:
case WAVE_CUE:
case WAVE_SAMPLER:
case WAVE_VALVEDATA:
case WAVE_FMT:
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: align buffer
//-----------------------------------------------------------------------------
int AlignToBoundary( CUtlBuffer &buf, int alignment )
{
int curPosition;
int newPosition;
byte padByte = 0;
buf.SeekPut( CUtlBuffer::SEEK_TAIL, 0 );
curPosition = buf.TellPut();
if ( alignment <= 1 )
return curPosition;
// advance to aligned position
newPosition = AlignValue( curPosition, alignment );
buf.EnsureCapacity( newPosition );
// write empty
for ( int i=0; i<newPosition-curPosition; i++ )
{
buf.Put( &padByte, 1 );
}
return newPosition;
}
//--------------------------------------------------------------------------------------
// SampleToXMABlockOffset
//
// Description: converts from a sample index to a block index + the number of samples
// to offset from the beginning of the block.
//
// Parameters:
// dwSampleIndex: sample index to convert
// pdwSeekTable: pointer to the file's XMA2 seek table
// nEntries: number of DWORD entries in the seek table
// out_pBlockIndex: index of block where the desired sample lives
// out_pOffset: number of samples in the block before the desired sample
//--------------------------------------------------------------------------------------
bool SampleToXMABlockOffset( DWORD dwSampleIndex, const DWORD *pdwSeekTable, DWORD nEntries, DWORD *out_pBlockIndex, DWORD *out_pOffset )
{
// Run through the seek table to find the block closest to the desired sample.
// Each seek table entry is the index (counting from the beginning of the file)
// of the first sample in the corresponding block, but there's no entry for the
// first block (since the index would always be zero).
bool bFound = false;
for ( DWORD i = 0; !bFound && i < nEntries; ++i )
{
if ( dwSampleIndex < BigLong( pdwSeekTable[i] ) )
{
*out_pBlockIndex = i;
bFound = true;
}
}
// Calculate the sample offset by figuring out what the sample index of the first sample
// in the block is, then subtracting that from dwSampleIndex.
if ( bFound )
{
DWORD dwStartOfBlock = (*out_pBlockIndex == 0) ? 0 : BigLong( pdwSeekTable[*out_pBlockIndex - 1] );
*out_pOffset = dwSampleIndex - dwStartOfBlock;
}
return bFound;
}
//-----------------------------------------------------------------------------
// Compile and compress vdat
//-----------------------------------------------------------------------------
bool CompressVDAT( chunk_t *pChunk )
{
CSentence *pSentence;
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
buf.EnsureCapacity( pChunk->size );
memcpy( buf.Base(), pChunk->pData, pChunk->size );
buf.SeekPut( CUtlBuffer::SEEK_HEAD, pChunk->size );
pSentence = new CSentence();
// Make binary version of VDAT
// Throws all phonemes into one word, discards sentence memory, etc.
pSentence->InitFromDataChunk( buf.Base(), buf.TellPut() );
pSentence->MakeRuntimeOnly();
CUtlBuffer binaryBuffer( 0, 0, 0 );
binaryBuffer.SetBigEndian( true );
pSentence->CacheSaveToBuffer( binaryBuffer, CACHED_SENTENCE_VERSION_ALIGNED );
delete pSentence;
unsigned int compressedSize = 0;
unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)binaryBuffer.Base(),
binaryBuffer.TellPut(), &compressedSize );
if ( pCompressedOutput )
{
if ( !g_bQuiet )
{
Msg( "CompressVDAT: Compressed %d to %d\n", binaryBuffer.TellPut(), compressedSize );
}
free( pChunk->pData );
pChunk->size = compressedSize;
pChunk->pData = pCompressedOutput;
}
else
{
// save binary VDAT as-is
free( pChunk->pData );
pChunk->size = binaryBuffer.TellPut();
pChunk->pData = (byte *)malloc( pChunk->size );
memcpy( pChunk->pData, binaryBuffer.Base(), pChunk->size );
}
// success
return true;
}
//-----------------------------------------------------------------------------
// Purpose: read chunks into provided array
//-----------------------------------------------------------------------------
bool ReadChunks( const char *pFileName, int &numChunks, chunk_t chunks[MAX_CHUNKS] )
{
numChunks = 0;
InFileRIFF riff( pFileName, *g_pSndIO );
if ( riff.RIFFName() != RIFF_WAVE )
{
return false;
}
IterateRIFF walk( riff, riff.RIFFSize() );
while ( walk.ChunkAvailable() )
{
chunks[numChunks].id = walk.ChunkName();
chunks[numChunks].size = walk.ChunkSize();
int size = chunks[numChunks].size;
if ( walk.ChunkName() == WAVE_FMT && size < sizeof( WAVEFORMATEXTENSIBLE ) )
{
// format chunks are variable and cast to different structures
// ensure the data footprint is at least the structure we want to manipulate
size = sizeof( WAVEFORMATEXTENSIBLE );
}
chunks[numChunks].pData = (byte *)malloc( size );
memset( chunks[numChunks].pData, 0, size );
walk.ChunkRead( chunks[numChunks].pData );
numChunks++;
if ( numChunks >= MAX_CHUNKS )
return false;
walk.ChunkNext();
}
// success
return true;
}
//-----------------------------------------------------------------------------
// Purpose: promote pcm 8 bit to 16 bit pcm
//-----------------------------------------------------------------------------
void ConvertPCMDataChunk8To16( chunk_t *pFormatChunk, chunk_t *pDataChunk )
{
WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData;
int sampleSize = ( pFormat->nChannels * pFormat->wBitsPerSample ) >> 3;
int sampleCount = pDataChunk->size / sampleSize;
int outputSize = sizeof( short ) * ( sampleCount * pFormat->nChannels );
short *pOut = (short *)malloc( outputSize );
// in-place convert data from 8-bits to 16-bits
Convert8To16( pDataChunk->pData, pOut, sampleCount, pFormat->nChannels );
free( pDataChunk->pData );
pDataChunk->pData = (byte *)pOut;
pDataChunk->size = outputSize;
pFormat->wFormatTag = WAVE_FORMAT_PCM;
pFormat->nBlockAlign = 2 * pFormat->nChannels;
pFormat->wBitsPerSample = 16;
pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels;
}
//-----------------------------------------------------------------------------
// Purpose: convert adpcm to 16 bit pcm
//-----------------------------------------------------------------------------
void ConvertADPCMDataChunkTo16( chunk_t *pFormatChunk, chunk_t *pDataChunk )
{
WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData;
int sampleCount = ADPCMSampleCount( (byte *)pFormat, pDataChunk->pData, pDataChunk->size );
int outputSize = sizeof( short ) * sampleCount * pFormat->nChannels;
short *pOut = (short *)malloc( outputSize );
// convert to PCM 16bit format
DecompressADPCMSamples( (byte*)pFormat, (byte*)pDataChunk->pData, pDataChunk->size, pOut );
free( pDataChunk->pData );
pDataChunk->pData = (byte *)pOut;
pDataChunk->size = outputSize;
pFormat->wFormatTag = WAVE_FORMAT_PCM;
pFormat->nBlockAlign = 2 * pFormat->nChannels;
pFormat->wBitsPerSample = 16;
pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels;
pFormatChunk->size = 16;
}
//-----------------------------------------------------------------------------
// Purpose: Decimate to 22K
//-----------------------------------------------------------------------------
void ConvertPCMDataChunk16To22K( chunk_t *pFormatChunk, chunk_t *pDataChunk )
{
WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData;
if ( pFormat->nSamplesPerSec != 44100 || pFormat->wBitsPerSample != 16 || pFormat->wFormatTag != WAVE_FORMAT_PCM )
{
// not in expected format
return;
}
int sampleSize = ( pFormat->nChannels * pFormat->wBitsPerSample ) >> 3;
int sampleCount = pDataChunk->size / sampleSize;
short *pOut = (short *)malloc( sizeof( short ) * ( sampleCount * pFormat->nChannels ) );
DecimateSampleRateBy2_16( (short *)pDataChunk->pData, pOut, sampleCount, pFormat->nChannels );
free( pDataChunk->pData );
pDataChunk->pData = (byte *)pOut;
pDataChunk->size = sizeof( short ) * ( sampleCount/2 * pFormat->nChannels );
pFormat->nSamplesPerSec = 22050;
pFormat->nBlockAlign = 2 * pFormat->nChannels;
pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels;
}
//-----------------------------------------------------------------------------
// Purpose: determine loop start
//-----------------------------------------------------------------------------
int FindLoopStart( int samplerChunk, int cueChunk )
{
int loopStartFromCue = -1;
int loopStartFromSampler = -1;
if ( cueChunk != -1 )
{
struct cuechunk_t
{
unsigned int dwName;
unsigned int dwPosition;
unsigned int fccChunk;
unsigned int dwChunkStart;
unsigned int dwBlockStart;
unsigned int dwSampleOffset;
};
struct cueRIFF_t
{
int cueCount;
cuechunk_t cues[1];
};
cueRIFF_t *pCue = (cueRIFF_t *)g_chunks[cueChunk].pData;
if ( pCue->cueCount > 0 )
{
loopStartFromCue = pCue->cues[0].dwSampleOffset;
}
}
if ( samplerChunk != -1 )
{
struct SampleLoop
{
unsigned int dwIdentifier;
unsigned int dwType;
unsigned int dwStart;
unsigned int dwEnd;
unsigned int dwFraction;
unsigned int dwPlayCount;
};
struct samplerchunk_t
{
unsigned int dwManufacturer;
unsigned int dwProduct;
unsigned int dwSamplePeriod;
unsigned int dwMIDIUnityNote;
unsigned int dwMIDIPitchFraction;
unsigned int dwSMPTEFormat;
unsigned int dwSMPTEOffset;
unsigned int cSampleLoops;
unsigned int cbSamplerData;
struct SampleLoop Loops[1];
};
// assume that the loop end is the sample end
// assume that only the first loop is relevant
samplerchunk_t *pSampler = (samplerchunk_t *)g_chunks[samplerChunk].pData;
if ( pSampler->cSampleLoops > 0 )
{
// only support normal forward loops
if ( pSampler->Loops[0].dwType == 0 )
{
loopStartFromSampler = pSampler->Loops[0].dwStart;
}
}
}
return ( max( loopStartFromCue, loopStartFromSampler ) );
}
//-----------------------------------------------------------------------------
// Purpose: returns chunk, -1 if not found
//-----------------------------------------------------------------------------
int FindChunk( unsigned int id )
{
int i;
for ( i=0; i<g_numChunks; i++ )
{
if ( g_chunks[i].id == id )
{
return i;
}
}
// not found
return - 1;
}
bool EncodeAsXMA( const char *pDebugName, CUtlBuffer &targetBuff, int quality, bool bIsVoiceOver )
{
#ifdef NO_X360_XDK
return false;
#else
int formatChunk = FindChunk( WAVE_FMT );
int dataChunk = FindChunk( WAVE_DATA );
if ( formatChunk == -1 || dataChunk == -1 )
{
// huh? these should have been pre-validated
return false;
}
int vdatSize = 0;
int vdatChunk = FindChunk( WAVE_VALVEDATA );
if ( vdatChunk != -1 )
{
vdatSize = g_chunks[vdatChunk].size;
}
int loopStart = FindLoopStart( FindChunk( WAVE_SAMPLER ), FindChunk( WAVE_CUE ) );
// format structure must be expected 16 bit PCM, otherwise encoder crashes
WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData;
pFormat->nAvgBytesPerSec = pFormat->nSamplesPerSec * pFormat->nChannels * 2;
pFormat->nBlockAlign = 2 * pFormat->nChannels;
pFormat->cbSize = 0;
XMAENCODERSTREAM inputStream = { 0 };
WAVEFORMATEXTENSIBLE wfx;
Assert( g_chunks[formatChunk].size <= sizeof( WAVEFORMATEXTENSIBLE ) );
memcpy( &wfx, g_chunks[formatChunk].pData, g_chunks[formatChunk].size );
if ( g_chunks[formatChunk].size < sizeof( WAVEFORMATEXTENSIBLE ) )
{
memset( (unsigned char*)&wfx + g_chunks[formatChunk].size, 0, sizeof( WAVEFORMATEXTENSIBLE ) - g_chunks[formatChunk].size );
}
memcpy( &inputStream.Format, &wfx, sizeof( WAVEFORMATEX ) );
inputStream.pBuffer = g_chunks[dataChunk].pData;
inputStream.BufferSize = g_chunks[dataChunk].size;
if ( loopStart != -1 )
{
// can only support a single loop point until end of file
inputStream.LoopStart = loopStart;
inputStream.LoopLength = inputStream.BufferSize / ( pFormat->nChannels * sizeof( short ) ) - loopStart;
}
void *pXMAData = NULL;
DWORD XMADataSize = 0;
XMA2WAVEFORMAT *pXMA2Format = NULL;
DWORD XMA2FormatSize = 0;
DWORD *pXMASeekTable = NULL;
DWORD XMASeekTableSize = 0;
HRESULT hr = S_OK;
DWORD xmaFlags = XMAENCODER_NOFILTER;
if ( loopStart != -1 )
{
xmaFlags |= XMAENCODER_LOOP;
}
int numAttempts = 1;
while ( numAttempts < 10 )
{
hr = XMA2InMemoryEncoder( 1, &inputStream, quality, xmaFlags, XMA_BLOCK_SIZE/1024, &pXMAData, &XMADataSize, &pXMA2Format, &XMA2FormatSize, &pXMASeekTable, &XMASeekTableSize );
if ( !FAILED( hr ) )
break;
// make small jumps
quality += 5;
if ( quality > 100 )
quality = 100;
if ( !g_bQuiet )
{
Msg( "XMA Encoding Error on '%s', Attempting increasing quality to %d\n", pDebugName, quality );
}
numAttempts++;
pXMAData = NULL;
XMADataSize = 0;
pXMA2Format = NULL;
XMA2FormatSize = 0;
pXMASeekTable = NULL;
XMASeekTableSize = 0;
}
if ( FAILED( hr ) )
{
// unrecoverable
return false;
}
else if ( numAttempts > 1 )
{
if ( !g_bQuiet )
{
Msg( "XMA Encoding Success on '%s' at quality %d\n", pDebugName, quality );
}
}
DWORD loopBlock = 0;
DWORD numLeadingSamples = 0;
DWORD numTrailingSamples = 0;
if ( loopStart != -1 )
{
// calculate start block/offset
DWORD loopBlockStartIndex = 0;
DWORD loopBlockStartOffset = 0;
if ( !SampleToXMABlockOffset( BigLong( pXMA2Format->LoopBegin ), pXMASeekTable, XMASeekTableSize/sizeof( DWORD ), &loopBlockStartIndex, &loopBlockStartOffset ) )
{
// could not determine loop point, out of range of encoded samples
Msg( "XMA Loop Encoding Error on '%s', loop %d\n", pDebugName, loopStart );
return false;
}
loopBlock = loopBlockStartIndex;
numLeadingSamples = loopBlockStartOffset;
if ( BigLong( pXMA2Format->LoopEnd ) < BigLong( pXMA2Format->SamplesEncoded ) )
{
// calculate end block/offset
DWORD loopBlockEndIndex = 0;
DWORD loopBlockEndOffset = 0;
if ( !SampleToXMABlockOffset( BigLong( pXMA2Format->LoopEnd ), pXMASeekTable, XMASeekTableSize/sizeof( DWORD ), &loopBlockEndIndex, &loopBlockEndOffset ) )
{
// could not determine loop point, out of range of encoded samples
Msg( "XMA Loop Encoding Error on '%s', loop %d\n", pDebugName, loopStart );
return false;
}
if ( loopBlockEndIndex != BigLong( pXMA2Format->BlockCount ) - 1 )
{
// end block MUST be last block
Msg( "XMA Loop Encoding Error on '%s', block end is %d/%d\n", pDebugName, loopBlockEndOffset, BigLong( pXMA2Format->BlockCount ) );
return false;
}
numTrailingSamples = BigLong( pXMA2Format->SamplesEncoded ) - BigLong( pXMA2Format->LoopEnd );
}
// check for proper encoding range
if ( loopBlock > 32767 )
{
Msg( "XMA Loop Encoding Error on '%s', loop block exceeds 16 bits %d\n", pDebugName, loopBlock );
return false;
}
if ( numLeadingSamples > 32767 )
{
Msg( "XMA Loop Encoding Error on '%s', leading samples exceeds 16 bits %d\n", pDebugName, numLeadingSamples );
return false;
}
if ( numTrailingSamples > 32767 )
{
Msg( "XMA Loop Encoding Error on '%s', trailing samples exceeds 16 bits %d\n", pDebugName, numTrailingSamples );
return false;
}
}
xwvHeader_t header;
memset( &header, 0, sizeof( xwvHeader_t ) );
int seekTableSize = 0;
if ( vdatSize || bIsVoiceOver )
{
// save the optional seek table only for vdat or vo
// the seek table size is expected to be derived by this calculation
seekTableSize = ( XMADataSize / XMA_BYTES_PER_PACKET ) * sizeof( int );
if ( seekTableSize != XMASeekTableSize )
{
Msg( "XMA Error: Unexpected seek table calculation in '%s'!", pDebugName );
return false;
}
}
if ( loopStart != -1 && ( vdatSize || bIsVoiceOver ) )
{
Msg( "XMA Warning: Unexpected loop in vo data '%s'!", pDebugName );
// do not write the seek table for looping sounds
seekTableSize = 0;
}
header.id = BigLong( XWV_ID );
header.version = BigLong( XWV_VERSION );
header.headerSize = BigLong( sizeof( xwvHeader_t ) );
header.staticDataSize = BigLong( seekTableSize + vdatSize );
header.dataOffset = BigLong( AlignValue( sizeof( xwvHeader_t) + seekTableSize + vdatSize, XBOX_DVD_SECTORSIZE ) );
header.dataSize = BigLong( XMADataSize );
// track the XMA number of samples that will get decoded
// which is NOT the same as what the source actually encoded
header.numDecodedSamples = pXMA2Format->SamplesEncoded;
if ( loopStart != -1 )
{
// the loop start is in source space (now meaningless), need the loop in XMA decoding sample space
header.loopStart = pXMA2Format->LoopBegin;
}
else
{
header.loopStart = BigLong( -1 );
}
header.loopBlock = BigShort( (unsigned short)loopBlock );
header.numLeadingSamples = BigShort( (unsigned short)numLeadingSamples );
header.numTrailingSamples = BigShort( (unsigned short)numTrailingSamples );
header.vdatSize = BigShort( (short)vdatSize );
header.format = XWV_FORMAT_XMA;
header.bitsPerSample = 16;
header.SetSampleRate( pFormat->nSamplesPerSec );
header.SetChannels( pFormat->nChannels );
header.quality = quality;
header.bHasSeekTable = ( seekTableSize != 0 );
// output header
targetBuff.Put( &header, sizeof( xwvHeader_t ) );
// output optional seek table
if ( seekTableSize )
{
// seek table is already in big-endian format
targetBuff.Put( pXMASeekTable, seekTableSize );
}
// output vdat
if ( vdatSize )
{
targetBuff.Put( g_chunks[vdatChunk].pData, g_chunks[vdatChunk].size );
}
AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE );
// write data
targetBuff.Put( pXMAData, XMADataSize );
// pad to EOF
AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE );
free( pXMAData );
free( pXMA2Format );
free( pXMASeekTable );
// xma encoder leaves its temporary files, we'll delete
scriptlib->DeleteTemporaryFiles( "LoopStrm*" );
scriptlib->DeleteTemporaryFiles( "EncStrm*" );
return true;
#endif
}
bool EncodeAsPCM( const char *pTargetName, CUtlBuffer &targetBuff )
{
int formatChunk = FindChunk( WAVE_FMT );
int dataChunk = FindChunk( WAVE_DATA );
if ( formatChunk == -1 || dataChunk == -1 )
{
// huh? these should have been pre-validated
return false;
}
WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData;
if ( pFormat->wBitsPerSample != 16 )
{
// huh? the input is expeted to be 16 bit PCM
return false;
}
int vdatSize = 0;
int vdatChunk = FindChunk( WAVE_VALVEDATA );
if ( vdatChunk != -1 )
{
vdatSize = g_chunks[vdatChunk].size;
}
chunk_t *pDataChunk = &g_chunks[dataChunk];
xwvHeader_t header;
memset( &header, 0, sizeof( xwvHeader_t ) );
int sampleSize = pFormat->nChannels * sizeof( short );
int sampleCount = pDataChunk->size / sampleSize;
header.id = BigLong( XWV_ID );
header.version = BigLong( XWV_VERSION );
header.headerSize = BigLong( sizeof( xwvHeader_t ) );
header.staticDataSize = BigLong( vdatSize );
header.dataOffset = BigLong( AlignValue( sizeof( xwvHeader_t) + vdatSize, XBOX_DVD_SECTORSIZE ) );
header.dataSize = BigLong( pDataChunk->size );
header.numDecodedSamples = BigLong( sampleCount );
header.loopStart = BigLong( -1 );
header.loopBlock = 0;
header.numLeadingSamples = 0;
header.numTrailingSamples = 0;
header.vdatSize = BigShort( (short)vdatSize );
header.format = XWV_FORMAT_PCM;
header.bitsPerSample = 16;
header.SetSampleRate( pFormat->nSamplesPerSec );
header.SetChannels( pFormat->nChannels );
header.quality = 100;
// output header
targetBuff.Put( &header, sizeof( xwvHeader_t ) );
// output vdat
if ( vdatSize )
{
targetBuff.Put( g_chunks[vdatChunk].pData, g_chunks[vdatChunk].size );
}
AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE );
for ( int i = 0; i < sampleCount * pFormat->nChannels; i++ )
{
((short *)pDataChunk->pData)[i] = BigShort( ((short *)pDataChunk->pData)[i] );
}
// write data
targetBuff.Put( pDataChunk->pData, pDataChunk->size );
// pad to EOF
AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: read source, do work, and write to target
//-----------------------------------------------------------------------------
bool CreateTargetFile_WAV( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
g_numChunks = 0;
// resolve relative source to absolute path
char fullSourcePath[MAX_PATH];
if ( _fullpath( fullSourcePath, pSourceName, sizeof( fullSourcePath ) ) )
{
pSourceName = fullSourcePath;
}
if ( !ReadChunks( pSourceName, g_numChunks, g_chunks ) )
{
Msg( "No RIFF Chunks on '%s'\n", pSourceName );
return false;
}
int formatChunk = FindChunk( WAVE_FMT );
if ( formatChunk == -1 )
{
Msg( "RIFF Format Chunk not found on '%s'\n", pSourceName );
return false;
}
int dataChunk = FindChunk( WAVE_DATA );
if ( dataChunk == -1 )
{
Msg( "RIFF Data Chunk not found on '%s'\n", pSourceName );
return false;
}
// get the conversion rules
conversion_t *pConversion = g_defaultConversionRules;
if ( V_stristr( g_szModPath, "\\portal" ) )
{
pConversion = g_portalConversionRules;
}
// conversion rules are based on matching subdir
for ( int i=1; ;i++ )
{
char subString[MAX_PATH];
if ( !pConversion[i].pSubDir )
{
// end of list
break;
}
sprintf( subString, "\\%s\\", pConversion[i].pSubDir );
if ( V_stristr( pSourceName, subString ) )
{
// use matched conversion rules
pConversion = &pConversion[i];
break;
}
}
bool bForceTo22K = pConversion->bForceTo22K;
int quality = pConversion->quality;
// cannot trust the localization depots to have matched their sources
// cannot allow 44K
if ( IsLocalizedFile( pSourceName ) )
{
bForceTo22K = true;
}
// classify strict vo from /sound/vo only
bool bIsVoiceOver = V_stristr( pSourceName, "\\sound\\vo\\" ) != NULL;
// can override default settings
quality = CommandLine()->ParmValue( "-xmaquality", quality );
if ( quality < 0 )
quality = 0;
else if ( quality > 100 )
quality = 100;
if ( !g_bQuiet )
{
Msg( "Encoding quality: %d on '%s'\n", quality, pSourceName );
}
int vdatSize = 0;
int vdatChunk = FindChunk( WAVE_VALVEDATA );
if ( vdatChunk != -1 )
{
// compile to optimal block
if ( !CompressVDAT( &g_chunks[vdatChunk] ) )
{
Msg( "Compress VDAT Error on '%s'\n", pSourceName );
return false;
}
vdatSize = g_chunks[vdatChunk].size;
}
// for safety (not trusting their decoding) and simplicity convert all data to 16 bit PCM before encoding
WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData;
if ( ( pFormat->wFormatTag == WAVE_FORMAT_PCM ) )
{
if ( pFormat->wBitsPerSample == 8 )
{
ConvertPCMDataChunk8To16( &g_chunks[formatChunk], &g_chunks[dataChunk] );
}
}
else if ( pFormat->wFormatTag == WAVE_FORMAT_ADPCM )
{
ConvertADPCMDataChunkTo16( &g_chunks[formatChunk], &g_chunks[dataChunk] );
}
else
{
Msg( "Unknown RIFF Format on '%s'\n", pSourceName );
return false;
}
// optionally decimate to 22K
if ( pFormat->nSamplesPerSec == 44100 && bForceTo22K )
{
if ( !g_bQuiet )
{
Msg( "Converting to 22K '%s'\n", pSourceName );
}
ConvertPCMDataChunk16To22K( &g_chunks[formatChunk], &g_chunks[dataChunk] );
}
CUtlBuffer targetBuff;
bool bSuccess;
bSuccess = EncodeAsXMA( pSourceName, targetBuff, quality, bIsVoiceOver );
if ( bSuccess )
{
WriteBufferToFile( pTargetName, targetBuff, bWriteToZip, g_WriteModeForConversions );
}
// release data
for ( int i = 0; i < g_numChunks; i++ )
{
free( g_chunks[i].pData );
}
return bSuccess;
}
//-----------------------------------------------------------------------------
// Purpose: MP3's are already pre-converted into .360.wav
//-----------------------------------------------------------------------------
bool CreateTargetFile_MP3( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
CUtlBuffer targetBuffer;
// ignore the .mp3 source, the .360.wav target should have been pre-converted, checked in, and exist
// use the expected target as the source
if ( !scriptlib->ReadFileToBuffer( pTargetName, targetBuffer ) )
{
// the .360.wav target does not exist
// try again using a .wav version and convert from that
char wavFilename[MAX_PATH];
V_StripExtension( pSourceName, wavFilename, sizeof( wavFilename ) );
V_SetExtension( wavFilename, ".wav", sizeof( wavFilename ) );
if ( scriptlib->DoesFileExist( wavFilename ) )
{
if ( CreateTargetFile_WAV( wavFilename, pTargetName, bWriteToZip ) )
{
return true;
}
}
return false;
}
// no conversion to write, but possibly zipped
bool bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, WRITE_TO_DISK_NEVER );
return bSuccess;
}
//-----------------------------------------------------------------------------
// Get the preload data for a wav file
//-----------------------------------------------------------------------------
bool GetPreloadData_WAV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
xwvHeader_t *pHeader = ( xwvHeader_t * )fileBufferIn.Base();
if ( pHeader->id != ( unsigned int )BigLong( XWV_ID ) ||
pHeader->version != ( unsigned int )BigLong( XWV_VERSION ) ||
pHeader->headerSize != BigLong( sizeof( xwvHeader_t ) ) )
{
// bad version
Msg( "Can't preload: '%s', has bad version\n", pFilename );
return false;
}
// ensure caller's buffer is clean
// caller determines preload size, via TellMaxPut()
preloadBufferOut.Purge();
unsigned int preloadSize = BigLong( pHeader->headerSize ) + BigLong( pHeader->staticDataSize );
preloadBufferOut.Put( fileBufferIn.Base(), preloadSize );
return true;
}
+45
View File
@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: .360.VTF Creation
//
//=====================================================================================//
#include "MakeGameData.h"
#include "vtf/vtf.h"
//-----------------------------------------------------------------------------
// Purpose: Create the 360 VTF, use the library!
//-----------------------------------------------------------------------------
bool CreateTargetFile_VTF( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
{
CUtlBuffer sourceBuffer;
CUtlBuffer targetBuffer;
if ( !scriptlib->ReadFileToBuffer( pSourceName, sourceBuffer ) )
{
return false;
}
// using library conversion routine
bool bSuccess = ConvertVTFTo360Format( pSourceName, sourceBuffer, targetBuffer, CompressCallback );
if ( bSuccess )
{
bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions );
}
return bSuccess;
}
//-----------------------------------------------------------------------------
// Get the preload data for a vtf file
//-----------------------------------------------------------------------------
bool GetPreloadData_VTF( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut )
{
if ( !GetVTFPreload360Data( pFilename, fileBufferIn, preloadBufferOut ) )
{
Msg( "Can't preload: '%s', has bad version\n", pFilename );
return false;
}
return true;
}
+593
View File
@@ -0,0 +1,593 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "MakeGameData.h"
static CUtlSymbolTable g_CriticalPreloadTable( 0, 32, true );
//-----------------------------------------------------------------------------
// Purpose: Compute preload data by file type. Calls into appropriate libraries
// to get the preload info. Libraries would use filename to generate
// the preload if there is a compilation step, otherwise the file buffer
// is a buffer loaded filename.
//-----------------------------------------------------------------------------
static bool GetPreloadBuffer( const char *pFilename, CUtlBuffer &fileBuffer, CUtlBuffer &preloadBuffer )
{
char fileExtension[MAX_PATH];
Q_ExtractFileExtension( pFilename, fileExtension, sizeof( fileExtension ) );
// adding an entire file IS ONLY for files that are expected to be read by the game as a single read
// NOT for files that have any seek pattern
bool bAddEntireFile = false;
// trivial small files, always add
if ( !Q_stricmp( fileExtension, "txt" ) ||
!Q_stricmp( fileExtension, "dat" ) ||
!Q_stricmp( fileExtension, "lst" ) ||
!Q_stricmp( fileExtension, "res" ) ||
!Q_stricmp( fileExtension, "vmt" ) ||
!Q_stricmp( fileExtension, "cfg" ) ||
!Q_stricmp( fileExtension, "bnf" ) ||
!Q_stricmp( fileExtension, "rc" ) ||
!Q_stricmp( fileExtension, "vbf" ) ||
!Q_stricmp( fileExtension, "vfe" ) ||
!Q_stricmp( fileExtension, "pcf" ) ||
!Q_stricmp( fileExtension, "inf" ) )
{
bAddEntireFile = true;
}
// critical resources get blindly added to the preload
if ( !bAddEntireFile && ( g_CriticalPreloadTable.Find( pFilename ) != UTL_INVAL_SYMBOL ) )
{
bAddEntireFile = true;
}
if ( bAddEntireFile && LZMA_IsCompressed( (unsigned char *)fileBuffer.Base() ) )
{
// sorry, not allowed to add entirely to preload if already compressed
// breaks the run-time filesystem due to inability to deliver file as-is
bAddEntireFile = false;
}
if ( bAddEntireFile )
{
if ( fileBuffer.TellMaxPut() >= 1*1024 )
{
// only compress preload files of reasonable size
unsigned int compressedSize = 0;
unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)fileBuffer.Base(),
fileBuffer.TellMaxPut(), &compressedSize );
if ( pCompressedOutput )
{
// add as compressed
preloadBuffer.EnsureCapacity( compressedSize );
preloadBuffer.Put( pCompressedOutput, compressedSize );
free( pCompressedOutput );
return true;
}
}
// add entire file to preload section
preloadBuffer.EnsureCapacity( fileBuffer.TellMaxPut() );
preloadBuffer.Put( fileBuffer.Base(), fileBuffer.TellMaxPut() );
return true;
}
// Each library will fetch the optional preload data into caller's buffer
if ( !Q_stricmp( fileExtension, "wav" ) )
{
return GetPreloadData_WAV( pFilename, fileBuffer, preloadBuffer );
}
else if ( !Q_stricmp( fileExtension, "vtf" ) )
{
return GetPreloadData_VTF( pFilename, fileBuffer, preloadBuffer );
}
else if ( !Q_stricmp( fileExtension, "vcs" ) )
{
return GetPreloadData_VCS( pFilename, fileBuffer, preloadBuffer );
}
else if ( !Q_stricmp( fileExtension, "vhv" ) )
{
return GetPreloadData_VHV( pFilename, fileBuffer, preloadBuffer );
}
else if ( !Q_stricmp( fileExtension, "vtx" ) )
{
return GetPreloadData_VTX( pFilename, fileBuffer, preloadBuffer );
}
else if ( !Q_stricmp( fileExtension, "vvd" ) )
{
return GetPreloadData_VVD( pFilename, fileBuffer, preloadBuffer );
}
// others...
return false;
}
void SetupCriticalPreloadScript( const char *pModPath )
{
characterset_t breakSet;
CharacterSetBuild( &breakSet, "" );
// purge any prior entries
g_CriticalPreloadTable.RemoveAll();
// populate table
char szCriticaList[MAX_PATH];
char szToken[MAX_PATH];
V_ComposeFileName( pModPath, "scripts\\preload_xbox.xsc", szCriticaList, sizeof( szCriticaList ) );
CUtlBuffer criticalListBuffer;
if ( ReadFileToBuffer( szCriticaList, criticalListBuffer, true, true ) )
{
for ( ;; )
{
int nTokenSize = criticalListBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) );
if ( nTokenSize <= 0 )
{
break;
}
V_strlower( szToken );
V_FixSlashes( szToken, CORRECT_PATH_SEPARATOR );
if ( UTL_INVAL_SYMBOL == g_CriticalPreloadTable.Find( szToken ) )
{
g_CriticalPreloadTable.AddString( szToken );
}
}
}
}
CXZipTool::CXZipTool()
{
m_pZip = NULL;
m_hPreloadFile = INVALID_HANDLE_VALUE;
m_hOutputZipFile = INVALID_HANDLE_VALUE;
m_PreloadFilename[0] = '\0';
}
CXZipTool::~CXZipTool()
{
Reset();
}
void CXZipTool::Reset()
{
if ( m_hOutputZipFile != INVALID_HANDLE_VALUE )
{
CloseHandle( m_hOutputZipFile );
m_hOutputZipFile = INVALID_HANDLE_VALUE;
}
if ( m_hPreloadFile != INVALID_HANDLE_VALUE )
{
CloseHandle( m_hPreloadFile );
m_hPreloadFile = INVALID_HANDLE_VALUE;
}
if ( m_PreloadFilename[0] )
{
DeleteFile( m_PreloadFilename );
m_PreloadFilename[0] = '\0';
}
if ( m_pZip )
{
IZip::ReleaseZip( m_pZip );
m_pZip = NULL;
}
m_ZipPreloadDirectoryEntries.Purge();
m_ZipCRCList.Purge();
m_ZipPreloadRemapEntries.Purge();
}
//-----------------------------------------------------------------------------
// Purpose: Add a file buffer to the zip
//-----------------------------------------------------------------------------
bool CXZipTool::AddBuffer( const char *pFilename, CUtlBuffer &fileBuffer, bool bDoPreload )
{
if ( !m_pZip )
{
return false;
}
// safely strip unecessary prefix, otherise pollutes CRC
if ( !strnicmp( pFilename, ".\\", 2 ) )
{
pFilename += 2;
}
// scan for CRC collision now, not at runtime
CRCEntry_t crcEntry;
crcEntry.fileNameCRC = HashStringCaselessConventional( pFilename );
crcEntry.filename = pFilename;
int idx = m_ZipCRCList.Find( crcEntry );
if ( -1 != idx )
{
if ( !V_stricmp( pFilename, m_ZipCRCList[idx].filename.String() ) )
{
// file has already been added, ignore as succesful
return true;
}
Msg( "ERROR: CRC Collision: '%s' with '%s'\n", pFilename, m_ZipCRCList[idx].filename.String() );
return false;
}
else
{
// add unique entry to lists
// must track filenames in a non-sort manner
m_ZipCRCList.Insert( crcEntry );
}
// default, no preload entry
unsigned short preloadDir = INVALID_PRELOAD_ENTRY;
if ( bDoPreload )
{
CUtlBuffer preloadBuffer;
bool bHasPreload = GetPreloadBuffer( pFilename, fileBuffer, preloadBuffer );
int preloadSize = preloadBuffer.TellMaxPut();
if ( bHasPreload && preloadSize > 0 )
{
if ( m_ZipPreloadDirectoryEntries.Count() >= 65534 )
{
Msg( "ERROR: Preload section FULL!, skipping %s\n", pFilename );
return FALSE;
}
// Initialize the entry header
ZIP_PreloadDirectoryEntry entry;
memset( &entry, 0, sizeof( entry ) );
entry.Length = preloadSize;
entry.DataOffset = SetFilePointer( m_hPreloadFile, 0, NULL, FILE_CURRENT );
// Add the directory entry to the preload table
preloadDir = m_ZipPreloadDirectoryEntries.AddToTail( entry );
// Append the preload data to the preload file
DWORD numBytesWritten;
BOOL bOK = WriteFile( m_hPreloadFile, preloadBuffer.Base(), preloadSize, &numBytesWritten, NULL );
if ( !bOK || preloadSize != numBytesWritten )
{
Msg( "ERROR: writing %d preload bytes of '%s'\n", preloadSize, pFilename );
return false;
}
if ( !g_bQuiet )
{
// Spew it
if ( LZMA_IsCompressed( (unsigned char *)preloadBuffer.Base() ) )
{
unsigned int actualSize = LZMA_GetActualSize( (unsigned char *)preloadBuffer.Base() );
Msg( "Preload: '%s': Compressed:%u Actual:%u\n", pFilename, preloadSize, actualSize );
}
else
{
Msg( "Preload: '%s': Length:%u\n", pFilename, preloadSize );
}
}
}
}
unsigned int fileSize = fileBuffer.TellMaxPut();
if ( fileSize > 0 )
{
// order in zip is sorted, not sequential
m_pZip->AddBufferToZip( pFilename, fileBuffer.Base(), fileSize, false );
// track the file in the zip directory to it's preload entry
// order in preload is sequential as buffers are added
preloadRemap_t remap;
remap.filename = pFilename;
remap.preloadDirIndex = preloadDir;
m_ZipPreloadRemapEntries.AddToTail( remap );
if ( !g_bQuiet )
{
Msg( "File: '%s': Length:%u\n", pFilename, fileSize );
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Load a file and add it to the zip
//-----------------------------------------------------------------------------
bool CXZipTool::AddFile( const char *pFilename, bool bDoPreload )
{
if ( !m_pZip )
{
return false;
}
FILE* pFile = fopen( pFilename, "rb" );
if( !pFile )
{
Msg( "ERROR: failed to open file: '%s'\n", pFilename );
return false;
}
// Get the length of the file
fseek( pFile, 0, SEEK_END );
unsigned fileSize = ftell( pFile );
fseek( pFile, 0, SEEK_SET);
// read file to buffer
CUtlBuffer fileBuffer;
fileBuffer.EnsureCapacity( fileSize );
fread( fileBuffer.Base(), fileSize, 1, pFile );
fclose( pFile );
fileBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, fileSize );
return AddBuffer( pFilename, fileBuffer, bDoPreload );
}
//-----------------------------------------------------------------------------
// Purpose: Add the preload section and save out the zip file
//-----------------------------------------------------------------------------
bool CXZipTool::End()
{
if ( !m_pZip )
{
return false;
}
// Add the preload section to the zip
if ( m_ZipPreloadDirectoryEntries.Count() )
{
CUtlBuffer sectionBuffer;
CByteswap byteSwap;
// pc tools write 360 native data
byteSwap.ActivateByteSwapping( IsPC() );
// determine the preload data footprint
unsigned int preloadDataSize = SetFilePointer( m_hPreloadFile, 0, NULL, FILE_CURRENT );
// finalize header
m_ZipPreloadHeader.DirectoryEntries = m_ZipPreloadRemapEntries.Count();
m_ZipPreloadHeader.PreloadDirectoryEntries = m_ZipPreloadDirectoryEntries.Count();
// determine the total section size ( treated as a single file inside zip )
unsigned int sectionSize = sizeof( ZIP_PreloadHeader ) +
m_ZipPreloadHeader.PreloadDirectoryEntries * sizeof( ZIP_PreloadDirectoryEntry ) +
m_ZipPreloadHeader.DirectoryEntries * sizeof( unsigned short ) +
preloadDataSize;
sectionSize = AlignValue( sectionSize, m_ZipPreloadHeader.Alignment );
sectionBuffer.EnsureCapacity( sectionSize );
// save data in order
// save the header
byteSwap.SwapFieldsToTargetEndian( &m_ZipPreloadHeader );
sectionBuffer.Put( &m_ZipPreloadHeader, sizeof( ZIP_PreloadHeader ) );
// fixup and save the preload directory
for ( int i=0; i<m_ZipPreloadDirectoryEntries.Count(); i++ )
{
ZIP_PreloadDirectoryEntry entry = m_ZipPreloadDirectoryEntries[i];
byteSwap.SwapFieldsToTargetEndian( &entry );
sectionBuffer.Put( &entry, sizeof( ZIP_PreloadDirectoryEntry ) );
}
// generate remap table
char fileName[MAX_PATH];
int fileSize;
int zipIndex = -1;
unsigned short *pRemapTable = (unsigned short *)malloc( m_ZipPreloadRemapEntries.Count() * sizeof( unsigned short ) );
for ( int i=0; i<m_ZipPreloadRemapEntries.Count(); i++ )
{
// zip files get iterated in the same order they are serialized to disk
fileName[0] = '\0';
fileSize = 0;
zipIndex = m_pZip->GetNextFilename( zipIndex, fileName, sizeof( fileName ), fileSize );
// find the file in the preload remap table
bool bFound = false;
int j;
for ( j=0; j<m_ZipPreloadRemapEntries.Count(); j++ )
{
if ( !Q_stricmp( fileName, m_ZipPreloadRemapEntries[j].filename.String() ) )
{
bFound = true;
break;
}
}
if ( !bFound )
{
// shouldn't happen, every file in the zip has a matching preload remap entry, that is valid or marked invalid
Msg( "ERROR: file '%s' was expected to have an entry in preload table\n", fileName );
}
// the remap table is used to go find a file's preload data (if available)
pRemapTable[i] = m_ZipPreloadRemapEntries[j].preloadDirIndex;
}
for ( int i=0; i<m_ZipPreloadRemapEntries.Count(); i++ )
{
unsigned short s = pRemapTable[i];
sectionBuffer.PutShort( BigShort( s ) );
}
free( pRemapTable );
// get and save preload data
void *pPreloadData = malloc( preloadDataSize );
SetFilePointer( m_hPreloadFile, 0, NULL, FILE_BEGIN );
DWORD numBytesRead;
BOOL bOK = ReadFile( m_hPreloadFile, pPreloadData, preloadDataSize, &numBytesRead, NULL );
if ( !bOK || numBytesRead != preloadDataSize )
{
Msg( "ERROR: failed to read %d bytes from temporary preload file\n", preloadDataSize );
}
CloseHandle( m_hPreloadFile );
m_hPreloadFile = INVALID_HANDLE_VALUE;
sectionBuffer.Put( pPreloadData, preloadDataSize );
free( pPreloadData );
// cannot have written more than was pre-calced, unless code was broken
Assert( (unsigned int)sectionBuffer.TellMaxPut() <= sectionSize );
while( (unsigned int)sectionBuffer.TellMaxPut() < sectionSize )
{
// pad to final alignment
sectionBuffer.PutChar( 0 );
}
m_pZip->AddBufferToZip( PRELOAD_SECTION_NAME, sectionBuffer.Base(), sectionBuffer.TellMaxPut(), false );
}
else
{
// Clear the preload section placeholder
m_pZip->RemoveFileFromZip( PRELOAD_SECTION_NAME );
}
m_pZip->SaveToDisk( m_hOutputZipFile );
Reset();
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Create the zip file
//-----------------------------------------------------------------------------
bool CXZipTool::Begin( const char *pZipFileName, unsigned int alignment )
{
// get the volume of the target zip
char drivePath[MAX_PATH];
_splitpath( pZipFileName, drivePath, NULL, NULL, NULL );
m_pZip = IZip::CreateZip( drivePath, true );
if ( alignment )
{
// making an aligned zip that uses an optimized (but incompatible) format
m_pZip->ForceAlignment( true, false, alignment );
}
// Open the output file
m_hOutputZipFile = CreateFile( pZipFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( m_hOutputZipFile == INVALID_HANDLE_VALUE )
{
Msg( "ERROR: failed to create zip file '%s'\n", pZipFileName );
return false;
}
// Create a temporary file for storing the preloaded data
scriptlib->MakeTemporaryFilename( g_szModPath, m_PreloadFilename, sizeof( m_PreloadFilename ) );
m_hPreloadFile = CreateFile( m_PreloadFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( m_hPreloadFile == INVALID_HANDLE_VALUE )
{
Msg( "ERROR: failed to create temporary file '%s' for preload data\n", m_PreloadFilename );
CloseHandle( m_hOutputZipFile );
m_hOutputZipFile = INVALID_HANDLE_VALUE;
return false;
}
memset( &m_ZipPreloadHeader, 0, sizeof( ZIP_PreloadHeader ) );
m_ZipPreloadHeader.Version = PRELOAD_HDR_VERSION;
m_ZipPreloadHeader.Alignment = alignment;
// Add a placeholder for the preload section
m_pZip->AddBufferToZip( PRELOAD_SECTION_NAME, NULL, 0, false );
preloadRemap_t remap;
remap.filename = PRELOAD_SECTION_NAME;
remap.preloadDirIndex = INVALID_PRELOAD_ENTRY;
m_ZipPreloadRemapEntries.AddToTail( remap );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Dump the preload contents
//-----------------------------------------------------------------------------
void CXZipTool::SpewPreloadInfo( const char *pZipName )
{
IZip *pZip = IZip::CreateZip( NULL, true );
HANDLE hZipFile = pZip->ParseFromDisk( pZipName );
if ( !hZipFile )
{
Msg( "Bad or missing zip file, failed to open '%s'\n", pZipName );
return;
}
CUtlBuffer preloadBuffer;
if ( !pZip->ReadFileFromZip( hZipFile, PRELOAD_SECTION_NAME, false, preloadBuffer ) )
{
Msg( "No preload info for '%s'\n", pZipName );
return;
}
preloadBuffer.ActivateByteSwapping( IsPC() );
ZIP_PreloadHeader header;
preloadBuffer.GetObjects( &header );
// get the dir table
ZIP_PreloadDirectoryEntry *pDir = (ZIP_PreloadDirectoryEntry *)malloc( header.PreloadDirectoryEntries * sizeof( ZIP_PreloadDirectoryEntry ) );
preloadBuffer.GetObjects( pDir, header.PreloadDirectoryEntries );
// get the remap table
unsigned short *pRemap = (unsigned short *)malloc( header.DirectoryEntries * sizeof( unsigned short ) );
for ( unsigned int i = 0; i < header.DirectoryEntries; i++ )
{
pRemap[i] = preloadBuffer.GetShort();
}
int zipIndex = -1;
int fileSize;
char fileName[MAX_PATH];
// iterate preload entries sequentially
CUtlDict< unsigned int, int > sizes( true );
for ( unsigned int i = 0; i < header.DirectoryEntries; i++ )
{
fileName[0] = '\0';
fileSize = 0;
zipIndex = pZip->GetNextFilename( zipIndex, fileName, sizeof( fileName ), fileSize );
unsigned short zipPreloadDirIndex = pRemap[i];
if ( zipPreloadDirIndex == INVALID_PRELOAD_ENTRY )
{
continue;
}
Msg( "Offset: 0x%8.8x Length: %5d %s (%d)\n", pDir[zipPreloadDirIndex].DataOffset, pDir[zipPreloadDirIndex].Length, fileName, fileSize );
// total preload sizes by extension
const char *pExt = V_GetFileExtension( fileName );
if ( !pExt )
{
pExt = "???";
}
int iIndex = sizes.Find( pExt );
if ( iIndex == sizes.InvalidIndex() )
{
iIndex = sizes.Insert( pExt );
sizes[iIndex] = 0;
}
sizes[iIndex] += pDir[zipPreloadDirIndex].Length;
}
Msg( "\n" );
Msg( "Preload Size: %.2f MB\n", (float)preloadBuffer.TellMaxPut()/(1024.0f * 1024.0f) );
Msg( "Zip Entries: %d\n", header.DirectoryEntries );
Msg( "Preload Entries: %d\n", header.PreloadDirectoryEntries );
// dump each extension's total size, necessary for debugging who is the largest contributor
for ( int i = 0; i < sizes.Count(); i++ )
{
Msg( "Extension: '%3s' %d bytes (%.2f%s)\n", sizes.GetElementName( i ), sizes[i], (float)sizes[i]/(float)preloadBuffer.TellMaxPut() * 100.0f, "%%" );
}
Msg( "\n" );
free( pRemap );
free( pDir );
IZip::ReleaseZip( pZip );
}
+61
View File
@@ -0,0 +1,61 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#pragma once
#include <stdio.h>
#include "utlbuffer.h"
#include "zip_uncompressed.h"
#include "generichash.h"
#include "zip_utils.h"
#include "byteswap.h"
#include "tier1/UtlVector.h"
#include "UtlSortVector.h"
struct CRCEntry_t
{
unsigned int fileNameCRC;
CUtlString filename;
};
struct preloadRemap_t
{
CUtlString filename;
unsigned short preloadDirIndex;
};
class CZipCRCLessFunc
{
public:
bool Less( CRCEntry_t const& src1, CRCEntry_t const& src2, void *pCtx )
{
return ( src1.fileNameCRC < src2.fileNameCRC );
}
};
class CXZipTool
{
public:
CXZipTool();
~CXZipTool();
void Reset();
bool Begin( const char* pFileName, unsigned int alignment = 0 );
bool End();
bool AddBuffer( const char* pFileName, CUtlBuffer &buffer, bool bPreload = true );
bool AddFile( const char* pFileName, bool bPreload = true );
void SpewPreloadInfo( const char *pZipName );
private:
IZip *m_pZip;
char m_PreloadFilename[MAX_PATH];
HANDLE m_hPreloadFile;
HANDLE m_hOutputZipFile;
ZIP_PreloadHeader m_ZipPreloadHeader;
CUtlVector< ZIP_PreloadDirectoryEntry > m_ZipPreloadDirectoryEntries;
CUtlSortVector< CRCEntry_t, CZipCRCLessFunc > m_ZipCRCList;
CUtlVector< preloadRemap_t > m_ZipPreloadRemapEntries;
};
File diff suppressed because it is too large Load Diff
+153
View File
@@ -0,0 +1,153 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
/***************************************************************************
*
* Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
*
* File: imaadpcm.h
* Content: IMA ADPCM CODEC.
* History:
* Date By Reason
* ==== == ======
* 04/29/01 dereks Created.
*
****************************************************************************/
#ifndef __IMAADPCM_H__
#define __IMAADPCM_H__
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <ctype.h>
#include <mmreg.h>
#include <msacm.h>
#define XBOX_ADPCM_SAMPLES_PER_BLOCK 64
#define WAVE_FORMAT_XBOX_ADPCM 0x0069
#define IMAADPCM_BITS_PER_SAMPLE 4
#define IMAADPCM_HEADER_LENGTH 4
#define IMAADPCM_MAX_CHANNELS 2
#define IMAADPCM_PCM_BITS_PER_SAMPLE 16
#define NUMELMS(a) (sizeof(a) / sizeof(a[0]))
typedef const WAVEFORMATEX *LPCWAVEFORMATEX;
typedef const IMAADPCMWAVEFORMAT *LPCIMAADPCMWAVEFORMAT;
#ifdef __cplusplus
//
// IMA ADPCM encoder function prototype
//
typedef BOOL (*LPFNIMAADPCMCONVERT)(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
//
// Codec mode
//
enum CODEC_MODE
{
CODEC_MODE_DECODE,
CODEC_MODE_ENCODE_NORMAL,
CODEC_MODE_ENCODE_OPTIMIZE_WHOLE_FILE,
CODEC_MODE_ENCODE_OPTIMIZE_EACH_BLOCK,
};
//
// IMA ADPCM CODEC
//
class CImaAdpcmCodec
{
private:
static const short m_asNextStep[16]; // Step increment array
static const short m_asStep[89]; // Step value array
IMAADPCMWAVEFORMAT m_wfxEncode; // Encoded format description
CODEC_MODE m_cmCodecMode; // Codec mode
int m_nStepIndexL; // Left-channel stepping index
int m_nStepIndexR; // Right-channel stepping index
LPFNIMAADPCMCONVERT m_pfnConvert; // Conversion function
public:
CImaAdpcmCodec(void);
~CImaAdpcmCodec(void);
public:
// Initialization
BOOL Initialize(LPCIMAADPCMWAVEFORMAT pwfxEncode, CODEC_MODE cmCodecMode);
// Size conversions
WORD GetEncodeAlignment(void);
WORD GetDecodeAlignment(void);
WORD GetSourceAlignment(void);
WORD GetDestinationAlignment(void);
// Data conversions
BOOL Convert(LPCVOID pvSrc, LPVOID pvDst, UINT cBlocks);
void Reset(void);
// Format descriptions
static void CreatePcmFormat(WORD nChannels, DWORD nSamplesPerSec, LPWAVEFORMATEX pwfxFormat);
static void CreateImaAdpcmFormat(WORD nChannels, DWORD nSamplesPerSec, WORD nSamplesPerBlock, LPIMAADPCMWAVEFORMAT pwfxFormat);
static BOOL IsValidPcmFormat(LPCWAVEFORMATEX pwfxFormat);
static BOOL IsValidImaAdpcmFormat(LPCIMAADPCMWAVEFORMAT pwfxFormat);
private:
// En/decoded data alignment
static WORD CalculateEncodeAlignment(WORD nSamplesPerBlock, WORD nChannels);
// Data conversion functions
static BOOL EncodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
static BOOL EncodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
static BOOL DecodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
static BOOL DecodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR);
static int EncodeSample(int nInputSample, int *nPredictedSample, int nStepSize);
static int DecodeSample(int nInputSample, int nPredictedSample, int nStepSize);
static int NextStepIndex(int nEncodedSample, int nStepIndex);
static BOOL ValidStepIndex(int nStepIndex);
/*static ULONGLONG CalcDifference(LPDWORD pvBuffer1, LPDWORD pvBuffer2, DWORD dwLength);*/
ULONGLONG CalcDifference(LPBYTE pvBuffer1, LPBYTE pvBuffer2, UINT cBlocks, UINT cTotalBlocks, DWORD dwBlockSize);
};
__inline WORD CImaAdpcmCodec::GetSourceAlignment(void)
{
return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetEncodeAlignment() : GetDecodeAlignment();
}
__inline WORD CImaAdpcmCodec::GetDestinationAlignment(void)
{
return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetDecodeAlignment() : GetEncodeAlignment();
}
__inline int CImaAdpcmCodec::NextStepIndex(int nEncodedSample, int nStepIndex)
{
nStepIndex += m_asNextStep[nEncodedSample];
if(nStepIndex < 0)
{
nStepIndex = 0;
}
else if(nStepIndex >= NUMELMS(m_asStep))
{
nStepIndex = NUMELMS(m_asStep) - 1;
}
return nStepIndex;
}
__inline BOOL CImaAdpcmCodec::ValidStepIndex(int nStepIndex)
{
return (nStepIndex >= 0) && (nStepIndex < NUMELMS(m_asStep));
}
#endif // __cplusplus
#endif // __IMAADPCM_H__
+381
View File
@@ -0,0 +1,381 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#include <windows.h>
#include <mmreg.h>
#include "../toollib/toollib.h"
#include "tier1/strtools.h"
#include "resample.h"
#define clamp(a,b,c) ( (a) > (c) ? (c) : ( (a) < (b) ? (b) : (a) ) )
const int NUM_COEFFS = 7;
static const float g_ResampleCoefficients[NUM_COEFFS] =
{
0.0457281f, 0.168088f, 0.332501f, 0.504486f, 0.663202f, 0.803781f, 0.933856f
};
// generates 1 output sample for 2 input samples
inline float DecimateSamplePair(float input0, float input1, const float pCoefficients[7], float xState[2], float yState[7] )
{
float tmp_0 = xState[0];
float tmp_1 = xState[1];
xState[0] = input0;
xState[1] = input1;
input0 = (input0 - yState[0]) * pCoefficients[0] + tmp_0;
input1 = (input1 - yState[1]) * pCoefficients[1] + tmp_1;
tmp_0 = yState[0];
tmp_1 = yState[1];
yState[0] = input0;
yState[1] = input1;
input0 = (input0 - yState[2]) * pCoefficients[2] + tmp_0;
input1 = (input1 - yState[3]) * pCoefficients[3] + tmp_1;
tmp_0 = yState[2];
tmp_1 = yState[3];
yState[2] = input0;
yState[3] = input1;
input0 = (input0 - yState[4]) * pCoefficients[4] + tmp_0;
input1 = (input1 - yState[5]) * pCoefficients[5] + tmp_1;
tmp_0 = yState[4];
yState[4] = input0;
yState[5] = input1;
input0 = (input0 - yState[6]) * pCoefficients[6] + tmp_0;
yState[6] = input0;
return (input0 + input1);
}
static void ExtractFloatSamples( float *pOut, const short *pInputBuffer, int sampleCount, int stride )
{
for ( int i = 0; i < sampleCount; i++ )
{
pOut[i] = pInputBuffer[0] * 1.0f / 32768.0f;
pInputBuffer += stride;
}
}
static void ExtractShortSamples( short *pOut, const float *pInputBuffer, float scale, int sampleCount, int stride )
{
for ( int i = 0; i < sampleCount; i++ )
{
int sampleOut = (int)(pInputBuffer[i] * scale);
sampleOut = clamp( sampleOut, -32768, 32767 );
pOut[0] = (short)(sampleOut);
pOut += stride;
}
}
struct decimatestate_t
{
float xState[2];
float yState[7];
};
void DecimateSampleBlock( float *pInOut, int sampleCount )
{
decimatestate_t block;
int outCount = sampleCount >> 1;
int pos = 0;
memset( &block, 0, sizeof(block) );
do
{
float input0 = pInOut[pos*2+0];
float input1 = pInOut[pos*2+1];
pInOut[pos] = DecimateSamplePair( input0, input1, g_ResampleCoefficients, block.xState, block.yState );
pos++;
} while( pos < outCount );
}
void DecimateSampleRateBy2_16( const short *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount )
{
float *pTmpBuf = new float[sampleCount];
for ( int i = 0; i < channelCount; i++ )
{
ExtractFloatSamples( pTmpBuf, pInputBuffer+i, sampleCount, channelCount );
DecimateSampleBlock( pTmpBuf, sampleCount );
ExtractShortSamples( pOutputBuffer+i, pTmpBuf, 0.5f * 32768.0f, sampleCount>>1, channelCount );
}
delete [] pTmpBuf;
}
struct adpcmstate_t
{
const ADPCMWAVEFORMAT *pFormat;
const ADPCMCOEFSET *pCoefficients;
int blockSize;
};
static int error_sign_lut[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 };
static int error_coefficients_lut[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
void ParseADPCM( adpcmstate_t &out, const byte *pFormatChunk )
{
out.pFormat = (const ADPCMWAVEFORMAT *)pFormatChunk;
if ( out.pFormat )
{
out.pCoefficients = out.pFormat->aCoef;
// number of bytes for samples
out.blockSize = ((out.pFormat->wSamplesPerBlock - 2) * out.pFormat->wfx.nChannels ) / 2;
// size of channel header
out.blockSize += 7 * out.pFormat->wfx.nChannels;
}
}
void DecompressBlockMono( const adpcmstate_t &state, short *pOut, const char *pIn, int count )
{
int pred = *pIn++;
int co1 = state.pCoefficients[pred].iCoef1;
int co2 = state.pCoefficients[pred].iCoef2;
// read initial delta
int delta = *((short *)pIn);
pIn += 2;
// read initial samples for prediction
int samp1 = *((short *)pIn);
pIn += 2;
int samp2 = *((short *)pIn);
pIn += 2;
// write out the initial samples (stored in reverse order)
*pOut++ = (short)samp2;
*pOut++ = (short)samp1;
// subtract the 2 samples in the header
count -= 2;
// this is a toggle to read nibbles, first nibble is high
int high = 1;
int error, sample=0;
// now process the block
while ( count )
{
// read the error nibble from the input stream
if ( high )
{
sample = (unsigned char) (*pIn++);
// high nibble
error = sample >> 4;
// cache low nibble for next read
sample = sample & 0xf;
// Next read is from cache, not stream
high = 0;
}
else
{
// stored in previous read (low nibble)
error = sample;
// next read is from stream
high = 1;
}
// convert to signed with LUT
int errorSign = error_sign_lut[error];
// interpolate the new sample
int predSample = (samp1 * co1) + (samp2 * co2);
// coefficients are fixed point 8-bit, so shift back to 16-bit integer
predSample >>= 8;
// Add in current error estimate
predSample += (errorSign * delta);
// Correct error estimate
delta = (delta * error_coefficients_lut[error]) >> 8;
// Clamp error estimate
if ( delta < 16 )
delta = 16;
// clamp
if ( predSample > 32767L )
predSample = 32767L;
else if ( predSample < -32768L )
predSample = -32768L;
// output
*pOut++ = (short)predSample;
// move samples over
samp2 = samp1;
samp1 = predSample;
count--;
}
}
//-----------------------------------------------------------------------------
// Purpose: Decode a single block of stereo ADPCM audio
// Input : *pOut - 16-bit output buffer
// *pIn - ADPCM encoded block data
// count - number of sample pairs to decode
//-----------------------------------------------------------------------------
void DecompressBlockStereo( const adpcmstate_t &state, short *pOut, const char *pIn, int count )
{
int pred[2], co1[2], co2[2];
int i;
for ( i = 0; i < 2; i++ )
{
pred[i] = *pIn++;
co1[i] = state.pCoefficients[pred[i]].iCoef1;
co2[i] = state.pCoefficients[pred[i]].iCoef2;
}
int delta[2], samp1[2], samp2[2];
for ( i = 0; i < 2; i++, pIn += 2 )
{
// read initial delta
delta[i] = *((short *)pIn);
}
// read initial samples for prediction
for ( i = 0; i < 2; i++, pIn += 2 )
{
samp1[i] = *((short *)pIn);
}
for ( i = 0; i < 2; i++, pIn += 2 )
{
samp2[i] = *((short *)pIn);
}
// write out the initial samples (stored in reverse order)
*pOut++ = (short)samp2[0]; // left
*pOut++ = (short)samp2[1]; // right
*pOut++ = (short)samp1[0]; // left
*pOut++ = (short)samp1[1]; // right
// subtract the 2 samples in the header
count -= 2;
// this is a toggle to read nibbles, first nibble is high
int high = 1;
int error, sample=0;
// now process the block
while ( count )
{
for ( i = 0; i < 2; i++ )
{
// read the error nibble from the input stream
if ( high )
{
sample = (unsigned char) (*pIn++);
// high nibble
error = sample >> 4;
// cache low nibble for next read
sample = sample & 0xf;
// Next read is from cache, not stream
high = 0;
}
else
{
// stored in previous read (low nibble)
error = sample;
// next read is from stream
high = 1;
}
// convert to signed with LUT
int errorSign = error_sign_lut[error];
// interpolate the new sample
int predSample = (samp1[i] * co1[i]) + (samp2[i] * co2[i]);
// coefficients are fixed point 8-bit, so shift back to 16-bit integer
predSample >>= 8;
// Add in current error estimate
predSample += (errorSign * delta[i]);
// Correct error estimate
delta[i] = (delta[i] * error_coefficients_lut[error]) >> 8;
// Clamp error estimate
if ( delta[i] < 16 )
delta[i] = 16;
// clamp
if ( predSample > 32767L )
predSample = 32767L;
else if ( predSample < -32768L )
predSample = -32768L;
// output
*pOut++ = (short)predSample;
// move samples over
samp2[i] = samp1[i];
samp1[i] = predSample;
}
count--;
}
}
int ADPCMSampleCountShortBlock( const adpcmstate_t &state, int shortBlockSize )
{
if ( shortBlockSize < 8 )
return 0;
int sampleCount = state.pFormat->wSamplesPerBlock;
// short block?, fixup sample count (2 samples per byte, divided by number of channels per sample set)
sampleCount -= ((state.blockSize - shortBlockSize) * 2) / state.pFormat->wfx.nChannels;
return sampleCount;
}
int ADPCMSampleCount( const byte *pFormatChunk, const byte *pDataChunk, int dataSize )
{
adpcmstate_t state;
ParseADPCM( state, pFormatChunk );
int numBlocks = dataSize / state.blockSize;
int mod = dataSize % state.blockSize;
return numBlocks * state.pFormat->wSamplesPerBlock + ADPCMSampleCountShortBlock(state, mod);
}
void DecompressADPCMSamples( const byte *pFormatChunk, const byte *pDataChunk, int dataSize, short *pOutputBuffer )
{
adpcmstate_t state;
ParseADPCM( state, pFormatChunk );
while ( dataSize > 0 )
{
int block = dataSize;
int sampleCount = state.pFormat->wSamplesPerBlock;
if ( block > state.blockSize )
{
block = state.blockSize;
}
else
{
sampleCount = ADPCMSampleCountShortBlock( state, block );
}
if ( state.pFormat->wfx.nChannels == 1 )
{
DecompressBlockMono( state, pOutputBuffer, (const char *)pDataChunk, sampleCount );
}
else
{
DecompressBlockStereo( state, pOutputBuffer, (const char *)pDataChunk, sampleCount );
}
pOutputBuffer += sampleCount * state.pFormat->wfx.nChannels;
dataSize -= block;
pDataChunk += block;
}
}
void Convert8To16( const byte *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount )
{
for ( int i = 0; i < sampleCount*channelCount; i++ )
{
unsigned short signedSample = (byte)((int)((unsigned)pInputBuffer[i]) - 128);
pOutputBuffer[i] = (short) (signedSample | (signedSample<<8));
}
}
+18
View File
@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef RESAMPLE_H
#define RESAMPLE_H
#ifdef _WIN32
#pragma once
#endif
void DecimateSampleRateBy2_16( const short *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount );
void DecompressADPCMSamples( const byte *pFormatChunk, const byte *pDataChunk, int dataSize, short *pOutputBuffer );
int ADPCMSampleCount( const byte *pFormatChunk, const byte *pDataChunk, int dataSize );
void Convert8To16( const byte *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount );
#endif // RESAMPLE_H
+68
View File
@@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
/*****************************************************************************
SOUND_IO.CPP
IO class for RIFF
*****************************************************************************/
#include "../toollib/toollib.h"
#include "tier2/riff.h"
//-----------------------------------------------------------------------------
// Purpose: Implements Audio IO on the engine's COMMON filesystem
//-----------------------------------------------------------------------------
class COM_IOReadBinary : public IFileReadBinary
{
public:
int open( const char *pFileName );
int read( void *pOutput, int size, int file );
void seek( int file, int pos );
unsigned int tell( int file );
unsigned int size( int file );
void close( int file );
};
int COM_IOReadBinary::open( const char *pFileName )
{
int hFile = -1;
_sopen_s( &hFile, pFileName, _O_RDONLY|_O_BINARY, _SH_DENYWR, _S_IREAD );
return hFile;
}
int COM_IOReadBinary::read( void *pOutput, int size, int file )
{
return _read( file, pOutput, size );
}
void COM_IOReadBinary::seek( int file, int pos )
{
_lseek( file, pos, SEEK_SET );
}
unsigned int COM_IOReadBinary::tell( int file )
{
return _lseek( file, 0, SEEK_CUR );
}
unsigned int COM_IOReadBinary::size( int file )
{
long pos;
long length;
pos = _lseek( file, 0, SEEK_CUR );
length = _lseek( file, 0, SEEK_END );
_lseek( file, pos, SEEK_SET );
return length;
}
void COM_IOReadBinary::close( int file )
{
_close( file );
}
static COM_IOReadBinary io;
IFileReadBinary *g_pSndIO = &io;