.Xの階層メッシュアニメーションを読み込んでみる4

.xの階層アニメーションを読み込んで再生するプログラムが完成したので公開します。

クォータニオンの符号の判定には皆さん、苦労されたのではないでしょうか。
ネットで広く公開されているサンプルはほとんどがDirectX用で
いちいち転置しなければならなかったり。
左手座標用に作成したアニメーションXファイルはクォータニオンのY軸とZ軸を-1倍しないと
OpenGLではおかしな表示になるとか。
回転角度が181度とマイナス179度ではクォータニオンの符号が反転してるけど
同じ回転行列になるとか。

いやはや、手間取りました。
最後に親階層から子階層へ脈々と行列を受け継いで完成です。

『固定機能:階層メッシュアニメーション編』の『階層構造』で作成した
sample4.xを表示しています。
尚、Cyberdelia で作成したアニメーションXファイルだけに対応しています。

 

 font.h

#pragma once
class GLFONT
{
public:
 HFONT Hfont;
 HDC Hdc;
 GLFONT(wchar_t *fontname, int size);
 void DrawStringW(int x,int y,wchar_t *format, ...);
};
//コンストラクタ フォント作成
GLFONT::GLFONT(wchar_t *fontname, int size)
{
 Hfont = CreateFontW(
        size,      //フォント高さ
        0,       //文字幅
        0,       //テキストの角度
        0,       //ベースラインとx軸との角度
        FW_REGULAR,     //フォントの太さ
        FALSE,      //イタリック体
        FALSE,      //アンダーライン
        FALSE,      //打ち消し線
        SHIFTJIS_CHARSET,   //文字セット
        OUT_DEFAULT_PRECIS,   //出力精度
        CLIP_DEFAULT_PRECIS,  //クリッピング精度
        ANTIALIASED_QUALITY,  //出力品質
        FIXED_PITCH | FF_MODERN, //ピッチとファミリー
        fontname);     //書体名

 Hdc = wglGetCurrentDC();
 SelectObject(Hdc, Hfont);
}
//ワイド文字列の描画
void GLFONT::DrawStringW(int x,int y,wchar_t *format, ...)
{
 wchar_t buf[256];
 va_list ap;
 int Length=0;
 int list=0;
 
 //ポインタがNULLの場合は終了
 if ( format == NULL )
  return;

 //文字列変換
 va_start(ap, format);
 vswprintf_s(buf, format, ap);
 va_end(ap);

 Length = wcslen(buf);
 list = glGenLists(Length);
 for( int i=0; i  wglUseFontBitmapsW(Hdc, buf[i], 1, list + (DWORD)i);
 }

 glDisable(GL_LIGHTING);
 glRasterPos2i(x, y);
 //ディスプレイリストで描画
 for( int i=0; i {
  glCallList(list + i);
 }
 glEnable(GL_LIGHTING);
 //ディスプレイリスト破棄
 glDeleteLists(list, Length);
 list = 0;
 Length = 0;
}

PNG.h

#pragma once
#include "lodepng.h"

//テクスチャクラス
class TEXTURE{
protected:
 LodePNG_Decoder decoder;//デコーダ
 unsigned char* buffer;//バッファ
 size_t buffersize, imagesize;//サイズ
public:
 TEXTURE();
 TEXTURE(const char* FileName);//コンストラクタ
 void LOAD_PNG(const char* FileName);//PNG読み込み
 unsigned char* image;//イメージポインタ
 unsigned int Width,Height;//画像サイズ
};
TEXTURE::TEXTURE(){
}
TEXTURE::TEXTURE(const char* FileName){
 LOAD_PNG(FileName);
}
void TEXTURE::LOAD_PNG(const char* FileName){
 LodePNG_Decoder_init(&decoder);
 //ロード
 LodePNG_loadFile(&buffer, &buffersize, FileName);
 //デコード
 LodePNG_decode(&decoder, &image, &imagesize, buffer, buffersize);
 //幅,高さ
 Width = decoder.infoPng.width;Height = decoder.infoPng.height;
}

xfile.h

#pragma once
#include "PNG.h"
#include <math.h>

#define PAI 3.14159

using namespace std;
struct MATRIX;
//クォータニオン構造体
struct QUATERNION{
 union {
  struct {
   float w;
   float x;
   float y;
   float z;
  };
  float Index[4];
 };
 MATRIX ToMatrix();//クォータニオンを回転行列にする
}qua;

//マトリクス構造体
struct MATRIX {
    union {
        struct {
            float _11, _12, _13, _14;
            float _21, _22, _23, _24;
            float _31, _32, _33, _34;
            float _41, _42, _43, _44;
        };
        float mat_4x4[4][4];
        float mat_16[16];
    };
 MATRIX(){//単位行列に初期化
  for(int i=0;i<16;i++){
   this->mat_16[i]=0;
  }
  this->_11=this->_22=this->_33=this->_44=1;
 }
  void PRINT(char* text){
  printf("%s\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n\n",
   text,
   this->_11,this->_21,this->_31,this->_41,
   this->_12,this->_22,this->_32,this->_42,
   this->_13,this->_23,this->_33,this->_43,
   this->_14,this->_24,this->_34,this->_44);
 }

 MATRIX Multiplication(MATRIX& mat);//合成
 QUATERNION ToQuaternion();//回転行列をクォータニオンにする
};
//合成
MATRIX MATRIX::Multiplication(MATRIX& mat)
{
 MATRIX ret;
 for(int y=0;y<4;y++){
  for(int x=0;x<4;x++){
   ret.mat_16[y*4+x]=mat.mat_16[y*4]*this->mat_16[x]+mat.mat_16[y*4+1]*this->mat_16[x+4]+mat.mat_16[y*4+2]*this->mat_16[x+8]+mat.mat_16[y*4+3]*this->mat_16[x+12];
  }
 }
 return ret;
}

float SGN(float x) {
 return (x >= 0.0f) ? +1.0f : -1.0f;
}

//回転行列をクォータニオンにする
QUATERNION MATRIX::ToQuaternion(){
 QUATERNION q;
 q.w = ( this->_11 + this->_22 + this->_33 + 1.0f) / 4.0f;
 q.x = ( this->_11 - this->_22 - this->_33 + 1.0f) / 4.0f;
 q.y = (-this->_11 + this->_22 - this->_33 + 1.0f) / 4.0f;
 q.z = (-this->_11 - this->_22 + this->_33 + 1.0f) / 4.0f;
 for(int i=0;i<4;i++){
  if(q.Index[i] < 0.0f) q.Index[i] = 0.0f;
  q.Index[i] = sqrt(q.Index[i]);
 }
 if(q.w >= q.x && q.w >= q.y && q.w >= q.z) {
  q.w *= +1.0f;
  q.x *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21);
  q.y *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21);
  q.z *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21);
 } else {
  q.w *= +1.0f*-1;
  q.x *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21)*-1;
  q.y *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21)*-1;
  q.z *= SGN(this->_23 - this->_32)*SGN(this->_31 - this->_13)*SGN(this->_12 - this->_21)*-1;
 }

 float nor = sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z *q.z);
 for(int i=0;i<4;i++){
  q.Index[i] /= nor;
 }
 return q;
}

