.Xを読み込んでみる4(表示編)

前回の読み込み編ではテンプレート無しで3角ポリゴンの Xファイルしか
読み込めませんでしたが、今回はテンプレートを読み飛ばし、3角と4角ポリゴンの
両方の Xファイルを読み込めるようにしました。
Xファイルは作成するソフトによって癖がありますので全ての3Dアプリが作る Xファイルに
対応する事はできません。とりあえずメタセコイアが作る Xファイルに対応しています。

 

PNG.h

#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

#include "PNG.h"

using namespace std;
//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;
}
//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;
//モデルクラス
class MODEL{
protected:
 vector <MATERIAL> Material;//マテリアル
 vector <TEXTURE*> TexData;//テクスチャデータ
 vector<GLuint> TexID;//テクスチャID
 GLuint TexID2;//代入用
 TEXTURE* tex;//代入用
public:
 MODEL();
 MODEL(char* FileName,int size);//コンストラクタ
 bool XFILE_Load(char* FileName,int size);//ロード
 void Draw();
};
MODEL::MODEL(){
}
MODEL::MODEL(char* FileName,int size){
 XFILE_Load(FileName, size);
}
//描画
void MODEL::Draw(){
 glEnableClientState(GL_VERTEX_ARRAY);
 glEnableClientState(GL_NORMAL_ARRAY);
 for(int i=0;i<(signed)Material.size();i++){
  glPushMatrix();
  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,(const GLfloat *)&Material[i].MaterialColor.ambient);
  glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,(const GLfloat *)&Material[i].MaterialColor.diffuse);
  glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat *)&Material[i].MaterialColor.specular);
  glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,Material[i].Shininess);
  if(Material[i].TexNo>0){
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, TexID[Material[i].TexNo-1]);
  }else{
   glDisable(GL_TEXTURE_2D);
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  }
  if(Material[i].Tridata.size()>1){
   glVertexPointer(3, GL_FLOAT,sizeof(Tri) , &Material[i].Tridata[0].TriVer.x);
   glNormalPointer(GL_FLOAT,sizeof(Tri),&Material[i].Tridata[0].TriNor.x);
   if(Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Tri), &Material[i].Tridata[0].TriUV.u);
   glDrawArrays(GL_TRIANGLES,0,Material[i].Tridata.size());
  }
  if(Material[i].Quaddata.size()>1){
   glVertexPointer(3, GL_FLOAT,sizeof(Quad) , &Material[i].Quaddata[0].QuadVer.x);
   glNormalPointer(GL_FLOAT,sizeof(Quad),&Material[i].Quaddata[0].QuadNor.x);
   if(Material[i].TexNo>0)glTexCoordPointer(2, GL_FLOAT, sizeof(Quad), &Material[i].Quaddata[0].QuadUV.u);
   glDrawArrays(GL_QUADS,0,Material[i].Quaddata.size());
  }
  glPopMatrix();
 }
 glDisableClientState(GL_VERTEX_ARRAY);
 glDisableClientState(GL_NORMAL_ARRAY);
 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 glDisable(GL_TEXTURE_2D);
}

//Xファイル読み込み
bool MODEL::XFILE_Load(char* FileName,int size){
 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];
 //Xファイルを開いて内容を読み込む
 FILE* fp=NULL;
 fopen_s(&fp,FileName,"rt");
 
 int v1=0,v2=0,v3=0,v4=0;
 int Count=0;
 bool flag=false;
 string str="";

 //読み込み 
 fseek(fp,SEEK_SET,0);
 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,"Material")==0)
  {
   if(flag)Material.push_back(mtl);
   flag=true;
   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;

   //テクスチャー
   fscanf_s(fp,"%s ",key,sizeof(key)); 
   if(strcmp(key,"TextureFilename")==0)
   {
    fgets(buf,sizeof(buf),fp);//直後の行にあると推定 改行する
    //map_Kd テクスチャー 
    fscanf_s(fp,"%s",buf,255);
    mtl.TextureName=buf;
    str=mtl.TextureName;
    mtl.TextureName=str.substr(str.find_first_of('\"',0)+1,str.find_last_of('\"',255)-1);
     //テクスチャを作成
    TexData.push_back(tex);
    TexData[TexData.size()-1] = new TEXTURE(mtl.TextureName.c_str());;
    mtl.TexNo=TexData.size();
    TexID.push_back(TexID2);
    glGenTextures(1, (GLuint *)&TexID[TexData.size()-1]);
    glBindTexture(GL_TEXTURE_2D, TexID[TexData.size()-1]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  
    glEnable(GL_TEXTURE_2D);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,TexData[TexData.size()-1]->Width, TexData[TexData.size()-1]->Height,
     0,GL_RGBA, GL_UNSIGNED_BYTE, TexData[TexData.size()-1]->image);
    glDisable(GL_TEXTURE_2D); 
   }
  }
  //頂点 読み込み
  if(strcmp(key,"Mesh")==0)
  {
   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 index = str.find("3;");
    if(index-first==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==-1)||(index-first>1)){
     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)
  {
   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 index = str.find("3;");
    if(index-first==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==-1)||(index-first>1)){
     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,"MeshTextureCoords")==0)
  {
   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++)
   {
    fscanf_s(fp,"%f;%f;,",&vec2d.u,&vec2d.v);
    uv.push_back(vec2d);
   }   
  }
  //マテリアルリスト
  if(strcmp(key,"MeshMaterialList")==0)
  {
   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(flag)Material.push_back(mtl);

 fclose(fp);

 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]];
    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]];
    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;
}

main.cpp

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

#define WIDTH 320
#define HEIGHT 240

float angle=0.0f;
MODEL* model;

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(0.0, 500.0, 500.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

 glRotatef(angle,1.0f,0.0f,0.0f);//回転
 glRotatef(angle,0.0f,1.0f,0.0f);//回転

 model->Draw();
 glutSwapBuffers();
}
void idle(void)
{
 glutPostRedisplay();
 angle+=0.2f;
}
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);
 model = new MODEL("sample.x",100);
}
int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutCreateWindow("Xローダ");
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 Init();
 glutMainLoop();
 return 0;
}
 

 

最終更新:2014年12月21日 13:22
添付ファイル