.Xのスキンメッシュアニメーションを読み込んでみる1

階層メッシュクラスを継承してスキンメッシュクラスを作成します。
ジョイントは球でボーンは四角錐にしました。
固定機能:スキニング編『スキンメッシュアニメーションの原理1』で
作成した man.x を表示しています。

Cyberdelia と ToyStudio では出力される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;
 Vector3f(){};
 Vector3f(float _x,float _y,float _z){
  x=_x;y=_y;z=_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;
 Vector4f(){};
 Vector4f(float _x,float _y,float _z,float _w){
  x=_x;y=_y;z=_z;w=_w;
 };
}vec4d;

//正規化
void normalize(Vector3f& v){
 float m=sqrt(v.x*v.x+v.y*v.y+v.z*v.z);
 if(m > 0.0f){m = 1.0f / m;}else{m = 0.0f;}
 v.x*=m;
 v.y*=m;
 v.z*=m;
}
//外積
void cross( Vector3f& src1, Vector3f& src2 ,Vector3f& dst){
 dst.x = src1.y*src2.z - src1.z*src2.y;
 dst.y = src1.z*src2.x - src1.x*src2.z;
 dst.z = src1.x*src2.y - src1.y*src2.x;
}
//内積
void dot(Vector3f& src1,Vector3f& src2,float& dst){
 dst= src1.x*src2.x+src1.y*src2.y+src1.z*src2.z;
}

//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 OUTSIDEMATERIAL{
 string MaterialName;//マテリアル名
 Reflection4 MaterialColor;//反射
 float Shininess;//shininess
 string TextureName;//テクスチャ名
 int TexNo;//テクスチャNO.
}outmtl;
//マテリアル構造体
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;//メッシュ
 vector<GLuint> MatNo;//マテリアルNO.
 ANIMATION Anim;//アニメーションデータ
 MATRIX BoneOfSet;//ボーンオフセット行列
 MATRIX FrameTransformMatrix;//親フレームからのトランスフォーム行列
 bool isBone;//ボーンフラグ
}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,float size);
 NODE Root;//ルートノード
 float Size;//サイズ
 int Animation_MaxFrame;//最大フレーム
private:
 bool Load_Mesh(FILE& fp,NODE& node);//メッシュ読み込み
 QUATERNION Spherical_Linear_Interpolation( QUATERNION& q1, QUATERNION& q2, float t);//球面線形補間
 char buffer[255];
protected:
 void Init();
 bool Load_Hierarchy(char* FileName); //階層メッシュ読み込み
 bool Load_Frame(FILE& fp,NODE& node,int& hierarchy);  //フレーム読み込み
 bool Load_Animation(FILE& fp);//アニメーション読み込み
 vector <string> Bone_Name;
 void Find_Frame(NODE& node,char* name);//フレームを探す
 MATRIX Linear_Interpolation(MATRIX& a,MATRIX& b,float t);//線形補間
 NODE* pNode;//ノードポインタ
 int Back;//階層戻し
 vector<MATRIX> bone_ofset;
 vector<OUTSIDEMATERIAL> OutSide_Mat;
};
//スキンメッシュクラス
class SKINNEDMESH : public HIERARCHY{
 public:
  bool SkinnedMeshFlag;//スキンメッシュか階層メッシュか
  int AnimTicksPerSecond;//一秒間のコマ数
  bool Load_SkinnedMesh(char* FileName, float size);//スキンメッシュ読み込み
  SKINNEDMESH();
  SKINNEDMESH(char* FileName,float size);
  void Draw_Joint(NODE& node,int Frame_Time,MATRIX& mat);//ジョイント描画
  void Draw_Bone(MATRIX& mat1,MATRIX& mat2);//ボーン描画
};
SKINNEDMESH::SKINNEDMESH(){
 SkinnedMeshFlag=false;
 AnimTicksPerSecond=60;
 Size=1;
 Animation_MaxFrame=0;
}
SKINNEDMESH::SKINNEDMESH(char *FileName, float size){
 //階層メッシュアニメーションかスキンメッシュアニメーションかの判定
 char key[255];
 FILE* fp=NULL;
 SkinnedMeshFlag=false;
 AnimTicksPerSecond=60;
 Animation_MaxFrame=0;
 fopen_s(&fp,FileName,"rt");
 //読み込み
 fseek(fp,0,SEEK_SET);
 while(!feof(fp)){
  //キーワード 読み込み
  ZeroMemory(key,sizeof(key));
  fscanf_s(fp,"%s ",key,sizeof(key));
  //テンプレート読み飛ばし
  if(strcmp(key,"template")==0){
   while(strcmp(key,"}")){
    fscanf_s(fp,"%s ",key,sizeof(key));
   }
   continue;
  }
  if(strcmp(key,"AnimTicksPerSecond")==0){
   fgets(key,sizeof(key),fp);
   fscanf_s(fp,"%d;",&AnimTicksPerSecond);
  }
  if((strcmp(key,"FrameTransformMatrix")==0)||(strcmp(key,"XSkinMeshHeader")==0)||
   (strcmp(key,"VertexDuplicationIndices")==0)||(strcmp(key,"SkinWeights")==0)){
    SkinnedMeshFlag=true;
  }
 }
 if(SkinnedMeshFlag){//スキンメッシュアニメーションなら
  Init();
  Size=size;
  Load_SkinnedMesh(FileName,size);
 }else{//階層メッシュアニメーションなら
 Init();
 Size=size;
 this->Load_Hierarchy(FileName);
 }
}

