123
This commit is contained in:
542
ResourceCompiler/CgfUtils.cpp
Normal file
542
ResourceCompiler/CgfUtils.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Crytek Character Animation source code
|
||||
//
|
||||
// History:
|
||||
// Created by Sergiy Migdalskiy
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "stdafx.h"
|
||||
#include "StringUtils.h"
|
||||
#include "CgfUtils.h"
|
||||
|
||||
using namespace CryStringUtils;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// given the chunk, parses it and returns the array of pointers to the strings with the bone names
|
||||
// in the supplied array. Returns true when successful
|
||||
// PARAMETERS:
|
||||
// chunkHeader - the header of the chunk in the chunk table
|
||||
// pChunk - the raw chunk data in the file
|
||||
// nChunkSize - the size of the raw data piece in the file
|
||||
// arrNames - the array that will be resized according to the number of entries, and each element of this array
|
||||
// will be the pointer to the corresponding 0-terminated name string.
|
||||
bool LoadBoneNameList (const CHUNK_HEADER& chunkHeader, const void* pChunk, unsigned nChunkSize, std::vector<const char*>& arrNames)
|
||||
{
|
||||
switch (chunkHeader.ChunkVersion)
|
||||
{
|
||||
case BONENAMELIST_CHUNK_DESC_0744::VERSION:
|
||||
{
|
||||
// the old chunk version - fixed-size name list
|
||||
const BONENAMELIST_CHUNK_DESC_0744* pNameChunk = (const BONENAMELIST_CHUNK_DESC_0744*)(pChunk);
|
||||
|
||||
int nGeomBones = pNameChunk->nEntities;
|
||||
|
||||
// just fill in the pointers to the fixed-size string buffers
|
||||
const NAME_ENTITY* pGeomBoneNameTable = (const NAME_ENTITY*)(pNameChunk+1);
|
||||
if(nGeomBones < 0 || nGeomBones > 0x800)
|
||||
return false;
|
||||
arrNames.resize(nGeomBones);
|
||||
for (int i = 0; i < nGeomBones; ++i)
|
||||
arrNames[i] = pGeomBoneNameTable[i].name;
|
||||
}
|
||||
break;
|
||||
|
||||
case BONENAMELIST_CHUNK_DESC_0745::VERSION:
|
||||
{
|
||||
// the new memory-economizing chunk with variable-length packed strings following tightly each other
|
||||
const BONENAMELIST_CHUNK_DESC_0745* pNameChunk = (const BONENAMELIST_CHUNK_DESC_0745*)(pChunk);
|
||||
int nGeomBones = pNameChunk->numEntities;
|
||||
|
||||
// we know how many strings there are there; the whole bunch of strings may
|
||||
// be followed by pad zeros, to enable alignment
|
||||
arrNames.resize(nGeomBones, "");
|
||||
|
||||
// scan through all the strings, each string following immediately the 0 terminator of the previous one
|
||||
const char* pNameListEnd = ((const char*)pNameChunk) + nChunkSize;
|
||||
const char* pName = (const char*)(pNameChunk+1);
|
||||
int nName = 0;
|
||||
while (*pName && pName < pNameListEnd && nName < nGeomBones)
|
||||
{
|
||||
arrNames[nName] = pName;
|
||||
pName += strnlen(pName, pNameListEnd) + 1;
|
||||
++nName;
|
||||
}
|
||||
if (nName < nGeomBones)
|
||||
{
|
||||
// the chunk is truncated
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
// if this is in the engine, log the error
|
||||
g_GetLog()->LogWarning ("\003inconsistent bone name list chunk: only %d out of %d bone names have been read.", nName, nGeomBones);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Attempts to load the material from the given material chunk to the "me" structure
|
||||
MatChunkLoadErrorEnum LoadMatEntity (const CHUNK_HEADER& chunkHeader, const void* pChunkData, unsigned nChunkSize, MAT_ENTITY& me)
|
||||
{
|
||||
memset(&me, 0, sizeof(MAT_ENTITY));
|
||||
|
||||
switch (chunkHeader.ChunkVersion)
|
||||
{
|
||||
case MTL_CHUNK_DESC_0746::VERSION:
|
||||
{
|
||||
const MTL_CHUNK_DESC_0746* pMatChunk = (const MTL_CHUNK_DESC_0746*)pChunkData;
|
||||
|
||||
me.m_New = 2;
|
||||
strcpy(me.name, pMatChunk->name);
|
||||
switch (pMatChunk->MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
{
|
||||
me.IsStdMat = true;
|
||||
me.col_d = pMatChunk->col_d;
|
||||
me.col_a = pMatChunk->col_a;
|
||||
//me.col_a.g=0;
|
||||
//me.col_a.b=0;
|
||||
me.col_s = pMatChunk->col_s;
|
||||
|
||||
me.specLevel = pMatChunk->specLevel;
|
||||
me.specShininess = pMatChunk->specShininess*100;
|
||||
me.opacity = pMatChunk->opacity;
|
||||
me.selfIllum = pMatChunk->selfIllum;
|
||||
me.flags = pMatChunk->flags;
|
||||
|
||||
me.Dyn_Bounce = pMatChunk->Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = pMatChunk->Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = pMatChunk->Dyn_SlidingFriction;
|
||||
/* //Timur[10/24/2001]
|
||||
strcpy(me.map_a, pMatChunk->tex_a.name);
|
||||
strcpy(me.map_d, pMatChunk->tex_d.name);
|
||||
strcpy(me.map_o, pMatChunk->tex_o.name);
|
||||
strcpy(me.map_b, pMatChunk->tex_b.name);
|
||||
strcpy(me.map_s, pMatChunk->tex_s.name);
|
||||
strcpy(me.map_g, pMatChunk->tex_g.name);
|
||||
strcpy(me.map_c, pMatChunk->tex_c.name);
|
||||
strcpy(me.map_e, pMatChunk->tex_rl.name);
|
||||
strcpy(me.map_rr, pMatChunk->tex_rr.name);
|
||||
strcpy(me.map_det, pMatChunk->tex_det.name);
|
||||
*/
|
||||
me.map_a = pMatChunk->tex_a;
|
||||
me.map_d = pMatChunk->tex_d;
|
||||
me.map_o = pMatChunk->tex_o;
|
||||
me.map_b = pMatChunk->tex_b;
|
||||
me.map_s = pMatChunk->tex_s;
|
||||
me.map_g = pMatChunk->tex_g;
|
||||
me.map_detail = pMatChunk->tex_fl;
|
||||
me.map_e = pMatChunk->tex_rl;
|
||||
me.map_subsurf = pMatChunk->tex_subsurf;
|
||||
me.map_displ = pMatChunk->tex_det;
|
||||
|
||||
me.nChildren = pMatChunk->nChildren;
|
||||
|
||||
me.alpharef = pMatChunk->alphaTest;
|
||||
}
|
||||
return MCLE_Success;
|
||||
|
||||
default:
|
||||
return MCLE_IgnoredType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MTL_CHUNK_DESC_0745::VERSION:
|
||||
{
|
||||
const MTL_CHUNK_DESC_0745* pMatChunk = (const MTL_CHUNK_DESC_0745*)pChunkData;
|
||||
|
||||
me.m_New = 1;
|
||||
strcpy(me.name, pMatChunk->name);
|
||||
switch (pMatChunk->MtlType)
|
||||
{
|
||||
case MTL_STANDARD:
|
||||
me.IsStdMat = true;
|
||||
me.col_d = pMatChunk->col_d;
|
||||
me.col_a = pMatChunk->col_a;
|
||||
//me.col_a.g=0;
|
||||
//me.col_a.b=0;
|
||||
me.col_s = pMatChunk->col_s;
|
||||
|
||||
me.specLevel = pMatChunk->specLevel;
|
||||
me.specShininess = pMatChunk->specShininess*100;
|
||||
me.opacity = pMatChunk->opacity;
|
||||
me.selfIllum = pMatChunk->selfIllum;
|
||||
me.flags = pMatChunk->flags;
|
||||
|
||||
me.Dyn_Bounce = pMatChunk->Dyn_Bounce;
|
||||
me.Dyn_StaticFriction = pMatChunk->Dyn_StaticFriction;
|
||||
me.Dyn_SlidingFriction = pMatChunk->Dyn_SlidingFriction;
|
||||
me.map_a = pMatChunk->tex_a;
|
||||
me.map_d = pMatChunk->tex_d;
|
||||
me.map_o = pMatChunk->tex_o;
|
||||
me.map_b = pMatChunk->tex_b;
|
||||
me.map_s = pMatChunk->tex_s;
|
||||
me.map_g = pMatChunk->tex_g;
|
||||
me.map_detail = pMatChunk->tex_c;
|
||||
me.map_e = pMatChunk->tex_rl;
|
||||
me.map_subsurf = pMatChunk->tex_subsurf;
|
||||
me.map_displ = pMatChunk->tex_det;
|
||||
|
||||
me.nChildren = pMatChunk->nChildren;
|
||||
|
||||
return MCLE_Success;
|
||||
|
||||
default:
|
||||
return MCLE_IgnoredType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return MCLE_UnknownVersion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if the given string is null, assigns the "" to the pointer
|
||||
void chkNullString (const char*&pszString)
|
||||
{
|
||||
if (!pszString)
|
||||
pszString = "";
|
||||
}
|
||||
|
||||
static void rtrim (char* szString)
|
||||
{
|
||||
for (char* p = szString + strlen (szString) - 1; p >= szString && isspace(*p); --p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static void ltrim (const char*& szString)
|
||||
{
|
||||
while (*szString && isspace(*szString))
|
||||
++szString;
|
||||
}
|
||||
|
||||
|
||||
CMatEntityNameTokenizer::CMatEntityNameTokenizer ():
|
||||
m_szMtlName (NULL),
|
||||
szName (""),
|
||||
szTemplate (""),
|
||||
szPhysMtl (""),
|
||||
nSortValue (0),
|
||||
bInvert (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CMatEntityNameTokenizer::tokenize (const char* szMtlFullName)
|
||||
{
|
||||
if (m_szMtlName)
|
||||
{
|
||||
free (m_szMtlName);
|
||||
m_szMtlName = NULL;
|
||||
}
|
||||
if (!szMtlFullName)
|
||||
return;
|
||||
|
||||
int nLen = (int)strlen(szMtlFullName);
|
||||
m_szMtlName = (char*)malloc (nLen+1);
|
||||
memcpy (m_szMtlName, szMtlFullName, nLen + 1);
|
||||
|
||||
szName = NULL;
|
||||
szTemplate = NULL;
|
||||
szPhysMtl = NULL;
|
||||
nSortValue = 0;
|
||||
bInvert = false;
|
||||
|
||||
// the state machine will parse the whole string
|
||||
enum StateEnum
|
||||
{
|
||||
kUnknown,
|
||||
kName,
|
||||
kTemplate,
|
||||
kPhysMtl,
|
||||
kIndex
|
||||
};
|
||||
|
||||
StateEnum nState = kName; // by default, the string begins with name
|
||||
this->szName = m_szMtlName;
|
||||
|
||||
for (char* p = m_szMtlName; *p; ++p)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '(': // template name begins
|
||||
this->szTemplate = p+1;
|
||||
nState = kTemplate;
|
||||
*p = '\0';
|
||||
break;
|
||||
|
||||
case '[': // render priority number begins
|
||||
*p = '\0';
|
||||
nState = kIndex;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
this->szPhysMtl = p+1;
|
||||
*p = '\0';
|
||||
nState = kPhysMtl;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (nState)
|
||||
{
|
||||
case kName:
|
||||
switch (*p)
|
||||
{
|
||||
/*case ' ': // there are no spaces in the name
|
||||
*p = '\0';
|
||||
break;*/
|
||||
|
||||
case ')':
|
||||
case ']':
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogError ("Invalid material name (unexpected closing bracket) \"%s\"", szMtlFullName);
|
||||
#endif
|
||||
break;
|
||||
};
|
||||
break;
|
||||
|
||||
case kTemplate:
|
||||
switch (*p)
|
||||
{
|
||||
case ')':
|
||||
nState = kUnknown;
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case kIndex:
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case ']':
|
||||
nState = kUnknown;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
this->nSortValue *= 10;
|
||||
this->nSortValue += *p - '0';
|
||||
break;
|
||||
|
||||
default:
|
||||
nState = kUnknown;
|
||||
#ifdef _CRY_ANIMATION_BASE_HEADER_
|
||||
g_GetLog()->LogError ("Invalid material name (unexpected symbol in index field) \"%s\"", szMtlFullName);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// take into account hte old form $s_... of setting the template name
|
||||
// if there was no () template, then use this one (after _)
|
||||
if ((!this->szTemplate || !this->szTemplate[0]) &&
|
||||
this->szName[0] == '$' && tolower(this->szName[1]) == 's' && this->szName[2] == '_')
|
||||
{
|
||||
this->szTemplate = this->szName + 3;
|
||||
}
|
||||
|
||||
// make sure all the strings get their pointers - if there's no name, then it will be an empty name
|
||||
chkNullString(this->szName);
|
||||
chkNullString(this->szTemplate);
|
||||
chkNullString(this->szPhysMtl);
|
||||
|
||||
// a special case (one more) - template name preceded by # means (or meant) the inverted template
|
||||
if (this->szTemplate[0] == '#')
|
||||
{
|
||||
this->szTemplate++;
|
||||
this->bInvert = true;
|
||||
}
|
||||
|
||||
// trim unneeded left and right leading spaces
|
||||
rtrim ((char*)this->szName);
|
||||
rtrim ((char*)this->szTemplate);
|
||||
rtrim ((char*)this->szPhysMtl);
|
||||
|
||||
ltrim (this->szName);
|
||||
ltrim (this->szTemplate);
|
||||
ltrim (this->szPhysMtl);
|
||||
}
|
||||
|
||||
CMatEntityNameTokenizer::~CMatEntityNameTokenizer ()
|
||||
{
|
||||
if (m_szMtlName)
|
||||
free (m_szMtlName);
|
||||
}
|
||||
|
||||
// operator that sorts the materials for rendering
|
||||
bool CMatEntityNameTokenizer::operator < (const CMatEntityNameTokenizer& right)const
|
||||
{
|
||||
if (this->nSortValue < right.nSortValue)
|
||||
return true;
|
||||
|
||||
if (this->nSortValue > right.nSortValue)
|
||||
return false;
|
||||
|
||||
int nComp = stricmp (this->szTemplate, right.szTemplate);
|
||||
|
||||
if (nComp < 0)
|
||||
return true;
|
||||
if (nComp > 0)
|
||||
return false;
|
||||
|
||||
nComp = stricmp (this->szName, right.szName);
|
||||
|
||||
if (nComp < 0)
|
||||
return true;
|
||||
if (nComp > 0)
|
||||
return false;
|
||||
|
||||
return false; // they're equal
|
||||
}
|
||||
|
||||
// given the in-permutation, constructs the inverse out-permutation, so that:
|
||||
// pOut[pIn[i]] == i
|
||||
// pIn[pOut[i]] == i
|
||||
void ConstructReversePermutation (const unsigned* pIn, unsigned* pOut, unsigned num)
|
||||
{
|
||||
unsigned i;
|
||||
#ifdef _DEBUG
|
||||
// we'll check the correctness of permutation by checking if there are duplicate entries in pIn
|
||||
// if there are no duplicate entries, according to Dirichle principle, there are no missed entries in pOut
|
||||
for (i = 0; i < num; ++i)
|
||||
pOut[i] = (unsigned)-1;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
assert (pIn[i] < num);
|
||||
assert ((int)pOut[pIn[i]] ==(unsigned)-1);
|
||||
pOut[pIn[i]] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remaps the materials according to the given permutation
|
||||
// the permutation is perm[new index] == old index
|
||||
void RemapMatEntities (MAT_ENTITY* pMtls, unsigned numMtls, unsigned* pPerm)
|
||||
{
|
||||
MAT_ENTITY* pOldMtls = new MAT_ENTITY[numMtls];
|
||||
memcpy (pOldMtls, pMtls, sizeof(MAT_ENTITY)*numMtls);
|
||||
|
||||
for (unsigned nNewMtl = 0; nNewMtl < numMtls; ++nNewMtl)
|
||||
memcpy (pMtls + nNewMtl, pOldMtls + pPerm[nNewMtl], sizeof(MAT_ENTITY));
|
||||
|
||||
delete[]pOldMtls;
|
||||
}
|
||||
|
||||
// copies the matrix from SBoneInitPosMatrix to Matrix
|
||||
void copyMatrix (Matrix44& matDst, const SBoneInitPosMatrix& matSrc)
|
||||
{
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
{
|
||||
matDst(i,0) = matSrc[i][0];
|
||||
matDst(i,1) = matSrc[i][1];
|
||||
matDst(i,2) = matSrc[i][2];
|
||||
}
|
||||
matDst(0,3) = 0;
|
||||
matDst(1,3) = 0;
|
||||
matDst(2,3) = 0;
|
||||
matDst(3,3) = 1;
|
||||
}
|
||||
|
||||
const char* getMtlType (unsigned nMtlType)
|
||||
{
|
||||
switch (nMtlType)
|
||||
{
|
||||
case MTL_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case MTL_STANDARD:
|
||||
return "STANDARD";
|
||||
case MTL_MULTI:
|
||||
return "MULTI";
|
||||
case MTL_2SIDED:
|
||||
return "2SIDED";
|
||||
default:
|
||||
return "#Unknown#";
|
||||
}
|
||||
}
|
||||
|
||||
const char* getTexType (unsigned char nTexType)
|
||||
{
|
||||
switch (nTexType)
|
||||
{
|
||||
case TEXMAP_AUTOCUBIC:
|
||||
return "TEXMAP_AUTOCUBIC";
|
||||
case TEXMAP_CUBIC:
|
||||
return "TEXMAP_CUBIC";
|
||||
case TEXMAP_ENVIRONMENT:
|
||||
return "TEXMAP_ENVIRONMENT";
|
||||
case TEXMAP_SCREENENVIRONMENT:
|
||||
return "!TEXMAP_SCREENENVIRONMENT(unsupported)!";
|
||||
default:
|
||||
return "#Unknown#";
|
||||
}
|
||||
}
|
||||
|
||||
string getLightType (LightTypes nType)
|
||||
{
|
||||
switch (nType)
|
||||
{
|
||||
case LT_OMNI:
|
||||
return "Omni";
|
||||
case LT_SPOT:
|
||||
return "Spot";
|
||||
case LT_DIRECT:
|
||||
return "Direct";
|
||||
case LT_AMBIENT:
|
||||
return "Ambient";
|
||||
default:
|
||||
{
|
||||
char szBuffer[32];
|
||||
printf (szBuffer, "Unknown(%d)", nType);
|
||||
return szBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string getMtlFlags (int nFlags)
|
||||
{
|
||||
string strResult;
|
||||
if (nFlags & MTLFLAG_WIRE)
|
||||
strResult += "MTLFLAG_WIRE|";
|
||||
if (nFlags & MTLFLAG_2SIDED)
|
||||
strResult += "MTLFLAG_2SIDED|";
|
||||
if (nFlags & MTLFLAG_FACEMAP)
|
||||
strResult += "MTLFLAG_FACEMAP|";
|
||||
if (nFlags & MTLFLAG_FACETED)
|
||||
strResult += "MTLFLAG_FACETED|";
|
||||
if (nFlags & MTLFLAG_ADDITIVE)
|
||||
strResult += "MTLFLAG_ADDITIVE|";
|
||||
if (nFlags & MTLFLAG_SUBTRACTIVE)
|
||||
strResult += "MTLFLAG_SUBTRACTIVE|";
|
||||
|
||||
if (!strResult.empty ())
|
||||
strResult.resize (strResult.length ()-1);
|
||||
|
||||
return strResult;
|
||||
}
|
||||
Reference in New Issue
Block a user