Files
scummvm-cursorfix/engines/hpl1/engine/impl/MeshLoaderColladaHelpers.cpp
2026-02-02 04:50:13 +01:00

2300 lines
71 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.
*/
#include "hpl1/engine/impl/MeshLoaderCollada.h"
#include "hpl1/engine/graphics/LowLevelGraphics.h"
#include "hpl1/engine/graphics/VertexBuffer.h"
#include "hpl1/engine/system/String.h"
#include "hpl1/engine/system/low_level_system.h"
#include "hpl1/engine/graphics/Material.h"
#include "hpl1/engine/graphics/Mesh.h"
#include "hpl1/engine/graphics/SubMesh.h"
#include "hpl1/engine/resources/MaterialManager.h"
#include "hpl1/engine/graphics/Animation.h"
#include "hpl1/engine/graphics/AnimationTrack.h"
#include "hpl1/engine/graphics/Bone.h"
#include "hpl1/engine/graphics/Skeleton.h"
#include "hpl1/engine/impl/tinyXML/tinyxml.h"
#include "hpl1/engine/math/Math.h"
namespace hpl {
#define GetAdress(sStr) \
if (sStr.size() > 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 Common::Array<cTempAnimData> tTempAnimDataVec;
typedef Hpl1::Std::set<float> tTempTimesSet;
typedef Hpl1::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.data(),
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.
// Don't scale refs - ported from HPL1R project authored by zenmumbler
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" || cString::ToLowerCase(cString::Sub(pNode->msName, 1, 3)) == "ref") {
}
// 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 Hpl1::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 positions and can include normals and tex coords as well.
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];
// FIXME: temporary fix for a memory fault caused by a negative index value
if ((lTriangleAdd + i * lTriElements + Geometry.mlTexIdxNum) >= 0)
DataVec[i].mlTex = vIndexArray[lTriangleAdd + i * lTriElements + Geometry.mlTexIdxNum];
}
}
const auto test = map_TestTris.find(DataVec);
if (test == map_TestTris.end()) {
map_TestTris.insert(DataVec);
// 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(Common::Array<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) {
Common::Array<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");
}
}*/
} // namespace hpl