Files
FC1/ResourceCompiler/ResourceCompiler.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1074 lines
27 KiB
C++

// ResourceCompiler.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <time.h>
#include <DbgHelp.h>
#include <io.h>
#include "ResourceCompiler.h"
#include "CmdLine.h"
#include "Config.h"
#include "CfgFile.h"
#include "FileUtil.h"
#include "IConvertor.h"
#include "FileUtil.h"
#include "CryChunkedFile.h"
#include "CgfUtils.h"
#include <StringUtils.h>
//! Section in rc.ini file for common settings.
#define COMMON_SECTION "Common"
static const char *RC_FILENAME_LOG= "rc_log.log";
static const char *RC_FILENAME_WARNINGS= "rc_log_warnings.log";
static const char *RC_FILENAME_ERRORS= "rc_log_errors.log";
static const char *RC_FILENAME_FILEDEP= "rc_stats_filedependencies.log";
static const char *RC_FILENAME_MATDEP= "rc_stats_materialdependencies.log";
//////////////////////////////////////////////////////////////////////////
// Globals.
//////////////////////////////////////////////////////////////////////////
// Determines whether a path to a file system object such as a file or directory is valid
BOOL RCPathFileExists (const char* szPath)
{
DWORD dwAttr = GetFileAttributes (szPath);
return (dwAttr != 0xFFFFFFFF);
}
//////////////////////////////////////////////////////////////////////////
// ResourceCompiler implementation.
//////////////////////////////////////////////////////////////////////////
ResourceCompiler::ResourceCompiler()
{
m_config = 0;
m_pIPhysicalWorld = 0;
m_hLogFile=0;
m_hErrorLogFile=0;
m_hWarningLogFile=0;
m_bWarningHeaderLine=false;
m_bErrorHeaderLine=false;
m_bStatistics = false;
m_bQuiet = false;
}
ResourceCompiler::~ResourceCompiler()
{
if (m_pIPhysicalWorld)
{
m_pIPhysicalWorld->Release();
m_pIPhysicalWorld = NULL;
}
// close files if open
if(m_hLogFile)fclose(m_hLogFile);m_hLogFile=0;
if(m_hErrorLogFile)fclose(m_hErrorLogFile);m_hErrorLogFile=0;
if(m_hWarningLogFile)fclose(m_hWarningLogFile);m_hWarningLogFile=0;
}
//////////////////////////////////////////////////////////////////////////
void ResourceCompiler::RegisterConvertor( IConvertor *conv )
{
m_extensionManager.RegisterConvertor( conv, this );
}
//////////////////////////////////////////////////////////////////////////
FILE* ResourceCompiler::OpenFile( const char *filename,const char *mode )
{
FILE *file = fopen(filename,mode);
// check if read only.
return file;
}
IRCLog *ResourceCompiler::GetIRCLog()
{
return(this);
}
// returns the file unix time - the latest of modification and creation times
DWORD ResourceCompiler::GetFileUnixTimeMax (const char* filename)
{
FILETIME ftWrite, ftCreate;
if (GetFileTime(filename, &ftWrite, &ftCreate))
{
return max (FileUtil::FiletimeToUnixTime(ftWrite),FileUtil::FiletimeToUnixTime(ftCreate));
}
else
return 0;
}
// returns the file unix time - the earliest of modification and creation times
DWORD ResourceCompiler::GetFileUnixTimeMin (const char* filename)
{
FILETIME ftWrite, ftCreate;
if (GetFileTime(filename, &ftWrite, &ftCreate))
{
return min (FileUtil::FiletimeToUnixTime(ftWrite),FileUtil::FiletimeToUnixTime(ftCreate));
}
else
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool ResourceCompiler::GetFileTime( const char *filename,FILETIME *ftimeModify, FILETIME*ftimeCreate )
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile( filename,&FindFileData );
if (hFind == INVALID_HANDLE_VALUE)
{
return false;
}
FindClose(hFind);
if (ftimeCreate)
{
ftimeCreate->dwLowDateTime = FindFileData.ftCreationTime.dwLowDateTime;
ftimeCreate->dwHighDateTime = FindFileData.ftCreationTime.dwHighDateTime;
}
if (ftimeModify)
{
ftimeModify->dwLowDateTime = FindFileData.ftLastWriteTime.dwLowDateTime;
ftimeModify->dwHighDateTime = FindFileData.ftLastWriteTime.dwHighDateTime;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
const char* ResourceCompiler::GetSectionName( Platform platform ) const
{
switch (platform)
{
case PLATFORM_PC: return "PC";
case PLATFORM_XBOX: return "XBOX";
case PLATFORM_PS2: return "PS2";
case PLATFORM_GAMECUBE: return "GAMECUBE";
default:
// unknown platform.
MessageBoxError( _T("Section name requested for unknown platform") );
assert(0);
}
return "";
}
void ResourceCompiler::RemoveOutputFiles()
{
DeleteFile(RC_FILENAME_LOG);
DeleteFile(RC_FILENAME_WARNINGS);
DeleteFile(RC_FILENAME_ERRORS);
DeleteFile(RC_FILENAME_FILEDEP);
DeleteFile(RC_FILENAME_MATDEP);
}
//////////////////////////////////////////////////////////////////////////
// Returns true if successfully converted at least one file
bool ResourceCompiler::Compile( Platform platform,IConfig *config,const char *filespec )
{
RemoveOutputFiles(); // to remove old files for less confusion
if (m_MainConfig.HasKey("statistics"))
m_bStatistics = true;
else
m_bStatistics = false;
m_bQuiet = config->HasKey("quiet");
if(!config->HasKey("logfiles"))
{
m_hLogFile=fopen(RC_FILENAME_LOG,"wb");
}
{
m_hWarningLogFile=fopen(RC_FILENAME_WARNINGS,"wb");
m_hErrorLogFile=fopen(RC_FILENAME_ERRORS,"wb");
}
m_config = config;
m_platform = platform;
DWORD dwFileSpecAttr = GetFileAttributes (filespec);
std::vector<CString> arrFiles; // files to convert, with relative paths
bool bRecursive = config->GetAs<bool>("recursive", true);
m_presets = new CfgFile();
CString presetcfg;
if(!config->Get("presetcfg", presetcfg))
{
Log("No preset configuration defined (e.g. presetcfg=rc_presets_pc.ini)");
// we should uncoment this soon (MM 05/28/2002)
// Log(" exiting...");return false; // it's better to have resource not working without that info
}
else if(!m_presets->Load(presetcfg))
{
Log("Failed to read preset configuration %s, exiting...", presetcfg.GetString());
return false;
};
CString path = Path::GetPath(filespec);
if (dwFileSpecAttr == 0xFFFFFFFF)
{
// there's no such file; so, this is probably a mask:
// path\*.mask
// Scan all files matching filespec.
FileUtil::ScanDirectory( path,Path::GetFile(filespec),arrFiles, bRecursive);
}
else
if (dwFileSpecAttr & FILE_ATTRIBUTE_DIRECTORY)
{
path = Path::AddBackslash(filespec);
// it's a directory; the mask can be found via /file=... option
FileUtil::ScanDirectory(path, config->GetAs<CString>("file", "*.*"), arrFiles, bRecursive);
}
else
arrFiles.push_back(Path::GetFile(filespec));
if (arrFiles.empty())
{
LogError( "The system cannot find the file specified, 0 file(s) converted" );
return false;
}
// determine the target output path (may be a different directory structure)
// if none is specified, the target is the same as the source, as before.
CString targetroot;
if (!config->Get( "targetroot", targetroot ))
{
targetroot = path;
};
targetroot = Path::AddBackslash(targetroot);
// these are the files that couldn't be converted
std::vector<CString> arrNonConvertedFiles;
// the number of files that were successfully converted
unsigned numFilesConverted = 0;
int nTimer = GetTickCount();
size_t i, iSize=arrFiles.size();
for (i = 0; i < iSize; i++)
{
// show progress
{
int iPercentage=(100*i)/(iSize);
char str[0x100];
_snprintf(str, sizeof(str),"Progress: %3d%% %s",iPercentage,arrFiles[i]);
SetConsoleTitle(str);
}
CString strFileName = path + arrFiles[i];
if (CompileFile( strFileName.GetString(),targetroot.GetString(), Path::GetPath(CString(targetroot+arrFiles[i])).GetString()))
++numFilesConverted;
else
arrNonConvertedFiles.push_back(strFileName);
}
nTimer = GetTickCount() - nTimer;
char szTimeMsg[128] ;
szTimeMsg[0] = '\0';
if (nTimer > 500)
sprintf (szTimeMsg, " in %.1f sec", nTimer/1000.0f);
if (arrNonConvertedFiles.empty())
Log ("%d file%s converted%s.", arrFiles.size(), arrFiles.size()>1?"s":"",szTimeMsg);
else
{
Log("");
Log("");
Log ( "%d of %d file%s converted%s. Couldn't convert the following files:", numFilesConverted, arrFiles.size(), arrFiles.size() > 1 ? "s":"", szTimeMsg);
Log("");
for (i = 0; i < arrNonConvertedFiles.size(); ++i)
Log ( " %s", arrNonConvertedFiles[i]);
Log("");
}
delete m_presets;
return numFilesConverted > 0;
}
void ResourceCompiler::EnsureDirectoriesPresent(const char *path)
{
DWORD dwFileSpecAttr = GetFileAttributes (path);
if (dwFileSpecAttr == 0xFFFFFFFF && *path)
{
EnsureDirectoriesPresent(Path::GetPath(Path::RemoveBackslash(path)).GetString());
Log("Creating directory %s (%s)", path, _mkdir(path) ? "failed" : "ok");
};
};
// makes the relative path out of any
CString NormalizePath(const char* szPath)
{
char szCurDir[0x800]="";
GetCurrentDirectory(sizeof(szCurDir),szCurDir);
strcat(szCurDir, "/");
char szFullPath[0x800];
if (!_fullpath(szFullPath, szPath, sizeof(szFullPath)))
strcpy (szFullPath, szPath);
char* p, *q;
CString sRes = szPath;
for (p = szCurDir, q = szFullPath; *p && *q; ++p, ++q)
{
if (tolower(*p)==tolower(*q))
continue;
if ((*p=='/'||*p=='\\')&&(*q=='/'||*q=='\\'))
continue;
return sRes;
}
if (*p)
return szPath;
return q; // return whatever has left after truncating the leading path
}
//////////////////////////////////////////////////////////////////////////
bool ResourceCompiler::CompileFile( const char *filename, const char *outroot, const char *outpath )
{
CmdLine cmdLine;
if (!RCPathFileExists(filename))
return false;
// get file extension.
CString ext = Path::GetExt(filename);
// get key for special copy/ignore options to certain extensions
CString extkey = "ext_";
extkey += ext;
CString extcommand;
m_config->Get(extkey.GetString(), extcommand);
if(extcommand=="ignore")
{
Log("Ignoring %s", filename);
return true;
};
if(extcommand=="copy")
{
CString dest = outpath;
dest += Path::GetFile(filename);
if(dest!=filename)
{
// TODO: can compare filestamps of source and destination to avoid copy, but maybe overkill
Log("Copying %s to %s", filename, dest.GetString());
CopyFile(filename, dest.GetString(), false); // overwrites any existing file, same as all converters
};
return true;
};
// find convertor matching platform and extension.
IConvertor *conv = m_extensionManager.FindConvertor( m_platform,ext.GetString() );
if (!conv)
{
// no convertor for this file.
return false;
}
CString sourcePath = Path::GetPath(filename);
CfgFile CfgFile; // file specifig config file
CString defFile = Path::ReplaceExtension(filename,DEF_FILE_EXTENSION);
CfgFile.SetFileName(defFile);
Config localConfig;
// Check if definition file exist for specified filename
if (RCPathFileExists(defFile.GetString()))
if (CfgFile.Load( defFile ))
{
CfgFile.SetConfig( COMMON_SECTION,localConfig.GetInternalRepresentation() );
CfgFile.SetConfig( GetSectionName(m_platform),localConfig.GetInternalRepresentation() );
}
localConfig.Merge(&m_MainConfig);
// Setup conversion context.
ConvertContext cc;
cc.config = &localConfig;
cc.platform = m_platform;
cc.pRC = this;
cc.sourceFile = Path::GetFile(filename);
cc.sourceFolder = Path::GetPath(filename);
if (!m_config->Get("MasterFolder", cc.masterFolder))
cc.masterFolder = "";
if (!cc.masterFolder.IsEmpty() && cc.masterFolder.Right(1)!="/" && cc.masterFolder.Right(1)!="\\")
cc.masterFolder += '\\';
cc.outputFile = "";
cc.outputFolder = outpath;
cc.pLog = this;
cc.pFileSpecificConfig = &CfgFile;
cc.presets = m_presets;
cc.bQuiet = m_bQuiet;
cc.sourceFolder = NormalizePath(cc.sourceFolder.GetString());
cc.outputFolder = NormalizePath(cc.outputFolder.GetString());
// Check if output file is valid (have same timestamp as input file).
conv->GetOutputFile( cc );
CString outputFileName = cc.outputFile;
CString outputFile = cc.getOutputPath();
//[Timur] outputFile, is Only filename. CString outputFile = outputFileName;
//cc.sourceFile = filename;
//cc.sourceFolder = "";
const char *sOutFile = cc.outputFile.GetString();
const char *sOutDir = cc.outputFolder.GetString();
EnsureDirectoriesPresent(CString(cc.masterFolder+cc.outputFolder).GetString());
// Compare time stamp of output file.
if (!m_config->HasKey("refresh"))
{
unsigned nTimeSrc = GetFileUnixTimeMax( filename );
unsigned nTimeTgt = GetFileUnixTimeMin( cc.getOutputPath().GetString() );
unsigned nFilterTimestamp = conv->GetTimestamp();
if (nTimeSrc < nTimeTgt && nFilterTimestamp < nTimeTgt)
{
// both Source and Filter code are older than target,
// thus the target is up to date
Log("Skipping %s: compiled file is up to date", filename);
return true; // wouter: was false
}
}
Log("");
Log("-------------------------------------------------------");
Log("Compiling %s", filename);
Log("");
//[Timur]
/*
// IConfig *config = m_config;
cc.config = &localConfig;
cc.platform = m_platform;
cc.pRC = this;
//cc.sourceFile = filename;
//cc.outputFile = outputFile;
//cc.outputFolder = outroot;
cc.pLog = this;
cc.pFileSpecificConfig = &CfgFile;
cc.presets = m_presets;
*/
OutputDebugString("Current file: '");
OutputDebugString(filename);
OutputDebugString("' ... ");
// file name changed - print new header for warnings and errors
SetHeaderLine(filename);
//convert GCF into CCG
bool bRet=conv->Process( cc );
OutputDebugString("processed\n");
if(!bRet)
LogError("failed to convert file");
// Release cloned config.
// if (config != m_config)
// config->Release();
return bRet;
}
void ResourceCompiler::SetHeaderLine( const char *inszLine )
{
m_bWarningHeaderLine=false;
m_bErrorHeaderLine=false;
m_sHeaderLine=inszLine;
}
void ResourceCompiler::LogLine( const ELogType ineType, const char* szText )
{
if (m_bQuiet)
{
if(m_hLogFile)
{
fprintf(m_hLogFile,"%s\n",szText);
}
return;
}
switch(ineType)
{
case eMessage:
printf (" "); // to make it aligned with E: and W:
break;
case eWarning:
printf ("W: "); // for Warning
if(m_hWarningLogFile)
{
if(!m_bWarningHeaderLine)
{
fprintf(m_hWarningLogFile,"\r\n-----------------------------------------------------------------\r\n\r\n");
fprintf(m_hWarningLogFile,"%s\r\n",m_sHeaderLine.c_str());
m_bWarningHeaderLine=true;
}
fprintf(m_hWarningLogFile," %s\r\n",szText);
fflush(m_hWarningLogFile);
}
break;
case eError:
printf ("E: "); // for Error
if(m_hErrorLogFile)
{
if(!m_bErrorHeaderLine)
{
fprintf(m_hErrorLogFile,"\r\n-----------------------------------------------------------------\r\n\r\n");
fprintf(m_hErrorLogFile,"%s\r\n",m_sHeaderLine.c_str());
m_bErrorHeaderLine=true;
}
fprintf(m_hErrorLogFile," %s\r\n",szText);
fflush(m_hErrorLogFile);
}
break;
default:assert(0);
}
if(m_hLogFile)
{
fprintf(m_hLogFile,"%s\r\n",szText);
//fflush(m_hLogFile); // No need to flush really, we cannot reboot here.
}
printf("%s\n",szText);
}
//! Load and parse the Crytek Chunked File into the universal (very big) structure
//! The caller should then call Release on the structure to free the mem
//! @param filename Full filename including path to the file
CryChunkedFile* ResourceCompiler::LoadCryChunkedFile (const char* szFileName)
{
CChunkFileReader_AutoPtr pReader = new CChunkFileReader ();
if (!pReader->open (szFileName))
return NULL;
try
{
return new CryChunkedFile(pReader);
}
catch (CryChunkedFile::Error& e)
{
LogError("%s", e.strDesc.c_str());
return NULL;
}
catch (...)
{
LogError("UNEXPECTED ERROR while trying to load Cry Chunked File \"%s\"", szFileName);
return NULL;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//! Print error message.
void MessageBoxError( const char *format,... )
{
va_list ArgList;
char szBuffer[1024];
va_start(ArgList, format);
vsprintf(szBuffer, format, ArgList);
va_end(ArgList);
CString str = "####-ERROR-####: ";
str += szBuffer;
// printf( "%s\n",str );
MessageBox( NULL,szBuffer,_T("Error"),MB_OK|MB_ICONERROR );
}
/*
//////////////////////////////////////////////////////////////////////////
//! Log message.
void Log( const char *format,... )
{
va_list ArgList;
char szBuffer[1024];
va_start(ArgList, format);
vsprintf(szBuffer, format, ArgList);
va_end(ArgList);
printf( "%s\n",szBuffer );
}
*/
//////////////////////////////////////////////////////////////////////////
void ResourceCompiler::show_help()
{
Log( "Usage: RC filespec /p=<Platform> [/Key1=Value1] [/Key2=Value2] etc..." );
Log( "" );
Log( " /p\tSpecifies target compilation platform." );
Log( " \tValid platforms: PC,XBOX,PS2,GC" );
Log( " /recursive");
}
//////////////////////////////////////////////////////////////////////////
static Platform GetPlatformFromName( const char *sPlatform )
{
// Platform name to enum mapping.
struct {
const char *name;
Platform platform;
} platformNames[] =
{
{ "PC",PLATFORM_PC },
{ "XBOX",PLATFORM_XBOX },
{ "PS2",PLATFORM_PS2 },
{ "GC",PLATFORM_GAMECUBE },
{ "GameCube",PLATFORM_GAMECUBE },
};
for (int i = 0; i < sizeof(platformNames)/sizeof(platformNames[0]); i++)
{
if (stricmp(platformNames[i].name,sPlatform) == 0)
return platformNames[i].platform;
}
return PLATFORM_UNKNOWN;
}
//////////////////////////////////////////////////////////////////////////
void RegisterConvertors( IResourceCompiler *rc )
{
IRCLog *log=rc->GetIRCLog(); assert(log);
string strDir;
{
char szRCPath[1000];
if (GetModuleFileName (NULL, szRCPath, sizeof(szRCPath)))
strDir = CryStringUtils::GetParentDirectory<string>(szRCPath) + "\\";
}
__finddata64_t fd;
int hSearch = _findfirst64 ((strDir + "ResourceCompiler*.dll").c_str(), &fd);
if (hSearch != -1)
do {
HMODULE hPlugin = LoadLibrary ((strDir+fd.name).c_str());
if (!hPlugin)
{
log->Log ("Error: Couldn't load plug-in module %s", fd.name);
continue;
}
FnRegisterConvertors fnRegister = hPlugin?(FnRegisterConvertors)GetProcAddress(hPlugin, "RegisterConvertors"):NULL;
if (!fnRegister)
{
log->Log ("Error: plug-in module %s doesn't have RegisterConvertors function", fd.name);
continue;
}
time_t nTime = GetTimestampForLoadedLibrary (hPlugin);
char* szTime = "unknown";
if (nTime)
{
szTime = asctime(localtime(&nTime));
szTime[strlen(szTime)-1] = '\0';
}
// Info ("timestamp %s", szTime);
log->Log("");
log->Log(" Loading \"%s\"", fd.name);
fnRegister (rc);
}
while(_findnext64(hSearch, &fd) != -1);
_findclose(hSearch);
log->Log("");
}
void TestMatEntityNameTokenizer ()
{
char szMatName[1024];
while (gets (szMatName))
{
CMatEntityNameTokenizer mt;
mt.tokenize(szMatName);
printf ("Your string: \"%s\"\n", szMatName);
printf ("name: \"%s\"\n", mt.szName);
printf ("template: \"%s\"\n", mt.szTemplate);
printf ("phys mtl: \"%s\"\n", mt.szPhysMtl);
printf ("sortValue: %d\n\n", mt.nSortValue);
}
}
//////////////////////////////////////////////////////////////////////////
int __cdecl main(int argc, char **argv, char **envp)
{
/*
int tmpDbgFlag;
tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
// Clear the upper 16 bits and OR in the desired freqency
tmpDbgFlag = (tmpDbgFlag & 0x0000FFFF) | (32768 << 16);
tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpDbgFlag);
// Check heap every
//_CrtSetBreakAlloc(2031);
*/
ResourceCompiler rc;
CmdLine cmdLine;
rc.Log("ResourceCompiler V 1.02 (Crytek)");
#ifdef _WIN64
rc.Log("64-bit edition");
#endif
rc.Log("================");
rc.Log("");
// string test = "asd" + string("asdf") + "asdf" + string("df");
// CString test2 = "asd" + CString("asdf") + "asdf" + CString("df");
bool bConfigFileLoaded = false;
// Load main config.
CfgFile cfgFile;
if (cfgFile.Load(RC_INI_FILE))
{
bConfigFileLoaded = true;
cfgFile.SetConfig( COMMON_SECTION,&rc.m_MainConfig );
}
// Parse command line.
cmdLine.Parse( argc,argv,&rc.m_MainConfig );
if (cmdLine.m_bHelp)
{
rc.show_help();
exit(0);
}
if (cmdLine.m_fileSpec.IsEmpty())
{
rc.Log( "The syntax of the command is incorrect, file not specified." );
rc.show_help();
return 1;
}
CString platformStr;
if (!rc.m_MainConfig.Get( "p",platformStr ))
{
// Platform switch not specified.
rc.Log("Platform not specified, defaulting to PC.");
rc.Log("Use /p=<Platform> switch to specify platform.");
rc.Log("");
platformStr = "PC";
rc.m_MainConfig.Set("p",platformStr.GetString());
}
// Detect platform.
Platform platform = GetPlatformFromName(platformStr.GetString());
if (platform == PLATFORM_UNKNOWN)
{
rc.Log( "Unknown platform %s specified",(const char*)platformStr.GetString() );
return 1;
}
rc.GetHWnd();
//rc.InitPhysics();
rc.Log("Registering sub compilers (ResourceCompiler*.dll)");
RegisterConvertors( &rc );
if (bConfigFileLoaded)
{
// Load configuration from per platform section.
cfgFile.SetConfig( rc.GetSectionName(platform),&rc.m_MainConfig );
}
rc.Compile( platform,&rc.m_MainConfig,cmdLine.m_fileSpec.GetString() );
rc.PostBuild(); // e.g. print material dependencies
if(rc.m_MainConfig.HasKey("wait"))
{
rc.Log("");
rc.Log(" <RETURN> (/wait was specified)"); // right aligned on 80 char screen
getchar();
};
return 0;
}
//! Returns the main application window
HWND ResourceCompiler::GetHWnd()
{
HMODULE hKernel32 = LoadLibrary ("kernel32.dll");
HWND hResult = GetDesktopWindow();
if (hKernel32)
{
//typedef WINBASEAPI HWND APIENTRY (*FnGetConsoleWindow )(VOID);
typedef HWND (APIENTRY*FnGetConsoleWindow )(VOID);
FnGetConsoleWindow GetConsoleWindow = (FnGetConsoleWindow)GetProcAddress (hKernel32, "GetConsoleWindow");
if (GetConsoleWindow)
{
hResult = GetConsoleWindow();
}
FreeLibrary (hKernel32);
}
return hResult;
}
HWND ResourceCompiler::GetEmptyWindow()
{
if (!m_hEmptyWindow)
{
const char szClassName[] = "DirectXWnd";
WNDCLASS wc;
memset (&wc, 0, sizeof(wc));
wc.style = CS_OWNDC;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE)GetModuleHandle (NULL);
wc.lpszClassName = szClassName;
ATOM atomWndClass = RegisterClass (&wc);
m_hEmptyWindow = CreateWindow (szClassName, "DirectXEmpty", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,256,256,NULL, NULL, wc.hInstance, 0);
}
return m_hEmptyWindow;
}
// ------------------------------------------------------
void ResourceCompiler::InitPhysics()
{
HMODULE hPhysics = LoadLibrary("CryPhysics.dll");
if (!hPhysics)
{
LogError("Cannot load physics dll");
return;
}
IPhysicalWorld *(*pfnCreatePhysicalWorld)(ILog *pLog) = (IPhysicalWorld*(*)(ILog*))GetProcAddress(hPhysics,"CreatePhysicalWorld");
if(!pfnCreatePhysicalWorld)
{
LogError("Cannot find procedure entry CreatePhysicalWorld in CryPhysics.dll");
FreeLibrary(hPhysics);
return;
}
m_pIPhysicalWorld = pfnCreatePhysicalWorld(this);
if (!m_pIPhysicalWorld)
{
LogError("Cannot create physical world");
FreeLibrary(hPhysics);
return;
}
Log ("Physical World created");
}
// ------------------------------------------------------
IPhysicalWorld* ResourceCompiler::GetPhysicalWorld()
{
if (!m_pIPhysicalWorld)
InitPhysics();
return m_pIPhysicalWorld;
}
// ------------------------------------------------------
void ResourceCompiler::AddDependencyMaterial( const char *inszSrcFilename, const char *inszMatName, const char *inszScriptName )
{
if (!m_bStatistics)
return;
CMatDep dep;
dep.m_sMatName=inszMatName;
dep.m_sScriptName=inszScriptName;
m_MaterialDependencies.insert( CMatDepPair(dep,inszSrcFilename) );
Log(" DepMat: <%s> <%s>",inszMatName,inszScriptName);
}
// ------------------------------------------------------
void ResourceCompiler::AddDependencyFile( const char *inszSrcFilename, const char *inszPathFileName )
{
if (!m_bStatistics)
return;
m_FileDependencies.insert( CFileDepPair(inszPathFileName,inszSrcFilename) );
Log(" DepFile: <%s>",inszPathFileName);
}
// ------------------------------------------------------
void ResourceCompiler::ShowFileDependencies()
{
const char *szFileName=RC_FILENAME_FILEDEP;
FILE *out=fopen(szFileName,"wb");
if(!out)
{
LogError("unable to open %s - file it not updated",szFileName);
return;
}
Log("writing %s (counted %d) ...",szFileName,m_FileDependencies.size());
Log("");
CFileDepMap::iterator it;
string sLastDep=""; // for a nice printout
bool bFirst=true;
for(it=m_FileDependencies.begin(); it!=m_FileDependencies.end(); ++it)
{
const string &rsDepFile = it->first;
const string &rsSrcFile = it->second;
if(bFirst || rsDepFile!=sLastDep)
{
fprintf(out,"\r\n");
fprintf(out,"'%s'\r\n",rsDepFile.c_str());
sLastDep=rsDepFile;
bFirst=false;
}
fprintf(out," used by: '%s'\r\n",rsSrcFile.c_str());
}
fprintf(out,"\r\n");
fprintf(out,"------------------------------------------------------------------------------\r\n");
fprintf(out,"\r\n");
fprintf(out,"all used files:\r\n");
fprintf(out,"\r\n");
bFirst=true;
for(it=m_FileDependencies.begin(); it!=m_FileDependencies.end(); ++it)
{
const string &rsDepFile = it->first;
const string &rsSrcFile = it->second;
if(bFirst || rsDepFile!=sLastDep)
{
fprintf(out," '%s'\r\n",rsDepFile.c_str());
sLastDep=rsDepFile;
bFirst=false;
}
}
fclose(out);
}
// ------------------------------------------------------
void ResourceCompiler::ShowMaterialDependencies()
{
const char *szFileName=RC_FILENAME_MATDEP;
FILE *out=fopen(szFileName,"wb");
if(!out)
{
LogError("unable to open %s - file it not updated",szFileName);
return;
}
Log("writing %s (counted %d) ...",szFileName,m_MaterialDependencies.size());
Log("");
CMatDepMap::iterator it;
CMatDep LastDep; // for a nice printout
bool bFirst=true;
// max info
for(it=m_MaterialDependencies.begin(); it!=m_MaterialDependencies.end(); ++it)
{
const CMatDep &rsMatDep = it->first;
const string &rsSrcFile = it->second;
if(bFirst || !(rsMatDep==LastDep))
{
fprintf(out,"\r\n");
fprintf(out,"scriptmaterial='%s' materialname='%s'\r\n",rsMatDep.m_sScriptName.c_str(),rsMatDep.m_sMatName.c_str());
LastDep=rsMatDep;
bFirst=false;
}
fprintf(out," used by: '%s'\r\n",rsSrcFile.c_str());
}
fprintf(out,"\r\n");
fprintf(out,"------------------------------------------------------------------------------\r\n");
fprintf(out,"\r\n");
fprintf(out,"all used scriptmaterials:\r\n");
fprintf(out,"\r\n");
// only the used scripsmaterials
bFirst=true;
for(it=m_MaterialDependencies.begin(); it!=m_MaterialDependencies.end(); ++it)
{
const CMatDep &rsMatDep = it->first;
const string &rsSrcFile = it->second;
if(bFirst || !(rsMatDep.m_sScriptName==LastDep.m_sScriptName))
{
fprintf(out," '%s'\r\n",rsMatDep.m_sScriptName.c_str());
LastDep=rsMatDep;
bFirst=false;
}
}
fclose(out);
}
// ------------------------------------------------------
void ResourceCompiler::PostBuild()
{
if (m_bStatistics)
{
ShowFileDependencies();
ShowMaterialDependencies();
}
}