//クォータニオンを回転行列にする
MATRIX QUATERNION::ToMatrix(){
 MATRIX ret;
    float sx = this->x * this->x;
    float sy = this->y * this->y;
    float sz = this->z * this->z;
    float cx = this->y * this->z;
    float cy = this->x * this->z;
    float cz = this->x * this->y;
    float wx = this->w * this->x;
    float wy = this->w * this->y;
    float wz = this->w * this->z;

 ret._11= 1.0f - 2.0f * (sy + sz);
 ret._12= 2.0f * (cz + wz);
 ret._13= 2.0f * (cy - wy);
 ret._21= 2.0f * (cz - wz);
 ret._22= 1.0f - 2.0f * (sx + sz);
 ret._23= 2.0f * (cx + wx);
 ret._31= 2.0f * (cy + wy);
 ret._32= 2.0f * (cx - wx);
 ret._33= 1.0f - 2.0f * (sx + sy);
 ret._41= 0.0f;
 ret._42= 0.0f;
 ret._43= 0.0f;
 return ret;
}

//3つのベクトル
struct Vector3f{
 float x;
 float y;
 float z;
}vec3d;
Vector3f & operator*(Vector3f &v,float size){
 v.x *= size;
 v.y *= size;
 v.z *= size;
 return v;
}
Vector3f & operator+(Vector3f &a,Vector3f &b){
 a.x+=b.x;
 a.y+=b.y;
 a.z+=b.z;
 return a;
}
//4つのベクトル
struct Vector4f{
 float x;
 float y;
 float z;
 float w;
}vec4d;
//4つのカラー
struct Color4{
 float r;
 float g;
 float b;
 float a;
};
//4つの反射
struct Reflection4{
 Color4 diffuse;
 Color4 ambient;
 Color4 emission;
 Color4 specular;
};
//UV座標
struct UV{
 float u;//u値
 float v;//v値
}vec2d;
//ポリゴンデータ
struct Triangle{
 Vector3f TriVer;
 Vector3f TriNor;
 UV TriUV;
}Tri;
//ポリゴンデータ
struct Quadrangle{
 Vector3f QuadVer;
 Vector3f QuadNor;
 UV QuadUV;
}Quad;
//マテリアル構造体
struct MATERIAL{
 string MaterialName;//マテリアル名
 Reflection4 MaterialColor;//反射
 float Shininess;//shininess
 string TextureName;//テクスチャ名
 int TexNo;//テクスチャNO.
 vector <Triangle> Tridata;//三角面データ
 vector <Quadrangle> Quaddata;//四角面データ
}mtl;
//メッシュ構造体
struct MESH{
public:
 vector <MATERIAL> Material;//マテリアル
 vector <TEXTURE*> TexData;//テクスチャデータ
 vector<GLuint> TexID;//テクスチャID
 GLuint TexID2;//代入用
 TEXTURE* tex;//代入用
}msh;
//アニメーションデータ構造体
struct ANIMATION{
public:
 vector <int> Key;//アニメーションキー
 vector <MATRIX> Matrix;//行列データ
}anm;
//ノード構造体
struct NODE{
 NODE* Node;//子ノード
 NODE* Next;//隣の階層
 string FrameName;//フレーム名
 MESH* Mesh;//メッシュ
 ANIMATION Anim;//アニメーションデータ
}nde;
//階層メッシュクラス
class HIERARCHY{
public:
 void Draw();//描画
 void Draw_Frame(NODE& node,int Frame_Time,MATRIX& mat);//フレーム描画
 void Animation_Draw(int Animation_NO,int Frame);//アニメーション描画
 HIERARCHY();
 HIERARCHY(char* FileName,int size);
 NODE Root;//ルートノード
 int Size;//サイズ 
 int Animation_MaxFrame;//最大フレーム
private:
 bool Load_Hierarchy(char* FileName); //階層メッシュ読み込み
 void Find_Frame(NODE& node,char* name);//フレームを探す
 bool Load_Frame(FILE& fp,NODE& node,int& hierarchy);  //フレーム読み込み
 bool Load_Mesh(FILE& fp,NODE& node);//メッシュ読み込み
 bool Load_Animation(FILE& fp);//アニメーション読み込み
 MATRIX Linear_Interpolation(MATRIX& a,MATRIX& b,float t);//線形補間
 QUATERNION Spherical_Linear_Interpolation( QUATERNION& q1, QUATERNION& q2, float t);//球面線形補間
 void Init();
 char buffer[255];
 int Back;//階層戻し
 NODE* pNode;//ノードポインタ
};
//コンストラクタ
HIERARCHY::HIERARCHY(){
 Init();
}
//コンストラクタ
HIERARCHY::HIERARCHY(char* FileName,int size){
 Init();
 Size=size;
 Load_Hierarchy(FileName);
}
//初期化
void HIERARCHY::Init(){
 Root.Node=NULL;
 Root.Next=NULL;
 Root.FrameName="Root";
 Root.Mesh=NULL;
}

