.MQOを自力で読み込んでみる3(表示編)

今回は取りあえず、頂点配列で表示してみます。
.MQO の頂点データはインデックスになっていますが UV座標のデータは
インデックスにはなっていないので glDrawElements を使うとテクスチャが
めちゃくちゃになってしまいます。
仕方が無いので glDrawArrays 用に配列データを作成し直して描画
する事にしました。

今回は取りあえず表示するだけという事で法線やライトなどは省略し、VBOにもしていません。
それとテクスチャに使える画像形式はPNGのみです。今の所。
今後はワイヤーフレーム表示とかにも挑戦してみます。

 

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

 MQO.h

#include <string>
#include <vector>
#include "PNG.h"

using namespace std;
//3つのベクトル
struct Vector3f{
 float x;
 float y;
 float z;
};
//4つのベクトル
struct Vector4f{
 float x;
 float y;
 float z;
 float w;
};
//4つの反射
struct Reflection4{
 float diffuse;
 float ambient;
 float emission;
 float specular;
};
//4つのカラー
struct Color4{
 float r;
 float g;
 float b;
 float a;
};
//UV座標
struct UV{
 float u;//u値
 float v;//v値
};
//面情報構造体
struct POLYGON{
 bool Polygon;//3角か4角か true=4;false=3;
 GLuint Index[4];//インデックス
 int MaterialID;//マテリアルNo.
 UV uv[4];//UV情報
};
//ポリゴンデータ
struct GROUP{
 bool Texture_Use;//テクスチャを使うか
 vector<Vector3f> TriVer;//3角頂点データ
 vector<Vector3f> QuadVer;//4角頂点データ
 vector<float> TriUV;//3角UV
 vector<float> QuadUV;//4角UV
}gro;
//オブジェクト構造体
struct OBJECT{
 bool View;//表示するか
 string Name;//オブジェクト名
 vector<GROUP> Group;//マテリアル毎のグループ
}obj;
//マテリアル構造体
struct MATERIAL{
 int MaterialID;//ID
 string MaterialName;//マテリアル名
 Color4 Color;//カラー
 Reflection4 ReflectionColor;//反射
 float Power;//shiness
 string TextureName;//テクスチャ名
}mtl;
//モデルクラス
class MODEL{
protected:
 FILE* fp;//ファイルポインタ
 char buf[255];//読み込み用バッファ
 string str;
 TEXTURE* tex2;
 GLuint texture2;
 //読み込み用
 vector<Vector3f> Vertex;//頂点データ
 POLYGON Poly;//面情報
 void Vertex_Set();//頂点情報セット
 void Material_Set();//マテリアル情報セット
 void Face_Set();//面情報セット
 string Split(string* str,char str1,char str2);//文字列分離
public:
 MODEL();
 MODEL(char* FileName);//コンストラクタ
 vector<MATERIAL> Material;//マテリアル
 vector<OBJECT> Object;//オブジェクトデータ
 vector<TEXTURE*> tex;//テクスチャデータ
 vector<GLuint> texture;//テクスチャID
 bool MQO_Load(char* FileName);//ロード
 void DRAW();//描画
};
MODEL::MODEL(){
}
MODEL::MODEL(char* FileName){
 MQO_Load(FileName);
}
//文字列分離
string MODEL::Split(string *str, char str1, char str2){
 string::size_type start = str->find(str1);
 string::size_type end = str->rfind(str2);
 return str->substr(start+1,end-start-1);
}
//モデル描画
void MODEL::DRAW(){ 
 glEnableClientState(GL_VERTEX_ARRAY);

 for(int i=0;i<(signed)Object.size();i++){
  if(Object[i].View){
  for(int j=0;j<(signed)Object[i].Group.size();j++){
   GLfloat material[] = { Material[j].Color.r, Material[j].Color.g, Material[j].Color.b, Material[j].Color.a };
   glMaterialfv(GL_FRONT, GL_DIFFUSE, material);
   if(Object[i].Group[j].Texture_Use){
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindTexture(GL_TEXTURE_2D, texture[j]);
   }else{
    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   }
   if(0<Object[i].Group[j].TriUV.size())glTexCoordPointer(2,GL_FLOAT,0,&Object[i].Group[j].TriUV[0]);
   if(0<Object[i].Group[j].TriVer.size()){
    glVertexPointer(3,GL_FLOAT,0,&Object[i].Group[j].TriVer[0]);
    glDrawArrays(GL_TRIANGLES,0,Object[i].Group[j].TriVer.size());
   }
   if(0<Object[i].Group[j].QuadUV.size())glTexCoordPointer(2,GL_FLOAT,0,&Object[i].Group[j].QuadUV[0]);
   if(0<(signed)Object[i].Group[j].QuadVer.size()){
    glVertexPointer(3,GL_FLOAT,0,&Object[i].Group[j].QuadVer[0]);
    glDrawArrays(GL_QUADS,0,Object[i].Group[j].QuadVer.size());
   }
  }}
 }
 
 glDisable(GL_TEXTURE_2D);
 glDisableClientState(GL_VERTEX_ARRAY);
 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
//マテリアルセット
void MODEL::Material_Set(){
 int mat;
 fscanf_s(fp, "%d", &mat);//マテリアル数
 fscanf_s(fp, "%s", buf,255);//"{"を読み飛ばす
 for(int i=0;i<mat;i++){
  Material.push_back(mtl);
  fscanf_s(fp, "%s", buf,255);//マテリアル名格納
  str=buf;
  Material[Material.size()-1].MaterialName=Split(&str,'\"','\"');//""を除去
  fgets(buf,255,fp);
  char* buf2;
  if((buf2 = strstr(buf,"col(")) != NULL ){//マテリアルカラー格納
  sscanf_s(buf2,"col(%f %f %f %f)",  &Material[Material.size()-1].Color.r, &Material[Material.size()-1].Color.g,
   &Material[Material.size()-1].Color.b, &Material[Material.size()-1].Color.a);
  }
  if((buf2 = strstr(buf,"dif(")) != NULL ){//ディフューズ格納
   sscanf_s(buf2,"dif(%f)",  &Material[Material.size()-1].ReflectionColor.diffuse);
  }
  if((buf2 = strstr(buf,"amb(")) != NULL ){//アンビエント格納
   sscanf_s(buf2,"amb(%f)",  &Material[Material.size()-1].ReflectionColor.ambient);
  }
  if((buf2 = strstr(buf,"emi(")) != NULL ){//エミッション格納
   sscanf_s(buf2,"emi(%f)",  &Material[Material.size()-1].ReflectionColor.emission);
  }
  if((buf2 = strstr(buf,"spc(")) != NULL ){//スペキュラー格納
   sscanf_s(buf2,"spc(%f)",  &Material[Material.size()-1].ReflectionColor.specular);
  }
  if((buf2 = strstr(buf,"power(")) != NULL ){//shiness格納
   sscanf_s(buf2,"power(%f)",  &Material[Material.size()-1].Power);
  }
  if((buf2 = strstr(buf,"tex(")) != NULL ){//テクスチャ名格納
   sscanf_s(buf2,"tex(%[^)])",buf,255);
   str=buf;
   Material[Material.size()-1].TextureName=Split(&str,'\"','\"');//""を除去

   tex.push_back(tex2);
   tex[Material.size()-1] = new TEXTURE(Material[Material.size()-1].TextureName.c_str());
   texture.push_back(texture2);
   glGenTextures(1, (GLuint *)&texture[Material.size()-1]);

   glBindTexture(GL_TEXTURE_2D, texture[Material.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,tex[Material.size()-1]->Width, tex[Material.size()-1]->Height,
    0,GL_RGBA, GL_UNSIGNED_BYTE, tex[Material.size()-1]->image);
   glDisable(GL_TEXTURE_2D);
  }
 }
}
//頂点情報セット
void MODEL::Vertex_Set(){
 int Vertex_Max;
 Vector3f v;
 fscanf_s(fp, "%d", &Vertex_Max);//頂点数取得
 fscanf_s(fp, "%s", buf,255);//"{"を読み飛ばす
 for(int i=0;i<Vertex_Max;i++){
  fscanf_s(fp,"%f %f %f",&v.x,&v.y,&v.z);
  Vertex.push_back(v);
 }
 fscanf_s(fp, "%s", buf,255);//"}"を読み飛ばす
 fscanf_s(fp, "%s", buf,255);
}
//面情報セット
void MODEL::Face_Set(){
 int Face_Max;
 int Face;
 Vector3f v;
 char* buf2;
 fscanf_s(fp, "%d", &Face_Max);//面数取得
 fscanf_s(fp, "%s", buf,255);//"{"を読み飛ばす
 for(int i=0;i<Face_Max;i++){
  fscanf_s(fp, "%d", &Face);
  if(Face==3){//3角形
   Poly.Polygon=false;
   fgets(buf,255,fp);
   if((buf2 = strstr(buf,"V(")) != NULL ){
    sscanf_s(buf2,"V(%d %d %d)",  &Poly.Index[0],&Poly.Index[1],&Poly.Index[2]);
   }
   if((buf2 = strstr(buf,"M(")) != NULL ){
    sscanf_s(buf2,"M(%d)",  &Poly.MaterialID);
   }
   if((buf2 = strstr(buf,"UV(")) != NULL ){
    sscanf_s(buf2,"UV(%f %f %f %f %f %f)",  &Poly.uv[0].u,&Poly.uv[0].v,
     &Poly.uv[1].u,&Poly.uv[1].v,&Poly.uv[2].u,&Poly.uv[2].v);
   }
   for(int i=0;i<3;i++){
    v=Vertex[Poly.Index[i]];
    Object[Object.size()-1].Group[Poly.MaterialID].TriVer.push_back(v);
    Object[Object.size()-1].Group[Poly.MaterialID].TriUV.push_back(Poly.uv[i].u);
    Object[Object.size()-1].Group[Poly.MaterialID].TriUV.push_back(Poly.uv[i].v);
   }
  }
  if(Face==4){//4角形
   Poly.Polygon=true;
   fgets(buf,255,fp);
   if((buf2 = strstr(buf,"V(")) != NULL ){
    sscanf_s(buf2,"V(%d %d %d %d)",  &Poly.Index[0],&Poly.Index[1],&Poly.Index[2],&Poly.Index[3]);
   }
   if((buf2 = strstr(buf,"M(")) != NULL ){
    sscanf_s(buf2,"M(%d)",  &Poly.MaterialID);
   }
   if((buf2 = strstr(buf,"UV(")) != NULL ){
    sscanf_s(buf2,"UV(%f %f %f %f %f %f %f %f)",  &Poly.uv[0].u,&Poly.uv[0].v,
     &Poly.uv[1].u,&Poly.uv[1].v,&Poly.uv[2].u,&Poly.uv[2].v,&Poly.uv[3].u,&Poly.uv[3].v);
   }
   for(int i=0;i<4;i++){
    v=Vertex[Poly.Index[i]];
    Object[Object.size()-1].Group[Poly.MaterialID].QuadVer.push_back(v);
    Object[Object.size()-1].Group[Poly.MaterialID].QuadUV.push_back(Poly.uv[i].u);
    Object[Object.size()-1].Group[Poly.MaterialID].QuadUV.push_back(Poly.uv[i].v);
   }
  }
 }
 Vertex.clear();
 fscanf_s(fp, "%s", buf,255);//"}"を読み飛ばす
 fscanf_s(fp, "%s", buf,255);
}
//メタセコイアファイル読み込み
bool MODEL::MQO_Load(char* FileName){
 int visible;
 if(fopen_s(&fp,FileName, "r")!=0){return false;}
 while (!feof(fp)) {
  fscanf_s(fp, "%s", buf,255);
  if (!strcmp(buf,"Material")){Material_Set();}
  if (!strcmp(buf,"Object")){
   Object.push_back(obj);
   for(int i=0;i<(signed)Material.size();i++){
    Object[Object.size()-1].Group.push_back(gro);
    if(Material[i].TextureName.length()==0){
     Object[Object.size()-1].Group[i].Texture_Use=false;
    }else{
     Object[Object.size()-1].Group[i].Texture_Use=true;
    }
   }
   fscanf_s(fp, "%s", buf,255);
   Object[Object.size()-1].Name=buf;
   while (!feof(fp)) {
    fscanf_s(fp, "%s", buf,255);
    if (!strcmp(buf,"visible")){
     fscanf_s(fp, "%d", &visible);
     if(visible==0){Object[Object.size()-1].View=false;}else{Object[Object.size()-1].View=true;}
    }
    if (!strcmp(buf,"vertex")){Vertex_Set();}
    if (!strcmp(buf,"face")){Face_Set();}
    if (!strcmp(buf,"}"))break;
   }
  }
 }
 fclose(fp);
 return true;
}



main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#include <GL/freeglut/freeglut.h>
#include "MQO.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, 0.0, 1000.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)
{
 angle+=2.0f;
 Sleep(1);
 glutPostRedisplay();
}
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_FRONT);
 model = new MODEL("sample.mqo");
}
int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("MQOローダ");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 Init();
 glutMainLoop();
 return 0;
}

 

 

 

 

 

 

 

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