1
This commit is contained in:
451
utils/vcdupdate/vcdupdate.cpp
Normal file
451
utils/vcdupdate/vcdupdate.cpp
Normal file
@ -0,0 +1,451 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
// Valve includes
|
||||
#include "appframework/tier3app.h"
|
||||
#include "datamodel/idatamodel.h"
|
||||
#include "filesystem.h"
|
||||
#include "icommandline.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "istudiorender.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "tier2/p4helpers.h"
|
||||
#include "p4lib/ip4.h"
|
||||
#include "sfmobjects/sfmsession.h"
|
||||
#include "datacache/idatacache.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
#include "vphysics_interface.h"
|
||||
#include "studio.h"
|
||||
#include "soundemittersystem/isoundemittersystembase.h"
|
||||
#include "tier2/soundutils.h"
|
||||
#include "tier2/fileutils.h"
|
||||
#include "tier3/choreoutils.h"
|
||||
#include "tier3/scenetokenprocessor.h"
|
||||
#include "soundchars.h"
|
||||
#include "choreoscene.h"
|
||||
#include "choreoactor.h"
|
||||
#include "choreochannel.h"
|
||||
#include "choreoevent.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <windows.h>
|
||||
#undef GetCurrentDirectory
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Standard spew functions
|
||||
//-----------------------------------------------------------------------------
|
||||
static SpewRetval_t SpewStdout( SpewType_t spewType, char const *pMsg )
|
||||
{
|
||||
if ( !pMsg )
|
||||
return SPEW_CONTINUE;
|
||||
|
||||
#ifdef _DEBUG
|
||||
OutputDebugString( pMsg );
|
||||
#endif
|
||||
|
||||
printf( pMsg );
|
||||
fflush( stdout );
|
||||
|
||||
return ( spewType == SPEW_ASSERT ) ? SPEW_DEBUGGER : SPEW_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The application object
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVcdUpdateApp : public CTier3SteamApp
|
||||
{
|
||||
typedef CTier3SteamApp BaseClass;
|
||||
|
||||
public:
|
||||
// Methods of IApplication
|
||||
virtual bool Create();
|
||||
virtual bool PreInit( );
|
||||
virtual int Main();
|
||||
virtual void Destroy() {}
|
||||
|
||||
void PrintHelp( );
|
||||
|
||||
private:
|
||||
struct VcdUpdateInfo_t
|
||||
{
|
||||
const char *m_pChangedWAVFile;
|
||||
const char *m_pChangedMDLFile;
|
||||
bool m_bWarnMissingMDL;
|
||||
bool m_bWarnNotMatchingMDL;
|
||||
};
|
||||
|
||||
void UpdateVcdFiles( const VcdUpdateInfo_t& info );
|
||||
void UpdateVcd( const char *pFullPath, const VcdUpdateInfo_t& info, studiohdr_t *pStudioHdr, float flWavDuration );
|
||||
bool UpdateVcd( CChoreoScene *pScene, const VcdUpdateInfo_t& info, studiohdr_t *pStudioHdr, float flWavDuration );
|
||||
};
|
||||
|
||||
|
||||
DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT( CVcdUpdateApp );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The application object
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CVcdUpdateApp::Create()
|
||||
{
|
||||
SpewOutputFunc( SpewStdout );
|
||||
|
||||
AppSystemInfo_t appSystems[] =
|
||||
{
|
||||
{ "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
|
||||
{ "p4lib.dll", P4_INTERFACE_VERSION },
|
||||
{ "datacache.dll", DATACACHE_INTERFACE_VERSION },
|
||||
{ "datacache.dll", MDLCACHE_INTERFACE_VERSION },
|
||||
{ "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
|
||||
{ "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
|
||||
{ "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
|
||||
{ "", "" } // Required to terminate the list
|
||||
};
|
||||
|
||||
AddSystems( appSystems );
|
||||
|
||||
IMaterialSystem *pMaterialSystem = reinterpret_cast< IMaterialSystem * >( FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ) );
|
||||
if ( !pMaterialSystem )
|
||||
{
|
||||
Error( "// ERROR: Unable to connect to material system interface!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
pMaterialSystem->SetShaderAPI( "shaderapiempty.dll" );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CVcdUpdateApp::PreInit( )
|
||||
{
|
||||
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
|
||||
|
||||
if ( !BaseClass::PreInit() )
|
||||
return false;
|
||||
|
||||
if ( !g_pFullFileSystem || !g_pMDLCache )
|
||||
{
|
||||
Error( "// ERROR: vcdupdate is missing a required interface!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add paths...
|
||||
if ( !SetupSearchPaths( NULL, false, true ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print help
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVcdUpdateApp::PrintHelp( )
|
||||
{
|
||||
Msg( "Usage: vcdupdate [-w <modified .wav file>] [-m <modified .mdl file>] [-e] [-n]\n" );
|
||||
Msg( " [-nop4] [-vproject <path to gameinfo.txt>]\n" );
|
||||
Msg( "vcdupdate will fixup all vcd files in the tree to account for other asset changes.\n" );
|
||||
Msg( "\t-w\t: Specifies the relative path to a .wav file that has changed.\n" );
|
||||
Msg( "\t-m\t: Specifies the relative path to a .mdl file that has changed.\n" );
|
||||
Msg( "\t-e\t: [Optional] Displays a warning about all .vcds that don't have actors w/ associated .mdls\n" );
|
||||
Msg( "\t\tSuch files cannot be auto-updated by vcdupdate and also can generate bugs.\n" );
|
||||
Msg( "\t-n\t: [Optional] Displays a warning about all .vcds whose actor names\n" );
|
||||
Msg( "\t\tare suspiciously different from the associated .mdl\n" );
|
||||
Msg( "\t-nop4\t: Disables auto perforce checkout/add.\n" );
|
||||
Msg( "\t-vproject\t: Specifies path to a gameinfo.txt file (which mod to build for).\n" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks a single VCD to see if it needs to be updated or not.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CVcdUpdateApp::UpdateVcd( CChoreoScene *pScene, const VcdUpdateInfo_t& info, studiohdr_t *pStudioHdr, float flWavDuration )
|
||||
{
|
||||
CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
|
||||
float pPoseParameters[MAXSTUDIOPOSEPARAM];
|
||||
memset( pPoseParameters, 0, MAXSTUDIOPOSEPARAM * sizeof(float) );
|
||||
|
||||
char pModelPath[MAX_PATH];
|
||||
if ( pStudioHdr )
|
||||
{
|
||||
g_pFullFileSystem->FullPathToRelativePathEx( info.m_pChangedMDLFile, "GAME", pModelPath, sizeof(pModelPath) );
|
||||
}
|
||||
|
||||
bool bChanged = false;
|
||||
int c = pScene->GetNumEvents();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
CChoreoEvent *pEvent = pScene->GetEvent( i );
|
||||
if ( !pEvent )
|
||||
continue;
|
||||
|
||||
switch ( pEvent->GetType() )
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case CChoreoEvent::SPEAK:
|
||||
{
|
||||
if ( !info.m_pChangedWAVFile )
|
||||
continue;
|
||||
|
||||
const char *pWavFile = GetSoundForEvent( pEvent, &studioHdr );
|
||||
if ( !pWavFile )
|
||||
continue;
|
||||
|
||||
char pRelativeWAVFile[MAX_PATH];
|
||||
Q_ComposeFileName( "sound", pWavFile, pRelativeWAVFile, sizeof(pRelativeWAVFile) );
|
||||
|
||||
char pFullWAVFile[MAX_PATH];
|
||||
g_pFullFileSystem->RelativePathToFullPath( pRelativeWAVFile, "GAME", pFullWAVFile, sizeof(pFullWAVFile) );
|
||||
|
||||
if ( Q_stricmp( pFullWAVFile, info.m_pChangedWAVFile ) )
|
||||
continue;
|
||||
|
||||
float flEndTime = pEvent->GetStartTime() + flWavDuration;
|
||||
if ( pEvent->GetEndTime() != flEndTime )
|
||||
{
|
||||
pEvent->SetEndTime( pEvent->GetStartTime() + flEndTime );
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CChoreoEvent::SEQUENCE:
|
||||
{
|
||||
if ( !pStudioHdr )
|
||||
continue;
|
||||
|
||||
CChoreoActor *pActor = pEvent->GetActor();
|
||||
if ( pActor->GetName()[0] == '!' )
|
||||
continue;
|
||||
const char *pModelName = pActor->GetFacePoserModelName();
|
||||
if ( !pModelName || !pModelName[0] || Q_stricmp( pModelPath, pModelName) )
|
||||
continue;
|
||||
|
||||
if ( UpdateSequenceLength( pEvent, &studioHdr, pPoseParameters, false, false ) )
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CChoreoEvent::GESTURE:
|
||||
{
|
||||
if ( !pStudioHdr )
|
||||
continue;
|
||||
|
||||
CChoreoActor *pActor = pEvent->GetActor();
|
||||
if ( pActor->GetName()[0] == '!' )
|
||||
continue;
|
||||
const char *pModelName = pActor->GetFacePoserModelName();
|
||||
if ( !pModelName || !pModelName[0] || Q_stricmp( pModelPath, pModelName ) )
|
||||
continue;
|
||||
|
||||
if ( UpdateGestureLength( pEvent, &studioHdr, pPoseParameters, false ) )
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
if ( AutoAddGestureKeys( pEvent, &studioHdr, pPoseParameters, false ) )
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bChanged;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks a single VCD to see if it needs to be updated or not.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVcdUpdateApp::UpdateVcd( const char *pFullPath, const VcdUpdateInfo_t& info, studiohdr_t *pStudioHdr, float flWavDuration )
|
||||
{
|
||||
CUtlBuffer buf;
|
||||
if ( !g_pFullFileSystem->ReadFile( pFullPath, NULL, buf ) )
|
||||
{
|
||||
Warning( "Unable to load file %s\n", pFullPath );
|
||||
return;
|
||||
}
|
||||
|
||||
SetTokenProcessorBuffer( (char *)buf.Base() );
|
||||
CChoreoScene *pScene = ChoreoLoadScene( pFullPath, NULL, GetTokenProcessor(), NULL );
|
||||
if ( !pScene )
|
||||
{
|
||||
Warning( "Unable to parse file %s\n", pFullPath );
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for validity.
|
||||
if ( info.m_bWarnNotMatchingMDL || info.m_bWarnMissingMDL )
|
||||
{
|
||||
char pBaseModelName[MAX_PATH];
|
||||
int nActorCount = pScene->GetNumActors();
|
||||
for ( int i = 0; i < nActorCount; ++i )
|
||||
{
|
||||
CChoreoActor* pActor = pScene->GetActor( i );
|
||||
const char *pActorName = pActor->GetName();
|
||||
if ( pActorName[0] == '!' )
|
||||
continue;
|
||||
|
||||
const char *pModelName = pActor->GetFacePoserModelName();
|
||||
if ( !pModelName || !pModelName[0] )
|
||||
{
|
||||
if ( info.m_bWarnMissingMDL )
|
||||
{
|
||||
Warning( "\t*** Missing .mdl association: File \"%s\"\tActor \"%s\"\n", pFullPath, pActorName );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( info.m_bWarnNotMatchingMDL )
|
||||
{
|
||||
Q_FileBase( pModelName, pBaseModelName, sizeof(pBaseModelName) );
|
||||
if ( !StringHasPrefix( pActorName, pBaseModelName ) )
|
||||
{
|
||||
Warning( "\t*** File \"%s\": Actor name and .mdl name suspiciously different:\n\t\tMDL \"%s\"\tActor \"%s\"\n", pFullPath, pModelName, pActorName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( UpdateVcd( pScene, info, pStudioHdr, flWavDuration ) )
|
||||
{
|
||||
Warning( "*** VCD %s requires update.\n", pFullPath );
|
||||
CP4AutoEditAddFile checkout( pFullPath );
|
||||
pScene->SaveToFile( pFullPath );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Loads up the changed files and builds list of vcds to convert, then converts them
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVcdUpdateApp::UpdateVcdFiles( const VcdUpdateInfo_t& info )
|
||||
{
|
||||
studiohdr_t *pStudioHdr = NULL;
|
||||
if ( info.m_pChangedMDLFile )
|
||||
{
|
||||
char pRelativeModelPath[MAX_PATH];
|
||||
g_pFullFileSystem->FullPathToRelativePathEx( info.m_pChangedMDLFile, "GAME", pRelativeModelPath, sizeof(pRelativeModelPath) );
|
||||
Q_SetExtension( pRelativeModelPath, ".mdl", sizeof(pRelativeModelPath) );
|
||||
MDLHandle_t hMDL = g_pMDLCache->FindMDL( pRelativeModelPath );
|
||||
if ( hMDL == MDLHANDLE_INVALID )
|
||||
{
|
||||
Warning( "vcdupdate: Model %s doesn't exist!\n", pRelativeModelPath );
|
||||
return;
|
||||
}
|
||||
|
||||
pStudioHdr = g_pMDLCache->GetStudioHdr( hMDL );
|
||||
if ( !pStudioHdr || g_pMDLCache->IsErrorModel( hMDL ) )
|
||||
{
|
||||
Warning( "vcdupdate: Model %s doesn't exist!\n", pRelativeModelPath );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float flWavDuration = -1.0f;
|
||||
if ( info.m_pChangedWAVFile )
|
||||
{
|
||||
flWavDuration = GetWavSoundDuration( info.m_pChangedWAVFile );
|
||||
}
|
||||
|
||||
CUtlVector< CUtlString > dirs;
|
||||
CUtlVector< CUtlString > vcds;
|
||||
GetSearchPath( dirs, "GAME" );
|
||||
int nCount = dirs.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
char pScenePath[MAX_PATH];
|
||||
Q_ComposeFileName( dirs[i], "scenes", pScenePath, sizeof(pScenePath) );
|
||||
AddFilesToList( vcds, pScenePath, NULL, "vcd" );
|
||||
}
|
||||
|
||||
int nVCDCount = vcds.Count();
|
||||
Msg( "Found %d VCDs to check if update is necessary.\n", nVCDCount );
|
||||
for ( int i = 0; i < nVCDCount; ++i )
|
||||
{
|
||||
UpdateVcd( vcds[i], info, pStudioHdr, flWavDuration );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The application object
|
||||
//-----------------------------------------------------------------------------
|
||||
int CVcdUpdateApp::Main()
|
||||
{
|
||||
// This bit of hackery allows us to access files on the harddrive
|
||||
g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD );
|
||||
|
||||
if ( CommandLine()->CheckParm( "-h" ) || CommandLine()->CheckParm( "-help" ) )
|
||||
{
|
||||
PrintHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
VcdUpdateInfo_t info;
|
||||
info.m_pChangedWAVFile = CommandLine()->ParmValue( "-w" );
|
||||
info.m_pChangedMDLFile = CommandLine()->ParmValue( "-m" );
|
||||
info.m_bWarnMissingMDL = CommandLine()->ParmValue( "-e" ) ? true : false;
|
||||
info.m_bWarnNotMatchingMDL = CommandLine()->ParmValue( "-n" ) ? true : false;
|
||||
|
||||
if ( !info.m_pChangedWAVFile && !info.m_pChangedMDLFile )
|
||||
{
|
||||
PrintHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Determine full paths
|
||||
char pFullMDLPath[MAX_PATH];
|
||||
char pFullWAVPath[MAX_PATH];
|
||||
if ( info.m_pChangedMDLFile )
|
||||
{
|
||||
char pRelativeMDLPath[MAX_PATH];
|
||||
if ( !Q_IsAbsolutePath( info.m_pChangedMDLFile ) )
|
||||
{
|
||||
Q_ComposeFileName( "models", info.m_pChangedMDLFile, pRelativeMDLPath, sizeof(pRelativeMDLPath) );
|
||||
g_pFullFileSystem->RelativePathToFullPath( pRelativeMDLPath, "GAME", pFullMDLPath, sizeof(pFullMDLPath) );
|
||||
}
|
||||
info.m_pChangedMDLFile = pFullMDLPath;
|
||||
}
|
||||
if ( info.m_pChangedWAVFile )
|
||||
{
|
||||
char pRelativeWAVPath[MAX_PATH];
|
||||
if ( !Q_IsAbsolutePath( info.m_pChangedWAVFile ) )
|
||||
{
|
||||
Q_ComposeFileName( "sound", info.m_pChangedWAVFile, pRelativeWAVPath, sizeof(pRelativeWAVPath) );
|
||||
g_pFullFileSystem->RelativePathToFullPath( pRelativeWAVPath, "GAME", pFullWAVPath, sizeof(pFullWAVPath) );
|
||||
}
|
||||
info.m_pChangedWAVFile = pFullWAVPath;
|
||||
}
|
||||
|
||||
// Do Perforce Stuff
|
||||
if ( CommandLine()->FindParm( "-nop4" ) )
|
||||
{
|
||||
g_p4factory->SetDummyMode( true );
|
||||
}
|
||||
|
||||
g_p4factory->SetOpenFileChangeList( "Automatically Updated VCD files" );
|
||||
|
||||
g_pSoundEmitterSystem->ModInit();
|
||||
UpdateVcdFiles( info );
|
||||
g_pSoundEmitterSystem->ModShutdown();
|
||||
return -1;
|
||||
}
|
Reference in New Issue
Block a user