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 > bindoc.cpp

View raw
#include "./funcs.hpp"

void write_string(FILE* binfile, const char* str, const uint32 len, const char* tag= NULL);
template <typename T> void write_number(FILE* binfile, const T* data, const uint32 len, const char* tag= NULL);
void write_materials(FILE* binfile, const std::set<std::string>& materials);
void write_mesh_geometries(FILE* binfile, const std::vector<mesh_geometry>& geoms);
void write_mesh_geometry(FILE* binfile, const mesh_geometry& geom);
void write_animations(FILE* binfile, const std::vector<animation>& animations);
void write_controllers(FILE* binfile, const bindoc& binDoc);
void write_scene(FILE* binfile, const scene_data& scene);

void write_bindoc(FILE* binFile, bindoc& binDoc)
{
  //write materials list
  write_materials(binFile, binDoc.materials);

  //write geometries
  write_mesh_geometries(binFile, binDoc.meshes);

  //write animations
  write_animations(binFile, binDoc.animations);

  //write controllers
  write_controllers(binFile, binDoc);

  //write scene
  write_scene(binFile, binDoc.scene);
}

void write_string(FILE* binfile, const char* str, const uint32 len, const char* tag)
{
  if(tag != NULL) printf("[%s](%s)[%d];\n", tag, str, len);
  fwrite((void*)&len, sizeof(uint32), 1, binfile);  
  fwrite((void*)str, sizeof(char), len, binfile);
}

template <typename T> void write_number(FILE* binfile, const T* data, const uint32 len, const char* tag) 
{
  if(tag != NULL) printf("[%s](%f...)[%d];\n", tag, (float)data[0], len); 
  fwrite((void*)data, sizeof(T), len, binfile);
}

void write_controller(FILE* binfile, const bindoc& binDoc, const armature_ctl& ctl)
{
  int skinMeshIndex= -1;
  find_mesh(ctl.skin_source, binDoc, skinMeshIndex);  
  ASSERT(skinMeshIndex != -1);

  const mesh_geometry& skinMesh= binDoc.meshes[skinMeshIndex];

  //write name
  write_string(binfile, ctl.name.c_str(), ctl.name.size(), ctl.name.c_str());

  //write ctrlId
  write_string(binfile, ctl.ctrlId.c_str(), ctl.ctrlId.size(), ctl.ctrlId.c_str());

  //write skin mesh source id
  write_string(binfile, ctl.skin_source.c_str(), ctl.skin_source.size(),  ctl.skin_source.c_str());

  //write bind shape matrix
  write_number<float>(binfile, &ctl.bind_shape_matrix.e00, 16, "bindmat");

  //write the number of armature joints
  uint32 numJoints= ctl.joints.size();
  write_number<uint32>(binfile, &numJoints, 1, "numjoints");

  //write the joint hierarchy array
  /*for(uint32 ci= 0; ci< numJoints; ci++){
    const armature_joint& jnt= ctl.joints[ci];

    //write number of child joints
    uint32 numChiJoints= jnt.child_joints.size();
    write_number<uint32>(binfile, &numChiJoints, 1, "numchijnt");

    //C child indices
    for(uint32 cji= 0; cji< numChiJoints; cji++){
      uint32 chjnti= jnt.child_joints[cji]->joint_arr_index;
      write_number<uint32>(binfile, &chjnti, 1);
    }
  }*/
  
  //ARMATURE JOINT DATA
  for(uint32 ci= 0; ci< numJoints; ci++){
    const armature_joint& jnt= ctl.joints[ci];

    //write joint name
    write_string(binfile, jnt.name.c_str(), jnt.name.size(), jnt.name.c_str());
    
    //write joint node id
    write_string(binfile, jnt.nodeId.c_str(), jnt.nodeId.size(), jnt.nodeId.c_str());

    //write transform matrix
    //write_number<float>(binfile, &jnt.transform.e00, 16);
    
    //write inverse transform
    write_number<float>(binfile, &jnt.inv_bind_transform.e00, 16);    
  }
  
  //ARMATURE-SKIN DATA
  const num1D_data& awghts= ctl.vertex_joint_weights;
  const num1D_data& aassoc= ctl.vertex_joint_assoc;//*currMesh.armature->vertex_joint_assoc;  

  uint32 wjstride= 3;
  uint32 nvert= skinMesh.vertices.size();//(ctl.vertex_joint_weights.size/wjstride)/sizeof(float);
  uint32 wjsize= nvert*wjstride;//why???
  
  write_number<uint32>(binfile, &wjsize, 1, "nvert*3");
  write_number<uint32>(binfile, &wjstride, 1, "stride=3");  

  //write assoc array to file
  for(uint32 vi= 0; vi< nvert; vi++){
    
    uint32 asi= skinMesh.vertices[vi].indices[0];//pos index is ident vertex index

    //write joint indices for vertex
    for(uint32 ji= 0; ji< wjstride; ji++){
      
      int assoc_ji= ((int*)aassoc.num_data)[asi*(wjstride*2)+ ji*2];
      write_number<int>(binfile, &assoc_ji, 1);
    }
  }

  //write weights array to file
  for(uint32 vi= 0; vi< nvert; vi++){
    
    uint32 asi= skinMesh.vertices[vi].indices[0];//pos index is ident vertex index

    for(uint32 wi= 0; wi< wjstride; wi++){
      
      int assoc_wi= ((int*)aassoc.num_data)[asi*(wjstride*2)+ wi*2+1];
      float weightVal= -1.0f;
      if(assoc_wi != -1){
        weightVal= ((float*)awghts.num_data)[assoc_wi];
      }
      write_number<float>(binfile, &weightVal, 1);      
    }
  }

}

