Program that converts geometric and animation 3D scene data, from a COLLADA "*.dae" file to a binary file, with a custom format.
#include <unordered_map>
#include "./funcs.hpp"
void compile_animations(bindoc& binDoc)
{
std::unordered_map<std::string, animation> uniqueAnims;
//make pre-compile unique animations
for(uint32 ai=0; ai< binDoc.animations.size(); ai++)
{
animation& readAnim= binDoc.animations[ai];
animation* temp= NULL;
if(uniqueAnims.find(readAnim.targetId) == uniqueAnims.end())
{
uniqueAnims[readAnim.targetId]= animation();
temp= &uniqueAnims.find(readAnim.targetId)->second;
temp->targetId= readAnim.targetId;
temp->animId= temp->targetId.substr(1)+"_animation";
temp->num_keyframes= readAnim.num_keyframes;
temp->animType= ANIMATION_TYPE::TRANSFORM;
//read timestamps
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float timestamp_= ((float*)readAnim.keyframe_timestamps.num_data)[sti];
temp->timestamps.push_back(timestamp_);
}
//init keyframe transforms
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
math::MAT4 mat_= math::MAT4();
mat_.identity();
temp->transforms.push_back(mat_);
temp->posFrames_.push_back(math::VEC3(0.0f, 0.0f, 0.0f));
temp->eulerAngleFrames_.push_back(math::VEC3(0.0f, 0.0f, 0.0f));
temp->scaleFrames_.push_back(math::VEC3(1.0f, 1.0f, 1.0f));
}
temp->compileFromROTLOCSCAL_= false;
}
else
{
temp= &uniqueAnims.find(readAnim.targetId)->second;
//compare timestamps
ASSERT(readAnim.num_keyframes == temp->timestamps.size());
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float timestamp_= ((float*)readAnim.keyframe_timestamps.num_data)[sti];
ASSERT(temp->timestamps[sti] == timestamp_);
}
}
//read animation keyframes
if(readAnim.animType == ANIMATION_TYPE::TRANSFORM){
temp->compileFromROTLOCSCAL_= false;
//read transforms directly
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float matR_[16];
memcpy(
&matR_[0],
&((float*)readAnim.keyframe_transforms.num_data)[sti*16],
16*sizeof(float)
);
math::MAT4 keyframe_= math::MAT4(matR_);
temp->transforms[sti]= keyframe_.transpose();
}
}
else if(
readAnim.animType == ANIMATION_TYPE::LOCX
|| readAnim.animType == ANIMATION_TYPE::LOCY
|| readAnim.animType == ANIMATION_TYPE::LOCZ
){
temp->compileFromROTLOCSCAL_= true;
//read loc transforms
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float frameC= 0.0f;
memcpy(
&frameC,
&((float*)readAnim.keyframe_transforms.num_data)[sti],
1*sizeof(float)
);
math::VEC3& pos_= temp->posFrames_[sti];
if(readAnim.animType == ANIMATION_TYPE::LOCX) pos_.x= frameC;
else if(readAnim.animType == ANIMATION_TYPE::LOCY) pos_.y= frameC;
else if(readAnim.animType == ANIMATION_TYPE::LOCZ) pos_.z= frameC;
}
}
else if(
readAnim.animType == ANIMATION_TYPE::ROTAX
|| readAnim.animType == ANIMATION_TYPE::ROTAY
|| readAnim.animType == ANIMATION_TYPE::ROTAZ
){
temp->compileFromROTLOCSCAL_= true;
//read rot transforms
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float frameC= 0.0f;
memcpy(
&frameC,
&((float*)readAnim.keyframe_transforms.num_data)[sti],
1*sizeof(8)
);
math::VEC3& rot_= temp->eulerAngleFrames_[sti];
if(readAnim.animType == ANIMATION_TYPE::ROTAX)
rot_.x= cDEG2RAD*frameC;
else if(readAnim.animType == ANIMATION_TYPE::ROTAY)
rot_.y= cDEG2RAD*frameC;
else if(readAnim.animType == ANIMATION_TYPE::ROTAZ)
rot_.z= cDEG2RAD*frameC;
}
}
else if(
readAnim.animType == ANIMATION_TYPE::SCALX
|| readAnim.animType == ANIMATION_TYPE::SCALY
|| readAnim.animType == ANIMATION_TYPE::SCALZ
){
temp->compileFromROTLOCSCAL_= true;
//read scale transforms
for(uint32 sti= 0; sti< readAnim.num_keyframes; sti++){
float frameC= 0.0f;
memcpy(
&frameC,
&((float*)readAnim.keyframe_transforms.num_data)[sti],
1*sizeof(float)
);
math::VEC3& scal_= temp->scaleFrames_[sti];
if(readAnim.animType == ANIMATION_TYPE::SCALX) scal_.x= frameC;
else if(readAnim.animType == ANIMATION_TYPE::SCALY) scal_.y= frameC;
else if(readAnim.animType == ANIMATION_TYPE::SCALZ) scal_.z= frameC;
}
}
}
//compile from loc, rot, scale
for(
auto itt= uniqueAnims.begin();
itt != uniqueAnims.end();
itt++
){
animation& temp= itt->second;
if(temp.compileFromROTLOCSCAL_== false) continue;
for(uint32 sti= 0; sti< temp.num_keyframes; sti++){
temp.transforms[sti].identity();
temp.transforms[sti].setPos(temp.posFrames_[sti]);
temp.transforms[sti].setRot(fROT_XYZ(temp.eulerAngleFrames_[sti]));
temp.transforms[sti].scale(temp.scaleFrames_[sti]);
}
}
//fill the raw data sources with the unified compiled data
for(
auto itt= uniqueAnims.begin();
itt != uniqueAnims.end();
itt++
){
animation& temp= itt->second;
//init timestamps data
temp.keyframe_timestamps= num1D_data();
temp.keyframe_timestamps.num_data= new float[temp.num_keyframes];
temp.keyframe_timestamps.size= temp.num_keyframes*sizeof(float);
temp.keyframe_timestamps.stride=1;
temp.keyframe_timestamps.gltype= GL_FLOAT;
//init transform matrix data
temp.keyframe_transforms= num1D_data();
temp.keyframe_transforms.num_data= new float[temp.num_keyframes*16];
temp.keyframe_transforms.size= temp.num_keyframes*16*sizeof(float);
temp.keyframe_transforms.stride= 16;
temp.keyframe_transforms.gltype= GL_FLOAT;
for(uint32 sti= 0; sti< temp.num_keyframes; sti++){
memcpy(
&((float*)temp.keyframe_timestamps.num_data)[sti],
&temp.timestamps[sti],
1*sizeof(float)
);
math::MAT4& m_= temp.transforms[sti];
memcpy(
&((float*)temp.keyframe_transforms.num_data)[sti*16],
&m_.e00,
16*sizeof(float)
);
}
}
//reset and fill bindoc animations with compiled data
binDoc.animations= std::vector<animation>();
for(
auto itt= uniqueAnims.begin();
itt != uniqueAnims.end();
itt++
){
animation& temp= itt->second;
binDoc.animations.push_back(temp);
}
}
void read_animations(TiXmlDocument* colladaDoc, bindoc& binDoc)
{
//read the library_animations node
TiXmlElement* libraryAnimationsNode= colladaDoc->RootElement()->FirstChildElement("library_animations");
if(libraryAnimationsNode== NULL) return;
//read animation nodes
TiXmlElement* animationNode= NULL;
for(
animationNode = libraryAnimationsNode->FirstChildElement("animation");
animationNode != NULL;
animationNode = animationNode->NextSiblingElement("animation")
){
if(read_animation(animationNode, binDoc.animations)) continue;
}
}
bool read_animation(TiXmlElement* animationNode, std::vector<animation>& animations)
{
//read the channel node and find the joint target
TiXmlElement* channelNode= animationNode->FirstChildElement("channel");
if(channelNode== NULL) return false;
if(channelNode->Attribute("target")== NULL) return false;
for(uint32 tti=0; tti< NUM_ANIMTARGET_TYPES; tti++)
{
std::string targetPropertySub("/"+ animtarget_types[tti]);//target property substr
const char* channelTargetAttr= channelNode->Attribute("target");
ASSERT(channelTargetAttr != NULL);
std::string channelTarget(channelTargetAttr);
//find & extract target
int tSubPos = channelTarget.find(targetPropertySub);
if(tSubPos == std::string::npos) continue;
//add animation node
animations.push_back(animation());
animation& anim= animations[animations.size()-1];
//read nim attributes
const char* idAttr= animationNode->Attribute("id");
if(idAttr != NULL)
{
anim.animId= std::string(idAttr);
}
//set animation type
anim.animType= ANIMATION_TYPE(tti);
channelTarget = channelTarget.substr(0, tSubPos);
anim.targetId= "#"+channelTarget;
//read the sampler node
TiXmlElement* samplerNode= animationNode->FirstChildElement("sampler");
if(samplerNode== NULL) return false;
//read sampler inputs and associated sources
TiXmlElement* inputNode= samplerNode->FirstChildElement("input");
while(inputNode!= NULL){
std::string sem(inputNode->Attribute("semantic"));
std::string sourceid(inputNode->Attribute("source"));
TiXmlElement* sourceNode= find_source(animationNode, sourceid.c_str());
anim.num_keyframes= 0;
if(sem.compare("INPUT")== 0)
{
//targetJoint.keyframe_timestamps= num1D_data();
read_num1D_source(sourceNode, anim.keyframe_timestamps);
}
else if(sem.compare("OUTPUT")== 0)
{
//targetJoint.keyframe_transforms= num1D_data();
read_num1D_source(sourceNode, anim.keyframe_transforms);
}
//read next input node
inputNode= inputNode->NextSiblingElement("input");
}
//set number of keyframes
anim.num_keyframes= (anim.keyframe_timestamps.size)/sizeof(float);
return true;
}
return false;
}
/*
int jointIndex= -1;
int armatureIndex= -1;
for(uint32 ai= 0; ai< armatures.size(); ai++)
{
armature_ctl& ctl= armatures[ai];
find_joint_by_id(ctl, channelTarget.c_str(), jointIndex);
if(jointIndex!= -1)
{
armatureIndex= ai;
}
}
if(jointIndex== -1) return false;
armature_ctl& targetCtl= armatures[armatureIndex];
armature_joint& targetJoint= targetCtl.joints[jointIndex];
*/