//ボーン描画
void SKINNEDMESH::Draw_Bone(MATRIX& mat1,MATRIX& mat2){
 glColor4f(0.0f,1.0f,1.0f,1.0f);
 glPushMatrix();
 glTranslatef(mat1._41,mat1._42,mat1._43);
 float length=-sqrt((mat1._41-mat2._41)*(mat1._41-mat2._41)+(mat1._42-mat2._42)*(mat1._42-mat2._42)+(mat1._43-mat2._43)*(mat1._43-mat2._43));
 if(mat1._41+mat1._42+mat1._43==0.0f)length=sqrt(mat2._41*mat2._41)+sqrt(mat2._42*mat2._42)+sqrt(mat2._43*mat2._43);
 if(mat1._41+mat1._42+mat1._43!=0){
  glRotatef(90.0f,0.0f,0.0f,1.0f);
  glRotatef(-90.0f,mat2._41-mat1._41,mat2._42-mat1._42,mat2._43-mat1._43);
  glutSolidCone(10.0f*Size, length, 4, 1);
 }
 glPopMatrix();
}
//ジョイント描画
void SKINNEDMESH::Draw_Joint(NODE& node,int Frame_Time,MATRIX& mat){
 glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
 glEnable(GL_COLOR_MATERIAL);
 MATRIX current=mat;
 while(1){
  if(node.isBone){
   glPushMatrix();
   mat=mat.Multiplication(node.FrameTransformMatrix);
   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(&mat.mat_16[0]);
     //glMultMatrixf(&Linear.mat_16[0]);
    }
   }
   glColor4f(1.0f,1.0f,0.0f,1.0f);
   glutSolidSphere(5.0*Size,8,8);
   glPopMatrix();
   Draw_Bone(current,mat);
  }

  if(node.Node!=NULL)Draw_Joint(*node.Node,Frame_Time,mat);
  if(node.Next!=NULL)Draw_Joint(*node.Next,Frame_Time,current);
  return;
 }
 return;
 glDisable(GL_COLOR_MATERIAL);
}

 

bool SKINNEDMESH::Load_SkinnedMesh(char *FileName, float size){
 //Xファイルを開いて内容を読み込む
 Back=-1;
 int Hierarchy=0;
 FILE* fp=NULL;
 fopen_s(&fp,FileName,"rt");
 //読み込み
 fseek(fp,0,SEEK_SET);
 Load_Frame(*fp,Root,Hierarchy);
 //ボーンフラグセット
 for(int i=0;i<(signed)Bone_Name.size();i++){
  Find_Frame(Root,(char*)Bone_Name[i].c_str());
  pNode->isBone=true;
  pNode->BoneOfSet=bone_ofset[i];
 }
 Bone_Name.clear();
 bone_ofset.clear();
 fseek(fp,0,SEEK_SET);
 this->Load_Animation(*fp);
 fclose(fp);

 return true;
}

//コンストラクタ
HIERARCHY::HIERARCHY(){
 Init();
}
//コンストラクタ
HIERARCHY::HIERARCHY(char* FileName,float size){
 Init();
 Size=size;
 Animation_MaxFrame=0;
 Load_Hierarchy(FileName);
}
//初期化
void HIERARCHY::Init(){
 Root.Node=NULL;
 Root.Next=NULL;
 Root.FrameName="Root";
 Root.Mesh=NULL;
 Root.isBone=false;
}