//球面線形補間
QUATERNION HIERARCHY::Spherical_Linear_Interpolation( QUATERNION& q1, QUATERNION& q2, float t)
{
  QUATERNION q;
    if((q1.w==q2.w)&&(q1.x==q2.x)&&(q1.y==q2.y)&&(q1.z==q2.z)){
   for(int i=0;i<4;i++){
    q.Index[i] = q1.Index[i];
   }
   return q;
  }
  float qr = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
  float ss = 1.0f - qr * qr;
 
  if (ss == 0.0f) {
   for(int i=0;i<4;i++){
    q.Index[i] = q1.Index[i];
   }
   return q;
  }else{
    float sp = sqrt(ss);
    float ph = acos(qr);
    float pt = ph * t;
    float t1 = sin(pt) / sp;
    float t0 = sin(ph - pt) / sp;

 for(int i=0;i<4;i++){
  q.Index[i] = (q1.Index[i] * t0 + q2.Index[i] * t1);
 }
 return q;
  }
}

//線形補間
MATRIX HIERARCHY::Linear_Interpolation(MATRIX& a,MATRIX& b,float t){
 MATRIX ret,r1,r2,r3;
 QUATERNION q1,q2,q3;
 Vector3f vec_A, vec_B, vec_R;
 //平行移動
 vec_A.x=a._41;
 vec_A.y=a._42;
 vec_A.z=a._43;
 vec_B.x=b._41;
 vec_B.y=b._42;
 vec_B.z=b._43;
 vec_R=vec_A*(1.0f-t) + vec_B*t;
 ret._41=vec_R.x;
 ret._42=vec_R.y;
 ret._43=vec_R.z;
 //スケーリング成分抜き出し
 vec_A.x=sqrt(a._11*a._11+a._21*a._21+a._31*a._31);
 vec_A.y=sqrt(a._12*a._12+a._22*a._22+a._32*a._32);
 vec_A.z=sqrt(a._13*a._13+a._23*a._23+a._33*a._33);
 vec_B.x=sqrt(b._11*b._11+b._21*b._21+b._31*b._31);
 vec_B.y=sqrt(b._12*b._12+b._22*b._22+b._32*b._32);
 vec_B.z=sqrt(b._13*b._13+b._23*b._23+b._33*b._33);
 
 for(int i=0;i<4;i++){
  for(int j=0;j<4;j++){
   r1.mat_4x4[j][i]=a.mat_4x4[j][i];
   r2.mat_4x4[j][i]=b.mat_4x4[j][i];
   if(i==0){if(j<3){r1.mat_4x4[j][i]=a.mat_4x4[j][i]/vec_A.x;r2.mat_4x4[j][i]=b.mat_4x4[j][i]/vec_B.x;}}
   if(i==1){if(j<3){r1.mat_4x4[j][i]=a.mat_4x4[j][i]/vec_A.y;r2.mat_4x4[j][i]=b.mat_4x4[j][i]/vec_B.y;}}
   if(i==2){if(j<3){r1.mat_4x4[j][i]=a.mat_4x4[j][i]/vec_A.z;r2.mat_4x4[j][i]=b.mat_4x4[j][i]/vec_B.z;}}
  }
 }
 
 //クォータニオンを補間
 q1=r1.ToQuaternion();
 q2=r2.ToQuaternion();
 q3=Spherical_Linear_Interpolation(q1,q2,t);
 r3=q3.ToMatrix();
 
 vec_R=vec_A*(1.0f-t) + vec_B*t;
 ret._11=r3._11*vec_R.x;
 ret._21=r3._21*vec_R.x;
 ret._31=r3._31*vec_R.x;
 ret._12=r3._12*vec_R.y;
 ret._22=r3._22*vec_R.y;
 ret._32=r3._32*vec_R.y;
 ret._13=r3._13*vec_R.z;
 ret._23=r3._23*vec_R.z;
 ret._33=r3._33*vec_R.z;

 return ret;
}
//フレーム描画
void HIERARCHY::Draw_Frame(NODE& node,int Frame_Time,MATRIX& mat){
 MATRIX current=mat;
 while(1){
  if(node.Mesh!=NULL){
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_NORMAL_ARRAY);
   glPushMatrix();
   glMultMatrixf(&mat.mat_16[0]);
   //線形補間
   for(int k=1;k<(signed)node.Anim.Key.size();k++){
    int Length=node.Anim.Key[k]-node.Anim.Key[k-1];//キー間の長さ
    int Current=Frame_Time-node.Anim.Key[k-1];//キー間の現在位置
    float t=(float)Current/(float)Length;
    if((node.Anim.Key[k-1]<=Frame_Time)&&(node.Anim.Key[k]>Frame_Time)){
     MATRIX Linear = Linear_Interpolation(node.Anim.Matrix[k-1],node.Anim.Matrix[k],t);
     mat=mat.Multiplication(Linear);
     glMultMatrixf(&Linear.mat_16[0]);
    }
   }
   for(int i=0;i<(signed)node.Mesh->Material.size();i++){
    glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.ambient);
    glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.diffuse);
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat *)&node.Mesh->Material[i].MaterialColor.specular);
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,node.Mesh->Material[i].Shininess);

    if(node.Mesh->Material[i].TexNo>0){
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, node.Mesh->TexID[node.Mesh->Material[i].TexNo-1]);
    }else{
     glDisable(GL_TEXTURE_2D);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }
    
    if(node.Mesh->Material[i].Tridata.size()>1){
     glVertexPointer(3, GL_FLOAT,sizeof(Tri) , &node.Mesh->Material[i].Tridata[0].TriVer.x);
     glNormalPointer(GL_FLOAT,sizeof(Tri),&node.Mesh->Material[i].Tridata[0].TriNor.x);
     //if(node.Mesh->Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Tri), &node.Mesh->Material[i].Tridata[0].TriUV.u);
     glDrawArrays(GL_TRIANGLES,0,node.Mesh->Material[i].Tridata.size());
    }
    if(node.Mesh->Material[i].Quaddata.size()>1){
     glVertexPointer(3, GL_FLOAT,sizeof(Quad) , &node.Mesh->Material[i].Quaddata[0].QuadVer.x);
     glNormalPointer(GL_FLOAT,sizeof(Quad),&node.Mesh->Material[i].Quaddata[0].QuadNor.x);
     //if(node.Mesh->Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Quad), &node.Mesh->Material[i].Quaddata[0].QuadUV.u);
     glDrawArrays(GL_QUADS,0,node.Mesh->Material[i].Quaddata.size());
    }
 
   }
   glDisableClientState(GL_VERTEX_ARRAY);
   glDisableClientState(GL_NORMAL_ARRAY);
   //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   //glDisable(GL_TEXTURE_2D);
   glPopMatrix();
  }

  if(node.Node!=NULL)Draw_Frame(*node.Node,Frame_Time,mat);
  if(node.Next!=NULL)Draw_Frame(*node.Next,Frame_Time,current);
  if(node.Node==NULL)return;
  if(node.Next==NULL)return;
  return;
 }
}
//アニメーション描画
void HIERARCHY::Animation_Draw(int Animation_NO,int Frame){
 MATRIX mat;
 Draw_Frame(Root,Frame,mat);
}
//描画
void HIERARCHY::Draw(){
 MATRIX mat;
 Draw_Frame(Root,0,mat);
}
//フレームを探す
void HIERARCHY::Find_Frame(NODE& node,char* name){
 while(1){
  if(strcmp(node.FrameName.c_str(),name)==0){
   pNode=&node;
   return;
  }
  if(node.Node!=NULL)Find_Frame(*node.Node,name);
  if(node.Next!=NULL)Find_Frame(*node.Next,name);
  if(node.Node==NULL)return;
  if(node.Next==NULL)return;
  return;
 }
 return;
}
//アニメーション読み込み
bool HIERARCHY::Load_Animation(FILE& fp){
 char buf[255];
 char name[255];
 vector <QUATERNION> Quaternion;
 vector <Vector3f> Transform;
 vector <Vector3f> Scaling;
 vector <int> Key1;
 vector <int> Key2;
 vector <int> Key3;
 int hierarchy=0,count=0,keyID,key=0,dummy=0,x=0,y=0,z=0,w=0;
 //合成行列
 MATRIX mix;

 //読み込み
 while(!feof(&fp))
 {
  ZeroMemory(buf,sizeof(buf));
  fscanf_s(&fp,"%s ",buf,sizeof(buf));
  //AnimationSetを探す
  if(strcmp(buf,"AnimationSet")==0){
    while(!feof(&fp))
    {
     fgets(buf,sizeof(buf),&fp);
     if(strstr(buf,"AnimationKey")==NULL){
      if((!strstr(buf,"{")==NULL)&&(!strstr(buf,"}")==NULL)){//名前の抽出
       sscanf_s(buf," { %s } ",&name,sizeof(name));
       pNode=NULL;
       Find_Frame(Root,name);
       pNode->Anim.Matrix.resize(Key3.size());
       for(int i=0;i<(signed)Key3.size();i++){
        if(Key1.size()==Key3.size()){
         Quaternion[i].y=Quaternion[i].y*-1;
         Quaternion[i].z=Quaternion[i].z*-1;

         mix=Quaternion[i].ToMatrix();
        }
        if(Key2.size()==Key3.size()){
         mix._11*=Scaling[i].x;
         mix._21*=Scaling[i].x;
         mix._31*=Scaling[i].x;
         mix._12*=Scaling[i].y;
         mix._22*=Scaling[i].y;
         mix._32*=Scaling[i].y;
         mix._13*=Scaling[i].z;
         mix._23*=Scaling[i].z;
         mix._33*=Scaling[i].z;
        }
        mix._41=Transform[i].x*Size;
        mix._42=Transform[i].y*Size;
        mix._43=Transform[i].z*Size;
        pNode->Anim.Key.push_back(Key3[i]);
        for(int j=0;j<16;j++)pNode->Anim.Matrix[i].mat_16[j]=mix.mat_16[j];
       }
       Animation_MaxFrame=Key3[Key3.size()-1];
       Quaternion.clear();
       Scaling.clear();
       Transform.clear();
       Key1.clear();
       Key2.clear();
       Key3.clear();
      }
     }else{
    fgets(buf,sizeof(buf),&fp);//キー 0 回転 , 1 拡大縮小 , 2 平行移動
    keyID=atoi(buf);
    fgets(buf,sizeof(buf),&fp);//キーデータの個数
    count=atoi(buf);
    switch (keyID){
     case 0:
      for(int i=0;i<count;i++){
       fscanf_s(&fp,"%d;%d;%f,%f,%f,%f;;,",&key,&dummy,&qua.w,&qua.x,&qua.y,&qua.z);
       Key1.push_back(key);
       Quaternion.push_back(qua);
      }
      break;
     case 1:
      for(int i=0;i<count;i++){
       fscanf_s(&fp,"%d;%d;%f,%f,%f;;,",&key,&dummy,&vec3d.x,&vec3d.y,&vec3d.z);
       Key2.push_back(key);
       Scaling.push_back(vec3d);
      }
      break;
     case 2:
      for(int i=0;i<count;i++){
       fscanf_s(&fp,"%d;%d;%f,%f,%f;;,",&key,&dummy,&vec3d.x,&vec3d.y,&vec3d.z);
       Key3.push_back(key);
       Transform.push_back(vec3d);
      }
      break;
     default:
      break;
    }
     }
    }
  }
 }
 Animation_MaxFrame=pNode->Anim.Key[pNode->Anim.Key.size()-1];
 Quaternion.clear();
 Scaling.clear();
 Transform.clear();
 Key1.clear();
 Key2.clear();
 Key3.clear();
 return true;
}
//メッシュ読み込み
bool HIERARCHY::Load_Mesh(FILE& fp,NODE& node){
 vector <Vector3f> Vertex;//頂点
 vector <Vector3f> Normal;//法線
 vector <UV> uv;//UV
 vector <int> VertexIndex;
 vector <int> NormalIndex;
 vector <int> MaterialIndex;
 vector <int> FaceIndex;

 char key[255];
 char buf[255];
 
 int v1=0,v2=0,v3=0,v4=0;
 int Count=0,Hierarchy=1;
 string str="";
 fscanf_s(&fp,"%s ",key,sizeof(key));
 node.Mesh =new MESH(msh);
 //読み込み
 while(!feof(&fp))
 {
  //キーワード 読み込み
  ZeroMemory(key,sizeof(key));
  fscanf_s(&fp,"%s ",key,sizeof(key));
  //階層+
  if(strcmp(key,"{")==0){
   Hierarchy++;
  }
  //階層-
  if(strcmp(key,"}")==0){
   Hierarchy--;
   if(Hierarchy==0){
    Count=0;
    //マテリアル毎のデータを作成
    for(int i=0;i<(signed)MaterialIndex.size();i++){
     if(FaceIndex[i]==3){
      for(int j=0;j<3;j++){
       Tri.TriVer=Vertex[VertexIndex[Count+j]];
       Tri.TriNor=Normal[NormalIndex[Count+j]];
       //Tri.TriUV=uv[VertexIndex[Count+j]];
       node.Mesh->Material[MaterialIndex[i]].Tridata.push_back(Tri);
      }
      Count+=3;
     }else{
      for(int j=0;j<4;j++){
       Quad.QuadVer=Vertex[VertexIndex[Count+j]];
       Quad.QuadNor=Normal[NormalIndex[Count+j]];
       //Quad.QuadUV=uv[VertexIndex[Count+j]];
       node.Mesh->Material[MaterialIndex[i]].Quaddata.push_back(Quad);
      }
      Count+=4;
     }
    }
    Vertex.clear();
    Normal.clear();
    uv.clear();
    VertexIndex.clear();
    NormalIndex.clear();
    MaterialIndex.clear();
    FaceIndex.clear();
    return true;
   }
  }
 
  if(strcmp(key,"Frame")==0){
   Count=0;
    //マテリアル毎のデータを作成
    for(int i=0;i<(signed)MaterialIndex.size();i++){
     if(FaceIndex[i]==3){
      for(int j=0;j<3;j++){
       Tri.TriVer=Vertex[VertexIndex[Count+j]];
       Tri.TriNor=Normal[NormalIndex[Count+j]];
       //Tri.TriUV=uv[VertexIndex[Count+j]];
       node.Mesh->Material[MaterialIndex[i]].Tridata.push_back(Tri);
      }
      Count+=3;
     }else{
      for(int j=0;j<4;j++){
       Quad.QuadVer=Vertex[VertexIndex[Count+j]];
       Quad.QuadNor=Normal[NormalIndex[Count+j]];
       //Quad.QuadUV=uv[VertexIndex[Count+j]];
       node.Mesh->Material[MaterialIndex[i]].Quaddata.push_back(Quad);
      }
      Count+=4;
     }
    }
    Vertex.clear();
    Normal.clear();
    uv.clear();
    VertexIndex.clear();
    NormalIndex.clear();
    MaterialIndex.clear();
    FaceIndex.clear();
    return true;
  }
 
  //頂点 読み込み
  if(strcmp(key,"Mesh")==0)
  {
   Hierarchy++;
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   Count=atoi(buf);
   for(int i=0;i<Count ;i++)
   {
    fscanf_s(&fp,"%f;%f;%f;,",&vec3d.x,&vec3d.y,&vec3d.z);
    Vertex.push_back(vec3d*(float)Size);
   }
   //頂点インデックス読み込み 
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),&fp);}//空行対策
   Count=atoi(buf);  
   for(int i=0;i<Count ;i++)
   {
    int dammy=0;
    fgets(buf,sizeof(buf),&fp);
    str=buf;
    string::size_type first = str.find_first_not_of(' ');
 string::size_type tab = str.find_first_not_of('\t');
    string::size_type index = str.find("3;");
    if(index-first-tab==0){
     sscanf_s(buf,"%d;%d,%d,%d;,",&dammy,&v1,&v2,&v3);
     VertexIndex.push_back(v1);
     VertexIndex.push_back(v2);
     VertexIndex.push_back(v3);
    }
    if(!(index-first-tab==0)){
     sscanf_s(buf,"%d;%d,%d,%d,%d;,",&dammy,&v1,&v2,&v3,&v4);
     VertexIndex.push_back(v1);
     VertexIndex.push_back(v2);
     VertexIndex.push_back(v3);
     VertexIndex.push_back(v4);
    }
    FaceIndex.push_back(dammy);
   }
  }

  //法線 読み込み
  if(strcmp(key,"MeshNormals")==0)
  {
   Hierarchy++;
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   Count=atoi(buf);
   for(int i=0;i<Count ;i++)
   {
    fscanf_s(&fp,"%f;%f;%f;,",&vec3d.x,&vec3d.y,&vec3d.z);
    Normal.push_back(vec3d);
   }
   //法線インデックス読み込み 
   fgets(buf,sizeof(buf),&fp);//データは2行下にあると推定 改行する
   fgets(buf,sizeof(buf),&fp);
   while(strchr(buf,';')==NULL){fgets(buf,sizeof(buf),&fp);}//空行対策
   Count=atoi(buf);  
   for(int i=0;i<Count ;i++)
   {
    int dammy=0;
    fgets(buf,sizeof(buf),&fp);
    str=buf;
    string::size_type first = str.find_first_not_of(' ');
 string::size_type tab = str.find_first_not_of('\t');
    string::size_type index = str.find("3;");
    if(index-first-tab==0){
     sscanf_s(buf,"%d;%d,%d,%d;,",&dammy,&v1,&v2,&v3);
     NormalIndex.push_back(v1);
     NormalIndex.push_back(v2);
     NormalIndex.push_back(v3);
    }
    if(!(index-first-tab==0)){
     sscanf_s(buf,"%d;%d,%d,%d,%d;,",&dammy,&v1,&v2,&v3,&v4);
     NormalIndex.push_back(v1);
     NormalIndex.push_back(v2);
     NormalIndex.push_back(v3);
     NormalIndex.push_back(v4);
    }
   }
  }

  //マテリアルリスト
  if(strcmp(key,"MeshMaterialList")==0)
  {
   Hierarchy++;
   fgets(buf,sizeof(buf),&fp);//空改行
   fgets(buf,sizeof(buf),&fp);//マテリアル数
   fgets(buf,sizeof(buf),&fp);//リスト要素数
   Count=atoi(buf);
   for(int i=0;i<Count;i++)
   {
    fgets(buf,sizeof(buf),&fp);
    int test=atoi(buf);
    MaterialIndex.push_back(test);
   }
  }
  //マテリアル読み込み
  if(strcmp(key,"Material")==0)
  {
   Hierarchy++;
   fgets(buf,sizeof(buf),&fp);//直後の行にあると推定 改行する
   //ディフューズ
   fscanf_s(&fp,"%f;%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z,&vec4d.w);
   mtl.MaterialColor.diffuse=(const Color4 &)vec4d;
   //SHININESS 
   fscanf_s(&fp,"%f;",&mtl.Shininess);
   //スペキュラー
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   mtl.MaterialColor.specular=(const Color4 &)vec4d;
   //エミッシブ
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   mtl.MaterialColor.ambient=(const Color4 &)vec4d;

   node.Mesh->Material.push_back(mtl);
  }
 }
 return false;
}
//フレーム読み込み
bool HIERARCHY::Load_Frame(FILE& fp,NODE& node,int& hierarchy){
 char key[255];
 int begin=0,end=0;
 int current=hierarchy;//現在の階層
 int file_pos;

 while(!feof(&fp))
 {
  //キーワード 読み込み
  ZeroMemory(key,sizeof(key));
  fscanf_s(&fp,"%s ",key,sizeof(key));
  //ヘッダー読み飛ばし
  if(strcmp(key,"Header")==0){
   while(strcmp(key,"}")){
    fscanf_s(&fp,"%s ",key,sizeof(key));
   }
   continue;
  }
  //テンプレート読み飛ばし
  if(strcmp(key,"template")==0){
   while(strcmp(key,"}")){
    fscanf_s(&fp,"%s ",key,sizeof(key));
   }
   continue;
  }
  //階層+
  if(strcmp(key,"{")==0){
   begin++;
  }
  //階層-
  if(strcmp(key,"}")==0){
   end++;
  }
  //フレーム
  if(strcmp(key,"Frame")==0){
   fscanf_s(&fp,"%s ",key,sizeof(key));

   if(((begin==0)&&(end==0))||(end-begin==-1)){//子ノード追加
    node.Node=new NODE(nde);
    node.Node->FrameName=key;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Node);
    fseek( &fp, file_pos, SEEK_SET );
    hierarchy++;
    Load_Frame(fp,*node.Node,hierarchy);//再帰呼び出し
   }

   if(Back==current){//階層戻り先にきた場合、同一階層追加
    Back=-1;
    node.Next=new NODE(nde);
    node.Next->FrameName=buffer;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Next);
    fseek( &fp, file_pos, SEEK_SET );
    Load_Frame(fp,*node.Next,current);//再帰呼び出し
   }
   if(end-begin>0){//"}"が"{"より多い時は階層を戻る
    strcpy_s(buffer,255,key);
    Back=current-(end-begin);
    return true;
   }
 
   if((end-begin==0)&&((begin!=0)&&(end!=0))){//同一階層追加
    node.Next=new NODE(nde);
    node.Next->FrameName=key;
    file_pos=ftell(&fp);
    Load_Mesh(fp,*node.Next);
    fseek( &fp, file_pos, SEEK_SET );
    Load_Frame(fp,*node.Next,current);//再帰呼び出し
   }
   //階層を戻る
   if((Back!=-1)&&(Back<current))return true;
  }
 }
 return true;
}
//階層メッシュ読み込み
bool HIERARCHY::Load_Hierarchy(char* FileName){
 //Xファイルを開いて内容を読み込む
 Back=-1;
 int Hierarchy=0;
 FILE* fp=NULL;
 fopen_s(&fp,FileName,"rt");
 //読み込み
 fseek(fp,0,SEEK_SET);
 Load_Frame(*fp,Root,Hierarchy);
 fseek(fp,0,SEEK_SET);
 Load_Animation(*fp);
 fclose(fp);
 return true;
}

