mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
2447 lines
72 KiB
C++
2447 lines
72 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-2010 - Frictional Games
|
|
*
|
|
* This file is part of HPL1 Engine.
|
|
*
|
|
* HPL1 Engine is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* HPL1 Engine is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with HPL1 Engine. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "hpl1/engine/impl/MeshLoaderCollada.h"
|
|
|
|
#include "hpl1/engine/system/LowLevelSystem.h"
|
|
#include "hpl1/engine/graphics/LowLevelGraphics.h"
|
|
#include "hpl1/engine/graphics/VertexBuffer.h"
|
|
#include "hpl1/engine/system/String.h"
|
|
|
|
#include "hpl1/engine/graphics/Mesh.h"
|
|
#include "hpl1/engine/graphics/SubMesh.h"
|
|
#include "hpl1/engine/resources/MaterialManager.h"
|
|
#include "hpl1/engine/graphics/Material.h"
|
|
|
|
#include "hpl1/engine/graphics/Bone.h"
|
|
#include "hpl1/engine/graphics/Skeleton.h"
|
|
#include "hpl1/engine/graphics/Animation.h"
|
|
#include "hpl1/engine/graphics/AnimationTrack.h"
|
|
|
|
#include "hpl1/engine/impl/tinyXML/tinyxml.h"
|
|
|
|
#include "hpl1/engine/math/Math.h"
|
|
|
|
namespace hpl {
|
|
|
|
#define GetAdress(sStr) if(sStr.length()>0 && sStr[0]=='#') sStr = cString::Sub(sStr,1);
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PRIVATE METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//This fucntions checks if y is up and if not switches palces with z and y.
|
|
cVector3f cMeshLoaderCollada::GetVectorPos(const cVector3f &avVec)
|
|
{
|
|
if(mbZToY)
|
|
{
|
|
return cVector3f(-avVec.x, avVec.z, avVec.y);
|
|
}
|
|
else
|
|
{
|
|
return avVec;
|
|
}
|
|
}
|
|
|
|
cVector3f cMeshLoaderCollada::GetVectorPosFromPtr(float *apVec)
|
|
{
|
|
if(mbZToY)
|
|
{
|
|
return cVector3f(-apVec[0],apVec[2],apVec[1]);
|
|
}
|
|
else
|
|
{
|
|
return cVector3f(apVec[0],apVec[1],apVec[2]);
|
|
}
|
|
}
|
|
|
|
cVector3f cMeshLoaderCollada::GetVectorScaleFromPtr(float *apVec)
|
|
{
|
|
if(mbZToY)
|
|
{
|
|
return cVector3f(apVec[0],apVec[2],apVec[1]);
|
|
}
|
|
else
|
|
{
|
|
return cVector3f(apVec[0],apVec[1],apVec[2]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
class cTempAnimData
|
|
{
|
|
public:
|
|
cTempAnimData(): mvTrans(0,0,0), mvRot(0,0,0), mvScale(1,1,1) {}
|
|
|
|
cVector3f mvTrans;
|
|
cVector3f mvRot;
|
|
cVector3f mvScale;
|
|
float mfTime;
|
|
|
|
int mlIndex;
|
|
};
|
|
|
|
typedef std::vector<cTempAnimData> tTempAnimDataVec;
|
|
|
|
typedef std::set<float> tTempTimesSet;
|
|
typedef std::set<float>::iterator tTempTimesSetIt;
|
|
|
|
static cTempAnimData* GetTempAnimData(float afTime, tTempAnimDataVec &avTempData)
|
|
{
|
|
for(size_t i=0; i<avTempData.size(); ++i)
|
|
{
|
|
if(avTempData[i].mfTime == afTime) return &avTempData[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/////////////////
|
|
|
|
//Get times in TimeVec closes to afTime.
|
|
static void GetAnimTimes(float afTime,float *apTimeBefore,float *apTimeAfter,tFloatVec* apTimeVec)
|
|
{
|
|
*apTimeBefore = -1; *apTimeAfter=-1;
|
|
for(size_t i=0; i<apTimeVec->size(); ++i)
|
|
{
|
|
float fTime = (*apTimeVec)[i];
|
|
|
|
if(fTime <= afTime)
|
|
{
|
|
*apTimeBefore = fTime;
|
|
}
|
|
else if(fTime >= afTime)
|
|
{
|
|
*apTimeAfter = fTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////
|
|
|
|
cAnimationTrack* cMeshLoaderCollada::CreateAnimTrack(cAnimation *apAnimation , cSkeleton *apSkeleton,
|
|
cColladaAnimation &aAnim, cColladaScene *apScene)
|
|
{
|
|
tTempAnimDataVec vTempData;
|
|
tTempTimesSet setTempTimes;
|
|
|
|
//Log("Animation: %s\n",aAnim.msName.c_str());
|
|
|
|
//Get the node that will be animated by this track
|
|
cColladaNode* pNode = apScene->GetNode(aAnim.msTargetNode);
|
|
if(pNode==NULL)
|
|
{
|
|
Error("Couldn't find node '%s' for animation id '%s'\n",aAnim.msTargetNode.c_str(), aAnim.msId.c_str());
|
|
return NULL;
|
|
}
|
|
|
|
cBone* pBone = NULL;
|
|
|
|
if(apSkeleton)
|
|
{
|
|
pBone = apSkeleton->GetBoneByName(aAnim.msTargetNode);
|
|
if(pBone == NULL)
|
|
{
|
|
Error("Couldn't find bone '%s'\n",aAnim.msTargetNode.c_str());
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
//Go through all sample and add the different times.
|
|
for(size_t i=0; i< aAnim.mvSamplers.size(); i++)
|
|
{
|
|
cColladaSampler &Sampler = aAnim.mvSamplers[i];
|
|
|
|
tFloatVec *pValueVec = aAnim.GetSourceVec(Sampler.msTimeArray);
|
|
if(pValueVec == NULL){
|
|
Error("Time array not found in sampler '%s'!\n",Sampler.msId.c_str());
|
|
return NULL;
|
|
}
|
|
|
|
//Go through all and add to set.
|
|
for(tFloatVecIt it = pValueVec->begin(); it != pValueVec->end(); ++it)
|
|
{
|
|
setTempTimes.insert(*it);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////
|
|
//Resize temp data and fill with times used.
|
|
vTempData.resize(setTempTimes.size());
|
|
int lCount=0;
|
|
for(tTempTimesSetIt it= setTempTimes.begin(); it != setTempTimes.end(); ++it,++lCount)
|
|
{
|
|
vTempData[lCount].mfTime = *it;
|
|
vTempData[lCount].mlIndex = lCount;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
//Go through all samples and get data
|
|
for(size_t i=0; i< aAnim.mvSamplers.size(); i++)
|
|
{
|
|
cColladaSampler &Sampler = aAnim.mvSamplers[i];
|
|
|
|
//Log("Sampler %s\n",Sampler.msId.c_str());
|
|
|
|
//////////////////////////
|
|
//Get the times
|
|
tFloatVec *pTimeVec = aAnim.GetSourceVec(Sampler.msTimeArray);
|
|
if(pTimeVec == NULL){
|
|
Error("Time array not found!\n");
|
|
return NULL;
|
|
}
|
|
|
|
//Get the Sid of the transformation that this sampler changes.
|
|
tString sTarget = cString::SetFileExt(cString::GetFileName(Sampler.msTarget),"");
|
|
tString sExt = cString::ToLowerCase(cString::GetFileExt(Sampler.msTarget));
|
|
|
|
////////////////////
|
|
//Get the transformation and add the values accordingly
|
|
cColladaTransform *pTrans = pNode->GetTransform(sTarget);
|
|
if(pTrans == NULL){
|
|
//Error("Transform '%s' not found!\n",sTarget.c_str());
|
|
continue;
|
|
}
|
|
|
|
///////////////////////////
|
|
//Get the values for the transformation
|
|
tFloatVec *pValueVec = aAnim.GetSourceVec(Sampler.msValueArray);
|
|
if(pValueVec == NULL){
|
|
Error("Value array not found!\n");
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////
|
|
//Set the translation in this sampler
|
|
if(pTrans->msType == "translate")
|
|
{
|
|
//Log("Loading Translation\n");
|
|
|
|
for(size_t j=0; j <pTimeVec->size(); j++)
|
|
{
|
|
//Check the translation type
|
|
//If only a single axis is changes the others are set to
|
|
//the node translation. THIS MIGHT BE WRONG!
|
|
//TODO: Maybe the bind matrix should be here:
|
|
cVector3f vTrans = pNode->m_mtxTransform.GetTranslation();
|
|
|
|
//Get the temp data:
|
|
cTempAnimData * pTempData = GetTempAnimData((*pTimeVec)[j], vTempData);
|
|
if(pTempData==NULL){ Error("Code error at %d\n",__LINE__); return NULL;}
|
|
|
|
// XYZ
|
|
if(sExt=="")
|
|
{
|
|
pTempData->mvTrans = cVector3f((*pValueVec)[j*3 + 0],
|
|
(*pValueVec)[j*3 +1],
|
|
(*pValueVec)[j*3 +2]);
|
|
}
|
|
// X
|
|
else if(sExt=="x")
|
|
{
|
|
pTempData->mvTrans = cVector3f((*pValueVec)[j],vTrans.y,vTrans.z);
|
|
}
|
|
// Y
|
|
else if(sExt=="y")
|
|
{
|
|
pTempData->mvTrans = cVector3f(vTrans.x,(*pValueVec)[j],vTrans.z);
|
|
}
|
|
// Z
|
|
else if(sExt=="z")
|
|
{
|
|
pTempData->mvTrans = cVector3f(vTrans.x,vTrans.y,(*pValueVec)[j]);
|
|
}
|
|
|
|
//What we wanna use is the relative movement of the bone.
|
|
//The exported translation sets new local translation!.
|
|
if(pBone)
|
|
pTempData->mvTrans -= pBone->GetLocalTransform().GetTranslation();
|
|
}
|
|
|
|
////////////////////////////////
|
|
//Go through all of Temp data and find times not added
|
|
float fTimeBefore=-1, fTimeAfter=-1;
|
|
for(size_t j=0; j<vTempData.size(); ++j)
|
|
{
|
|
GetAnimTimes(vTempData[j].mfTime,&fTimeBefore, &fTimeAfter, pTimeVec);
|
|
|
|
//Time exists
|
|
if(fTimeBefore == vTempData[j].mfTime){
|
|
//Log("Sample %s time %f is in place!\n",Sampler.msId.c_str(), vTempData[j].mfTime);
|
|
continue;
|
|
}
|
|
//Time between two keys
|
|
else if(fTimeBefore>=0 && fTimeAfter>=0)
|
|
{
|
|
cTempAnimData *pBefore = GetTempAnimData(fTimeBefore,vTempData);
|
|
cTempAnimData *pAfter = GetTempAnimData(fTimeAfter,vTempData);
|
|
|
|
float fT = (vTempData[j].mfTime - pBefore->mfTime)/(pAfter->mfTime - pBefore->mfTime);
|
|
|
|
vTempData[j].mvTrans = pBefore->mvTrans*(1.0f-fT) + pAfter->mvTrans*fT;
|
|
|
|
//Log("Interpolated sample %s time %f between %f and %f. T=%f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pBefore->mfTime,pAfter->mfTime,fT);
|
|
}
|
|
//Time before start
|
|
else if(fTimeBefore<0 && fTimeAfter>=0)
|
|
{
|
|
cTempAnimData *pAfter = GetTempAnimData(fTimeAfter,vTempData);
|
|
|
|
vTempData[j].mvTrans = pAfter->mvTrans;
|
|
|
|
//Log("Added before at sample %s time %f using %f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pAfter->mfTime);
|
|
}
|
|
//Time after end
|
|
else if(fTimeBefore>=0 && fTimeAfter<0)
|
|
{
|
|
cTempAnimData *pBefore = GetTempAnimData(fTimeBefore,vTempData);
|
|
|
|
vTempData[j].mvTrans = pBefore->mvTrans;
|
|
|
|
//Log("Added after at sample %s time %f using %f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pBefore->mfTime);
|
|
}
|
|
}
|
|
}
|
|
//////////////////////////////////
|
|
//Add the rotation in this sampler
|
|
else if(pTrans->msType == "rotate")
|
|
{
|
|
for(size_t j=0; j <pTimeVec->size(); j++)
|
|
{
|
|
//Get the temp data:
|
|
cTempAnimData * pTempData = GetTempAnimData((*pTimeVec)[j], vTempData);
|
|
if(pTempData==NULL){ Error("Code error at %d\n",__LINE__); return NULL;}
|
|
|
|
|
|
pTempData->mvRot += cVector3f(pTrans->mvValues[0],
|
|
pTrans->mvValues[1],
|
|
pTrans->mvValues[2]) * (*pValueVec)[j];
|
|
}
|
|
|
|
auto vecProj = cMath::GetVectorX<cVector3f>;
|
|
//if(pTrans->mvValues[0]>0.001f) lVecNum =0;
|
|
if (pTrans->mvValues[1] > 0.001f) vecProj = cMath::GetVectorY<cVector3f>;
|
|
else if (pTrans->mvValues[2] > 0.001f) vecProj = cMath::GetVectorZ<cVector3f>;
|
|
|
|
////////////////////////////////
|
|
//Go through all of Temp data and find times not added
|
|
float fTimeBefore=-1, fTimeAfter=-1;
|
|
for(size_t j=0; j<vTempData.size(); ++j)
|
|
{
|
|
GetAnimTimes(vTempData[j].mfTime,&fTimeBefore, &fTimeAfter, pTimeVec);
|
|
|
|
//Time exists
|
|
if(fTimeBefore == vTempData[j].mfTime){
|
|
//Log("Sample %s time %f is in place!\n",Sampler.msId.c_str(), vTempData[j].mfTime);
|
|
continue;
|
|
}
|
|
//Time between two keys
|
|
else if(fTimeBefore>=0 && fTimeAfter>=0)
|
|
{
|
|
cTempAnimData *pBefore = GetTempAnimData(fTimeBefore,vTempData);
|
|
cTempAnimData *pAfter = GetTempAnimData(fTimeAfter,vTempData);
|
|
|
|
float fT = (vTempData[j].mfTime - pBefore->mfTime)/(pAfter->mfTime - pBefore->mfTime);
|
|
|
|
vecProj(vTempData[j].mvRot) = vecProj(pBefore->mvRot)*(1.0f-fT) +
|
|
vecProj(pAfter->mvRot)*fT;
|
|
|
|
//Log("Interpolated sample %s time %f between %f and %f. T=%f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pBefore->mfTime,pAfter->mfTime,fT);
|
|
}
|
|
//Time before start
|
|
else if(fTimeBefore<0 && fTimeAfter>=0)
|
|
{
|
|
cTempAnimData *pAfter = GetTempAnimData(fTimeAfter,vTempData);
|
|
|
|
vecProj(vTempData[j].mvRot) = vecProj(pAfter->mvRot);
|
|
|
|
//Log("Added before at sample %s time %f using %f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pAfter->mfTime);
|
|
}
|
|
//Time after end
|
|
else if(fTimeBefore>=0 && fTimeAfter<0)
|
|
{
|
|
cTempAnimData *pBefore = GetTempAnimData(fTimeBefore,vTempData);
|
|
|
|
vecProj(vTempData[j].mvRot) = vecProj(pBefore->mvRot);
|
|
|
|
//Log("Added after at sample %s time %f using %f\n",
|
|
// Sampler.msId.c_str(), vTempData[j].mfTime,
|
|
// pBefore->mfTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*Log("Animation %s\n",aAnim.msName.c_str());
|
|
for(size_t i=0; i <vTempData.size(); i++)
|
|
{
|
|
Log("Time: %f T: (%s) R: (%s) S: (%s)\n", vTempData[i].mfTime,
|
|
vTempData[i].mvTrans.ToString().c_str(),
|
|
vTempData[i].mvRot.ToString().c_str(),
|
|
vTempData[i].mvScale.ToString().c_str());
|
|
}*/
|
|
|
|
//Create new animation track
|
|
cAnimationTrack * pTrack = apAnimation->CreateTrack(aAnim.msTargetNode,
|
|
eAnimTransformFlag_Rotate |
|
|
eAnimTransformFlag_Translate |
|
|
eAnimTransformFlag_Scale);
|
|
//Iterate the temporary data and add to the track.
|
|
for(size_t i=0; i < vTempData.size(); i++)
|
|
{
|
|
cKeyFrame *pFrame = pTrack->CreateKeyFrame(vTempData[i].mfTime - apScene->mfStartTime);
|
|
|
|
pFrame->trans = vTempData[i].mvTrans;
|
|
pFrame->scale = vTempData[i].mvScale;
|
|
|
|
//Create the quaternion from rotations.
|
|
cVector3f vRadRot = vTempData[i].mvRot;
|
|
vRadRot = cVector3f(cMath::ToRad(vRadRot.x),cMath::ToRad(vRadRot.y),cMath::ToRad(vRadRot.z) );
|
|
cMatrixf mtxRot = cMath::MatrixRotate(vRadRot, eEulerRotationOrder_XYZ);
|
|
cQuaternion qRot;
|
|
qRot.FromRotationMatrix(mtxRot);
|
|
|
|
pFrame->rotation = qRot;
|
|
}
|
|
|
|
return pTrack;
|
|
}
|
|
|
|
static tString gsTemp;
|
|
static const char* GetTabs(int alDepth)
|
|
{
|
|
gsTemp = "";
|
|
|
|
for(int i=0;i<alDepth;i++)gsTemp+="\t";
|
|
|
|
return gsTemp.c_str();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
void cMeshLoaderCollada::CalcLocalMatrixRec(cBone* apBone, cMatrixf a_mtxParentGlobal, int alDepth)
|
|
{
|
|
//Log("%s %s \n",GetTabs(alDepth),apBone->GetName().c_str());
|
|
|
|
if(apBone->GetValue()==0){
|
|
Warning("Bone '%s' is not attached to skin!\n",apBone->GetName().c_str());
|
|
|
|
return;
|
|
}
|
|
|
|
cMatrixf mtxGlobal = apBone->GetLocalTransform();
|
|
cMatrixf mtxInvParent = cMath::MatrixInverse(a_mtxParentGlobal);
|
|
|
|
cMatrixf mtxLocal = cMath::MatrixMul(mtxInvParent,mtxGlobal);
|
|
|
|
apBone->SetTransform(mtxLocal);
|
|
|
|
a_mtxParentGlobal = mtxGlobal;
|
|
|
|
cBoneIterator it = apBone->GetChildIterator();
|
|
|
|
while(it.HasNext())
|
|
{
|
|
CalcLocalMatrixRec(it.Next(),a_mtxParentGlobal,alDepth+1);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cMeshLoaderCollada::CreateSkeletonBone(cColladaNode* apColladaNode, cBone* apParentBone)
|
|
{
|
|
if(apColladaNode->msType != "JOINT") return;
|
|
|
|
cBone *pBone = apParentBone->CreateChildBone(apColladaNode->msId);
|
|
|
|
pBone->SetTransform(apColladaNode->m_mtxTransform);
|
|
|
|
tColladaNodeListIt it = apColladaNode->mlstChildren.begin();
|
|
for(; it != apColladaNode->mlstChildren.end();it++)
|
|
{
|
|
CreateSkeletonBone(*it, pBone);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
iVertexBuffer * cMeshLoaderCollada::CreateVertexBuffer(cColladaGeometry & aGeometry,
|
|
eVertexBufferUsageType aUsageType)
|
|
//,tColladaExtraVtxListVec &vExtraVtxVec)
|
|
{
|
|
//tVertexVec vVertexVec;
|
|
//tUIntVec vIndexVec;
|
|
//SplitVertices(aGeometry,vExtraVtxVec,vVertexVec,vIndexVec);
|
|
|
|
//Log("Creating vertex buffer for '%s'\n",aGeometry.msName.c_str());
|
|
|
|
//TEMP: use the one in geometry directly.
|
|
//vExtraVtxVec = aGeometry.mvExtraVtxVec;
|
|
|
|
//Create vertex buffer and fill it
|
|
iVertexBuffer *pVtxBuff = mpLowLevelGraphics->CreateVertexBuffer(
|
|
eVertexFlag_Position | eVertexFlag_Normal | eVertexFlag_Texture0 | eVertexFlag_Color0 |
|
|
eVertexFlag_Texture1,
|
|
eVertexBufferDrawType_Tri, aUsageType,
|
|
(int)aGeometry.mvVertexVec.size(), (int)aGeometry.mvIndexVec.size());
|
|
|
|
pVtxBuff->SetTangents(true);
|
|
pVtxBuff->ResizeArray(eVertexFlag_Texture1,(int)aGeometry.mvTangents.size());
|
|
|
|
//Add vertices
|
|
for(size_t j=0; j<aGeometry.mvVertexVec.size();j++)
|
|
{
|
|
pVtxBuff->AddVertex(eVertexFlag_Position,aGeometry.mvVertexVec[j].pos);
|
|
pVtxBuff->AddVertex(eVertexFlag_Normal,aGeometry.mvVertexVec[j].norm);
|
|
pVtxBuff->AddVertex(eVertexFlag_Texture0,aGeometry.mvVertexVec[j].tex);
|
|
|
|
pVtxBuff->AddColor(eVertexFlag_Color0,cColor(1,1));
|
|
}
|
|
|
|
//Add tangents
|
|
memcpy(pVtxBuff->GetArray(eVertexFlag_Texture1),&aGeometry.mvTangents[0],
|
|
aGeometry.mvTangents.size()*sizeof(float));
|
|
|
|
//Add indices
|
|
for(size_t j=0; j<aGeometry.mvIndexVec.size();j++)
|
|
{
|
|
//Flip order of indices
|
|
size_t idx = (j/3)*3 + (2-(j%3));
|
|
|
|
pVtxBuff->AddIndex(aGeometry.mvIndexVec[idx]);
|
|
}
|
|
|
|
//Compile the vertex buffer
|
|
pVtxBuff->Compile(0);//eVertexCompileFlag_CreateTangents);
|
|
|
|
return pVtxBuff;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cMeshLoaderCollada::LoadLights(TiXmlElement* apRootElem, tColladaLightVec &avColladaLightVec)
|
|
{
|
|
TiXmlElement* pLightElem = apRootElem->FirstChildElement("light");
|
|
for(;pLightElem!=NULL; pLightElem = pLightElem->NextSiblingElement("light"))
|
|
{
|
|
cColladaLight Light;
|
|
Light.msId = cString::ToString(pLightElem->Attribute("id"),"");
|
|
Light.msName = cString::ToString(pLightElem->Attribute("name"),"");
|
|
|
|
TiXmlElement *pTechniqueCommonElem = pLightElem->FirstChildElement("technique_common");
|
|
|
|
//////////////////////////////////////////////
|
|
//COLLADA 1.4
|
|
if(pTechniqueCommonElem)
|
|
{
|
|
TiXmlElement *pTypeElem = pTechniqueCommonElem->FirstChildElement();
|
|
if(pTypeElem==NULL){
|
|
Log("No Type element found!\n");
|
|
continue;
|
|
}
|
|
|
|
Light.msType = cString::ToString(pTypeElem->Value(),"");
|
|
|
|
/////////////
|
|
//Color
|
|
TiXmlElement *pParamElem = pTypeElem->FirstChildElement("color");
|
|
if(pParamElem)
|
|
{
|
|
TiXmlText *pText = pParamElem->FirstChild()->ToText();
|
|
tFloatVec vColor;
|
|
cString::GetFloatVec(pText->Value(), vColor);
|
|
Light.mDiffuseColor.r = vColor[0];
|
|
Light.mDiffuseColor.g = vColor[1];
|
|
Light.mDiffuseColor.b = vColor[2];
|
|
}
|
|
else
|
|
{
|
|
Light.mDiffuseColor = cColor(1,1);
|
|
}
|
|
|
|
/////////////
|
|
//Angle
|
|
pParamElem = pTypeElem->FirstChildElement("falloff_angle");
|
|
if(pParamElem)
|
|
{
|
|
TiXmlText *pText = pParamElem->FirstChild()->ToText();
|
|
Light.mfAngle = cString::ToFloat(pText->Value(),0);
|
|
}
|
|
else
|
|
{
|
|
Light.mfAngle =0;
|
|
}
|
|
}
|
|
///////////////////////////////////////////////
|
|
//COLLADA 1.3 (NOT SUPPORTED ANY LONGER)
|
|
else
|
|
{
|
|
Light.msType = cString::ToLowerCase(cString::ToString(pLightElem->Attribute("type"),""));
|
|
|
|
TiXmlElement *pParamElem = pLightElem->FirstChildElement("param");
|
|
for(; pParamElem; pParamElem = pParamElem->NextSiblingElement("param"))
|
|
{
|
|
tString sName = cString::ToString(pParamElem->Attribute("name"),"");
|
|
TiXmlText *pText = pParamElem->FirstChild()->ToText();
|
|
|
|
if(sName == "COLOR")
|
|
{
|
|
tFloatVec vColor;
|
|
cString::GetFloatVec(pText->Value(), vColor);
|
|
Light.mDiffuseColor.r = vColor[0];
|
|
Light.mDiffuseColor.g = vColor[1];
|
|
Light.mDiffuseColor.b = vColor[2];
|
|
}
|
|
else if(sName == "ANGLE")
|
|
{
|
|
Light.mfAngle = cString::ToFloat(pText->Value(),0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Log("Loaded light '%s', type '%s', color: %f %f %f\n", Light.msId.c_str(),
|
|
// Light.msType.c_str(),
|
|
// Light.mDiffuseColor.r,Light.mDiffuseColor.g,Light.mDiffuseColor.b);
|
|
|
|
avColladaLightVec.push_back(Light);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
static cColladaAnimation& GetAnimationFromTarget(const tString& asTargetNode,
|
|
tColladaAnimationVec &avAnimations)
|
|
{
|
|
for(size_t i=0; i< avAnimations.size(); i++)
|
|
{
|
|
if(avAnimations[i].msTargetNode == asTargetNode)
|
|
{
|
|
return avAnimations[i];
|
|
}
|
|
}
|
|
|
|
//No animation with that target found, create new.
|
|
avAnimations.push_back(cColladaAnimation());
|
|
cColladaAnimation& Anim = avAnimations[avAnimations.size() -1];
|
|
Anim.msTargetNode = asTargetNode;
|
|
|
|
return Anim;
|
|
}
|
|
|
|
void cMeshLoaderCollada::LoadAnimations(TiXmlElement* apRootElem, tColladaAnimationVec &avAnimations,
|
|
cColladaScene *apColladaScene)
|
|
{
|
|
TiXmlElement* pAnimElem = apRootElem->FirstChildElement("animation");
|
|
for(;pAnimElem!=NULL; pAnimElem = pAnimElem->NextSiblingElement("animation"))
|
|
{
|
|
/////////////////////////////////////////////
|
|
//Check what animation to use.
|
|
TiXmlElement *pTestChannelElem = pAnimElem->FirstChildElement("channel");
|
|
if(pTestChannelElem==NULL){Warning("Animation missing channel!\n"); continue;}
|
|
|
|
//Get target node name
|
|
tString sTestTarget = cString::ToString(pTestChannelElem->Attribute("target"),"");
|
|
tStringVec vTargetStrings;
|
|
tString sTargetSepp = "/";
|
|
cString::GetStringVec(sTestTarget,vTargetStrings,&sTargetSepp);
|
|
sTestTarget = vTargetStrings[0];
|
|
|
|
cColladaAnimation& Anim = GetAnimationFromTarget(sTestTarget, avAnimations);
|
|
|
|
//Anim.msName = cString::ToString(pAnimElem->Attribute("name"),""); No need..
|
|
Anim.msId = cString::ToString(pAnimElem->Attribute("id"),"");
|
|
|
|
//////////////////////////////////
|
|
// Load all Channels
|
|
TiXmlElement *pChannelElem = pAnimElem->FirstChildElement("channel");
|
|
for(; pChannelElem!=NULL ; pChannelElem = pChannelElem->NextSiblingElement("channel"))
|
|
{
|
|
cColladaChannel Channel;
|
|
Channel.msId = cString::ToString(pChannelElem->Attribute("id"),"");
|
|
Channel.msSource = cString::ToString(pChannelElem->Attribute("source"),"");
|
|
Channel.msTarget = cString::ToString(pChannelElem->Attribute("target"),"");
|
|
GetAdress(Channel.msSource);
|
|
|
|
Anim.mvChannels.push_back(Channel);
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// Load all Samplers
|
|
TiXmlElement *pSamplerElem = pAnimElem->FirstChildElement("sampler");
|
|
for(; pSamplerElem!=NULL ; pSamplerElem = pSamplerElem->NextSiblingElement("sampler"))
|
|
{
|
|
cColladaSampler Sampler;
|
|
Sampler.msId = cString::ToString(pSamplerElem->Attribute("id"),"");
|
|
|
|
//Iterate the inputs and find the needed types.
|
|
TiXmlElement *pInput = pSamplerElem->FirstChildElement("input");
|
|
for(; pInput!=NULL ; pInput = pInput->NextSiblingElement("input"))
|
|
{
|
|
tString sSemantic = cString::ToString(pInput->Attribute("semantic"),"");
|
|
tString sSource = cString::ToString(pInput->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
if(sSemantic == "INPUT")
|
|
{
|
|
Sampler.msTimeArray = sSource;
|
|
}
|
|
else if(sSemantic == "OUTPUT")
|
|
{
|
|
Sampler.msValueArray = sSource;
|
|
}
|
|
}
|
|
Anim.mvSamplers.push_back(Sampler);
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// Set target for the Samplers (to make it easier later on).
|
|
// These values will only work if the samplers are not shared among channels
|
|
for(size_t i=0; i< Anim.mvChannels.size(); i++)
|
|
{
|
|
for(size_t j=0; j<Anim.mvSamplers.size(); j++)
|
|
{
|
|
if(Anim.mvChannels[i].msSource == Anim.mvSamplers[j].msId)
|
|
{
|
|
Anim.mvSamplers[j].msTarget = Anim.mvChannels[i].msTarget;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// Iterate through all the sources
|
|
TiXmlElement *pSourceElem = pAnimElem->FirstChildElement("source");
|
|
for(; pSourceElem!=NULL ; pSourceElem = pSourceElem->NextSiblingElement("source"))
|
|
{
|
|
Anim.mvSources.push_back(cColladaAnimSource());
|
|
cColladaAnimSource &Source = Anim.mvSources[Anim.mvSources.size() -1];
|
|
|
|
Source.msId = cString::ToString(pSourceElem->Attribute("id"),"");
|
|
|
|
TiXmlElement *pArrayElem = pSourceElem->FirstChildElement("float_array");
|
|
if(pArrayElem == NULL){
|
|
//Warning("No array element found for animation data (shouldn't be anything bad)!\n");
|
|
continue;
|
|
}
|
|
|
|
int lCount = cString::ToInt(pArrayElem->Attribute("count"),0);
|
|
|
|
Source.mvValues.reserve(lCount);
|
|
|
|
TiXmlText *pText = pArrayElem->FirstChild()->ToText();
|
|
cString::GetFloatVec(pText->Value(),Source.mvValues);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
|
|
void cMeshLoaderCollada::LoadColladaScene(TiXmlElement* apRootElem,cColladaNode *apParentNode,
|
|
cColladaScene *apScene,tColladaLightVec *apColladaLightVec)
|
|
{
|
|
cColladaNode *pNode = apParentNode->CreateChild();
|
|
apScene->mlstNodes.push_back(pNode);
|
|
|
|
//The local matrix
|
|
cMatrixf mtxTransform = cMatrixf::Identity;
|
|
|
|
//Vector to save transform values in later on.
|
|
tFloatVec vValVec;
|
|
vValVec.reserve(5);
|
|
|
|
///////////////////////////////////////////
|
|
//Get properties
|
|
pNode->msId = cString::ToString(apRootElem->Attribute("id"),"");
|
|
pNode->msName = cString::ToString(apRootElem->Attribute("name"),"");
|
|
pNode->msType = cString::ToString(apRootElem->Attribute("type"),"");
|
|
|
|
/////////////////////////////////////////////
|
|
//Get source, if there is any.
|
|
TiXmlElement *pInstanceElem = apRootElem->FirstChildElement("instance_geometry");
|
|
if(pInstanceElem==NULL) pInstanceElem = apRootElem->FirstChildElement("instance_light");
|
|
if(pInstanceElem==NULL) pInstanceElem = apRootElem->FirstChildElement("instance_controller");
|
|
if(pInstanceElem==NULL) pInstanceElem = apRootElem->FirstChildElement("instance");
|
|
if(pInstanceElem)
|
|
{
|
|
tString sSource = cString::ToString(pInstanceElem->Attribute("url"),"");
|
|
if(sSource[0] == '#') pNode->mbSourceIsFile = false;
|
|
else pNode->mbSourceIsFile = true;
|
|
|
|
GetAdress(sSource);
|
|
|
|
pNode->msSource = sSource;
|
|
}
|
|
|
|
//Log("Node. %s, type: %s\n",pNode->msId.c_str(),pNode->msType.c_str());
|
|
|
|
cVector3f vTranslation = cVector3f(0,0,0);
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//Iterate through all of the transforms.
|
|
TiXmlElement *pTransformElem = apRootElem->FirstChildElement();
|
|
while(pTransformElem)
|
|
{
|
|
tString sVal = pTransformElem->Value();
|
|
tString sSid = cString::ToString(pTransformElem->Attribute("sid"),"");
|
|
|
|
TiXmlNode *pChildElem = pTransformElem->FirstChild();
|
|
if(pChildElem==NULL){
|
|
pTransformElem = pTransformElem->NextSiblingElement();
|
|
continue;
|
|
}
|
|
|
|
//Log("val: %s\n",sVal.c_str());
|
|
|
|
TiXmlText *pText= pChildElem->ToText();
|
|
if(pText==NULL)
|
|
{
|
|
pTransformElem = pTransformElem->NextSiblingElement();
|
|
continue;
|
|
}
|
|
|
|
cString::GetFloatVec(pText->Value(), vValVec);
|
|
|
|
// Translation
|
|
if(sVal == "translate")
|
|
{
|
|
cVector3f vTrans = GetVectorPosFromPtr(&vValVec[0]);
|
|
|
|
mtxTransform = cMath::MatrixMul(mtxTransform, cMath::MatrixTranslate(vTrans));
|
|
}
|
|
// Rotation
|
|
else if(sVal == "rotate")
|
|
{
|
|
cQuaternion qRot;
|
|
cVector3f vRotAxis = GetVectorPosFromPtr(&vValVec[0]);
|
|
|
|
qRot.FromAngleAxis(cMath::ToRad(vValVec[3]),vRotAxis);
|
|
|
|
mtxTransform = cMath::MatrixMul(mtxTransform, cMath::MatrixQuaternion(qRot));
|
|
}
|
|
// Scaling
|
|
else if(sVal == "scale")
|
|
{
|
|
cVector3f vScale = GetVectorScaleFromPtr(&vValVec[0]);
|
|
pNode->mvScale = vScale;
|
|
|
|
//If this node is a light, do not apply scale.
|
|
if(apColladaLightVec && GetLight(pNode->msSource, *apColladaLightVec))
|
|
{
|
|
}
|
|
//Colliders do not use scale.
|
|
else if(cString::ToLowerCase(cString::Sub(pNode->msName,1,8))=="collider"
|
|
|| cString::ToLowerCase(cString::Sub(pNode->msName,1,12))=="charcollider"
|
|
|| cString::ToLowerCase(cString::Sub(pNode->msName,1,4))=="area")
|
|
{
|
|
|
|
}
|
|
//This a geometry node (or something else..). Apply scale as normal
|
|
else
|
|
{
|
|
mtxTransform = cMath::MatrixMul(mtxTransform, cMath::MatrixScale(vScale));
|
|
}
|
|
}
|
|
|
|
pNode->mlstTransforms.push_back(cColladaTransform());
|
|
cColladaTransform &Transform = pNode->mlstTransforms.back();
|
|
|
|
Transform.msSid = sSid;
|
|
Transform.mvValues = vValVec;
|
|
Transform.msType = sVal;
|
|
|
|
/*Log("Transform:\n");
|
|
Log("Sid: %s type: %s ",Transform.msSid.c_str(), Transform.msType.c_str());
|
|
Log("Values: ");
|
|
for(size_t i=0; i < Transform.mvValues.size();i++)
|
|
{
|
|
Log("%f ",Transform.mvValues[i]);
|
|
}
|
|
Log("\n");*/
|
|
|
|
vValVec.clear();
|
|
pTransformElem = pTransformElem->NextSiblingElement();
|
|
}
|
|
|
|
pNode->m_mtxTransform = mtxTransform;
|
|
pNode->m_mtxWorldTransform = cMath::MatrixMul(apParentNode->m_mtxWorldTransform, mtxTransform);
|
|
|
|
//Load all children
|
|
TiXmlElement *pNodeElem = apRootElem->FirstChildElement("node");
|
|
while(pNodeElem)
|
|
{
|
|
LoadColladaScene(pNodeElem, pNode,apScene,apColladaLightVec);
|
|
|
|
pNodeElem = pNodeElem->NextSiblingElement("node");
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
void cMeshLoaderCollada::LoadControllers(TiXmlElement* apRootElem,
|
|
tColladaControllerVec &avColladaControllerVec,
|
|
tColladaGeometryVec *apColladaGeometryVec)
|
|
{
|
|
TiXmlElement* pCtrlElem = apRootElem->FirstChildElement("controller");
|
|
for(;pCtrlElem!=NULL; pCtrlElem = pCtrlElem->NextSiblingElement("controller"))
|
|
{
|
|
avColladaControllerVec.push_back(cColladaController());
|
|
|
|
cColladaController &Controller = avColladaControllerVec[avColladaControllerVec.size()-1];
|
|
|
|
Controller.msId = cString::ToString(pCtrlElem->Attribute("id"),"");
|
|
|
|
///////////////////////////////////////
|
|
// Get Skin element.
|
|
TiXmlElement *pSkinElem = pCtrlElem->FirstChildElement("skin");
|
|
if(pSkinElem==NULL){ Error("No Skin found in controller!\n"); continue;}
|
|
|
|
Controller.msTarget = cString::ToString(pSkinElem->Attribute("source"),"");
|
|
GetAdress(Controller.msTarget);
|
|
|
|
//Get the bind matrix
|
|
TiXmlElement *pBindMatrixElem = pSkinElem->FirstChildElement("bind_shape_matrix");
|
|
if(pBindMatrixElem)
|
|
{
|
|
TiXmlText *pText = pBindMatrixElem->FirstChild()->ToText();
|
|
tFloatVec vValues;
|
|
cString::GetFloatVec(pText->Value(), vValues);
|
|
|
|
Controller.m_mtxBindShapeMatrix.FromVec(&vValues[0]);
|
|
}
|
|
else
|
|
{
|
|
Warning("No bind matrix in controller '%s' using identity\n",Controller.msId.c_str());
|
|
Controller.m_mtxBindShapeMatrix = cMatrixf::Identity;
|
|
}
|
|
|
|
|
|
//These are used so you can find what the different sources contain.
|
|
tString sJointNameSource="";
|
|
tString sJointWeightSource="";
|
|
tString sJointMatrixSource="";
|
|
int lJointOffset=-1;
|
|
int lWeightOffset=-1;
|
|
|
|
////////////////////////////////////////
|
|
// Load Joint information
|
|
{
|
|
TiXmlElement *pJointsElem = pSkinElem->FirstChildElement("joints");
|
|
if(pJointsElem==NULL){ Warning("Couldn't find joint element for controller!\n"); continue;}
|
|
|
|
TiXmlElement *pInputElem = pJointsElem->FirstChildElement("input");
|
|
for(; pInputElem != NULL; pInputElem = pInputElem->NextSiblingElement("input"))
|
|
{
|
|
tString sSemantic = cString::ToString(pInputElem->Attribute("semantic"),"");
|
|
tString sSource = cString::ToString(pInputElem->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
//The names of the joints
|
|
if(sSemantic=="JOINT")
|
|
{
|
|
sJointNameSource = sSource;
|
|
}
|
|
else if(sSemantic=="INV_BIND_MATRIX")
|
|
{
|
|
sJointMatrixSource = sSource;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Load Joint weight info
|
|
{
|
|
TiXmlElement *pJointWeightElem = pSkinElem->FirstChildElement("vertex_weights");
|
|
if(pJointWeightElem==NULL){ Warning("Couldn't find vertex_weights element for controller!\n"); continue;}
|
|
|
|
TiXmlElement *pInputElem = pJointWeightElem->FirstChildElement("input");
|
|
for(; pInputElem != NULL; pInputElem = pInputElem->NextSiblingElement("input"))
|
|
{
|
|
tString sSemantic = cString::ToString(pInputElem->Attribute("semantic"),"");
|
|
tString sSource = cString::ToString(pInputElem->Attribute("source"),"");
|
|
int lOffset = cString::ToInt(pInputElem->Attribute("offset"),-1);
|
|
GetAdress(sSource);
|
|
|
|
//The names of the joints
|
|
if(sSemantic=="JOINT")
|
|
{
|
|
lJointOffset = lOffset;
|
|
}
|
|
//The weight of the joints
|
|
else if(sSemantic=="WEIGHT")
|
|
{
|
|
lWeightOffset = lOffset;
|
|
sJointWeightSource = sSource;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Get the sources and load / apply them
|
|
TiXmlElement *pSourceElem = pSkinElem->FirstChildElement("source");
|
|
while(pSourceElem)
|
|
{
|
|
tString sId = cString::ToString(pSourceElem->Attribute("id"),"");
|
|
|
|
//////////////////
|
|
//Name of joints
|
|
if(sId == sJointNameSource)
|
|
{
|
|
TiXmlElement *pNameArrayElem = pSourceElem->FirstChildElement("Name_array");
|
|
if(pNameArrayElem==NULL){ Warning("Couldn't find name array!\n"); continue;}
|
|
|
|
int lCount = cString::ToInt(pNameArrayElem->Attribute("count"),0);
|
|
|
|
//Reserve for faster push_back
|
|
Controller.mvJoints.reserve(lCount);
|
|
|
|
TiXmlText *pNameText = pNameArrayElem->FirstChild()->ToText();
|
|
if(pNameText==NULL){ Error("No joint name data found!\n"); continue;}
|
|
|
|
cString::GetStringVec(pNameText->Value(),Controller.mvJoints);
|
|
}
|
|
//////////////////
|
|
//Joint weights or matrices
|
|
else if(sId == sJointWeightSource || sId == sJointMatrixSource)
|
|
{
|
|
TiXmlElement *pFloatArrayElem = pSourceElem->FirstChildElement("float_array");
|
|
if(pFloatArrayElem==NULL){ Warning("Couldn't find name array!\n"); continue;}
|
|
|
|
int lCount = cString::ToInt(pFloatArrayElem->Attribute("count"),0);
|
|
|
|
//Get the text data
|
|
TiXmlText *pText = pFloatArrayElem->FirstChild()->ToText();
|
|
if(pText==NULL){ Error("No value data found!\n"); return;}
|
|
|
|
//Convert text to floats
|
|
tFloatVec vValVec;
|
|
vValVec.reserve(lCount);
|
|
cString::GetFloatVec(pText->Value(), vValVec);
|
|
|
|
//Weights
|
|
if(sId == sJointWeightSource)
|
|
{
|
|
Controller.mvWeights = vValVec;
|
|
}
|
|
//Matrices
|
|
else
|
|
{
|
|
Controller.mvMatrices.reserve(lCount / 16);
|
|
|
|
for(int i=0; i< (lCount / 16); i++)
|
|
{
|
|
cMatrixf mtxTemp(&vValVec[i*16]);
|
|
Controller.mvMatrices.push_back(mtxTemp);
|
|
}
|
|
}
|
|
}
|
|
|
|
pSourceElem = pSourceElem->NextSiblingElement("source");
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Get joint - vertex pairs.
|
|
{
|
|
TiXmlElement *pJointWeightElem = pSkinElem->FirstChildElement("vertex_weights");
|
|
if(pJointWeightElem==NULL){ Warning("Couldn't find vertex_weights element for controller!\n"); continue;}
|
|
|
|
////////////////////////////
|
|
// Vcount - get the number of joints for each vertex.
|
|
TiXmlElement *pVCountElem = pJointWeightElem->FirstChildElement("vcount");
|
|
if(pVCountElem==NULL){ Warning("Couldn't find vertex_weights vcount element for controller!\n"); continue;}
|
|
|
|
//Get the text data
|
|
TiXmlText *pVCountText = pVCountElem->FirstChild()->ToText();
|
|
if(pVCountText==NULL){ Error("No value data found!\n"); continue;}
|
|
|
|
tIntVec vVCount;
|
|
cString::GetIntVec(pVCountText->Value(),vVCount);
|
|
|
|
/////////////////////////////
|
|
//V - Get the pairs
|
|
TiXmlElement *pVElem = pJointWeightElem->FirstChildElement("v");
|
|
if(pVElem==NULL){ Warning("Couldn't find vertex_weights v element for controller!\n"); continue;}
|
|
|
|
//Get the text data
|
|
TiXmlText *pVText = pVElem->FirstChild()->ToText();
|
|
if(pVText==NULL){ Error("No value data found!\n"); continue;}
|
|
|
|
tIntVec vV;
|
|
cString::GetIntVec(pVText->Value(),vV);
|
|
|
|
int lVtx=0;
|
|
int lNumOfPairs = ((int)vV.size())/2;
|
|
int lPairCount=0;
|
|
|
|
Controller.mvPairs.resize(vVCount.size());
|
|
for(int lPair=0; lPair<lNumOfPairs; ++lPair)
|
|
{
|
|
cColladaJointPair Pair;
|
|
|
|
Pair.mlJoint = vV[lPair*2 + lJointOffset];
|
|
Pair.mlWeight = vV[lPair*2 + lWeightOffset];
|
|
|
|
//Log("Pair: %d, %d vtx: %d\n",Pair.mlJoint, Pair.mlWeight,lVtx);
|
|
|
|
Controller.mvPairs[lVtx].push_back(Pair);
|
|
|
|
//Check if it is time for a new vertex.
|
|
lPairCount++;
|
|
if(lPairCount >= vVCount[lVtx]){
|
|
lVtx++; lPairCount =0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
static tVector3fVec *gpVertexVec = NULL;
|
|
|
|
///////////////////////////////////////////
|
|
|
|
class cColladaTestTri
|
|
{
|
|
public:
|
|
cColladaTestTri(cColladaVtxIndex *apTriIndex)
|
|
{
|
|
//Log("TestTri:\n");
|
|
//Get the vectors
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
mvPos[i] = (*gpVertexVec)[apTriIndex[i].mlVtx];
|
|
|
|
//Log("Pos%d: %s\n",i,mvPos[i].ToString().c_str());
|
|
}
|
|
|
|
//Sort the vectors
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
for(int j=0; j<3;j++)
|
|
{
|
|
if(j==i)continue;
|
|
|
|
if(mvPos[i] < mvPos[j])
|
|
{
|
|
cVector3f vTemp = mvPos[i];
|
|
mvPos[i] = mvPos[j];
|
|
mvPos[j] = vTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
//for(int i=0; i<3; i++) Log("Pos%d: %s\n",i,mvPos[i].ToString().c_str());
|
|
}
|
|
|
|
cVector3f mvPos[3];
|
|
};
|
|
|
|
///////////////////////////////////////////
|
|
|
|
class cColladaTestTriCompare
|
|
{
|
|
public:
|
|
bool operator()(const cColladaTestTri& aTri1, const cColladaTestTri& aTri2)const
|
|
{
|
|
//0
|
|
if(aTri1.mvPos[0].x != aTri2.mvPos[0].x) return aTri1.mvPos[0].x < aTri2.mvPos[0].x;
|
|
if(aTri1.mvPos[0].y != aTri2.mvPos[0].y) return aTri1.mvPos[0].y < aTri2.mvPos[0].y;
|
|
if(aTri1.mvPos[0].z != aTri2.mvPos[0].z) return aTri1.mvPos[0].z < aTri2.mvPos[0].z;
|
|
//1
|
|
if(aTri1.mvPos[1].x != aTri2.mvPos[1].x) return aTri1.mvPos[1].x < aTri2.mvPos[1].x;
|
|
if(aTri1.mvPos[1].y != aTri2.mvPos[1].y) return aTri1.mvPos[1].y < aTri2.mvPos[1].y;
|
|
if(aTri1.mvPos[1].z != aTri2.mvPos[1].z) return aTri1.mvPos[1].z < aTri2.mvPos[1].z;
|
|
//2
|
|
if(aTri1.mvPos[2].x != aTri2.mvPos[2].x) return aTri1.mvPos[2].x < aTri2.mvPos[2].x;
|
|
if(aTri1.mvPos[2].y != aTri2.mvPos[2].y) return aTri1.mvPos[2].y < aTri2.mvPos[2].y;
|
|
if(aTri1.mvPos[2].z != aTri2.mvPos[2].z) return aTri1.mvPos[2].z < aTri2.mvPos[2].z;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////
|
|
|
|
typedef std::set<cColladaTestTri, cColladaTestTriCompare> tColladaTestTriMap;
|
|
typedef tColladaTestTriMap::iterator tColladaTestTriMapIt;
|
|
|
|
|
|
///////////////////////////////////////////
|
|
|
|
void cMeshLoaderCollada::LoadGeometry(TiXmlElement* apRootElem, tColladaGeometryVec &avColladaGeometryVec, cColladaScene *apColladaScene)
|
|
{
|
|
TiXmlElement* pGeomElem = apRootElem->FirstChildElement("geometry");
|
|
for(; pGeomElem!=NULL; pGeomElem = pGeomElem->NextSiblingElement("geometry"))
|
|
{
|
|
avColladaGeometryVec.push_back(cColladaGeometry());
|
|
|
|
//tColladaVtxArrayVec vArrayVec;
|
|
///tColladaVtxIndexVec vIndices;
|
|
|
|
cColladaGeometry &Geometry = avColladaGeometryVec[avColladaGeometryVec.size()-1];
|
|
|
|
//Get main properties
|
|
Geometry.msId = cString::ToString(pGeomElem->Attribute("id"),"");
|
|
Geometry.msName = cString::ToString(pGeomElem->Attribute("name"),"");
|
|
|
|
if(Geometry.msName == "")
|
|
{
|
|
Geometry.msName = Geometry.msId;
|
|
//Fix to skip a max addition on mesh names
|
|
int lPos = cString::GetLastStringPos(Geometry.msName,"-");
|
|
if(lPos >0) Geometry.msName = cString::Sub(Geometry.msName,0,lPos);
|
|
}
|
|
|
|
//There should only be one mesh
|
|
TiXmlElement* pMeshElem = pGeomElem->FirstChildElement("mesh");
|
|
if(pMeshElem==NULL){
|
|
Warning("No Mesh element found in geometry element '%s'!\n",Geometry.msName.c_str());
|
|
continue;
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
//Check if the geometry should loaded
|
|
if(cString::Sub(Geometry.msName,0,4) == "_ref" ||
|
|
cString::Sub(Geometry.msName,0,3) == "_bb" ||
|
|
cString::Sub(Geometry.msName,0,4) == "_ps" ||
|
|
cString::Sub(Geometry.msName,0,6) == "_sound")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
//Iterate through all sources (the vertices)
|
|
TiXmlElement* pSourceElem = pMeshElem->FirstChildElement("source");
|
|
while(pSourceElem)
|
|
{
|
|
//Add a new array
|
|
Geometry.mvArrayVec.push_back(cColladaVtxArray());
|
|
int lPos = (int)Geometry.mvArrayVec.size()-1;
|
|
|
|
//Get id
|
|
tString sSourceId = cString::ToString(pSourceElem->Attribute("id"),"");
|
|
//Log("Vertex id: '%s' \n",sSourceId.c_str());
|
|
|
|
Geometry.mvArrayVec[lPos].msId = sSourceId;
|
|
|
|
LoadVertexData(pSourceElem,Geometry.mvArrayVec[lPos].mvArray);
|
|
|
|
/*Log("Array: %s\n",sSourceId.c_str());
|
|
for(int i=0; i< (int)Geometry.mvArrayVec[lPos].mvArray.size(); i++)
|
|
{
|
|
Log("(%s) ",Geometry.mvArrayVec[lPos].mvArray[i].ToString().c_str());
|
|
}
|
|
Log("\n");*/
|
|
|
|
pSourceElem = pSourceElem->NextSiblingElement("source");
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
//Get the "real" name for the vertices
|
|
//This always includes postions and can include normals and tex coords aswell.
|
|
TiXmlElement* pVerticesElem = pMeshElem->FirstChildElement("vertices");
|
|
if(pVerticesElem==NULL){ Error("Vertices not found!\n"); return;}
|
|
|
|
//Iterate the inputs
|
|
TiXmlElement* pVtxInput = pVerticesElem->FirstChildElement("input");
|
|
while(pVtxInput)
|
|
{
|
|
tString sSemantic = cString::ToString(pVtxInput->Attribute("semantic"),"");
|
|
|
|
if(sSemantic == "POSITION")
|
|
{
|
|
tString sSource = cString::ToString(pVtxInput->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
//Log("Position vertex source: %s\n", sSource.c_str());
|
|
|
|
for(int i=0;i<(int) Geometry.mvArrayVec.size(); i++)
|
|
{
|
|
//If the vertex array is found just change the name and break.
|
|
if(Geometry.mvArrayVec[i].msId == sSource)
|
|
{
|
|
Geometry.mvArrayVec[i].msId = cString::ToString(pVerticesElem->Attribute("id"),"");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tString sSource = cString::ToString(pVtxInput->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
//Log("%s vertex source: %s\n",sSemantic.c_str(), sSource.c_str());
|
|
|
|
//Find array and set some properties
|
|
for(int i=0;i<(int) Geometry.mvArrayVec.size(); i++)
|
|
if(Geometry.mvArrayVec[i].msId == sSource)
|
|
{
|
|
Geometry.mvArrayVec[i].msType = sSemantic;
|
|
Geometry.mvArrayVec[i].mbIsInVertex = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pVtxInput = pVtxInput->NextSiblingElement("input");
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
//Get the Triangles, save them in a row
|
|
bool bMultiTexture = false;
|
|
TiXmlElement* pTriElem = pMeshElem->FirstChildElement("triangles");
|
|
if(pTriElem==NULL)
|
|
{
|
|
pTriElem = pMeshElem->FirstChildElement("polylist");
|
|
if(pTriElem && pTriElem->NextSibling("polylist")) bMultiTexture = true;
|
|
|
|
}
|
|
else
|
|
{
|
|
if(pTriElem->NextSibling("triangles")) bMultiTexture = true;
|
|
|
|
}
|
|
|
|
if(bMultiTexture)
|
|
{
|
|
cColladaNode *pGeomNode = apColladaScene->GetNodeFromSource(Geometry.msId);
|
|
tString sParentName = pGeomNode->pParent ? pGeomNode->pParent->msName : "[none]";
|
|
Warning("Geometry '%s' in node '%s' with parent '%s' seem to have multitexturing!\n",Geometry.msName.c_str(), pGeomNode->msName.c_str(),
|
|
sParentName.c_str());
|
|
}
|
|
|
|
|
|
if(pTriElem==NULL){
|
|
//Warning("No triangle or polylist element found, testing polygons.\n");
|
|
pTriElem = pMeshElem->FirstChildElement("polygons");
|
|
if(pTriElem==NULL){
|
|
Error("No Polygons found!\n"); return;
|
|
}
|
|
}
|
|
int lTriElements =0;
|
|
|
|
int lTriCount = cString::ToInt(pTriElem->Attribute("count"),0);
|
|
Geometry.msMaterial = cString::ToString(pTriElem->Attribute("material"),"");
|
|
GetAdress(Geometry.msMaterial);
|
|
|
|
//Get the inputs to figure what the indices in he triangles mean.
|
|
TiXmlElement* pTriInputElem = pTriElem->FirstChildElement("input");
|
|
while(pTriInputElem)
|
|
{
|
|
tString sSemantic = cString::ToString(pTriInputElem->Attribute("semantic"),"");
|
|
tString sSource = cString::ToString(pTriInputElem->Attribute("source"),"");
|
|
int lIdx = cString::ToInt(pTriInputElem->Attribute("idx"),-1);
|
|
if(lIdx < 0) lIdx = cString::ToInt(pTriInputElem->Attribute("offset"),-1);
|
|
|
|
GetAdress(sSource);
|
|
|
|
int lArrayNum = -1;
|
|
|
|
//Get what array that belongs to this input.
|
|
for(int i=0; i<(int)Geometry.mvArrayVec.size(); i++)
|
|
{
|
|
if(Geometry.mvArrayVec[i].msId == sSource)
|
|
{
|
|
lArrayNum = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Set the properties for the sort
|
|
if(sSemantic == "VERTEX")
|
|
{
|
|
Geometry.mlPosIdxNum = lIdx;
|
|
Geometry.mlPosArrayIdx = lArrayNum;
|
|
}
|
|
else if(sSemantic == "NORMAL")
|
|
{
|
|
Geometry.mlNormIdxNum = lIdx;
|
|
Geometry.mlNormArrayIdx = lArrayNum;
|
|
}
|
|
else if(sSemantic == "TEXCOORD")
|
|
{
|
|
Geometry.mlTexIdxNum = lIdx;
|
|
Geometry.mlTexArrayIdx = lArrayNum;
|
|
}
|
|
|
|
//Increase element num
|
|
if(lTriElements < lIdx+1) lTriElements =lIdx+1;
|
|
|
|
//next input
|
|
pTriInputElem = pTriInputElem->NextSiblingElement("input");
|
|
}
|
|
|
|
//Go through the arrays and check if any are in the vertex
|
|
for(int i=0; i<(int)Geometry.mvArrayVec.size(); i++)
|
|
{
|
|
if(Geometry.mvArrayVec[i].mbIsInVertex)
|
|
{
|
|
if(Geometry.mvArrayVec[i].msType == "NORMAL") {
|
|
Geometry.mlNormArrayIdx = i;
|
|
Geometry.mlNormIdxNum = Geometry.mlPosIdxNum;
|
|
}
|
|
else if(Geometry.mvArrayVec[i].msType == "TEXCOORD") {
|
|
Geometry.mlTexArrayIdx = i;
|
|
Geometry.mlTexIdxNum = Geometry.mlPosIdxNum;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Check so that none of the arrays are missing
|
|
if(Geometry.mlNormArrayIdx<0){
|
|
Warning("No normals for geometry '%s'\n",Geometry.msName.c_str());
|
|
continue;
|
|
}
|
|
if(Geometry.mlTexArrayIdx<0 && Geometry.msName[0] != '_'){
|
|
Warning("No tex coords for geometry '%s'\n",Geometry.msName.c_str());
|
|
continue;
|
|
}
|
|
|
|
//////////////////////////////
|
|
// If Z is up axis, go through all the geometry and convert
|
|
if(mbZToY)
|
|
{
|
|
//Positions
|
|
tVector3fVec &vVtxVec = Geometry.mvArrayVec[Geometry.mlPosArrayIdx].mvArray;
|
|
for(int i=0; i < (int)vVtxVec.size();i++)
|
|
{
|
|
vVtxVec[i] = GetVectorPos(vVtxVec[i]);
|
|
}
|
|
|
|
//Normals
|
|
tVector3fVec &vNormVec = Geometry.mvArrayVec[Geometry.mlNormArrayIdx].mvArray;
|
|
for(int i=0; i < (int)vNormVec.size();i++)
|
|
{
|
|
vNormVec[i] = GetVectorPos(vNormVec[i]);
|
|
}
|
|
}
|
|
|
|
//reserve space for the indices
|
|
Geometry.mvIndices.reserve(lTriElements * 3);
|
|
|
|
//Set the vertex array used.
|
|
gpVertexVec = &Geometry.mvArrayVec[Geometry.mlPosArrayIdx].mvArray;
|
|
|
|
tColladaTestTriMap map_TestTris;
|
|
|
|
// Load all the Indices
|
|
TiXmlElement* pPElem = pTriElem->FirstChildElement("p");
|
|
while(pPElem)
|
|
{
|
|
TiXmlText *pText = pPElem->FirstChild()->ToText();
|
|
if(pText==NULL){ Error("No tri data found!\n"); return;}
|
|
|
|
//Get the indices for the triangle
|
|
tIntVec vIndexArray;
|
|
cString::GetIntVec(pText->Value(),vIndexArray);
|
|
|
|
int lTriangleNum = (int)vIndexArray.size()/ (3*lTriElements);
|
|
for(int triangle=0; triangle< lTriangleNum; triangle++)
|
|
{
|
|
cColladaVtxIndex DataVec[3];
|
|
int lTriangleAdd = triangle*3*lTriElements;
|
|
|
|
//Iterate the points in triangle
|
|
//If Z is used as y the order must be reversed.
|
|
//Turns out, it is not so... because x is negated.
|
|
/*if(mbZToY)
|
|
{
|
|
for(int i=2; i>= 0; i--)
|
|
{
|
|
DataVec[2-i].mlVtx = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlPosIdxNum];
|
|
DataVec[2-i].mlNorm = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlNormIdxNum];
|
|
DataVec[2-i].mlTex = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlTexIdxNum];
|
|
}
|
|
}
|
|
else*/
|
|
{
|
|
for(int i=0; i< 3; i++)
|
|
{
|
|
DataVec[i].mlVtx = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlPosIdxNum];
|
|
DataVec[i].mlNorm = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlNormIdxNum];
|
|
DataVec[i].mlTex = vIndexArray[lTriangleAdd + i*lTriElements + Geometry.mlTexIdxNum];
|
|
}
|
|
}
|
|
|
|
std::pair<tColladaTestTriMapIt,bool> TestPair = map_TestTris.insert(DataVec);
|
|
if(TestPair.second)
|
|
{
|
|
//Add the data to the indices
|
|
for(int i=0;i<3;i++)
|
|
{
|
|
Geometry.mvIndices.push_back(DataVec[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cColladaNode *pGeomNode = apColladaScene->GetNodeFromSource(Geometry.msId);
|
|
if(pGeomNode)
|
|
{
|
|
tString sParentName = pGeomNode->pParent ? pGeomNode->pParent->msName : "[none]";
|
|
Warning("Geometry '%s' in node '%s' with parent '%s' has two faces using same vertices! Skipping face.\n",Geometry.msName.c_str(), pGeomNode->msName.c_str(),
|
|
sParentName.c_str());
|
|
}
|
|
else
|
|
{
|
|
Warning("Geometry '%s' has two faces using same vertices! Skipping face. (note: the geometry node could not be found either!)\n",Geometry.msId.c_str());
|
|
}
|
|
//Error("Geometry '%s' has two faces using same vertices! Skipping face.\n",Geometry.msName.c_str());
|
|
}
|
|
}
|
|
|
|
//Next p
|
|
pPElem = pPElem->NextSiblingElement("p");
|
|
}
|
|
|
|
///////////////////////////////////
|
|
//Split the vertices and make em usable
|
|
SplitVertices(Geometry,Geometry.mvExtraVtxVec,Geometry.mvVertexVec,Geometry.mvIndexVec);
|
|
Geometry.Clear();
|
|
|
|
////////////////////////////////////
|
|
//Create Tangents
|
|
tFloatVec vPosVec; vPosVec.resize(Geometry.mvVertexVec.size() *4);
|
|
tFloatVec vNormVec; vNormVec.resize(Geometry.mvVertexVec.size() *3);
|
|
tFloatVec vTexVec; vTexVec.resize(Geometry.mvVertexVec.size() *3);
|
|
|
|
float *pPosData = &vPosVec[0];
|
|
float *pNormData = &vNormVec[0];
|
|
float *pTexData = &vTexVec[0];
|
|
|
|
//Fill vectors
|
|
for(size_t i=0; i<Geometry.mvVertexVec.size(); ++i)
|
|
{
|
|
cVertex &vertex = Geometry.mvVertexVec[i];
|
|
|
|
pPosData[0] = vertex.pos.x;
|
|
pPosData[1] = vertex.pos.y;
|
|
pPosData[2] = vertex.pos.z;
|
|
pPosData[3] = 1;
|
|
|
|
pNormData[0] = vertex.norm.x;
|
|
pNormData[1] = vertex.norm.y;
|
|
pNormData[2] = vertex.norm.z;
|
|
|
|
pTexData[0] = vertex.tex.x;
|
|
pTexData[1] = vertex.tex.y;
|
|
pTexData[2] = vertex.tex.z;
|
|
|
|
pPosData +=4;
|
|
pNormData +=3;
|
|
pTexData +=3;
|
|
}
|
|
|
|
//Creates tangents
|
|
Geometry.mvTangents.resize(Geometry.mvVertexVec.size() *4);
|
|
cMath::CreateTriTangentVectors( &Geometry.mvTangents[0],
|
|
&Geometry.mvIndexVec[0], (int)Geometry.mvIndexVec.size(),
|
|
&vPosVec[0],4, &vTexVec[0],&vNormVec[0],
|
|
(int)Geometry.mvVertexVec.size());
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
|
|
void cMeshLoaderCollada::LoadVertexData(TiXmlElement* apSourceElem, tVector3fVec &avVtxVec)
|
|
{
|
|
//Get some info on the build up of the array
|
|
TiXmlElement* pTechniqueElem = apSourceElem->FirstChildElement("technique_common");
|
|
if(pTechniqueElem==NULL) pTechniqueElem = apSourceElem->FirstChildElement("technique");
|
|
if(pTechniqueElem==NULL){ Warning("No technique or technique_common element found!\n"); return;}
|
|
|
|
//Get some attributes from the accessor
|
|
TiXmlElement* pAccessor = pTechniqueElem->FirstChildElement("accessor");
|
|
if(pAccessor==NULL){ Warning("No accessor element for source data found!\n"); return;}
|
|
|
|
int lElements = cString::ToInt(pAccessor->Attribute("stride"),0);
|
|
int lVtxCount = cString::ToInt(pAccessor->Attribute("count"),0);
|
|
|
|
//Log("Elems: %d Count: %d\n",lElements,lVtxCount);
|
|
|
|
//Load the array
|
|
TiXmlElement* pDataElem = apSourceElem->FirstChildElement("float_array");
|
|
if(pDataElem==NULL)
|
|
{
|
|
//try with array as well.
|
|
pDataElem = apSourceElem->FirstChildElement("array");
|
|
if(pDataElem==NULL){
|
|
Warning("No data found!\n"); return;
|
|
}
|
|
}
|
|
|
|
TiXmlText* pTextElem = pDataElem->FirstChild()->ToText();
|
|
if(pTextElem==NULL){ Warning("No text found!\n"); return;}
|
|
|
|
const char* pChars = pTextElem->Value();
|
|
|
|
FillVertexVec(pChars,avVtxVec,lElements,lVtxCount);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cMeshLoaderCollada::LoadImages(TiXmlElement* apRootElem, tColladaImageVec &avColladaImageVec)
|
|
{
|
|
TiXmlElement* pImageElem = apRootElem->FirstChildElement("image");
|
|
while(pImageElem)
|
|
{
|
|
cColladaImage Image;
|
|
Image.msId = cString::ToString(pImageElem->Attribute("id"),"");
|
|
Image.msName = cString::ToString(pImageElem->Attribute("name"),"");
|
|
|
|
TiXmlElement* pInitFromElem = pImageElem->FirstChildElement("init_from");
|
|
//COLLADA 1.4
|
|
if(pInitFromElem)
|
|
{
|
|
if(pInitFromElem->FirstChild())
|
|
{
|
|
TiXmlText *pText = pInitFromElem->FirstChild()->ToText();
|
|
Image.msSource = cString::ToString(pText->Value(),"");
|
|
}
|
|
else
|
|
{
|
|
Image.msSource = "";
|
|
}
|
|
}
|
|
//COLLADA 1.3
|
|
else
|
|
{
|
|
Image.msSource = cString::ToString(pImageElem->Attribute("source"),"");
|
|
}
|
|
|
|
avColladaImageVec.push_back(Image);
|
|
|
|
pImageElem = pImageElem->NextSiblingElement("image");
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
class cEffectNewParam
|
|
{
|
|
public:
|
|
tString msId;
|
|
tString msType;
|
|
tString msData;
|
|
};
|
|
|
|
tString* GetFinalSource(std::vector<cEffectNewParam> &avParams,tString& asId)
|
|
{
|
|
for(size_t i=0; i<avParams.size(); ++i)
|
|
{
|
|
if(asId == avParams[i].msId)
|
|
{
|
|
return GetFinalSource(avParams,avParams[i].msData);
|
|
}
|
|
}
|
|
|
|
return &asId;
|
|
}
|
|
|
|
void cMeshLoaderCollada::LoadTextures(TiXmlElement* apRootElem, tColladaTextureVec &avColladaTextureVec)
|
|
{
|
|
TiXmlElement* pTextureElem = apRootElem->FirstChildElement();
|
|
for(;pTextureElem!=NULL; pTextureElem = pTextureElem->NextSiblingElement())
|
|
{
|
|
cColladaTexture Texture;
|
|
|
|
//Get the main properties of the texture
|
|
Texture.msId = cString::ToString(pTextureElem->Attribute("id"),"");
|
|
|
|
/////////////////////////////////////////
|
|
//COLLADA 1.4
|
|
TiXmlElement *pProfileCommon = pTextureElem->FirstChildElement("profile_COMMON");
|
|
if(pProfileCommon)
|
|
{
|
|
std::vector<cEffectNewParam> vNewParams;
|
|
//////////////////////////
|
|
//Iterate all newparams
|
|
TiXmlElement *pNewParamElem = pProfileCommon->FirstChildElement("newparam");
|
|
for(; pNewParamElem != NULL; pNewParamElem = pNewParamElem->NextSiblingElement("newparam"))
|
|
{
|
|
vNewParams.push_back(cEffectNewParam());
|
|
cEffectNewParam& newParam = vNewParams.back();
|
|
|
|
newParam.msId = pNewParamElem->Attribute("sid");
|
|
|
|
TiXmlElement *pChildElem = pNewParamElem->FirstChildElement();
|
|
if(pChildElem)
|
|
{
|
|
newParam.msType = pChildElem->Value();
|
|
//Log("Newparam '%s' type '%s'\n",newParam.msId.c_str(),newParam.msType.c_str());
|
|
|
|
tString sDataName ="";
|
|
if(newParam.msType == "surface") sDataName = "init_from";
|
|
else if(newParam.msType == "sampler2D") sDataName = "source";
|
|
|
|
if(sDataName == "") continue;
|
|
TiXmlElement *pValueElem = pChildElem->FirstChildElement(sDataName.c_str());
|
|
if(pValueElem)
|
|
{
|
|
TiXmlText *pText = pValueElem->FirstChild()->ToText();
|
|
newParam.msData = pText->Value();
|
|
}
|
|
else
|
|
{
|
|
Warning("Data element '%s' missing from newparam '%s'\n",sDataName.c_str(),
|
|
newParam.msId.c_str());
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//////////////////////////
|
|
//Get the first technique
|
|
TiXmlElement *pTechniqueElem = pProfileCommon->FirstChildElement("technique");
|
|
if(pTechniqueElem==NULL){
|
|
Warning("No effect technique element found!\n");
|
|
continue;
|
|
}
|
|
|
|
TiXmlElement *pTypeElem = pTechniqueElem->FirstChildElement();
|
|
if(pTypeElem==NULL){
|
|
Warning("No effect type element found!\n");
|
|
continue;
|
|
}
|
|
if(cString::ToString(pTypeElem->Value(), "") == "extra"){
|
|
pTypeElem = pTypeElem->NextSiblingElement();
|
|
if(pTypeElem==NULL){
|
|
Warning("No effect type element found!\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
///////////////////////
|
|
//Diffuse
|
|
TiXmlElement *pDiffuseElem = pTypeElem->FirstChildElement("diffuse");
|
|
if(pDiffuseElem)
|
|
{
|
|
TiXmlElement *pLocalTexture = pDiffuseElem->FirstChildElement("texture");
|
|
if(pLocalTexture)
|
|
{
|
|
tString _tstr = cString::ToString(pLocalTexture->Attribute("texture"),"");
|
|
Texture.msImage = *GetFinalSource(vNewParams,_tstr);
|
|
}
|
|
else
|
|
{
|
|
Texture.msImage = "";
|
|
//Warning("No diffuse texture effect element for effect '%s'! No file texture file will be loaded.\n",
|
|
// Texture.msId.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning("No diffuse effect element!\n");
|
|
}
|
|
}
|
|
/////////////////////////////////////////
|
|
//COLLADA 1.3
|
|
else
|
|
{
|
|
////////////////////////////
|
|
//Iterate root params
|
|
TiXmlElement* pParamElem = pTextureElem->FirstChildElement("param");
|
|
while(pParamElem)
|
|
{
|
|
|
|
pParamElem = pParamElem->NextSiblingElement("param");
|
|
}
|
|
|
|
///////////////////////////
|
|
//Iterate techniques
|
|
TiXmlElement* pTechniqueElem = pTextureElem->FirstChildElement("technique");
|
|
while(pTechniqueElem)
|
|
{
|
|
tString sProfile = cString::ToString(pTechniqueElem->Attribute("profile"),"");
|
|
|
|
////////////////////////////
|
|
//Technique params:
|
|
TiXmlElement* pTechParam = pTechniqueElem->FirstChildElement("param");
|
|
while(pTechParam)
|
|
{
|
|
pTechParam = pTechParam->NextSiblingElement("param");
|
|
}
|
|
|
|
///////////////////////////////
|
|
//Technique inputs:
|
|
TiXmlElement* pTechInput = pTechniqueElem->FirstChildElement("input");
|
|
while(pTechInput)
|
|
{
|
|
tString sSemantic = cString::ToString(pTechInput->Attribute("semantic"),"");
|
|
|
|
//Get the image of the texture
|
|
if(sSemantic == "IMAGE")
|
|
{
|
|
Texture.msImage = cString::ToString(pTechInput->Attribute("source"),"");
|
|
}
|
|
|
|
pTechInput = pTechInput->NextSiblingElement("input");
|
|
}
|
|
|
|
pTechniqueElem = pTechniqueElem->NextSiblingElement("technique");
|
|
}
|
|
}
|
|
|
|
|
|
//Log("Texture: id: '%s' image: '%s'\n",Texture.msId.c_str(), Texture.msImage.c_str());
|
|
|
|
avColladaTextureVec.push_back(Texture);
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cMeshLoaderCollada::LoadMaterials(TiXmlElement* apRootElem, tColladaMaterialVec &avColladaMaterialVec)
|
|
{
|
|
TiXmlElement* pMaterialElem = apRootElem->FirstChildElement("material");
|
|
while(pMaterialElem)
|
|
{
|
|
cColladaMaterial Material;
|
|
Material.msId = cString::ToString(pMaterialElem->Attribute("id"),"");
|
|
Material.msName = cString::ToString(pMaterialElem->Attribute("name"),"");
|
|
|
|
///////////////////////////////////////////
|
|
// COLLADA 1.4
|
|
TiXmlElement *pIstanceEffectElem = pMaterialElem->FirstChildElement("instance_effect");
|
|
if(pIstanceEffectElem)
|
|
{
|
|
Material.msTexture = cString::ToString(pIstanceEffectElem->Attribute("url"),"");
|
|
}
|
|
///////////////////////////////////////////
|
|
// COLLADA 1.3
|
|
else
|
|
{
|
|
//The rest of the material loader is gonna be a little lame
|
|
//Just gonna look for a texture.
|
|
|
|
TiXmlElement* pShaderElem = pMaterialElem->FirstChildElement("shader");
|
|
if(pShaderElem==NULL){ Warning("No shader found!\n"); continue;}
|
|
|
|
TiXmlElement* pTechElem = pShaderElem->FirstChildElement("technique");
|
|
if(pTechElem==NULL){ Warning("No technique found!\n"); continue;}
|
|
|
|
TiXmlElement* pPassElem = pTechElem->FirstChildElement("pass");
|
|
if(pPassElem==NULL){ Warning("No pass found!\n"); continue;}
|
|
|
|
//Iterate through the inputs and try to find a texture
|
|
TiXmlElement* pInputElem = pPassElem->FirstChildElement("input");
|
|
while(pInputElem)
|
|
{
|
|
tString sSemantic = cString::ToString(pInputElem->Attribute("semantic"),"");
|
|
|
|
if(sSemantic == "TEXTURE")
|
|
{
|
|
Material.msTexture = cString::ToString(pInputElem->Attribute("source"),"");
|
|
}
|
|
|
|
pInputElem = pInputElem->NextSiblingElement("input");
|
|
}
|
|
}
|
|
|
|
//Log("Material: id: '%s' name: '%s' texture: '%s'\n",Material.msId.c_str(),
|
|
// Material.msName.c_str(),
|
|
// Material.msTexture.c_str());
|
|
|
|
//Add to vector
|
|
avColladaMaterialVec.push_back(Material);
|
|
|
|
//Next material
|
|
pMaterialElem = pMaterialElem->NextSiblingElement("material");
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HELPER METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
static cVertex IndexDataToVertex(const cColladaVtxIndex &aData, const cColladaGeometry &aGeometry)
|
|
{
|
|
cVertex Vtx;
|
|
|
|
Vtx.col = cColor(1,1);
|
|
Vtx.pos = aGeometry.mvArrayVec[aGeometry.mlPosArrayIdx].mvArray[aData.mlVtx];
|
|
if(aGeometry.mlNormArrayIdx>=0)
|
|
Vtx.norm = aGeometry.mvArrayVec[aGeometry.mlNormArrayIdx].mvArray[aData.mlNorm];
|
|
if(aGeometry.mlTexArrayIdx>=0)
|
|
Vtx.tex = aGeometry.mvArrayVec[aGeometry.mlTexArrayIdx].mvArray[aData.mlTex];
|
|
|
|
//Flip the y coord on the tex
|
|
Vtx.tex.y = 1 - Vtx.tex.y;
|
|
|
|
return Vtx;
|
|
}
|
|
|
|
static cColladaExtraVtx IndexDataToExtra(const cColladaVtxIndex &aData, int alNewVtx)
|
|
{
|
|
cColladaExtraVtx Extra;
|
|
Extra.mlNewVtx = alNewVtx;
|
|
Extra.mlVtx = aData.mlVtx;
|
|
Extra.mlNorm = aData.mlNorm;
|
|
Extra.mlTex = aData.mlTex;
|
|
return Extra;
|
|
}
|
|
|
|
|
|
void cMeshLoaderCollada::SplitVertices(cColladaGeometry &aGeometry,tColladaExtraVtxListVec &avExtraVtxVec,
|
|
tVertexVec &avVertexVec, tUIntVec &avIndexVec)
|
|
{
|
|
//Resize the extra array and the vertex array
|
|
int lVtxSize = (int)aGeometry.mvArrayVec[aGeometry.mlPosArrayIdx].mvArray.size();
|
|
avExtraVtxVec.resize(lVtxSize);
|
|
avVertexVec.resize(lVtxSize);
|
|
avIndexVec.resize(aGeometry.mvIndices.size());
|
|
|
|
tColladaVtxIndexVec &vIndices = aGeometry.mvIndices;
|
|
|
|
for(int i=0; i<(int) vIndices.size(); i++)
|
|
{
|
|
cColladaVtxIndex &Data = vIndices[i];
|
|
//Log("Index %d: ", i);
|
|
|
|
//If the vertex extra is empty this is the first of
|
|
//this vertex added, so no need to split.
|
|
if(avExtraVtxVec[Data.mlVtx].empty())
|
|
{
|
|
avExtraVtxVec[Data.mlVtx].push_back(IndexDataToExtra(Data, Data.mlVtx));
|
|
|
|
avVertexVec[Data.mlVtx] = IndexDataToVertex(Data,aGeometry);
|
|
avIndexVec[i] = Data.mlVtx;
|
|
//Log("New vertex added");
|
|
}
|
|
//There is already a vertex added at this position, check if this exist
|
|
//else create a new.
|
|
else
|
|
{
|
|
bool bFound = false;
|
|
tColladaExtraVtxListIt it = avExtraVtxVec[Data.mlVtx].begin();
|
|
for(; it != avExtraVtxVec[Data.mlVtx].end(); ++it)
|
|
{
|
|
//If the split has already been made for this combo just set the vertex position.
|
|
if(it->Equals(Data))
|
|
{
|
|
avIndexVec[i] = it->mlNewVtx;
|
|
bFound = true;
|
|
//Log("Old vertex split used");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//If no split was found create a new
|
|
if(bFound == false)
|
|
{
|
|
//The new vertex will be put at the end.
|
|
avExtraVtxVec[Data.mlVtx].push_back(IndexDataToExtra(Data, (int)avVertexVec.size()));
|
|
avIndexVec[i] = (int)avVertexVec.size();
|
|
|
|
avVertexVec.push_back(IndexDataToVertex(Data,aGeometry));
|
|
//Log("New split made");
|
|
}
|
|
}
|
|
|
|
//Log("\n");
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
tString cMeshLoaderCollada::GetTopString(const tString asPath)
|
|
{
|
|
int pos = cString::GetLastStringPos(asPath,"-");
|
|
|
|
if(pos<0) return "";
|
|
|
|
return asPath.substr(pos+1);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cMeshLoaderCollada::FillVertexVec(const char* apChars,tVector3fVec &avVtxVec, int alElements, int alVtxCount)
|
|
{
|
|
if((int)avVtxVec.size() < alVtxCount) avVtxVec.resize(alVtxCount);
|
|
|
|
int lArraySize = alElements * alVtxCount;
|
|
|
|
int lArrayCount=0;
|
|
int lStringCount =0;
|
|
|
|
float vValArray[3];
|
|
int lValArrayCount=0;
|
|
char vTempChar[20];
|
|
int lTempCharCount=0;
|
|
|
|
int lVertexNum =0;
|
|
|
|
while(lArrayCount < lArraySize)
|
|
{
|
|
char c= apChars[lStringCount];
|
|
//if a space is found, convert the previous characters to a float.
|
|
if(c == ' ' || c == 0 || c== '\n' || c=='\t')
|
|
{
|
|
if(lTempCharCount>0)
|
|
{
|
|
//Add the float to temp float array
|
|
vTempChar[lTempCharCount] =0;
|
|
vValArray[lValArrayCount] = (float)atof(vTempChar);
|
|
|
|
lTempCharCount=0;
|
|
lArrayCount++;
|
|
|
|
//If enough values have been added put in vector and add to array.
|
|
lValArrayCount++;
|
|
if(lValArrayCount == alElements)
|
|
{
|
|
lValArrayCount =0;
|
|
cVector3f vVec;
|
|
vVec.x = vValArray[0];vVec.y = vValArray[1];
|
|
if(alElements==3) vVec.z = vValArray[2];
|
|
|
|
avVtxVec[lVertexNum] = vVec;
|
|
lVertexNum++;
|
|
//Log("%s\n", vVec.ToString().c_str());
|
|
}
|
|
}
|
|
}
|
|
//If character is not a space, add to temp char.
|
|
else
|
|
{
|
|
vTempChar[lTempCharCount] = apChars[lStringCount];
|
|
lTempCharCount++;
|
|
}
|
|
|
|
lStringCount++;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
tString cMeshLoaderCollada::GetMaterialTextureFile(const tString &asMaterial,
|
|
tColladaMaterialVec &avColladaMaterialVec,
|
|
tColladaTextureVec &avColladaTextureVec,
|
|
tColladaImageVec &avColladaImageVec)
|
|
{
|
|
//Get the texture Id
|
|
tString sTexId ="";
|
|
for(size_t mat=0; mat < avColladaMaterialVec.size(); mat++)
|
|
{
|
|
if(avColladaMaterialVec[mat].msId == asMaterial)
|
|
{
|
|
sTexId = avColladaMaterialVec[mat].msTexture;
|
|
GetAdress(sTexId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(sTexId == "")
|
|
{
|
|
Warning("Material '%s' was not found!\n",asMaterial.c_str());
|
|
return "";
|
|
}
|
|
|
|
//Get file Id
|
|
tString sFileId="";
|
|
for(size_t tex=0; tex < avColladaTextureVec.size(); tex++)
|
|
{
|
|
if(avColladaTextureVec[tex].msId == sTexId)
|
|
{
|
|
sFileId = avColladaTextureVec[tex].msImage;
|
|
GetAdress(sFileId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(sFileId == "")
|
|
{
|
|
Warning("Texture '%s' was not found!\n",sTexId.c_str());
|
|
return "";
|
|
}
|
|
|
|
//Get file source
|
|
for(size_t img=0; img < avColladaImageVec.size(); img++)
|
|
{
|
|
if(avColladaImageVec[img].msId == sFileId)
|
|
{
|
|
return cString::GetFileName(avColladaImageVec[img].msSource);
|
|
}
|
|
}
|
|
|
|
Warning("Couldn't file image file id '%s'\n",sFileId.c_str());
|
|
|
|
return "";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
/*
|
|
OLD SKINNING DATA
|
|
void cMeshLoaderCollada::LoadControllers(TiXmlElement* apRootElem,
|
|
tColladaControllerVec &avColladaControllerVec,
|
|
tColladaGeometryVec &avColladaGeometryVec)
|
|
{
|
|
TiXmlElement* pCtrlElem = apRootElem->FirstChildElement("controller");
|
|
for(;pCtrlElem!=NULL; pCtrlElem = pCtrlElem->NextSiblingElement("controller"))
|
|
{
|
|
avColladaControllerVec.push_back(cColladaController());
|
|
|
|
cColladaController &Controller = avColladaControllerVec[avColladaControllerVec.size()-1];
|
|
|
|
tString sTarget =cString::ToString(pCtrlElem->Attribute("target"),"");
|
|
tString sId = cString::ToString(pCtrlElem->Attribute("id"),"");
|
|
|
|
Controller.msId = sId;
|
|
|
|
///////////////////////////////////////
|
|
// Get Skin element.
|
|
TiXmlElement *pSkinElem = pCtrlElem->FirstChildElement("skin");
|
|
if(pSkinElem==NULL){ Error("No Skin found in controller!\n"); continue;}
|
|
|
|
//1.4 support, check skin for source if not found.
|
|
if(sTarget == ""){
|
|
sTarget = cString::ToString(pSkinElem->Attribute("source"),"");
|
|
GetAdress(sTarget);
|
|
}
|
|
|
|
Controller.msTarget = sTarget;
|
|
|
|
|
|
////////////////////////////////////////
|
|
// Find the geometry for the controller.
|
|
cColladaGeometry* pGeom =NULL;
|
|
for(int i=0;i<(int)avColladaGeometryVec.size();i++)
|
|
{
|
|
if(sTarget == avColladaGeometryVec[i].msId)
|
|
{
|
|
if(avColladaGeometryVec[i].mvIndices.empty())
|
|
{
|
|
Error("Target geometry is empty!\n");
|
|
break;
|
|
}
|
|
|
|
pGeom = &avColladaGeometryVec[i];
|
|
break;
|
|
}
|
|
}
|
|
if(pGeom==NULL){
|
|
Error("Target '%s' for Controller '%s' couldn't be found\n",sTarget.c_str(),sId.c_str());
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////
|
|
// Get the types of sources used in the controller.
|
|
tString sNormalSourceId;
|
|
tString sPositionSourceId;
|
|
tString sJointSourceId;
|
|
|
|
TiXmlElement *pVerticesElem = pSkinElem->FirstChildElement("vertices");
|
|
if(pVerticesElem==NULL){ Error("No vertices element!\n"); continue;}
|
|
|
|
TiXmlElement *pVtxInput = pVerticesElem->FirstChildElement("input");
|
|
while(pVtxInput)
|
|
{
|
|
tString sSemantic = cString::ToString(pVtxInput->Attribute("semantic"),"");
|
|
tString sSource = cString::ToString(pVtxInput->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
//Log("Vertex: %s Sem: %s\n",sSource.c_str(), sSemantic.c_str());
|
|
|
|
//Check the semantic and set the strings to point to right source.
|
|
if(sSemantic == "BIND_SHAPE_POSITION")
|
|
{
|
|
sPositionSourceId = sSource;
|
|
}
|
|
else if(sSemantic == "BIND_SHAPE_NORMAL")
|
|
{
|
|
sNormalSourceId = sSource;
|
|
}
|
|
else if(sSemantic == "JOINTS_AND_WEIGHTS")
|
|
{
|
|
sJointSourceId = sSource;
|
|
}
|
|
|
|
pVtxInput = pVtxInput->NextSiblingElement("input");
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Get the sources and load / apply them
|
|
|
|
TiXmlElement *pSourceElem = pSkinElem->FirstChildElement("source");
|
|
while(pSourceElem)
|
|
{
|
|
tString sId = cString::ToString(pSourceElem->Attribute("id"),"");
|
|
|
|
//Log("Loading controller source %s\n",sId.c_str());
|
|
|
|
//new vectors for positions
|
|
if(sId == sPositionSourceId)
|
|
{
|
|
if(pGeom->mlPosArrayIdx >= 0)
|
|
{
|
|
LoadVertexData(pSourceElem, pGeom->mvArrayVec[pGeom->mlPosArrayIdx].mvArray);
|
|
}
|
|
}
|
|
//new vectors for normals
|
|
else if(sId == sNormalSourceId)
|
|
{
|
|
if(pGeom->mlNormArrayIdx >= 0)
|
|
LoadVertexData(pSourceElem, pGeom->mvArrayVec[pGeom->mlNormArrayIdx].mvArray);
|
|
}
|
|
//data for joints
|
|
else if(sId == sJointSourceId)
|
|
{
|
|
LoadJointData(pSourceElem, Controller);
|
|
}
|
|
|
|
pSourceElem = pSourceElem->NextSiblingElement("source");
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
|
|
void cMeshLoaderCollada::LoadJointData(TiXmlElement* apSourceElem, cColladaController &aController)
|
|
{
|
|
tString sJointArrayName ="";
|
|
tString sMatrixArrayName ="";
|
|
tString sWeightArrayName ="";
|
|
|
|
/////////////////////////////////
|
|
//Get technique element
|
|
TiXmlElement *pTechniqueElem = apSourceElem->FirstChildElement("technique");
|
|
if(pTechniqueElem==NULL){ Warning("No technique element found!\n"); return;}
|
|
|
|
|
|
/////////////////////////////////
|
|
//Get the names of joint, matrix and weight array.
|
|
TiXmlElement *pAccessorElem = pTechniqueElem->FirstChildElement("accessor");
|
|
while(pAccessorElem)
|
|
{
|
|
tString sSource = cString::ToString(pAccessorElem->Attribute("source"),"");
|
|
GetAdress(sSource);
|
|
|
|
TiXmlElement *pParamElem = pAccessorElem->FirstChildElement("param");
|
|
if(pParamElem==NULL){ Warning("Accessor contains no param!\n"); return;}
|
|
|
|
tString sParamName = cString::ToString(pParamElem->Attribute("name"),"");
|
|
|
|
if(sParamName == "JOINT")
|
|
{
|
|
sJointArrayName = sSource;
|
|
}
|
|
else if(sParamName == "INV_BIND_MATRIX")
|
|
{
|
|
sMatrixArrayName = sSource;
|
|
}
|
|
else if(sParamName == "WEIGHT")
|
|
{
|
|
sWeightArrayName = sSource;
|
|
}
|
|
|
|
pAccessorElem = pAccessorElem->NextSiblingElement("accessor");
|
|
}
|
|
|
|
//Log("Joint: %s Matrix: %s Weight: %s\n",sJointArrayName.c_str(),
|
|
// sMatrixArrayName.c_str(),
|
|
// sWeightArrayName.c_str());
|
|
|
|
/////////////////////////////////
|
|
// Get the pairs
|
|
TiXmlElement *pCombinerElem = pTechniqueElem->FirstChildElement("combiner");
|
|
if(pCombinerElem == NULL){ Error("No combiner found!\n"); return;}
|
|
|
|
int lPairCount = cString::ToInt(pCombinerElem->Attribute("count"),0);
|
|
|
|
aController.mvPairs.resize(lPairCount);
|
|
//Log("Pair Count: %d\n",lPairCount);
|
|
|
|
//Check which element is joint and which is weight.
|
|
TiXmlElement *pCombInput = pCombinerElem->FirstChildElement("input");
|
|
while(pCombInput)
|
|
{
|
|
tString sSemantic = cString::ToString(pCombInput->Attribute("semantic"),"");
|
|
int lIdx = cString::ToInt(pCombInput->Attribute("idx"),0);
|
|
|
|
if(sSemantic == "JOINT")
|
|
{
|
|
aController.mlJointPairIdx = lIdx;
|
|
//Log("Joint has idx %d\n",lIdx);
|
|
}
|
|
else if(sSemantic == "WEIGHT")
|
|
{
|
|
aController.mlWeightPairIdx = lIdx;
|
|
//Log("Weight has idx %d\n",lIdx);
|
|
}
|
|
else
|
|
{
|
|
Warning("Unknown semantic '%s' found in combiner input\n", sSemantic);
|
|
}
|
|
|
|
pCombInput = pCombInput->NextSiblingElement("input");
|
|
}
|
|
|
|
// Load the data for the pairs
|
|
int lPairIdx =0;
|
|
TiXmlElement *pCombV = pCombinerElem->FirstChildElement("v");
|
|
while(pCombV)
|
|
{
|
|
TiXmlText *pText = pCombV->FirstChild()->ToText();
|
|
if(pText==NULL){ Error("No index data found!\n"); return;}
|
|
|
|
//Get the indices joints and weights
|
|
tIntVec vIndexArray;
|
|
cString::GetIntVec(pText->Value(),vIndexArray);
|
|
|
|
//Add each pair in a list at each vertex
|
|
int lNumOfPairs = (int) vIndexArray.size() /2;
|
|
for(int i=0;i<lNumOfPairs;i++)
|
|
{
|
|
cColladaJointPair Pair;
|
|
|
|
Pair.mlJoint = vIndexArray[i*2 + aController.mlJointPairIdx];
|
|
Pair.mlWeight = vIndexArray[i*2 + aController.mlWeightPairIdx];
|
|
|
|
//Log("Pair: %d, %d\n",Pair.mlJoint, Pair.mlWeight);
|
|
|
|
aController.mvPairs[lPairIdx].push_back(Pair);
|
|
}
|
|
|
|
|
|
lPairIdx++;
|
|
pCombV = pCombV->NextSiblingElement("v");
|
|
}
|
|
|
|
|
|
/////////////////////////////////
|
|
// Get the arrays
|
|
|
|
////////////////////////////////
|
|
//Get the names of the joints:
|
|
TiXmlElement *pNameArrayElem = apSourceElem->FirstChildElement("Name_array");
|
|
if(pNameArrayElem==NULL){ Error("No name array found!\n"); return;}
|
|
|
|
tString sNameId = cString::ToString(pNameArrayElem->Attribute("id"),"");
|
|
int lNameCount = cString::ToInt(pNameArrayElem->Attribute("count"),0);
|
|
|
|
if(sNameId != sJointArrayName){
|
|
Error("Name array and joint array is not the same!\n");
|
|
return;
|
|
}
|
|
|
|
TiXmlText *pNameText = pNameArrayElem->FirstChild()->ToText();
|
|
if(pNameText==NULL){ Error("No joint name data found!\n"); return;}
|
|
|
|
aController.mvJoints.reserve(lNameCount);
|
|
cString::GetStringVec(pNameText->Value(), aController.mvJoints);
|
|
|
|
|
|
//////////////////////////////
|
|
// Get weights and matrices
|
|
TiXmlElement *pFloatArrayElem = apSourceElem->FirstChildElement("float_array");
|
|
while(pFloatArrayElem)
|
|
{
|
|
tString sId = cString::ToString(pFloatArrayElem->Attribute("id"),"");
|
|
int lCount = cString::ToInt(pFloatArrayElem->Attribute("count"),0);
|
|
|
|
TiXmlText *pText = pFloatArrayElem->FirstChild()->ToText();
|
|
if(pText==NULL){ Error("No value data found!\n"); return;}
|
|
|
|
tFloatVec vValVec;
|
|
vValVec.reserve(lCount);
|
|
cString::GetFloatVec(pText->Value(), vValVec);
|
|
|
|
//Get the matrix arrray
|
|
if(sId == sMatrixArrayName)
|
|
{
|
|
aController.mvMatrices.reserve(lCount / 16);
|
|
|
|
for(int i=0; i< (lCount / 16); i++)
|
|
{
|
|
cMatrixf mtxTemp(&vValVec[i*16]);
|
|
|
|
aController.mvMatrices.push_back(mtxTemp);
|
|
|
|
//Log("Mtx: %s\n",cMath::MatrixToChar(mtxTemp));
|
|
}
|
|
}
|
|
//Get the weight array
|
|
else if(sId == sWeightArrayName)
|
|
{
|
|
aController.mvWeights = vValVec;
|
|
|
|
//for(int i=0; i <(int)aController.mvWeights.size();i++)
|
|
//{
|
|
//Log("Weight: %f\n",Controller.mvWeights[i]);
|
|
//}
|
|
}
|
|
|
|
pFloatArrayElem = pFloatArrayElem->NextSiblingElement("float_array");
|
|
}
|
|
}*/
|
|
|
|
}
|