void write_controllers(FILE* binfile, const bindoc& binDoc)
{
  const std::vector<armature_ctl>& controllers= binDoc.armature_ctls;
  //write number of controllers
  uint32 numCtls= controllers.size();
  write_number<uint32>(binfile, &numCtls, 1, "numctls");

  //write controllers
  for(uint32 ci=0; ci< numCtls; ci++){
    write_controller(binfile, binDoc, controllers[ci]);
  }

}

void write_animation(FILE* binfile, const animation& anim)
{
  ASSERT(anim.animType == ANIMATION_TYPE::TRANSFORM);//additional validation

  //write animation id
  write_string(binfile, anim.animId.c_str(), anim.animId.size(), anim.animId.c_str());
  
  //write animation target id
  write_string(binfile, anim.targetId.c_str(), anim.targetId.size(), anim.targetId.c_str());

  //write number of keyframes
  uint32 nKeyFrames= anim.num_keyframes;
  write_number<uint32>(binfile, &nKeyFrames, 1, "animnkeys");

  //write keyframe timestamps
  for(uint32 fi=0; fi< nKeyFrames; fi++){
    float keyframe_= anim.timestamps[fi];
    write_number<float>(binfile, &keyframe_, 1);
  }

  //write keyframe transforms
  for(uint32 fi=0; fi< nKeyFrames; fi++){
    const math::MAT4& transform_= anim.transforms[fi];
    write_number<float>(binfile, &transform_.e00, 16);
  }  
}

void write_animations(FILE* binfile, const std::vector<animation>& animations)
{
  //write number of animations
  uint32 numAnims= animations.size();
  write_number<uint32>(binfile, &numAnims, 1, "numanims");

  //write animations
  for(uint32 ai= 0; ai< numAnims; ai++)
  {
    write_animation(binfile, animations[ai]);
  }
}

void write_scene_node(FILE* binfile, const scene_node& node)
{
  //write type
  int nodetype= (int)node.node_type;
  write_number<int>(binfile, &nodetype, 1);
  
  //write name
  write_string(binfile, node.name.c_str(), node.name.size(), node.name.c_str());
  //write id
  write_string(binfile, node.nodeId.c_str(), node.nodeId.size(), node.nodeId.c_str());

  //write instance type
  int insttype= (int)node.instance_type;
  write_number<int>(binfile, &insttype, 1);
  //write instance id
  write_string(binfile, node.instance_id.c_str(), node.instance_id.size());  

  //write transform matrix
  write_number<float>(binfile, &node.transform.e00, 16, "nodetransf");

  //write num of child nodes
  uint32 nchinodes= node.child_nodes.size();
  write_number<uint32>(binfile, &nchinodes, 1, "nodenchild");

  //write child nodes
  for(uint32 chi=0; chi< nchinodes; chi++)
  {
    write_scene_node(binfile, node.child_nodes[chi]);
  }
}

void write_scene(FILE* binfile, const scene_data& scene)
{
  //write scene name
  write_string(binfile, scene.name.c_str(), scene.name.size(), "scenename");
  
  //write number of scene nodes
  uint32 nnodes= scene.scene_nodes.size();
  write_number<uint32>(binfile, &nnodes, 1, "scenennodes");

  //write scene nodes
  for(uint32 si= 0; si< nnodes; si++)
  {
    write_scene_node(binfile, scene.scene_nodes[si]);
  }
}

void write_materials(FILE* binfile, const std::set<std::string>& materials)
{
  uint32 matNum= materials.size();
  write_number<uint32>(binfile, &matNum, 1, "nmats");

  std::set<std::string>::iterator it;
  for (it = materials.begin(); it != materials.end(); ++it)
  {
    std::string matName;
    size_t spos= it->find("-material", 0);
    matName= it->substr(0, spos);

    write_string(binfile, matName.c_str(), matName.size(), "matname");
  }
}

