123
This commit is contained in:
650
CryAnimation/CryModelLoader.cpp
Normal file
650
CryAnimation/CryModelLoader.cpp
Normal file
@@ -0,0 +1,650 @@
|
||||
#include "stdafx.h"
|
||||
#include <StlUtils.h>
|
||||
#include <CryCompiledFile.h>
|
||||
#include "ChunkFileReader.h"
|
||||
#include "CryModel.h"
|
||||
#include "CryModelState.h"
|
||||
#include "CryModelLoader.h"
|
||||
#include "CryModelGeometryLoader.h"
|
||||
#include "StringUtils.h"
|
||||
#include "CrySkinMorph.h"
|
||||
#include "CrySkinMorphBuilder.h"
|
||||
#include "ControllerManager.h"
|
||||
#include "CgfUtils.h"
|
||||
#include "CVars.h"
|
||||
#include "CryModelSubmesh.h"
|
||||
using namespace CryStringUtils;
|
||||
|
||||
class CAutoFile
|
||||
{
|
||||
FILE* m_f;
|
||||
public:
|
||||
CAutoFile (const char* szName, const char* szMode)
|
||||
{
|
||||
m_f = g_GetPak()->FOpen (szName, szMode);
|
||||
}
|
||||
~CAutoFile ()
|
||||
{
|
||||
if (m_f)
|
||||
g_GetPak()->FClose (m_f);
|
||||
}
|
||||
|
||||
long GetSize()
|
||||
{
|
||||
if (g_GetPak()->FSeek (m_f, 0, SEEK_END))
|
||||
return -1;
|
||||
|
||||
long nSize = g_GetPak()->FTell (m_f);
|
||||
|
||||
if (g_GetPak()->FSeek(m_f, 0, SEEK_SET))
|
||||
return -1;
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
bool Read (void* pData, unsigned nSize)
|
||||
{
|
||||
return (1 == g_GetPak()->FRead (pData, nSize, 1, m_f));
|
||||
}
|
||||
|
||||
operator FILE*() {return m_f;}
|
||||
};
|
||||
|
||||
|
||||
CryModelLoader::CryModelLoader (CControllerManager* pControllerManager):
|
||||
m_pControllerManager (pControllerManager),
|
||||
m_fCalFile (NULL),
|
||||
m_nCafFindFileHandle (-1),
|
||||
m_pModel (NULL),
|
||||
m_bLoadFromCCG (false),
|
||||
m_bExtCCG(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CryModelLoader::~CryModelLoader()
|
||||
{
|
||||
// clean up the resources
|
||||
clear();
|
||||
}
|
||||
|
||||
// cleans up the resources allocated during load
|
||||
void CryModelLoader::clear()
|
||||
{
|
||||
m_strGeomFileNameNoExt = "";
|
||||
m_strCalFileName = "";
|
||||
|
||||
if (m_fCalFile)
|
||||
{
|
||||
g_GetPak()->FClose (m_fCalFile);
|
||||
m_fCalFile = NULL;
|
||||
}
|
||||
|
||||
if (m_nCafFindFileHandle != -1)
|
||||
{
|
||||
g_GetPak()->FindClose(m_nCafFindFileHandle);
|
||||
m_nCafFindFileHandle = -1;
|
||||
}
|
||||
|
||||
if (m_pModel)
|
||||
{
|
||||
delete m_pModel;
|
||||
m_pModel = NULL;
|
||||
}
|
||||
|
||||
m_arrLodFiles.clear();
|
||||
m_arrBufferCCG.clear();
|
||||
}
|
||||
|
||||
bool IsValidFile (const char* szFilePath)
|
||||
{
|
||||
FILE* f = g_GetPak()->FOpen(szFilePath, "rb");
|
||||
if (f)
|
||||
{
|
||||
g_GetPak()->FClose (f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CryModel* CryModelLoader::loadNew (CryCharBody* pBody, const string& strGeomFileName, float fScale)
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeGeomLoad);
|
||||
// make sure we call done() whenever we return from this function
|
||||
CAutoClearLoader _autoClear (this);
|
||||
|
||||
const char* szExt = FindExtension(strGeomFileName.c_str());
|
||||
m_strGeomFileNameNoExt.assign (strGeomFileName.c_str(), *szExt?szExt-1:szExt);
|
||||
m_bExtCCG = !stricmp(szExt, "ccg");
|
||||
m_fScale = fScale;
|
||||
|
||||
m_bLoadFromCCG = g_GetCVars()->ca_EnableCCG() && IsValidFile (getCCGFilePath().c_str());
|
||||
|
||||
// first, initialize the search of animations. If the file has no animations at all (no cal file, no _..caf files)
|
||||
// then this is not an animated file and must be loaded somewhere else (namely in the 3D Engine)
|
||||
if (!m_bLoadFromCCG)
|
||||
searchAnimations (); // no need to exit if no animations: maybe it's a body part
|
||||
|
||||
g_GetLog()->UpdateLoadingScreen ("\003Loading %s", cutString(m_bLoadFromCCG?getCCGFilePath():strGeomFileName, 40).c_str());
|
||||
// find how many LODs we have
|
||||
if (!(m_bLoadFromCCG?preloadCCG():preloadCGFs()))
|
||||
return NULL;
|
||||
|
||||
m_pModel = new CryModel (pBody, m_pControllerManager);
|
||||
|
||||
if (m_bLoadFromCCG)
|
||||
{
|
||||
if (!loadCCG())
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!loadCGFs())
|
||||
return NULL;
|
||||
|
||||
//m_pModel->buildMorphSkins();
|
||||
|
||||
if (!loadTextures())
|
||||
return NULL;
|
||||
|
||||
m_pModel->m_pDefaultModelState->GetCryModelSubmesh(0)->GenerateRenderArrays (strGeomFileName.c_str());
|
||||
|
||||
if (!loadAnimations())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// needed for XBox development
|
||||
extern void exportTestModel(CryGeometryInfo* pGeometry, CLeafBuffer* pLeafBuffer);
|
||||
// on this stage, if m_pCryModel == NULL, it means the loader couldn't load the model
|
||||
if (m_pModel)
|
||||
exportTestModel( m_pModel->getGeometryInfo(), m_pModel->m_pDefaultModelState->m_pLeafBuffers[0]);
|
||||
#endif
|
||||
|
||||
|
||||
if (g_GetCVars()->ca_ZDeleteConstructionData())
|
||||
{
|
||||
m_pModel->clearConstructionData();
|
||||
}
|
||||
else
|
||||
g_GetLog()->LogWarning ("\005The construction data wasn't deleted");
|
||||
|
||||
// return the initialized(loaded) model, forgetting about it so that it doesn't get destructed by the following call to done()
|
||||
return detachModel();
|
||||
}
|
||||
|
||||
|
||||
// tries to find out if there are any animations for this file; if there are some,
|
||||
// prepares to load them and returns true; otherwise returns false
|
||||
bool CryModelLoader::searchAnimations ()
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeGeomChunkLoad);
|
||||
// make up the cal file name
|
||||
m_strCalFileName = m_strGeomFileNameNoExt + ".cal";
|
||||
|
||||
// try to find out - if there are any animations for this file. if there are none, then return an error
|
||||
m_fCalFile = g_GetPak()->FOpen(m_strCalFileName.c_str(), "r");
|
||||
m_nCafFindFileHandle = -1;
|
||||
|
||||
if (!m_fCalFile)
|
||||
{
|
||||
// finish making search path
|
||||
string strSeachFilter = m_strGeomFileNameNoExt + "_*.caf";
|
||||
|
||||
// search
|
||||
m_nCafFindFileHandle = g_GetPak()->FindFirst (strSeachFilter.c_str(), &m_fileinfo);
|
||||
}
|
||||
|
||||
return m_fCalFile || m_nCafFindFileHandle != -1;
|
||||
}
|
||||
|
||||
|
||||
// searches for lod models for the given model; returns false in case of some error
|
||||
bool CryModelLoader::preloadCGFs()
|
||||
{
|
||||
AUTO_PROFILE_SECTION (g_dTimeGeomChunkLoadFileIO);
|
||||
CChunkFileReader_AutoPtr pReader = new CChunkFileReader ();
|
||||
// first try to open LOD 0
|
||||
if (!pReader->open (m_strGeomFileNameNoExt + ".cgf"))
|
||||
{
|
||||
g_GetLog()->LogError ("\003CryModelLoader::preloadCGFs(%s): main file not found", m_strGeomFileNameNoExt.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == pReader->numChunksOfType(ChunkType_BoneAnim))
|
||||
return false; // the cgf doesn't contain bone info
|
||||
|
||||
m_arrLodFiles.reinit (1);
|
||||
m_arrLodFiles[0] = pReader;
|
||||
|
||||
for (unsigned nLOD = 1; nLOD < g_nMaxGeomLodLevels; ++nLOD)
|
||||
{
|
||||
pReader = new CChunkFileReader();
|
||||
if (pReader->open(m_strGeomFileNameNoExt + "_lod" + toString(nLOD) + ".cgf"))
|
||||
m_arrLodFiles.push_back(pReader);
|
||||
else
|
||||
break; // we have opened all the LOD files so far
|
||||
|
||||
indicateProgress();
|
||||
}
|
||||
|
||||
// we have LOD 0, so it's optional to have any other and we return true anyway
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// loads the CCG in memory buffer m_arrBufferCCG
|
||||
bool CryModelLoader::preloadCCG()
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeGeomChunkLoadFileIO);
|
||||
CAutoFile fIn (getCCGFilePath().c_str(), "rb");
|
||||
if (!fIn)
|
||||
return false;
|
||||
|
||||
long nSize = fIn.GetSize();
|
||||
if (nSize <= 0)
|
||||
return false;
|
||||
|
||||
m_arrBufferCCG.resize(nSize);
|
||||
|
||||
if (!fIn.Read (&m_arrBufferCCG[0], nSize))
|
||||
return false;
|
||||
|
||||
// data has been read - automatically close the file and return success
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// loads animations for already loaded model
|
||||
bool CryModelLoader::loadAnimations()
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeAnimLoadBind);
|
||||
|
||||
// the number of animations loaded
|
||||
unsigned numAnimations = 0;
|
||||
|
||||
{
|
||||
AUTO_PROFILE_SECTION (g_dTimeTest1);
|
||||
if(m_fCalFile)
|
||||
numAnimations = loadAnimationsWithCAL ();
|
||||
else
|
||||
if (m_nCafFindFileHandle != -1)
|
||||
numAnimations = loadAnimationsNoCAL ();
|
||||
}
|
||||
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeTest2);
|
||||
if (!numAnimations && !m_pModel->numMorphTargets())
|
||||
{
|
||||
g_GetLog()->LogWarning ("\004CryModelLoader::loadAnimations(%s): couldn't find any animations for the model. Standalone character will be useless.", m_strGeomFileNameNoExt.c_str());
|
||||
//return false;
|
||||
}
|
||||
|
||||
if (!m_bLoadFromCCG)
|
||||
{
|
||||
g_GetLog()->UpdateLoadingScreenPlus ("\003 precomputing");
|
||||
m_pModel->LoadPostInitialize (!m_bBoneInitPosInitialized);
|
||||
g_GetLog()->UpdateLoadingScreenPlus ("\003done.");
|
||||
}
|
||||
}
|
||||
|
||||
if (numAnimations)
|
||||
g_GetLog()->UpdateLoadingScreen(" %d animations loaded (total animations: %d)", numAnimations, m_pControllerManager->NumAnimations());
|
||||
|
||||
// m_pControllerManager->LogUsageStats();
|
||||
//m_pModel->shrinkControllerArrays();
|
||||
|
||||
return m_pModel->m_pDefaultModelState
|
||||
&& ((m_pModel->numBoneInfos()
|
||||
&& m_pModel->m_pDefaultModelState->getRootBone())
|
||||
|| m_pModel->numMorphTargets());
|
||||
}
|
||||
|
||||
// loads the animations from the array: pre-allocates the necessary controller arrays
|
||||
// the 0th animation is the default animation
|
||||
unsigned CryModelLoader::loadAnimationArray (const AnimFileArray& arrAnimFiles)
|
||||
{
|
||||
unsigned nAnimID = 0;
|
||||
if (arrAnimFiles.empty())
|
||||
return 0;
|
||||
|
||||
indicateProgress("\003 Anims");
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeAnimLoadBindPreallocate);
|
||||
m_pModel->prepareLoadCAFs ((unsigned)arrAnimFiles.size());
|
||||
}
|
||||
|
||||
indicateProgress("\003:");
|
||||
|
||||
// load the default animation - it must be always loaded synchronously
|
||||
|
||||
unsigned nDefAnimFlags = arrAnimFiles[0].nAnimFlags;
|
||||
if (!stricmp(arrAnimFiles[0].strAnimName.c_str(), "default"))
|
||||
nDefAnimFlags |= GlobalAnimation::FLAGS_DEFAULT_ANIMATION;
|
||||
|
||||
if(m_pModel->LoadCAF(arrAnimFiles[0].strFileName.c_str(), m_fScale, nAnimID, arrAnimFiles[0].strAnimName.c_str(), nDefAnimFlags) >= 0)
|
||||
nAnimID++;
|
||||
else
|
||||
if (g_GetCVars()->ca_Debug())
|
||||
g_GetLog()->LogWarning ("\005Default pose for %s was not found, object may not skin as expected", m_strGeomFileNameNoExt.c_str());
|
||||
|
||||
for (unsigned i = 1; i < arrAnimFiles.size(); ++i)
|
||||
{
|
||||
if (m_pModel->LoadCAF(arrAnimFiles[i].strFileName.c_str(), m_fScale, nAnimID, arrAnimFiles[i].strAnimName.c_str(),arrAnimFiles[i].nAnimFlags) >= 0)
|
||||
{
|
||||
nAnimID++;
|
||||
//if((i%10)==0)
|
||||
// indicateProgress();
|
||||
}
|
||||
else
|
||||
g_GetLog()->LogWarning ("\002Animation (Caf) file \"%s\" could not be read (it's an animation of \"%s.cgf\")", arrAnimFiles[i].strFileName.c_str(), m_strGeomFileNameNoExt.c_str());
|
||||
}
|
||||
indicateProgress("\003done;");
|
||||
return nAnimID;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// loads animations for the given file from the given directory, loading
|
||||
// all cal files which begin with the cgf file name and underscope (this
|
||||
// is the convention for the cgf's that don't have cal file associated)
|
||||
// PARAMETERS:
|
||||
// m_strGeomFileNameNoExt - the name of the cgf/cid file without extension
|
||||
// m_nCafFindFileHandle - the search handle opened by _findfirst() for all cal files belonging to this cgf
|
||||
// m_fScale - the scale factor to be applied to all controllers
|
||||
unsigned CryModelLoader::loadAnimationsNoCAL ()
|
||||
{
|
||||
// animation files to load, excluding the default animation
|
||||
AnimFileArray arrAnimFiles;
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeAnimLoadBindNoCal);
|
||||
// make search path
|
||||
string strDirName = GetParentDirectory (m_strGeomFileNameNoExt).c_str();
|
||||
|
||||
// load the default pose first
|
||||
string strDefaultPose = (m_strGeomFileNameNoExt + "_default.caf").c_str();
|
||||
|
||||
arrAnimFiles.reserve (64);
|
||||
// we need default animation immediately, but unlikely we'll need it in the future (so we can unload it)
|
||||
arrAnimFiles.push_back (SAnimFile(strDefaultPose, "default", GlobalAnimation::FLAGS_DEFAULT_ANIMATION));
|
||||
|
||||
// the name of the base cgf (before the understrike) + 1
|
||||
unsigned nBaseNameLength = unsigned(m_strGeomFileNameNoExt.length() - strDirName.length());
|
||||
indicateProgress();
|
||||
do
|
||||
{
|
||||
SAnimFile AnimFile;
|
||||
AnimFile.strFileName = strDirName + "\\" + m_fileinfo.name;
|
||||
|
||||
if(!stricmp(AnimFile.strFileName.c_str(), strDefaultPose.c_str()))
|
||||
// skip the default pose as it has already been loaded
|
||||
continue;
|
||||
|
||||
//if (!stricmp(FindExtension(fileinfo.name), "caf")) // actually ,according to the search mask, this should be met automatically
|
||||
char* szExtension = StripFileExtension(m_fileinfo.name);
|
||||
assert (!stricmp(szExtension, "caf"));
|
||||
assert (strlen(m_fileinfo.name) > nBaseNameLength);
|
||||
|
||||
AnimFile.strAnimName = m_fileinfo.name + nBaseNameLength;
|
||||
arrAnimFiles.push_back (AnimFile);
|
||||
}
|
||||
while (g_GetPak()->FindNext( m_nCafFindFileHandle, &m_fileinfo ) != -1);
|
||||
}
|
||||
return loadAnimationArray(arrAnimFiles);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// loads animations for this cgf from the given cal file
|
||||
// does NOT close the file (the file belongs to the calling party)
|
||||
// PARAMETERS
|
||||
// m_strGeomFileNameNoExt - the name of the cgf/cid file without extension
|
||||
// m_fCalFile - the file opened by fopen() for the cal associated with this cgf
|
||||
// m_fScale - the scale factor to be applied to all controllers
|
||||
unsigned CryModelLoader::loadAnimationsWithCAL ()
|
||||
{
|
||||
AnimFileArray arrAnimFiles;
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeAnimLoadBindWithCal);
|
||||
// Load cal file and load animations from animations folder
|
||||
// make anim folder name
|
||||
// make search path
|
||||
string strDirName = GetParentDirectory(m_strGeomFileNameNoExt).c_str();
|
||||
string strAnimDirName = GetParentDirectory(strDirName, 2) + "\\animations";
|
||||
// the flags applicable to the currently being loaded animation
|
||||
unsigned nAnimFlags = 0;
|
||||
|
||||
arrAnimFiles.reserve (256);
|
||||
|
||||
indicateProgress();
|
||||
for (int i = 0; m_fCalFile && !g_GetPak()->FEof(m_fCalFile); ++i)
|
||||
{
|
||||
char sBuffer[512]="";
|
||||
g_GetPak()->FGets(sBuffer,512,m_fCalFile);
|
||||
char*szAnimName;
|
||||
char*szFileName;
|
||||
|
||||
if(sBuffer[0] == '/' || sBuffer[0]=='\r' || sBuffer[0]=='\n' || sBuffer[0]==0)
|
||||
continue;
|
||||
|
||||
//if(sscanf(sBuffer, "%s=%s", szAnimName, szFileName) != 2)
|
||||
// continue;
|
||||
szAnimName = strtok (sBuffer, " \t\n\r=");
|
||||
if (!szAnimName)
|
||||
continue;
|
||||
szFileName = strtok(NULL, " \t\n\r=");
|
||||
if (!szFileName || szFileName[0] == '?')
|
||||
{
|
||||
m_pModel->RegisterDummyAnimation(szAnimName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (szAnimName[0] == '/' && szAnimName[1] == '/')
|
||||
continue; // comment
|
||||
|
||||
{ // remove firsrt '\' and replace '/' with '\'
|
||||
while(szFileName[0]=='/' || szFileName[0]=='\\')
|
||||
memmove(szFileName,szFileName+1,sizeof(szFileName)-1);
|
||||
|
||||
for(char * p = szFileName+strlen(szFileName); p>=szFileName; p--)
|
||||
if(*p == '/')
|
||||
*p = '\\';
|
||||
}
|
||||
|
||||
// process the possible directives
|
||||
if (szAnimName[0] == '$')
|
||||
{
|
||||
const char* szDirective = szAnimName + 1;
|
||||
if (!stricmp(szDirective, "AnimationDir")
|
||||
||!stricmp(szDirective, "AnimDir")
|
||||
||!stricmp(szDirective, "AnimationDirectory")
|
||||
||!stricmp(szDirective, "AnimDirectory"))
|
||||
{
|
||||
strAnimDirName = strDirName + "\\" + szFileName;
|
||||
// delete the trailing slashes
|
||||
while (
|
||||
!strAnimDirName.empty()
|
||||
&& strAnimDirName [strAnimDirName.length()-1] == '\\'
|
||||
)
|
||||
strAnimDirName[strAnimDirName.length()-1] = '\0';
|
||||
}
|
||||
else
|
||||
if (!stricmp (szDirective, "ModelOffsetX"))
|
||||
{
|
||||
float fValue;
|
||||
if (sscanf (szFileName, "%f", &fValue) != 1)
|
||||
g_GetLog ()->LogToFile("\003Warning:directive ModelOffsetX %s couldn't be read in file %s.cal", szFileName, m_strGeomFileNameNoExt.c_str());
|
||||
else
|
||||
m_pModel->m_vModelOffset.x = fValue;
|
||||
}
|
||||
else
|
||||
if (!stricmp (szDirective, "ModelOffsetY"))
|
||||
{
|
||||
float fValue;
|
||||
if (sscanf (szFileName, "%f", &fValue) != 1)
|
||||
g_GetLog ()->LogToFile("\003Warning:directive ModelOffsetY %s couldn't be read in file %s.cal", szFileName, m_strGeomFileNameNoExt.c_str());
|
||||
else
|
||||
m_pModel->m_vModelOffset.y = fValue;
|
||||
}
|
||||
else
|
||||
if (!stricmp (szDirective, "ModelOffsetZ"))
|
||||
{
|
||||
float fValue;
|
||||
if (sscanf (szFileName, "%f", &fValue) != 1)
|
||||
g_GetLog ()->LogToFile("\003Warning:directive ModelOffsetZ %s couldn't be read in file %s.cal", szFileName, m_strGeomFileNameNoExt.c_str());
|
||||
else
|
||||
m_pModel->m_vModelOffset.z = fValue;
|
||||
}
|
||||
else
|
||||
if (!stricmp(szDirective, "AutoUnload"))
|
||||
{
|
||||
switch (CryStringUtils::toYesNoType(szFileName))
|
||||
{
|
||||
case CryStringUtils::nYNT_Yes:
|
||||
nAnimFlags &= ~GlobalAnimation::FLAGS_DISABLE_AUTO_UNLOAD;
|
||||
break;
|
||||
case CryStringUtils::nYNT_No:
|
||||
nAnimFlags |= GlobalAnimation::FLAGS_DISABLE_AUTO_UNLOAD;
|
||||
break;
|
||||
default:
|
||||
g_GetLog()->LogWarning ("\003invalid option for AutoUnload directive (must be yes or no) in file %s.cal", m_strGeomFileNameNoExt.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!stricmp(szDirective, "DelayLoad"))
|
||||
{
|
||||
switch (CryStringUtils::toYesNoType(szFileName))
|
||||
{
|
||||
case CryStringUtils::nYNT_Yes:
|
||||
nAnimFlags &= ~GlobalAnimation::FLAGS_DISABLE_DELAY_LOAD;
|
||||
break;
|
||||
case CryStringUtils::nYNT_No:
|
||||
nAnimFlags |= GlobalAnimation::FLAGS_DISABLE_DELAY_LOAD;
|
||||
break;
|
||||
default:
|
||||
g_GetLog()->LogWarning ("\003invalid option for DelayLoad directive (must be yes or no) in file %s.cal", m_strGeomFileNameNoExt.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_GetLog()->LogWarning ("\003Unknown directive %s", szDirective);
|
||||
continue;
|
||||
}
|
||||
|
||||
arrAnimFiles.push_back(SAnimFile (strAnimDirName + "\\" + szFileName, szAnimName,nAnimFlags));
|
||||
}
|
||||
if (arrAnimFiles.empty())
|
||||
return false;
|
||||
}
|
||||
return loadAnimationArray (arrAnimFiles);
|
||||
}
|
||||
|
||||
|
||||
// loads the CCG (including all the LODs in it)
|
||||
bool CryModelLoader::loadCCG()
|
||||
{
|
||||
CCFMemReader Reader (&m_arrBufferCCG[0], (unsigned)m_arrBufferCCG.size());
|
||||
if (Reader.IsEnd())
|
||||
return false;
|
||||
|
||||
string strDirName = GetParentDirectory(m_strGeomFileNameNoExt).c_str();
|
||||
string strAnimDirName = GetParentDirectory(strDirName, 2) + "\\animations";
|
||||
if (!m_pModel->initFromCCG(strDirName, strAnimDirName, Reader, m_fScale))
|
||||
return false;
|
||||
|
||||
// when we load CCG, we always have the init pose initialized,
|
||||
// otherwise we fail to load
|
||||
m_bBoneInitPosInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// loads the geometry files (LOD files, starting with the main one)
|
||||
bool CryModelLoader::loadCGFs()
|
||||
{
|
||||
unsigned numLODs = (unsigned)m_arrLodFiles.size();
|
||||
m_pModel->m_arrGeomInfo.reinit (numLODs);
|
||||
|
||||
CryModelGeometryLoader GeomLoader;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < numLODs; ++i)
|
||||
{
|
||||
if (!GeomLoader.load (m_pModel, m_arrLodFiles[i], i, m_fScale))
|
||||
{
|
||||
if (i)
|
||||
g_GetLog()->LogWarning ("\003Modes LOD %d can't be loaded. Please reexport the LOD file. Animated object will not be loaded.", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
m_bBoneInitPosInitialized = GeomLoader.hasBoneInfoInitPos();
|
||||
}
|
||||
|
||||
if (g_GetCVars()->ca_NoMtlSorting())
|
||||
return true;
|
||||
|
||||
m_pModel->deleteUnusedMaterials();
|
||||
|
||||
unsigned numMtls = (unsigned)m_pModel->m_arrMaterials.size();
|
||||
|
||||
// this will map from the new material id to the old material id after sorting
|
||||
// the materials
|
||||
std::vector<unsigned> arrMapMtlsOld, arrMapMtlsNew;
|
||||
arrMapMtlsOld.resize (numMtls);
|
||||
for (i = 0; i < numMtls; ++i)
|
||||
arrMapMtlsOld[i] = i;
|
||||
|
||||
// initial (identity) mapping created, now tokenize the material names
|
||||
std::vector<CMatEntityNameTokenizer> arrTokenizers;
|
||||
arrTokenizers.resize (numMtls);
|
||||
for (i = 0; i < numMtls; ++i)
|
||||
arrTokenizers[i].tokenize (m_pModel->m_arrMaterials[i].name);
|
||||
|
||||
|
||||
// now sort the indices to receive the correct distribution of materials
|
||||
// thus we'll effectively receive perm[new]=old
|
||||
std::sort (arrMapMtlsOld.begin(), arrMapMtlsOld.end(), CMatEntityIndexSort(&arrTokenizers[0], numMtls));
|
||||
|
||||
//std::swap (arrMapMtlsOld.front(), arrMapMtlsOld.back());
|
||||
|
||||
// form the permutation perm[old]=new
|
||||
arrMapMtlsNew.resize (numMtls);
|
||||
ConstructReversePermutation(&arrMapMtlsOld[0], &arrMapMtlsNew[0], numMtls);
|
||||
|
||||
// resort the material entities in the model
|
||||
RemapMatEntities (&m_pModel->m_arrMaterials[0], numMtls, &arrMapMtlsOld[0]);
|
||||
|
||||
// now remap the material ids in the faces
|
||||
for (i = 0; i < m_pModel->numLODs(); ++i)
|
||||
m_pModel->getGeometryInfo(i)->remapMtlIds(&arrMapMtlsNew[0], numMtls);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CryModelLoader::loadTextures()
|
||||
{
|
||||
AUTO_PROFILE_SECTION(g_dTimeShaderLoad);
|
||||
if (g_GetCVars()->ca_Debug())
|
||||
g_GetLog()->UpdateLoadingScreen("\005 Loading shaders from %s", m_strGeomFileNameNoExt.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// forgets about the m_pModel (so that it doesn't get deleted upon done()),
|
||||
// and returns it
|
||||
CryModel* CryModelLoader::detachModel()
|
||||
{
|
||||
CryModel* pModel = m_pModel; // this model will be returned
|
||||
m_pModel = NULL; // forget about the model
|
||||
return pModel;
|
||||
}
|
||||
|
||||
void CryModelLoader::indicateProgress(const char*szMsg)
|
||||
{
|
||||
if (szMsg)
|
||||
g_GetLog()->UpdateLoadingScreenPlus(szMsg?szMsg:"\003.");
|
||||
}
|
||||
Reference in New Issue
Block a user