「OpenGLプログラミングメモ」というサイトを参考にC/C++およびOpenGLの勉強をしているのですが、モデルテクスチャの表示で躓いています。
プログラムを実行するとモデルの表示はされるのですがテクスチャの表示がされず、その原因が分からず困っています。
ModelHandler.h
#ifndef MODELHANDLER
#define MODELHANDLER
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <GL/glut.h>
#include <Windows.h>
#include <vector>
#include "math.h"
#include "LoadTexture.h"
using namespace std;
/*****************************************************************************
* モデル処理全般をこなすクラス
*****************************************************************************/
class ModelHandler
{
public:
// ======================================================================
// 関数
//=======================================================================
ModelHandler(char *name, int size);
~ModelHandler();
void draw(); // モデルの表示関数
private:
// ======================================================================
// 構造体
//=======================================================================
// 三角ポリゴンデータ
typedef struct _TRIANGLE
{
VECTOR3F triVer; // 頂点情報
VECTOR3F triNor; // 法線情報
VECTOR2F triUV; // テクスチャ座標
} TRIANGLE;
// 四角ポリゴンデータ
typedef struct _QUADANGLE
{
VECTOR3F quadVer; // 頂点情報
VECTOR3F quadNor; // 法線情報
VECTOR2F quadUV; // テクスチャ座標
} QUADANGLE;
// 光データ
typedef struct _REFLECTION
{
VECTOR4F diffuse; // 拡散光
VECTOR3F emission; // 放射光
VECTOR3F specular; // 鏡面反射光
} REFLECTION;
// ポリゴンデータ
typedef struct _POLYGON
{
float shininess; // 光の強さ
REFLECTION materialColor; // 光データ
char *texName; // テクスチャ名
int texNo; // テクスチャ番号
vector<TRIANGLE> tridata; // 三角ポリゴンだった場合の格納先
vector<QUADANGLE> quaddata; // 四角ポリゴンだった場合の格納先
} POLYGON;
//=======================================================================
// 関数
//=======================================================================
void load(char *name, int size); // ファイル読み込み関数
VECTOR3F changeSize(VECTOR3F &v, float size); // モデルサイズの変更
//=======================================================================
// 変数
//=======================================================================
vector<POLYGON> polygon; // ポリゴンデータ(ポリゴン毎にマテリアルが違うので配列で分けてる)
vector<LoadTexture *> texData; // テクスチャ用変数
vector<GLuint> texID; // テクスチャID
};
#endif
#include "ModelHandler.h"
//----------------------------------------------------------------------------------
// コンストラクタ
//----------------------------------------------------------------------------------
ModelHandler :: ModelHandler(char *name, int size)
{
load(name, size);
}
//----------------------------------------------------------------------------------
// xファイル読み込み
//----------------------------------------------------------------------------------
void ModelHandler :: load(char *name, int size)
{
POLYGON plg = {0};
vector<VECTOR3F> vertex;
vector<VECTOR3F> normal;
vector<VECTOR2F> uv;
vector<int> faceIndex;
vector<int> vertexIndex;
vector<int> normalIndex;
vector<int> materialIndex;
char buf[256]; // ファイル読み込み用バッファ
FILE *xFile = NULL;
try
{
fopen_s(&xFile, name, "r");
if(NULL == xFile) throw "ModelFile not found";
fseek(xFile, 0, SEEK_SET);
// ファイルの読み込み開始
while(!feof(xFile))
{
fscanf_s(xFile, "%s", &buf, sizeof(buf));
// テンプレート回避
if(0 == strcmp(buf, "template"))
{
fgets(buf, sizeof(buf), xFile);
}
// 頂点の読み込み------------------------------------------------------
if(0 == strcmp(buf, "Mesh"))
{
fgets(buf, sizeof(buf), xFile);
fgets(buf, sizeof(buf), xFile);
// 頂点数の読み込み
int count = atoi(buf);
VECTOR3F v; // 頂点情報の一時格納先
// 頂点の読み込み
for(int i = 0; i < count; i++)
{
fscanf_s(xFile, "%f;%f;%f;,", &v.x, &v.y, &v.z);
vertex.push_back(changeSize(v, (float)size));
}
fgets(buf, sizeof(buf), xFile);
fscanf_s(xFile, "%d", &count); // 総インデックス数の読み込み
fgets(buf, sizeof(buf), xFile);
// 面インデックスの読み込み
int dummy, v1, v2, v3, v4;
for(int i = 0; i < count; i++)
{
// インデックス数の読み込み
fscanf_s(xFile, "%d;", &dummy);
faceIndex.push_back(dummy);
// インデックスの読み込み
if(3 == dummy)
{
fscanf_s(xFile, "%d,%d,%d;,", &v1, &v2, &v3);
vertexIndex.push_back(v1);
vertexIndex.push_back(v2);
vertexIndex.push_back(v3);
}
if(4 == dummy)
{
fscanf_s(xFile, "%d,%d,%d,%d;,", &v1, &v2, &v3, &v4);
vertexIndex.push_back(v1);
vertexIndex.push_back(v2);
vertexIndex.push_back(v3);
vertexIndex.push_back(v4);
}
}
}
// 法線の読み込み---------------------------------------------------------
if(0 == strcmp(buf, "MeshNormals"))
{
fgets(buf, sizeof(buf), xFile);
fgets(buf, sizeof(buf), xFile);
// 法線数の読み込み
int count = atoi(buf);
VECTOR3F v; // 法線の一時格納先
// 法線の読み込み
for(int i = 0; i < count; i++)
{
fscanf_s(xFile, "%f;%f;%f;,", &v.x, &v.y, &v.z);
normal.push_back(v);
}
fgets(buf, sizeof(buf), xFile);
fscanf_s(xFile, "%d;", &count); //総インデックス数の読み込み
fgets(buf, sizeof(buf), xFile);
// 法線インデックスの読み込み
int dummy, v1, v2, v3, v4;
for(int i = 0; i < count; i++)
{
// インデックス数の読み込み
fscanf_s(xFile, "%d;", &dummy);
// インデックスの読み込み
if(3 == dummy)
{
fscanf_s(xFile, "%d,%d,%d;,", &v1, &v2, &v3);
normalIndex.push_back(v1);
normalIndex.push_back(v2);
normalIndex.push_back(v3);
}
if(4 == dummy)
{
fscanf_s(xFile, "%d,%d,%d,%d;,", &v1, &v2, &v3, &v4);
normalIndex.push_back(v1);
normalIndex.push_back(v2);
normalIndex.push_back(v3);
normalIndex.push_back(v4);
}
}
}
// テクスチャ座標の読み込み---------------------------------------------
if(0 == strcmp(buf, "MeshTextureCoords"))
{
fgets(buf, sizeof(buf), xFile);
fgets(buf, sizeof(buf), xFile);
int count = atoi(buf); // テクスチャ座標数の読み込み
VECTOR2F v; // テクスチャ座標の一時格納先
// テクスチャ座標の読み込み
for(int i = 0; i < count; i++)
{
fscanf_s(xFile, "%f;%f;,", &v.u, &v.v);
v.v *= -1;
uv.push_back(v);
}
}
// マテリアルリストの読み込み-------------------------------------------
if(0 == strcmp(buf, "MeshMaterialList"))
{
fgets(buf, sizeof(buf), xFile);
fgets(buf, sizeof(buf), xFile);
fgets(buf, sizeof(buf), xFile);
int dummy, nMaterialIndex;
nMaterialIndex = atoi(buf); // 総インデックス数の読み込み
// マテリアルインデックスの読み込み
for(int i = 0; i < nMaterialIndex; i++)
{
fscanf_s(xFile, "%d,", &dummy);
materialIndex.push_back(dummy);
}
}
// マテリアルの読み込み--------------------------------------------------
if(0 == strcmp(buf, "Material"))
{
fgets(buf, sizeof(buf), xFile);
// 拡散光(Diffuse)の読み込み
fscanf_s(xFile, "%f;%f;%f;%f;;",
&plg.materialColor.diffuse.x,
&plg.materialColor.diffuse.y,
&plg.materialColor.diffuse.z,
&plg.materialColor.diffuse.w);
// 反射光の強さ(Shininess)の読み込み
fscanf_s(xFile, "%f;", &plg.shininess);
// 反射光(Specular)の読み込み
fscanf_s(xFile, "%f;%f;%f;;",
&plg.materialColor.specular.x,
&plg.materialColor.specular.y,
&plg.materialColor.specular.z);
// 放射光(Emission)の読み込み
fscanf_s(xFile, "%f;%f;%f;;",
&plg.materialColor.emission.x,
&plg.materialColor.emission.y,
&plg.materialColor.emission.z);
fscanf_s(xFile,"%s ",&buf, sizeof(buf));
// テクスチャの読み込み
if(0 == strcmp(buf, "TextureFilename"))
{
fgets(buf, sizeof(buf), xFile);
// テクスチャ名の読み込み
fscanf_s(xFile, " \"%[^\"]", &buf, sizeof(buf));
plg.texName = new char[strlen(buf) + 1]; // テクスチャ名+終端文字分のメモリ確保
strcpy(plg.texName, buf);
// パスの生成(テクスチャファイルがあるフォルダへのパスを作る)
const char *basePath = ".\\\\リソース\\\\"; // 基本パス
size_t len = strlen(basePath) + strlen(plg.texName);
char *nameBuf = new char[len + 1];
nameBuf[len] = 0;
strcpy(nameBuf, basePath);
strcat(nameBuf, plg.texName); // パスの合成
// テクスチャファイルの読み込み
GLuint texID2; // 代入用ダミー変数
LoadTexture *tex; // 代入用ダミー変数
texData.push_back(tex); // 格納するための空の要素を用意
texData[texData.size() - 1] = new LoadTexture(nameBuf); // テクスチャデータを格納する
plg.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_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glEnable(GL_TEXTURE_2D);
// テクスチャの関連付け
glTexImage2D(
GL_TEXTURE_2D, // テクスチャの次元数
0, // 詳細レベル番号
GL_RGB, // テクスチャのカラー要素数
texData[texData.size() - 1]->GetSize().w, // テクスチャの幅
texData[texData.size() - 1]->GetSize().h, // テクスチャの高さ
0, // テクスチャの境界幅
GL_BGRA_EXT, // ピクセルデータのフォーマット
GL_UNSIGNED_BYTE, // データ型
texData[texData.size() - 1]->GetPixels()); // ピクセルデータの保管場所
glDisable(GL_TEXTURE_2D);
}
polygon.push_back(plg); // ポリゴンの要素を増やす
}
}
int count = 0;
TRIANGLE tri;
QUADANGLE quad;
// ポリゴンをマテリアルごとに分ける------------------------------------------
for(int i = 0; i < (signed)materialIndex.size(); i++)
{
if(3 == faceIndex[i])
{
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]];
polygon[materialIndex[i]].tridata.push_back(tri);
}
count += 3;
}
if(4 == faceIndex[i])
{
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]];
polygon[materialIndex[i]].quaddata.push_back(quad);
}
count += 4;
}
}
if(NULL != plg.texName)
{
delete plg.texName;
}
vertex.clear();
normal.clear();
uv.clear();
faceIndex.clear();
vertexIndex.clear();
normalIndex.clear();
materialIndex.clear();
fclose(xFile);
}
catch(char *e)
{
cout << e << endl;
}
}
//--------------------------------------------------------------------------------------
// モデルの表示
//--------------------------------------------------------------------------------------
void ModelHandler :: draw()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
for(int i = 0; i < (signed)polygon.size(); i++)
{
glPushMatrix();
{
glMaterialfv(GL_FRONT, GL_DIFFUSE, (const GLfloat *)&polygon[i].materialColor.diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, (const GLfloat *)&polygon[i].materialColor.specular);
glMaterialfv(GL_FRONT, GL_SHININESS, &polygon[i].shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, (const GLfloat *)&polygon[i].materialColor.emission);
if(0 < polygon[i].texNo)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID[polygon[i].texNo - 1]);
}
else
{
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if(1 < polygon[i].tridata.size())
{
glVertexPointer(3, GL_FLOAT, sizeof(TRIANGLE), &polygon[i].tridata[0].triVer.x);
glNormalPointer(GL_FLOAT, sizeof(TRIANGLE), &polygon[i].tridata[0].triNor.x);
if(0 < polygon[i].texNo)
glTexCoordPointer(2, GL_FLOAT, sizeof(TRIANGLE), &polygon[i].tridata[0].triUV.u);
glDrawArrays(GL_TRIANGLES, 0, polygon[i].tridata.size());
}
if(1 < polygon[i].quaddata.size())
{
glVertexPointer(3, GL_FLOAT, sizeof(QUADANGLE), &polygon[i].quaddata[0].quadVer.x);
glNormalPointer(GL_FLOAT, sizeof(QUADANGLE), &polygon[i].quaddata[0].quadNor.x);
if(0 < polygon[i].texNo)
glTexCoordPointer(2, GL_FLOAT, sizeof(QUADANGLE), &polygon[i].quaddata[0].quadUV.u);
glDrawArrays(GL_QUADS, 0, polygon[i].quaddata.size());
}
}
glPopMatrix();
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
//--------------------------------------------------------------------------------------
// モデルサイズの変更
//--------------------------------------------------------------------------------------
VECTOR3F ModelHandler::changeSize(VECTOR3F &v, float size)
{
v.x *= size;
v.y *= size;
v.z *= size;
return v;
}
#ifndef _LOADTEXTURE
#define _LOADTEXTURE
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include "Math.h"
using namespace std;
class LoadTexture
{
public:
//============================================================
// 関数
//============================================================
LoadTexture(char *name);
~LoadTexture();
unsigned char *GetPixels();
VECTOR2L GetSize();
private:
//============================================================
// 関数
//============================================================
void Load_BMP(char *name);
//============================================================
// 変数
//============================================================
BITMAPINFOHEADER bi;
unsigned char *pixels;
VECTOR2L texSize;
};
#endif
#include "LoadTexture.h"
LoadTexture::LoadTexture(char *name)
{
Load_BMP(name);
}
void LoadTexture::Load_BMP(char *name)
{
// テクスチャファイルの読み込み
FILE *texFile;
try
{
fopen_s(&texFile, name, "rb");
// 例外処理
if(NULL == texFile) throw "TextureFile not found";
// ファイルヘッダの読み込み
BITMAPFILEHEADER bf;
fread_s(&bf, sizeof(BITMAPFILEHEADER), sizeof(BITMAPFILEHEADER), 1, texFile);
// 情報ヘッダの読み込み
fread_s(&bi, sizeof(BITMAPINFOHEADER), sizeof(BITMAPINFOHEADER), 1, texFile);
// 画像データの読み込み
long pixSize = bi.biWidth * bi.biHeight * 3;
pixels = new unsigned char[pixSize];
fread_s(pixels, pixSize, pixSize, 1, texFile);
fclose(texFile);
}
catch (char *e)
{
cout << e << endl;
getchar();
}
}
unsigned char *LoadTexture::GetPixels()
{
return pixels;
}
VECTOR2L LoadTexture::GetSize()
{
texSize.w = bi.biWidth;
texSize.h = bi.biHeight;
return texSize;
}
あと、余談なのですがglutを使用したプログラムでウィンドウを閉じたとき、動的に確保したメモリはどこで開放すれば良いのでしょうか。