void write_mesh_geometries(FILE* binfile, const std::vector<mesh_geometry>& geoms)
{
  //write number of geometries
  uint32 gsize= (uint32)geoms.size();
  write_number<uint32>(binfile, &gsize, 1, "nmeshes");

  //write geometries
  for(uint32 gi= 0; gi< geoms.size(); gi++){
    write_mesh_geometry(binfile, geoms[gi]);
  }
}

void write_mesh_geometry(FILE* binfile, const mesh_geometry& geom)
{

  const raw_meshdata& meshdata= geom.raw;

  //write name
  write_string(binfile, geom.name.c_str(), geom.name.size(), "gname");

  //write id
  write_string(binfile, geom.meshId.c_str(), geom.meshId.size(), "gid");

  //gen sources offset map
  uint32 nsrc= meshdata.sources.size();
  uint32 ninp= 1;
  GLenum primType= -1;
  uint32 sourceSemOffsetMap[nsrc];
  const uint32* inputSemantMap= NULL;

  //Note: Assuming that every prim group is like the first group. Atleast do a check maybe!
  {
    //determine primitive type
    primType= meshdata.prim_groups[0].primitive;

    //determine semantics map
    inputSemantMap= &meshdata.prim_groups[0].input_semantics[0];

    //determine number of inputs
    ninp= meshdata.prim_groups[0].inputs_count;
    for(uint32 si= 0; si< nsrc; si++){
      for(uint32 ini= 0; ini< meshdata.prim_groups[0].input_semantics.size(); ini++){
        if(meshdata.prim_groups[0].input_semantics[ini] == meshdata.sources[si].semantic)
        sourceSemOffsetMap[si]= ini;
      }
    }
  }

  //write primitive type
  write_number<GLenum>(binfile, &primType, 1, "gprim");

  //write number of sources
  write_number<uint32>(binfile, &nsrc, 1, "gnsrc");

  //write number of inputs
  write_number<uint32>(binfile, &ninp, 1, "gninp");
  
  //write semantics map
  ASSERT(inputSemantMap != NULL);
  write_number<uint32>(binfile, inputSemantMap, ninp, "ginpsem");

  //write sources
  for(uint32 si= 0; si< nsrc; si++){
    const num1D_data& sourceData= meshdata.sources[si];

    //assume numeric array source data = correct assumption
    /*uint32 elSize= (sourceData.gltype== GL_FLOAT)
      ? sizeof(float)
      : (sourceData.gltype== GL_INT)? sizeof(int): 1;*/
    uint32 numEl= geom.vertices.size()*sourceData.stride;
    
    write_number<uint32>(binfile, &sourceData.semantic, 1, "srcsem");//semantic
    write_number<GLenum>(binfile, &sourceData.gltype, 1, "srcgltype");//type
    write_number<uint32>(binfile, &numEl, 1, "srcnel");//number of elements
    write_number<uint32>(binfile, &sourceData.stride, 1, "srcstride");//stride      

    int indi= sourceSemOffsetMap[si];

    if(sourceData.gltype== GL_FLOAT){
      float* fdata= (float*)sourceData.data();
      for(uint32 ii= 0; ii< geom.vertices.size(); ii++){
        const vertex* vert= &geom.vertices[ii];
        for(uint32 gi= 0; gi< sourceData.stride; gi++){
          float val= fdata[vert->indices[indi]*sourceData.stride+gi];
          write_number<float>(binfile, &val, 1, "f");
        }
      }
    }
    else if(sourceData.gltype== GL_INT){
      int* idata= (int*) sourceData.data();
      for(uint32 ii= 0; ii< geom.vertices.size(); ii++){
        const vertex* vert= &geom.vertices[ii];
        for(uint32 gi= 0; gi< sourceData.stride; gi++){
          int val= idata[vert->indices[indi]*sourceData.stride+gi];
          write_number<int>(binfile, &val, 1, "i");
        }
      }
    }
  }

  //write material ref
  for(uint32 ii= 0; ii< geom.vertices.size(); ii++)
  {
    const vertex* vert= &geom.vertices[ii];
    int matId= vert->material_id;
    write_number<int>(binfile, &matId, 1);
  }

  //write indices
  uint32 numIndices= geom.indices.size();
  write_number<uint32>(binfile, &numIndices, 1, "nindic");
  write_number<uint32>(binfile, &geom.indices[0], numIndices, "indic");

  //write edges
  uint32 numEdges= geom.edges.size();
  write_number<uint32>(binfile, &numEdges, 1, "nedges");
  for(uint32 ei= 0; ei< numEdges; ei++)
  {
    write_number<int>(binfile, &geom.edges[ei].posit[0], 2);
  }

  //write triangles
  uint32 numTriangle= geom.triangles.size();
  write_number<uint32>(binfile, &numTriangle, 1, "ntriag");
  for(uint32 ti= 0; ti< numTriangle; ti++)
  {
    write_number<int>(binfile, &geom.triangles[ti].posit[0], 3);
    write_number<int>(binfile, &geom.triangles[ti].edges[0], 3);
  }
}