main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#include <GL/freeglut/freeglut.h>
#include "xfile.h"
#include "font.h"

#define WIDTH 640
#define HEIGHT 480

float angle=0.0f;
HIERARCHY* hierarchy;

GLFONT *font;
wstring wstr;
wchar_t wchar[255];
int CurrentFrame;

void display(void)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glViewport(0,0,WIDTH,HEIGHT);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(30.0, WIDTH/HEIGHT, 0.1, 2000.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(-1200.0, 500.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

 //階層アニメーション
 hierarchy->Animation_Draw(0,CurrentFrame);

  glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 glOrtho(0, WIDTH, HEIGHT, 0, -1, 1);

 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 wstr=L"最大フレーム[";
 _itow_s(hierarchy->Animation_MaxFrame,wchar,255,10);
 wstr+=wchar;
 wstr+=L"]";
 font->DrawStringW(0,16,(wchar_t *)wstr.c_str());
 wstr=L"現在のフレーム[";
 _itow_s(CurrentFrame,wchar,255,10);
 wstr+=wchar;
 wstr+=L"]";
 font->DrawStringW(0,32,(wchar_t *)wstr.c_str());

 glutSwapBuffers();
}
void idle(void)
{
 if(hierarchy->Animation_MaxFrame<CurrentFrame)CurrentFrame=0;
 Sleep(1);
 glutPostRedisplay();
}
//タイマー
void timer(int value) {
 CurrentFrame+=30;
 glutTimerFunc(10 , timer , 0);
}

void Init(){
 glClearColor(0.0, 0.0, 0.0, 1.0);
 glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHTING);
 glEnable(GL_CULL_FACE);
 glCullFace(GL_BACK);

 hierarchy = new HIERARCHY("sample4.x",100);
 font = new GLFONT(L"MS明朝", 16);

}
int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("Xの階層メッシュアニメーション読み込み");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 glutTimerFunc(10 , timer , 0);
 Init();
 glutMainLoop();
 return 0;
}

 

 

 

 

最終更新:2014年04月16日 19:32
添付ファイル