//球面線形補間
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];
 char *next;
 int hierarchy=0,count=0,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));
    //テンプレート読み飛ばし
  if(strcmp(buf,"template")==0){
   while(strcmp(buf,"}")){
    fscanf_s(&fp,"%s ",buf,sizeof(buf));
   }
   continue;
  }
  //AnimationSetを探す
  if(strcmp(buf,"AnimationSet")==0){
    while(!feof(&fp))
    {
     fgets(buf,sizeof(buf),&fp);
     if((!strstr(buf,"Animation")==NULL)&&(strstr(buf,"Animation_")==NULL)){
      fgets(buf,sizeof(buf),&fp);
      fgets(buf,sizeof(buf),&fp);
      if((!strstr(buf,"{")==NULL)&&(!strstr(buf,"}")==NULL)){//名前の抽出
       sscanf_s(buf," { %s } ",&name,sizeof(name));
       strtok_s( name, "}" ,&next);
       pNode=NULL;
       Find_Frame(Root,name);
       while(!feof(&fp)){
        fgets(buf,sizeof(buf),&fp);
      if(!strstr(buf,"AnimationKey")==NULL){
       fgets(buf,sizeof(buf),&fp);
       fgets(buf,sizeof(buf),&fp);//キータイプ 4…行列タイプ]
       if(strstr(buf,"4;")==NULL)printf("対応していません");
       fgets(buf,sizeof(buf),&fp);//キー数
       count=atoi(buf);
       for(int i=0;i<count;i++){
        fscanf_s(&fp,"%d;%d;",&key,&dummy);//キーの位置;データの数
        if((count-1==i)&&(Animation_MaxFrame<key))Animation_MaxFrame=key;
        pNode->Anim.Key.push_back(key);
        if(dummy!=16)printf("対応していません");
        fscanf_s(&fp,"%f,%f,%f,%f,",&mix.mat_16[0],&mix.mat_16[1],&mix.mat_16[2],&mix.mat_16[3]);
        fscanf_s(&fp,"%f,%f,%f,%f,",&mix.mat_16[4],&mix.mat_16[5],&mix.mat_16[6],&mix.mat_16[7]);
        fscanf_s(&fp,"%f,%f,%f,%f,",&mix.mat_16[8],&mix.mat_16[9],&mix.mat_16[10],&mix.mat_16[11]);
        fscanf_s(&fp,"%f,%f,%f,%f;;",&mix.mat_16[12],&mix.mat_16[13],&mix.mat_16[14],&mix.mat_16[15]);
        fgets(buf,sizeof(buf),&fp);
        mix._41*=Size;
        mix._42*=Size;
        mix._43*=Size;
        pNode->Anim.Matrix.push_back(mix);
       }
      }
       }
      }
     }
    }
  }
 }
 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,matCount=0,Hierarchy=1;
 string str="";
 fscanf_s(&fp,"%s ",key,sizeof(key));
 //読み込み
 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;
    if(Vertex.size()>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]];
       if(MaterialIndex[i]>=(signed)node.Mesh->Material.size()){
        mtl.MaterialName=this->OutSide_Mat[MaterialIndex[i]].MaterialName;
        mtl.MaterialColor=this->OutSide_Mat[MaterialIndex[i]].MaterialColor;
        mtl.Shininess=this->OutSide_Mat[MaterialIndex[i]].Shininess;
        node.Mesh->Material.push_back(mtl);
       }
       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;
     }
    }
       }else{
    node.Mesh=NULL;
   }
    Vertex.clear();
    Normal.clear();
    uv.clear();
    VertexIndex.clear();
    NormalIndex.clear();
    MaterialIndex.clear();
    FaceIndex.clear();
    return true;
   }
  }
 
  if(strcmp(key,"Frame")==0){
   Count=0;
   if(Vertex.size()>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;
     }
    }
       }else{
    node.Mesh=NULL;
   }
    Vertex.clear();
    Normal.clear();
    uv.clear();
    VertexIndex.clear();
    NormalIndex.clear();
    MaterialIndex.clear();
    FaceIndex.clear();
    return true;
  }
 
  //頂点 読み込み
  if(strcmp(key,"Mesh")==0)
  {
   node.Mesh =new MESH(msh);
   Hierarchy++;
   fgets(buf,sizeof(buf),&fp);
   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);
   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);
   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);
   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);//マテリアル数
   matCount=atoi(buf);
   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);
   }
   char *next;
   for(int i=0;i<matCount;i++)
   {
    fgets(buf,sizeof(buf),&fp);
 sscanf_s(buf," { %s } ",&buf,sizeof(buf));
 strtok_s( buf, "}" ,&next);
 for(int j=0;j<(signed)this->OutSide_Mat.size();j++){
  if(strcmp(this->OutSide_Mat[j].MaterialName.c_str(),buf)==0)node.MatNo.push_back(j);
 }
   }
  }
 }
 return false;
}
//フレーム読み込み
bool HIERARCHY::Load_Frame(FILE& fp,NODE& node,int& hierarchy){
 char key[255];
 char *next;
 int begin=0,end=0;
 int current=hierarchy;//現在の階層
 int file_pos;
 int count;
 MATRIX dum;

 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,"Material")==0)
  {
   begin++;
   fgets(key,sizeof(key),&fp);
   strtok_s( key, "\n" ,&next);
   outmtl.MaterialName=key;
   fgets(key,sizeof(key),&fp);
   //ディフューズ
   fscanf_s(&fp,"%f;%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z,&vec4d.w);
   outmtl.MaterialColor.diffuse=(const Color4 &)vec4d;
   //SHININESS 
   fscanf_s(&fp,"%f;",&outmtl.Shininess);
   //スペキュラー
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   outmtl.MaterialColor.specular=(const Color4 &)vec4d;
   //エミッシブ
   fscanf_s(&fp,"%f;%f;%f;;",&vec4d.x,&vec4d.y,&vec4d.z);
   outmtl.MaterialColor.ambient=(const Color4 &)vec4d;

   this->OutSide_Mat.push_back(outmtl);
  }
  //ボーン
  if(strcmp(key,"SkinWeights")==0){
   begin++;
   fgets(key,sizeof(key),&fp);
   fscanf_s(&fp,"%s;",key,sizeof(key));
   sscanf_s(key,"\"%s\";",&key,sizeof(key));
   strtok_s( key, "\"" ,&next);
   Bone_Name.push_back(key);
   fgets(key,sizeof(key),&fp);
   fgets(key,sizeof(key),&fp);
   count=atoi(key);
   for(int i=0;i<count*2;i++){fgets(key,sizeof(key),&fp);}
   fscanf_s(&fp,"%f,%f,%f,%f,",&dum.mat_16[0],&dum.mat_16[1],&dum.mat_16[2],&dum.mat_16[3]);
   fscanf_s(&fp,"%f,%f,%f,%f,",&dum.mat_16[4],&dum.mat_16[5],&dum.mat_16[6],&dum.mat_16[7]);
   fscanf_s(&fp,"%f,%f,%f,%f,",&dum.mat_16[8],&dum.mat_16[9],&dum.mat_16[10],&dum.mat_16[11]);
   fscanf_s(&fp,"%f,%f,%f,%f;;",&dum.mat_16[12],&dum.mat_16[13],&dum.mat_16[14],&dum.mat_16[15]);
   bone_ofset.push_back(dum);
  }
  //親フレームからのトランスフォーム行列
  if(strcmp(key,"FrameTransformMatrix")==0){
   begin++;
   fgets(key,sizeof(key),&fp);
   fscanf_s(&fp,"%f,%f,%f,%f,",&node.FrameTransformMatrix.mat_16[0],&node.FrameTransformMatrix.mat_16[1],&node.FrameTransformMatrix.mat_16[2],&node.FrameTransformMatrix.mat_16[3]);
   fscanf_s(&fp,"%f,%f,%f,%f,",&node.FrameTransformMatrix.mat_16[4],&node.FrameTransformMatrix.mat_16[5],&node.FrameTransformMatrix.mat_16[6],&node.FrameTransformMatrix.mat_16[7]);
   fscanf_s(&fp,"%f,%f,%f,%f,",&node.FrameTransformMatrix.mat_16[8],&node.FrameTransformMatrix.mat_16[9],&node.FrameTransformMatrix.mat_16[10],&node.FrameTransformMatrix.mat_16[11]);
   fscanf_s(&fp,"%f,%f,%f,%f;;",&node.FrameTransformMatrix.mat_16[12],&node.FrameTransformMatrix.mat_16[13],&node.FrameTransformMatrix.mat_16[14],&node.FrameTransformMatrix.mat_16[15]);
   node.FrameTransformMatrix._41*=Size;
   node.FrameTransformMatrix._42*=Size;
   node.FrameTransformMatrix._43*=Size;
  }
 
  //フレーム
  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;
    node.Node->isBone=false;
    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;
    node.Next->isBone=false;
    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;
    node.Next->isBone=false;
    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;
SKINNEDMESH* SkinMesh;

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

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, 5000.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(-1000.0, 300.0, 200.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

 glRotatef(angle, 0.0f, 1.0f, 0.0f);
 SkinMesh->Animation_Draw(0,CurrentFrame);


 glDisable(GL_LIGHTING);
 glDisable(GL_DEPTH_TEST);
 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 SkinMesh->Animation_Draw(0,CurrentFrame);
 SkinMesh->Draw_Joint(SkinMesh->Root,CurrentFrame,mat);
 glEnable(GL_DEPTH_TEST);
 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 glEnable(GL_LIGHTING);

 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(SkinMesh->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)
{
 glutPostRedisplay();
}
//タイマー
void timer(int value) {
 angle+=1.0f;
 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);

 SkinMesh = new SKINNEDMESH("man.x",1.0f);
 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(100 , timer , 0);
 Init();
 glutMainLoop();
 return 0;
}

最終更新:2014年04月17日 00:29
添付ファイル