project: COLLADA 2 BIN

Details

Program that converts geometric and animation 3D scene data, from a COLLADA "*.dae" file to a binary file, with a custom format.

  • current version: 1.0
  • last updated: February, 2019
Download source

src > animations.cpp

View raw
#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];
*/