#ifndef ASSIMP_BUILD_NO_SMD_IMPORTER
#include "SMDLoader.h"
#include "fast_atof.h"
#include "SkeletonMeshBuilder.h"
#include <assimp/Importer.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <memory>
using namespace Assimp;
static const aiImporterDesc desc = {
"Valve SMD Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"smd vta"
};
SMDImporter::SMDImporter()
: configFrameID(),
mBuffer(),
pScene( nullptr ),
iFileSize( 0 ),
iSmallestFrame( -1 ),
dLengthOfAnim( 0.0 ),
bHasUVs(false ),
iLineNumber(-1) {
}
SMDImporter::~SMDImporter() {
}
bool SMDImporter::CanRead( const std::string& pFile, IOSystem* , bool) const
{
return SimpleExtensionCheck(pFile,"smd","vta");
}
const aiImporterDesc* SMDImporter::GetInfo () const
{
return &desc;
}
void SMDImporter::SetupProperties(const Importer* pImp)
{
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_SMD_KEYFRAME,-1);
if(static_cast<unsigned int>(-1) == configFrameID) {
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
void SMDImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
if( file.get() == NULL) {
throw DeadlyImportError( "Failed to open SMD/VTA file " + pFile + ".");
}
iFileSize = (unsigned int)file->FileSize();
this->pScene = pScene;
mBuffer.resize( iFileSize + 1 );
TextFileToBuffer(file.get(), mBuffer );
iSmallestFrame = (1 << 31);
bHasUVs = true;
iLineNumber = 1;
aszTextures.reserve(10);
asTriangles.reserve(1000);
asBones.reserve(20);
ParseFile();
if (asTriangles.empty())
{
if (asBones.empty())
{
throw DeadlyImportError("SMD: No triangles and no bones have "
"been found in the file. This file seems to be invalid.");
}
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
}
if (!asBones.empty())
{
for (std::vector<SMD::Bone>::const_iterator
i = asBones.begin();
i != asBones.end();++i)
{
if (!(*i).mName.length())
{
DefaultLogger::get()->warn("SMD: Not all bones have been initialized");
break;
}
}
FixTimeValues();
}
if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
CreateOutputMeshes();
CreateOutputMaterials();
}
CreateOutputAnimations();
CreateOutputNodes();
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)
{
SkeletonMeshBuilder skeleton(pScene);
}
}
void SMDImporter::LogErrorNoThrow(const char* msg)
{
char szTemp[1024];
ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,msg);
DefaultLogger::get()->error(szTemp);
}
void SMDImporter::LogWarning(const char* msg)
{
char szTemp[1024];
ai_assert(strlen(msg) < 1000);
ai_snprintf(szTemp,1024,"Line %u: %s",iLineNumber,msg);
DefaultLogger::get()->warn(szTemp);
}
void SMDImporter::FixTimeValues()
{
double dDelta = (double)iSmallestFrame;
double dMax = 0.0f;
for (std::vector<SMD::Bone>::iterator
iBone = asBones.begin();
iBone != asBones.end();++iBone)
{
for (std::vector<SMD::Bone::Animation::MatrixKey>::iterator
iKey = (*iBone).sAnim.asKeys.begin();
iKey != (*iBone).sAnim.asKeys.end();++iKey)
{
(*iKey).dTime -= dDelta;
dMax = std::max(dMax, (*iKey).dTime);
}
}
dLengthOfAnim = dMax;
}
void SMDImporter::CreateOutputMeshes()
{
if (aszTextures.empty())
aszTextures.push_back(std::string());
pScene->mNumMeshes = (unsigned int) aszTextures.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
typedef std::vector<unsigned int> FaceList;
FaceList* aaiFaces = new FaceList[pScene->mNumMeshes];
unsigned int iNum = (unsigned int)asTriangles.size() / pScene->mNumMeshes;
iNum += iNum >> 1;
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
aaiFaces[i].reserve(iNum);
iNum = 0;
for (std::vector<SMD::Face>::const_iterator
iFace = asTriangles.begin();
iFace != asTriangles.end();++iFace,++iNum)
{
if (UINT_MAX == (*iFace).iTexture)aaiFaces[(*iFace).iTexture].push_back( 0 );
else if ((*iFace).iTexture >= aszTextures.size())
{
DefaultLogger::get()->error("[SMD/VTA] Material index overflow in face");
aaiFaces[(*iFace).iTexture].push_back((unsigned int)aszTextures.size()-1);
}
else aaiFaces[(*iFace).iTexture].push_back(iNum);
}
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiMesh*& pcMesh = pScene->mMeshes[i] = new aiMesh();
ai_assert(!aaiFaces[i].empty());
pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
pcMesh->mNumVertices = (unsigned int)aaiFaces[i].size()*3;
pcMesh->mNumFaces = (unsigned int)aaiFaces[i].size();
pcMesh->mMaterialIndex = i;
typedef std::pair<unsigned int,float> TempWeightListEntry;
typedef std::vector< TempWeightListEntry > TempBoneWeightList;
TempBoneWeightList* aaiBones = new TempBoneWeightList[asBones.size()]();
for (unsigned int iBone = 0; iBone < asBones.size();++iBone)
{
aaiBones[iBone].reserve(pcMesh->mNumVertices/asBones.size());
}
pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
aiVector3D* pcNormals = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
aiVector3D* pcVerts = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
aiVector3D* pcUVs = NULL;
if (bHasUVs)
{
pcUVs = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
pcMesh->mNumUVComponents[0] = 2;
}
iNum = 0;
for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace)
{
pcMesh->mFaces[iFace].mIndices = new unsigned int[3];
pcMesh->mFaces[iFace].mNumIndices = 3;
unsigned int iSrcFace = aaiFaces[i][iFace];
SMD::Face& face = asTriangles[iSrcFace];
*pcVerts++ = face.avVertices[0].pos;
*pcVerts++ = face.avVertices[1].pos;
*pcVerts++ = face.avVertices[2].pos;
*pcNormals++ = face.avVertices[0].nor;
*pcNormals++ = face.avVertices[1].nor;
*pcNormals++ = face.avVertices[2].nor;
if (pcUVs)
{
*pcUVs++ = face.avVertices[0].uv;
*pcUVs++ = face.avVertices[1].uv;
*pcUVs++ = face.avVertices[2].uv;
}
for (unsigned int iVert = 0; iVert < 3;++iVert)
{
float fSum = 0.0f;
for (unsigned int iBone = 0;iBone < face.avVertices[iVert].aiBoneLinks.size();++iBone)
{
TempWeightListEntry& pairval = face.avVertices[iVert].aiBoneLinks[iBone];
if (pairval.first >= asBones.size() ||
pairval.first == face.avVertices[iVert].iParentNode)
{
DefaultLogger::get()->error("[SMD/VTA] Bone index overflow. "
"The bone index will be ignored, the weight will be assigned "
"to the vertex' parent node");
continue;
}
aaiBones[pairval.first].push_back(TempWeightListEntry(iNum,pairval.second));
fSum += pairval.second;
}
if (fSum < 0.975f && face.avVertices[iVert].iParentNode != UINT_MAX)
{
if (face.avVertices[iVert].iParentNode >= asBones.size())
{
DefaultLogger::get()->error("[SMD/VTA] Bone index overflow. "
"The index of the vertex parent bone is invalid. "
"The remaining weights will be normalized to 1.0");
if (fSum)
{
fSum = 1 / fSum;
for (unsigned int iBone = 0;iBone < face.avVertices[iVert].aiBoneLinks.size();++iBone)
{
TempWeightListEntry& pairval = face.avVertices[iVert].aiBoneLinks[iBone];
if (pairval.first >= asBones.size())continue;
aaiBones[pairval.first].back().second *= fSum;
}
}
}
else
{
aaiBones[face.avVertices[iVert].iParentNode].push_back(
TempWeightListEntry(iNum,1.0f-fSum));
}
}
pcMesh->mFaces[iFace].mIndices[iVert] = iNum++;
}
}
iNum = 0;
for (unsigned int iBone = 0; iBone < asBones.size();++iBone)
if (!aaiBones[iBone].empty())++iNum;
if (false && iNum)
{
pcMesh->mNumBones = iNum;
pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
iNum = 0;
for (unsigned int iBone = 0; iBone < asBones.size();++iBone)
{
if (aaiBones[iBone].empty())continue;
aiBone*& bone = pcMesh->mBones[iNum] = new aiBone();
bone->mNumWeights = (unsigned int)aaiBones[iBone].size();
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
bone->mOffsetMatrix = asBones[iBone].mOffsetMatrix;
bone->mName.Set( asBones[iBone].mName );
asBones[iBone].bIsUsed = true;
for (unsigned int iWeight = 0; iWeight < bone->mNumWeights;++iWeight)
{
bone->mWeights[iWeight].mVertexId = aaiBones[iBone][iWeight].first;
bone->mWeights[iWeight].mWeight = aaiBones[iBone][iWeight].second;
}
++iNum;
}
}
delete[] aaiBones;
}
delete[] aaiFaces;
}
void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent)
{
ai_assert( NULL != pcNode );
ai_assert( 0 == pcNode->mNumChildren );
ai_assert( NULL == pcNode->mChildren);
for (unsigned int i = 0; i < asBones.size();++i)
{
SMD::Bone& bone = asBones[i];
if (bone.iParent == iParent)++pcNode->mNumChildren;
}
pcNode->mChildren = new aiNode*[pcNode->mNumChildren];
unsigned int qq = 0;
for (unsigned int i = 0; i < asBones.size();++i)
{
SMD::Bone& bone = asBones[i];
if (bone.iParent != iParent)continue;
aiNode* pc = pcNode->mChildren[qq++] = new aiNode();
pc->mName.Set(bone.mName);
pc->mTransformation = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrix;
pc->mParent = pcNode;
AddBoneChildren(pc,i);
}
}
void SMDImporter::CreateOutputNodes()
{
pScene->mRootNode = new aiNode();
if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mRootNode->mMeshes[i] = i;
}
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE &&
1 == pScene->mRootNode->mNumChildren)
{
aiNode* pcOldRoot = pScene->mRootNode;
pScene->mRootNode = pcOldRoot->mChildren[0];
pcOldRoot->mChildren[0] = NULL;
delete pcOldRoot;
pScene->mRootNode->mParent = NULL;
}
else
{
::strcpy(pScene->mRootNode->mName.data, "<SMD_root>");
pScene->mRootNode->mName.length = 10;
}
}
void SMDImporter::CreateOutputAnimations()
{
unsigned int iNumBones = 0;
for (std::vector<SMD::Bone>::const_iterator
i = asBones.begin();
i != asBones.end();++i)
{
if ((*i).bIsUsed)++iNumBones;
}
if (!iNumBones)
{
return;
}
pScene->mNumAnimations = 1;
pScene->mAnimations = new aiAnimation*[1];
aiAnimation*& anim = pScene->mAnimations[0] = new aiAnimation();
anim->mDuration = dLengthOfAnim;
anim->mNumChannels = iNumBones;
anim->mTicksPerSecond = 25.0;
aiNodeAnim** pp = anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
unsigned int a = 0;
for (std::vector<SMD::Bone>::const_iterator
i = asBones.begin();
i != asBones.end();++i)
{
if (!(*i).bIsUsed)continue;
aiNodeAnim* p = pp[a] = new aiNodeAnim();
p->mNodeName.Set( i->mName);
p->mNumRotationKeys = (unsigned int) (*i).sAnim.asKeys.size();
if (p->mNumRotationKeys)
{
p->mNumPositionKeys = p->mNumRotationKeys;
aiVectorKey* pVecKeys = p->mPositionKeys = new aiVectorKey[p->mNumRotationKeys];
aiQuatKey* pRotKeys = p->mRotationKeys = new aiQuatKey[p->mNumRotationKeys];
for (std::vector<SMD::Bone::Animation::MatrixKey>::const_iterator
qq = (*i).sAnim.asKeys.begin();
qq != (*i).sAnim.asKeys.end(); ++qq)
{
pRotKeys->mTime = pVecKeys->mTime = (*qq).dTime;
pRotKeys->mValue = aiQuaternion( (*qq).vRot.x, (*qq).vRot.y, (*qq).vRot.z );
pVecKeys->mValue = (*qq).vPos;
++pVecKeys; ++pRotKeys;
}
}
++a;
}
}
void SMDImporter::ComputeAbsoluteBoneTransformations()
{
for (unsigned int i = 0; i < asBones.size();++i)
{
SMD::Bone& bone = asBones[i];
uint32_t iIndex = 0;
double dMin = 10e10;
for (unsigned int i = 0; i < bone.sAnim.asKeys.size();++i)
{
double d = std::min(bone.sAnim.asKeys[i].dTime,dMin);
if (d < dMin)
{
dMin = d;
iIndex = i;
}
}
bone.sAnim.iFirstTimeKey = iIndex;
}
unsigned int iParent = 0;
while (iParent < asBones.size())
{
for (unsigned int iBone = 0; iBone < asBones.size();++iBone)
{
SMD::Bone& bone = asBones[iBone];
if (iParent == bone.iParent)
{
SMD::Bone& parentBone = asBones[iParent];
uint32_t iIndex = bone.sAnim.iFirstTimeKey;
const aiMatrix4x4& mat = bone.sAnim.asKeys[iIndex].matrix;
aiMatrix4x4& matOut = bone.sAnim.asKeys[iIndex].matrixAbsolute;
iIndex = parentBone.sAnim.iFirstTimeKey;
const aiMatrix4x4& mat2 = parentBone.sAnim.asKeys[iIndex].matrixAbsolute;
matOut = mat * mat2;
}
}
++iParent;
}
for (iParent = 0; iParent < asBones.size();++iParent)
{
SMD::Bone& bone = asBones[iParent];
bone.mOffsetMatrix = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrixAbsolute;
bone.mOffsetMatrix.Inverse();
}
}
\
void SMDImporter::CreateOutputMaterials()
{
pScene->mNumMaterials = (unsigned int)aszTextures.size();
pScene->mMaterials = new aiMaterial*[std::max(1u, pScene->mNumMaterials)];
for (unsigned int iMat = 0; iMat < pScene->mNumMaterials;++iMat)
{
aiMaterial* pcMat = new aiMaterial();
pScene->mMaterials[iMat] = pcMat;
aiString szName;
szName.length = (size_t)ai_snprintf(szName.data,MAXLEN,"Texture_%u",iMat);
pcMat->AddProperty(&szName,AI_MATKEY_NAME);
if (aszTextures[iMat].length())
{
::strncpy(szName.data, aszTextures[iMat].c_str(),MAXLEN-1);
szName.length = aszTextures[iMat].length();
pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
}
if (0 == pScene->mNumMaterials)
{
pScene->mNumMaterials = 1;
aiMaterial* pcHelper = new aiMaterial();
pScene->mMaterials[0] = pcHelper;
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr;
clr.b = clr.g = clr.r = 0.7f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
aiString szName;
szName.Set(AI_DEFAULT_MATERIAL_NAME);
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
}
}
void SMDImporter::ParseFile()
{
const char* szCurrent = &mBuffer[0];
for ( ;; )
{
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
if (TokenMatch(szCurrent,"version",7))
{
if(!SkipSpaces(szCurrent,&szCurrent)) break;
if (1 != strtoul10(szCurrent,&szCurrent))
{
DefaultLogger::get()->warn("SMD.version is not 1. This "
"file format is not known. Continuing happily ...");
}
continue;
}
if (TokenMatch(szCurrent,"nodes",5))
{
ParseNodesSection(szCurrent,&szCurrent);
continue;
}
if (TokenMatch(szCurrent,"triangles",9))
{
ParseTrianglesSection(szCurrent,&szCurrent);
continue;
}
if (TokenMatch(szCurrent,"vertexanimation",15))
{
bHasUVs = false;
ParseVASection(szCurrent,&szCurrent);
continue;
}
if (TokenMatch(szCurrent,"skeleton",8))
{
ParseSkeletonSection(szCurrent,&szCurrent);
continue;
}
SkipLine(szCurrent,&szCurrent);
}
return;
}
unsigned int SMDImporter::GetTextureIndex(const std::string& filename)
{
unsigned int iIndex = 0;
for (std::vector<std::string>::const_iterator
i = aszTextures.begin();
i != aszTextures.end();++i,++iIndex)
{
if (0 == ASSIMP_stricmp ( filename.c_str(),(*i).c_str()))return iIndex;
}
iIndex = (unsigned int)aszTextures.size();
aszTextures.push_back(filename);
return iIndex;
}
void SMDImporter::ParseNodesSection(const char* szCurrent,
const char** szCurrentOut)
{
for ( ;; )
{
if (0 == ASSIMP_strincmp(szCurrent,"end",3) &&
IsSpaceOrNewLine(*(szCurrent+3)))
{
szCurrent += 4;
break;
}
ParseNodeInfo(szCurrent,&szCurrent);
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
*szCurrentOut = szCurrent;
}
void SMDImporter::ParseTrianglesSection(const char* szCurrent,
const char** szCurrentOut)
{
for ( ;; )
{
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
if (TokenMatch(szCurrent,"end",3))
break;
ParseTriangle(szCurrent,&szCurrent);
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
*szCurrentOut = szCurrent;
}
void SMDImporter::ParseVASection(const char* szCurrent,
const char** szCurrentOut)
{
unsigned int iCurIndex = 0;
for ( ;; )
{
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
if (TokenMatch(szCurrent,"end",3))
break;
if (TokenMatch(szCurrent,"time",4))
{
int iTime = 0;
if(!ParseSignedInt(szCurrent,&szCurrent,iTime) || configFrameID != (unsigned int)iTime)break;
SkipLine(szCurrent,&szCurrent);
}
else
{
if(0 == iCurIndex)
{
asTriangles.push_back(SMD::Face());
}
if (++iCurIndex == 3)iCurIndex = 0;
ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true);
}
}
if (iCurIndex != 2 && !asTriangles.empty())
{
asTriangles.pop_back();
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
*szCurrentOut = szCurrent;
}
void SMDImporter::ParseSkeletonSection(const char* szCurrent,
const char** szCurrentOut)
{
int iTime = 0;
for ( ;; )
{
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
if (TokenMatch(szCurrent,"end",3))
break;
else if (TokenMatch(szCurrent,"time",4))
{
if(!ParseSignedInt(szCurrent,&szCurrent,iTime))break;
iSmallestFrame = std::min(iSmallestFrame,iTime);
SkipLine(szCurrent,&szCurrent);
}
else ParseSkeletonElement(szCurrent,&szCurrent,iTime);
}
*szCurrentOut = szCurrent;
}
#define SMDI_PARSE_RETURN { \
SkipLine(szCurrent,&szCurrent); \
*szCurrentOut = szCurrent; \
return; \
}
void SMDImporter::ParseNodeInfo(const char* szCurrent,
const char** szCurrentOut)
{
unsigned int iBone = 0;
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
if(!ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone index");
SMDI_PARSE_RETURN;
}
if (iBone >= asBones.size())asBones.resize(iBone+1);
SMD::Bone& bone = asBones[iBone];
bool bQuota = true;
if ('\"' != *szCurrent)
{
LogWarning("Bone name is expcted to be enclosed in "
"double quotation marks. ");
bQuota = false;
}
else ++szCurrent;
const char* szEnd = szCurrent;
for ( ;; )
{
if (bQuota && '\"' == *szEnd)
{
iBone = (unsigned int)(szEnd - szCurrent);
++szEnd;
break;
}
else if (IsSpaceOrNewLine(*szEnd))
{
iBone = (unsigned int)(szEnd - szCurrent);
break;
}
else if (!(*szEnd))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone name");
SMDI_PARSE_RETURN;
}
++szEnd;
}
bone.mName = std::string(szCurrent,iBone);
szCurrent = szEnd;
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)bone.iParent))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone parent index. Assuming -1");
SMDI_PARSE_RETURN;
}
SMDI_PARSE_RETURN;
}
void SMDImporter::ParseSkeletonElement(const char* szCurrent,
const char** szCurrentOut,int iTime)
{
aiVector3D vPos;
aiVector3D vRot;
unsigned int iBone = 0;
if(!ParseUnsignedInt(szCurrent,&szCurrent,iBone))
{
DefaultLogger::get()->error("Unexpected EOF/EOL while parsing bone index");
SMDI_PARSE_RETURN;
}
if (iBone >= asBones.size())
{
LogErrorNoThrow("Bone index in skeleton section is out of range");
SMDI_PARSE_RETURN;
}
SMD::Bone& bone = asBones[iBone];
bone.sAnim.asKeys.push_back(SMD::Bone::Animation::MatrixKey());
SMD::Bone::Animation::MatrixKey& key = bone.sAnim.asKeys.back();
key.dTime = (double)iTime;
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.x))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.y))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.z))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.z");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.x))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.y))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.z))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.z");
SMDI_PARSE_RETURN;
}
key.matrix.FromEulerAnglesXYZ(vRot.x,vRot.y,vRot.z);
{
aiMatrix4x4 mTemp;
mTemp.a4 = vPos.x;
mTemp.b4 = vPos.y;
mTemp.c4 = vPos.z;
key.matrix = key.matrix * mTemp;
}
SMDI_PARSE_RETURN;
}
void SMDImporter::ParseTriangle(const char* szCurrent,
const char** szCurrentOut)
{
asTriangles.push_back(SMD::Face());
SMD::Face& face = asTriangles.back();
if(!SkipSpaces(szCurrent,&szCurrent))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing a triangle");
return;
}
const char* szLast = szCurrent;
while (!IsSpaceOrNewLine(*++szCurrent));
face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
for (unsigned int iVert = 0; iVert < 3;++iVert)
{
ParseVertex(szCurrent,&szCurrent,
face.avVertices[iVert]);
}
*szCurrentOut = szCurrent;
}
bool SMDImporter::ParseFloat(const char* szCurrent,
const char** szCurrentOut, float& out)
{
if(!SkipSpaces(&szCurrent))
return false;
*szCurrentOut = fast_atoreal_move<float>(szCurrent,out);
return true;
}
bool SMDImporter::ParseUnsignedInt(const char* szCurrent,
const char** szCurrentOut, unsigned int& out)
{
if(!SkipSpaces(&szCurrent))
return false;
out = strtoul10(szCurrent,szCurrentOut);
return true;
}
bool SMDImporter::ParseSignedInt(const char* szCurrent,
const char** szCurrentOut, int& out)
{
if(!SkipSpaces(&szCurrent))
return false;
out = strtol10(szCurrent,szCurrentOut);
return true;
}
void SMDImporter::ParseVertex(const char* szCurrent,
const char** szCurrentOut, SMD::Vertex& vertex,
bool bVASection )
{
if (SkipSpaces(&szCurrent) && IsLineEnd(*szCurrent))
{
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
return ParseVertex(szCurrent,szCurrentOut,vertex,bVASection);
}
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)vertex.iParentNode))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.x))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.y))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.z))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.z");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.x))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.y))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.z))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.z");
SMDI_PARSE_RETURN;
}
if (bVASection)SMDI_PARSE_RETURN;
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.x))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.y))
{
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.y");
SMDI_PARSE_RETURN;
}
unsigned int iSize = 0;
if(!ParseUnsignedInt(szCurrent,&szCurrent,iSize))SMDI_PARSE_RETURN;
vertex.aiBoneLinks.resize(iSize,std::pair<unsigned int, float>(0,0.0f));
for (std::vector<std::pair<unsigned int, float> >::iterator
i = vertex.aiBoneLinks.begin();
i != vertex.aiBoneLinks.end();++i)
{
if(!ParseUnsignedInt(szCurrent,&szCurrent,(*i).first))
SMDI_PARSE_RETURN;
if(!ParseFloat(szCurrent,&szCurrent,(*i).second))
SMDI_PARSE_RETURN;
}
SMDI_PARSE_RETURN;
}
#endif