Files
scummvm/engines/hpl1/engine/impl/MeshLoaderColladaHelpers.cpp
T
2022-12-23 14:03:26 +01:00

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");
}
}*/
}