diff options
Diffstat (limited to 'movieobjects/dmemakefileutils.cpp')
| -rw-r--r-- | movieobjects/dmemakefileutils.cpp | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/movieobjects/dmemakefileutils.cpp b/movieobjects/dmemakefileutils.cpp new file mode 100644 index 0000000..5f20661 --- /dev/null +++ b/movieobjects/dmemakefileutils.cpp @@ -0,0 +1,613 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Interface for makefiles to build differently depending on where they are run from +// +//===========================================================================// + +#include "movieobjects/dmemakefileutils.h" +#include "movieobjects/dmemdlmakefile.h" +#include "movieobjects/dmedccmakefile.h" +#include "tier2/fileutils.h" +#include "filesystem.h" + + +//----------------------------------------------------------------------------- +// Statics +//----------------------------------------------------------------------------- +IMPLEMENT_DMEMAKEFILE_UTIL_CLASS( CDmeMakefileUtils ); + + +//----------------------------------------------------------------------------- +// Default implementation +//----------------------------------------------------------------------------- +static CDmeMakefileUtils s_MakefileUtils; +IDmeMakefileUtils *GetDefaultDmeMakefileUtils() +{ + return &s_MakefileUtils; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CDmeMakefileUtils::CDmeMakefileUtils() : BaseClass( false ) +{ + m_CompilationStep = NOT_COMPILING; + m_hCompileProcess = PROCESS_HANDLE_INVALID; + m_nCurrentCompileTask = -1; + m_nExitCode = 0; +} + +CDmeMakefileUtils::~CDmeMakefileUtils() +{ + +} + + +//----------------------------------------------------------------------------- +// Here's where systems can access other interfaces implemented by this object +//----------------------------------------------------------------------------- +void *CDmeMakefileUtils::QueryInterface( const char *pInterfaceName ) +{ + if ( !V_strcmp( pInterfaceName, DMEMAKEFILE_UTILS_INTERFACE_VERSION ) ) + return (IDmeMakefileUtils*)this; + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Initialization.. set up messagemaps +//----------------------------------------------------------------------------- +InitReturnVal_t CDmeMakefileUtils::Init() +{ + InitializeFuncMaps(); + return INIT_OK; +} + + +//----------------------------------------------------------------------------- +// Looks for an appropriate method to compile this element with +//----------------------------------------------------------------------------- +CCompileFuncAdapterBase *CDmeMakefileUtils::DetermineCompileAdapter( CDmElement *pElement ) +{ + int nBestInheritanceDepth = -1; + CCompileFuncAdapterBase *pBestAdapter = NULL; + + CompileFuncTree_t *pTree = GetCompileTree(); + while ( pTree ) + { + CCompileFuncAdapterBase *pCurr = pTree->m_pFirstAdapter; + for ( ; pCurr; pCurr = pCurr->m_pNext ) + { + // Choose this factory if it's more derived than the previous best + int nInheritanceDepth = pElement->GetInheritanceDepth( pCurr->m_ElementType ); + if ( nInheritanceDepth < 0 ) + continue; + + if ( nInheritanceDepth == 0 ) + { + // Found exact match.. do it! + return pCurr; + } + + // Don't look for the best thingy if we're not the root + if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth >= nBestInheritanceDepth ) ) + continue; + + nBestInheritanceDepth = nInheritanceDepth; + pBestAdapter = pCurr; + } + + pTree = pTree->m_pBaseAdapterTree; + } + + // Return the closest match we could find + return pBestAdapter; +} + + +//----------------------------------------------------------------------------- +// Looks for an appropriate method to open this element with +//----------------------------------------------------------------------------- +COpenEditorFuncAdapterBase *CDmeMakefileUtils::DetermineOpenEditorAdapter( CDmElement *pElement ) +{ + int nBestInheritanceDepth = -1; + COpenEditorFuncAdapterBase *pBestAdapter = NULL; + OpenEditorFuncTree_t *pTree = GetOpenEditorTree(); + while ( pTree ) + { + COpenEditorFuncAdapterBase *pCurr = pTree->m_pFirstAdapter; + for ( ; pCurr; pCurr = pCurr->m_pNext ) + { + // Choose this factory if it's more derived than the previous best + int nInheritanceDepth = pElement->GetInheritanceDepth( pCurr->m_ElementType ); + if ( nInheritanceDepth < 0 ) + continue; + + // Found exact match.. do it! + if ( nInheritanceDepth == 0 ) + return pCurr; + + if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth >= nBestInheritanceDepth ) ) + continue; + + nBestInheritanceDepth = nInheritanceDepth; + pBestAdapter = pCurr; + } + + pTree = pTree->m_pBaseAdapterTree; + } + return pBestAdapter; +} + + +//----------------------------------------------------------------------------- +// Opens a element in an external editor +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::PerformOpenEditor( CDmElement *pElement ) +{ + COpenEditorFuncAdapterBase *pAdapter = DetermineOpenEditorAdapter( pElement ); + if ( pAdapter ) + { + pAdapter->OpenEditor( pElement ); + } +} + + +//----------------------------------------------------------------------------- +// Queues up a compilation task +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::AddCompilationTask( CDmElement* pElement, CCompileFuncAdapterBase *pAdapter ) +{ + Assert( m_CompilationStep == BUILDING_STANDARD_DEPENDENCIES || m_CompilationStep == BUILDING_ALL_DEPENDENCIES ); + + // Queue up the compilation task + int j = m_CompileTasks.AddToTail(); + m_CompileTasks[j].m_hElement = pElement; + m_CompileTasks[j].m_pAdapter = pAdapter; +} + +void CDmeMakefileUtils::AddCompilationTask( CDmElement* pElement ) +{ + CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pElement ); + if ( pAdapter ) + { + // Queue up the compilation task + AddCompilationTask( pElement, pAdapter ); + } +} + + +//----------------------------------------------------------------------------- +// Sets the compile process +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::SetCompileProcess( ProcessHandle_t hProcess ) +{ + Assert( m_CompilationStep == PERFORMING_COMPILATION ); + m_hCompileProcess = hProcess; + if ( m_hCompileProcess == PROCESS_HANDLE_INVALID ) + { + m_CompilationStep = AFTER_COMPILATION_FAILED; + } +} + + +//----------------------------------------------------------------------------- +// Default implementatations for compile dependencies +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::AddCompileDependencies( CDmeMakefile *pMakefile, bool bBuildAllDependencies ) +{ + if ( !pMakefile ) + return true; + + CUtlVector< CUtlString > outputs; + int nCount = pMakefile->GetSourceCount(); + for ( int i = 0; i < nCount; ++i ) + { + CDmeSource *pSource = pMakefile->GetSource( i ); + if ( !pSource ) + continue; + + CDmeMakefile *pDependentMakefile = pSource->GetDependentMakefile(); + if ( !pDependentMakefile ) + continue; + + bool bShouldBuildFile = bBuildAllDependencies; + + // Does the output files exist? + int j = 0; + if ( !bBuildAllDependencies ) + { + pDependentMakefile->GetOutputs( outputs ); + int nOutputCount = outputs.Count(); + for ( j = 0; j < nOutputCount; ++j ) + { + // If the file doesn't exist, we have to build it + if ( !g_pFullFileSystem->FileExists( outputs[j] ) ) + break; + + bShouldBuildFile = true; + break; + } + } + + if ( !bShouldBuildFile ) + continue; + + CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pDependentMakefile ); + if ( pAdapter ) + { + // Add dependent makefiles first + if ( !pAdapter->PerformCompilationStep( pDependentMakefile, bBuildAllDependencies ? BUILDING_ALL_DEPENDENCIES : BUILDING_STANDARD_DEPENDENCIES ) ) + return false; + } + + // Queue up the compilation task + AddCompilationTask( pDependentMakefile, pAdapter ); + } + return true; +} + + +//----------------------------------------------------------------------------- +// Default implementatations for precompilation step +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::PerformCompilationStep( CDmElement *pElement, CompilationStep_t step ) +{ + // Do nothing + return true; +} + +bool CDmeMakefileUtils::PerformCompilationStep( CDmeMakefile *pMakefile, CompilationStep_t step ) +{ + switch( step ) + { + case BUILDING_ALL_DEPENDENCIES: + return AddCompileDependencies( pMakefile, true ); + + case BUILDING_STANDARD_DEPENDENCIES: + return AddCompileDependencies( pMakefile, false ); + + case BEFORE_COMPILATION: + pMakefile->PreCompile(); + break; + + case AFTER_COMPILATION_SUCCEEDED: + pMakefile->PostCompile(); + break; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Starts the next compile task +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::StartNextCompileTask( ) +{ + Assert( m_hCompileProcess == PROCESS_HANDLE_INVALID ); + ++m_nCurrentCompileTask; + if ( m_nCurrentCompileTask == m_CompileTasks.Count() ) + { + PerformCompilationStep( AFTER_COMPILATION_SUCCEEDED ); + m_nCurrentCompileTask = -1; + m_CompileTasks.RemoveAll(); + return; + } + + m_hCompileProcess = PROCESS_HANDLE_INVALID; + + // NOTE: PerformCompilationStep is expected to call SetCompileProcess to set m_hCompileProcess + CompileInfo_t &info = m_CompileTasks[m_nCurrentCompileTask]; + bool bOk = info.m_pAdapter->PerformCompilationStep( info.m_hElement, PERFORMING_COMPILATION ); + + if ( !bOk || ( m_hCompileProcess == PROCESS_HANDLE_INVALID ) ) + { + AbortCurrentCompilation(); + return; + } +} + + +//----------------------------------------------------------------------------- +// Performs the compilation step on all elements +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::PerformCompilationStep( CompilationStep_t step ) +{ + // Iterate through all elements and run a compilation step + m_CompilationStep = step; + int nCount = m_CompileTasks.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CompileInfo_t &info = m_CompileTasks[i]; + if ( info.m_hElement.Get() ) + { + if ( !info.m_pAdapter->PerformCompilationStep( info.m_hElement, step ) ) + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Main entry point for compilation +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::PerformCompile( CDmElement *pElement, bool bBuildAllDependencies ) +{ + if ( IsCurrentlyCompiling() ) + { + AbortCurrentCompilation(); + } + + CCompileFuncAdapterBase *pAdapter = DetermineCompileAdapter( pElement ); + if ( !pAdapter ) + { + m_CompilationStep = AFTER_COMPILATION_FAILED; + return; + } + + // Add dependent makefiles first + m_CompilationStep = bBuildAllDependencies ? BUILDING_ALL_DEPENDENCIES : BUILDING_STANDARD_DEPENDENCIES; + if ( !pAdapter->PerformCompilationStep( pElement, m_CompilationStep ) ) + { + AbortCurrentCompilation(); + return; + } + + // Queue up the compilation task + AddCompilationTask( pElement, pAdapter ); + + // Iterate through all elements and run a precompilation step + // NOTE: This is where perforce integration should go + if ( !PerformCompilationStep( BEFORE_COMPILATION ) ) + { + AbortCurrentCompilation(); + return; + } + + // Dequeue the first compile task and start it up + m_CompilationStep = PERFORMING_COMPILATION; + StartNextCompileTask(); +} + + +//----------------------------------------------------------------------------- +// Are we in the middle of compiling this makefile? +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::IsCurrentlyCompiling() +{ + return ( m_CompilationStep != NOT_COMPILING ); +} + + +//----------------------------------------------------------------------------- +// Aborts any current compilation +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::AbortCurrentCompilation() +{ + if ( m_hCompileProcess != PROCESS_HANDLE_INVALID ) + { + g_pProcessUtils->AbortProcess( m_hCompileProcess ); + m_hCompileProcess = PROCESS_HANDLE_INVALID; + } + + if ( IsCurrentlyCompiling() ) + { + PerformCompilationStep( AFTER_COMPILATION_FAILED ); + m_nCurrentCompileTask = -1; + m_CompileTasks.RemoveAll(); + } +} + + +//----------------------------------------------------------------------------- +// Returns the exit code of the failed compilation (if COMPILATION_FAILED occurred) +//----------------------------------------------------------------------------- +int CDmeMakefileUtils::GetExitCode() +{ + return m_nExitCode; +} + + +//----------------------------------------------------------------------------- +// Returns output from the compilation +//----------------------------------------------------------------------------- +int CDmeMakefileUtils::GetCompileOutputSize() +{ + if ( m_hCompileProcess == PROCESS_HANDLE_INVALID ) + return 0; + return g_pProcessUtils->GetProcessOutputSize( m_hCompileProcess ); +} + +CompilationState_t CDmeMakefileUtils::UpdateCompilation( char *pOutputBuf, int nBufLen ) +{ + switch( m_CompilationStep ) + { + case BUILDING_STANDARD_DEPENDENCIES: + case BUILDING_ALL_DEPENDENCIES: + case BEFORE_COMPILATION: + return COMPILATION_NOT_COMPLETE; + + case AFTER_COMPILATION_FAILED: + m_CompilationStep = NOT_COMPILING; + return COMPILATION_FAILED; + + case AFTER_COMPILATION_SUCCEEDED: + m_CompilationStep = NOT_COMPILING; + return COMPILATION_SUCCESSFUL; + } + + // This is the PERFORMING_COMPILATION case: + + // FIXME: Check return codes from compile process.. + // fail if compilation process had a problem + if ( m_hCompileProcess == PROCESS_HANDLE_INVALID ) + { + if ( nBufLen > 0 ) + { + pOutputBuf[0] = 0; + } + return COMPILATION_SUCCESSFUL; + } + + if ( nBufLen > 0 ) + { + g_pProcessUtils->GetProcessOutput( m_hCompileProcess, pOutputBuf, nBufLen ); + } + + if ( !g_pProcessUtils->IsProcessComplete( m_hCompileProcess ) ) + return COMPILATION_NOT_COMPLETE; + + m_nExitCode = g_pProcessUtils->GetProcessExitCode( m_hCompileProcess ); + bool bCompileSucceeded = ( m_nExitCode == 0 ); + g_pProcessUtils->CloseProcess( m_hCompileProcess ); + m_hCompileProcess = PROCESS_HANDLE_INVALID; + + if ( !bCompileSucceeded ) + { + AbortCurrentCompilation(); + return COMPILATION_NOT_COMPLETE; + } + + StartNextCompileTask(); + if ( m_CompilationStep == PERFORMING_COMPILATION ) + return COMPILATION_NOT_COMPLETE; + + CompilationState_t retVal = ( m_CompilationStep == AFTER_COMPILATION_SUCCEEDED ) ? COMPILATION_SUCCESSFUL : COMPILATION_FAILED; + m_CompilationStep = NOT_COMPILING; + return retVal; +} + + +//----------------------------------------------------------------------------- +// Type-specific compilation functions +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::PerformCompilationStep( CDmeMDLMakefile *pMakeFile, CompilationStep_t step ) +{ + if ( step != PERFORMING_COMPILATION ) + return PerformCompilationStep( static_cast<CDmeMakefile*>( pMakeFile ), step ); + + char pBinDirectory[MAX_PATH]; + GetModSubdirectory( "..\\bin", pBinDirectory, sizeof(pBinDirectory) ); + Q_RemoveDotSlashes( pBinDirectory ); + + char pStudioMDLCmd[MAX_PATH]; +#ifdef _DEBUG + Q_snprintf( pStudioMDLCmd, sizeof(pStudioMDLCmd), "%s\\studiomdl.exe -allowdebug %s", pBinDirectory, pMakeFile->GetFileName() ); +#else + Q_snprintf( pStudioMDLCmd, sizeof(pStudioMDLCmd), "%s\\studiomdl.exe %s", pBinDirectory, pMakeFile->GetFileName() ); +#endif + + ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( pStudioMDLCmd, true ); + SetCompileProcess( hProcess ); + return true; +} + + +//----------------------------------------------------------------------------- +// Exports a Maya file to a DMX file +//----------------------------------------------------------------------------- +bool CDmeMakefileUtils::PerformCompilationStep( CDmeMayaMakefile *pMakeFile, CompilationStep_t step ) +{ + if ( step != PERFORMING_COMPILATION ) + return PerformCompilationStep( static_cast<CDmeMakefile*>( pMakeFile ), step ); + + // FIXME: Create batch export command here + CUtlString mayaCommand; + mayaCommand = "vsDmxIO -export"; + + CUtlVector< CDmeHandle< CDmeSourceMayaFile > > sources; + pMakeFile->GetSources( sources ); + + if ( !sources.Count() ) + return false; + + CDmeSourceMayaFile *pDmeSourceDCCFile( sources[ 0 ].Get() ); + + mayaCommand += " -selection"; + + char pObjectId[128]; + UniqueIdToString( pMakeFile->GetId(), pObjectId, sizeof(pObjectId) ); + mayaCommand += " -makefileObjectId \\\""; + mayaCommand += pObjectId; + mayaCommand += "\\\""; + + mayaCommand += " -"; + mayaCommand += pDmeSourceDCCFile->m_ExportType.GetAttribute()->GetName(); + + switch ( pDmeSourceDCCFile->m_ExportType.Get() ) + { + case 1: // skeletal animation + mayaCommand += " skeletalAnimation"; + + mayaCommand += " -"; + mayaCommand += pDmeSourceDCCFile->m_FrameStart.GetAttribute()->GetName(); + mayaCommand += " "; + mayaCommand += pDmeSourceDCCFile->m_FrameStart.Get(); + + mayaCommand += " -"; + mayaCommand += pDmeSourceDCCFile->m_FrameEnd.GetAttribute()->GetName(); + mayaCommand += " "; + mayaCommand += pDmeSourceDCCFile->m_FrameEnd.Get(); + + mayaCommand += " -"; + mayaCommand += pDmeSourceDCCFile->m_FrameIncrement.GetAttribute()->GetName(); + mayaCommand += " "; + mayaCommand += pDmeSourceDCCFile->m_FrameIncrement.Get(); + break; + default: // Model + mayaCommand += " model"; + break; + } + + char pFileName[MAX_PATH]; + Q_strncpy( pFileName, pMakeFile->GetFileName(), sizeof( pFileName ) ); + Q_FixSlashes( pFileName, '/' ); + mayaCommand += " -filename \\\""; + mayaCommand += pFileName; + mayaCommand += "\\\""; + + const int rootObjectCount( pDmeSourceDCCFile->m_RootDCCObjects.Count() ); + for ( int rootObjectIndex( 0 ); rootObjectIndex < rootObjectCount; ++rootObjectIndex ) + { + mayaCommand += " "; + mayaCommand += pDmeSourceDCCFile->m_RootDCCObjects[ rootObjectIndex ]; + } + + char pSourcePath[MAX_PATH]; + pMakeFile->GetSourceFullPath( pDmeSourceDCCFile, pSourcePath, sizeof(pSourcePath) ); + + // Maya wants forward slashes + Q_FixSlashes( pSourcePath, '/' ); + + char pMayaCommand[1024]; + Q_snprintf( pMayaCommand, sizeof(pMayaCommand), "mayabatch.exe -batch -file \"%s\" -command \"%s\"", pSourcePath, mayaCommand.Get() ); + ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( pMayaCommand, true ); + SetCompileProcess( hProcess ); + return true; +} + + +//----------------------------------------------------------------------------- +// Opens Maya with a particular file +//----------------------------------------------------------------------------- +void CDmeMakefileUtils::OpenEditor( CDmeSourceMayaFile *pDmeSourceDCCFile ) +{ + CDmeMayaMakefile *pMakefile = FindReferringElement< CDmeMayaMakefile >( pDmeSourceDCCFile, "sources" ); + if ( !pMakefile ) + return; + + char pSourcePath[MAX_PATH]; + pMakefile->GetSourceFullPath( pDmeSourceDCCFile, pSourcePath, sizeof(pSourcePath) ); + + // Maya wants forward slashes + Q_FixSlashes( pSourcePath, '/' ); + + char pMayaCommand[1024]; + Q_snprintf( pMayaCommand, sizeof(pMayaCommand), "maya.exe -file \"%s\"", pSourcePath ); + g_pProcessUtils->StartProcess( pMayaCommand, true ); +} |