注意すべき点としては以下の二つでしょうか。
まず、画面を消去する命令を呼んでいませんから、毎フレーム描画すると前の画面に上書きすることになり地獄絵図になります。
そこで、glClear(GL_COLOR_BUFFER_BIT);を呼び出して画面を消去するようにしましょう。
次に、画像ファイルをロードする部分ですが、さっきのサイトのコードをそのままコピペしても期待する結果が得られるわけがありません。
画像の読み込みは自力で行い、RGBの羅列又はRGBAの羅列をglTexImage2D関数の最後の引数にぶち込みましょう。
もちろんそれに合わせてGL_RGBAをGL_RGBに変える作業も忘れてはいけません。
とりあえず私が作ったコードを載せておきます。
ちなみに対応画像の形式は24bitビットマップイメージのみです。
► スポイラーを表示
WinMain.cpp
texture.h
texture.cpp
#include
#include
#pragma comment(lib, "glfw3.lib")
#pragma comment(lib, "glfw3dll.lib")
#pragma comment(lib, "opengl32.lib")
#pragma warning(disable:4098)
#pragma warning(disable:4996)
#include "texture.h"
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC)
{
const int windowW = 640;
const int windowH = 480;
if (glfwInit() == GL_FALSE)
{
glfwTerminate();
return -1;
}
GLFWwindow * pWindow = glfwCreateWindow(windowW, windowH, "OpenGL Window", NULL, NULL);
if (pWindow == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(pWindow);
glfwSwapInterval(1); // 垂直同期信号を1回待つ設定にする
// 描画範囲の指定
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowW, 0.0f, windowH, -1.0f, 1.0f);
GLuint id = LoadTexture("texture.bmp");
float degree = 0.0f;
while(glfwWindowShouldClose(pWindow) == 0)
{
glClear(GL_COLOR_BUFFER_BIT);
const float x = 200.0f;
const float y = 120.0f;
const float width = 308.0f;
const float height = 231.0f;
static const GLfloat vtx[] = {
x, y,
x+width, y,
x+width, y+height,
x, y+height,
};
glVertexPointer(2, GL_FLOAT, 0/*配列のオフセット*/, vtx);
// Step5. テクスチャの領域指定
static const GLfloat texuv[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};
glTexCoordPointer(2, GL_FLOAT, 0, texuv);
// Step6. テクスチャの画像指定
glBindTexture(GL_TEXTURE_2D, id);
// Step7. テクスチャの描画
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
glfwSwapBuffers(pWindow);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
#pragma once
//==========================================
// 関数 : LoadTexture
// 目的 : テクスチャデータのロード
// 戻り値: GLuint テクスチャID
// 引数 : const char *pszFName ファイル名
//==========================================
unsigned int LoadTexture(const char *pszFName);
//==========================================
// 関数 : ReleaseTexture
// 目的 : テクスチャデータの解放
// 戻り値: なし
// 引数 : GLuint uTexID テクスチャID
//==========================================
void ReleaseTexture(unsigned int uTexID);
// インクルード
#include
#include
#include
#include "Texture.h"
#include
#pragma comment(lib, "glfw3.lib")
#pragma comment(lib, "glfw3dll.lib")
#pragma comment(lib, "opengl32.lib")
#pragma warning(disable:4098)
#pragma warning(disable:4996)
// 定数定義
#define FILE_HEADER_BYTE (14)
#define BYTE_OF_INFO_HEADER_SIZE (4)
#define SIZE_OF_CORE_HEADER (12)
#define SIZE_OF_INFO_HEADER (40)
//==================================================
// 構造体定義
//==================================================
struct TBMPImage
{
int nWidth; // 画像の横幅(ピクセル数)をここに格納してください
int nHeight; // 画像の縦幅(ピクセル数)をここに格納してください。マイナス値を格納すると、RGB情報が上から下に向かって格納されていると判断されます
unsigned char * pbyPixels; // RGB情報を格納するメモリ領域をmallocで確保し、その先頭アドレスをここに格納してください
/*
* R,G,Bはそれぞれ1バイトです
* R→G→B→R→G→B→R…となるようにデータを格納してください
* 気を使って2次元配列にする必要はありません
*/
BOOL bEffective; // TRUE...対応可能ファイル形式 FALSE...対応不可ファイル形式
//********************************************************************
// 必要があればここに構造体のメンバを記述
};
//==========================================
// 関数 : LoadHeader
// 目的 : BMPファイルのファイルヘッダ部の読み込み
// 戻り値: BOOL 成功...TRUE, 失敗...FALSE
// 引数 : FILE * pf ファイルポインタ
//==========================================
BOOL LoadHeader(FILE * pf);
//==========================================
// 関数 : LoadInfo
// 目的 : BMPファイルの情報ヘッダ部の読み込み
// 戻り値: BOOL 成功...TRUE, 失敗...FALSE
// 引数 : FILE * pf ファイルポインタ
// int * pnWidth 横幅を格納したい変数へのアドレス
// int * pnHeight 縦幅を格納したい変数へのアドレス
// unsigned short * pwBitCount ビット数を格納したい変数へのアドレス
// unsigned long * pdwCompression 圧縮情報を格納したい変数へのアドレス
//==========================================
BOOL LoadInfo(FILE * pf, int * pnWidth, int * pnHeight, unsigned short * pwBitCount, unsigned long * pdwCompression);
//==========================================
// 関数 : ComputePaddingByte
// 目的 : 不要なデータのバイト数を求めてそれを返す
// 戻り値: long 不要なデータのバイト数
// 引数 : int nWidth 画像の横幅(ピクセル数)
//==========================================
long ComputePaddingByte(int nWidth);
//==========================================
// 関数 : BGR_to_RGB
// 目的 : BGRの順に並んでいる色情報をRGBの順に並べ替える
// 戻り値: なし
// 引数 : unsigned char * pbyRGBDatas RGB情報が格納されたメモリの先頭アドレス
// unsigned int uPixelNum 画像の総ピクセル数
//==========================================
void BGR_to_RGB(unsigned char * pbyRGBDatas, unsigned int uPixelNum);
//==========================================
// 関数 : LoadRGB
// 目的 : RGB情報を読み込む
// 戻り値: unsigned char * RGB情報が格納されたメモリのアドレス。読み込みに失敗した場合NULLを返す
// 引数 : FILE * pf ファイルポインタ
// int nWidth 画像の横幅(ピクセル数)
// int nHeight 画像の縦幅(ピクセル数)
//==========================================
unsigned char * LoadRGB(FILE * pf, int nWidth, int nHeight);
//==========================================
// 関数 : LoadBMPFromFilePointer
// 目的 : 受け取ったファイルポインタが示すBMPファイルのロード
// 戻り値: TBMPImage ※読み込みに失敗した場合はNULLを返す
// 引数 : FILE * pf ファイルポインタ
//==========================================
TBMPImage * LoadBMPFromFilePointer(FILE * pf);
//==========================================
// 関数 : LoadBMP
// 目的 : BMPのロード
// 戻り値: TBMPImage * ※読み込みに失敗した場合はNULLを返す
// 引数 : const char *pszFName ファイル名
//==========================================
TBMPImage * LoadBMP(const char *pszFName)
{
TBMPImage * pBmp; // BMP用構造体のポインタ
//********************************************************************
// ここにBMPの読み込み処理を記述
FILE * pf = fopen(pszFName, "rb"); // ファイルをオープン
if (pf == NULL) return NULL; // ファイルのオープンに失敗した場合、処理を終了して関数から脱出する
pBmp = LoadBMPFromFilePointer(pf); // BMP情報を読み込む。内部でメモリが確保される。その先頭アドレスを受け取る
fclose(pf); // ファイルをクローズ
return pBmp;
}
//==========================================
// 関数 : LoadBMPFromFilePointer
// 目的 : 受け取ったファイルポインタが示すBMPファイルのロード
// 戻り値: TBMPImage * ※読み込みに失敗した場合はNULLを返す
// 引数 : FILE * pf ファイルポインタ
//==========================================
TBMPImage * LoadBMPFromFilePointer(FILE * pf)
{
TBMPImage * pBmp; // BMP用構造体のポインタ
int nWidth; // 横幅情報受け取り用
int nHeight; // 縦幅情報受け取り用
unsigned short wBitCount; // ビット数情報受け取り用
unsigned long dwCompression; // 圧縮情報受け取り用
BOOL nResult; // 処理結果受け取り用
nResult = LoadHeader(pf);
if (nResult == FALSE) return NULL; // ファイルヘッダ部の読み込みに失敗した場合、処理を終了して関数から脱出する
// 情報ヘッダ部の読み込みを行い、横幅・縦幅・ビット数・圧縮情報 のデータを受け取る
nResult = LoadInfo(pf, &nWidth, &nHeight, &wBitCount, &dwCompression);
if (nResult == FALSE) return NULL; // 情報ヘッダ部の読み込みに失敗した場合、処理を終了して関数から脱出する
pBmp = (TBMPImage *)malloc(sizeof(TBMPImage)); // TBMPImage型変数を動的確保する
pBmp->nWidth = nWidth; // 先ほど取得した横幅情報を代入する
pBmp->nHeight = nHeight; // 先ほど取得した縦幅情報を代入する
pBmp->pbyPixels = NULL; // ピクセル情報を入れるポインタはNULLで初期化しておく
if (wBitCount != 24) // 24bit形式でなかった場合
{
pBmp->bEffective = FALSE; // 対応できない形式であるため、フラグを折って関数から脱出する
return pBmp;
}
if (dwCompression != 0) // 圧縮されている場合
{
pBmp->bEffective = FALSE; // 対応できない形式であるため、フラグを折って関数から脱出する
return pBmp;
}
pBmp->bEffective = TRUE; // 以上の条件をクリアしたということは対応できる形式であるため、フラグを立てておく
pBmp->pbyPixels = LoadRGB(pf, pBmp->nWidth, pBmp->nHeight); // RGB情報を読み込む
if (pBmp->pbyPixels == NULL) // RGB情報の読み込みに失敗した場合
{
free(pBmp); // TBMPImage用に確保したメモリを解放する
return NULL;
}
return pBmp;
}
//==========================================
// 関数 : LoadHeader
// 目的 : BMPファイルのファイルヘッダ部の読み込み
// 戻り値: BOOL 成功...TRUE, 失敗...FALSE
// 引数 : FILE * pf ファイルポインタ
//==========================================
BOOL LoadHeader(FILE * pf)
{
typedef struct
{
unsigned char byB; // 文字コード'B'が入るはず
unsigned char byM; // 文字コード'M'が入るはず
// これ以下の変数は今回は関係ない。ファイル読み込みサイズの関係で数合わせをしているだけ ********
unsigned long dwSize;
unsigned short wReserved1;
unsigned short wReserved2;
unsigned long dwOffBits;
// *********************************************************************************************
} TBMPHeader;
TBMPHeader header; // ファイルヘッダ部データ受け取り用
// ファイルからファイルヘッダ部を読み込み、失敗した場合はFALSEを返して関数から脱出する
if (fread(&header, FILE_HEADER_BYTE, 1, pf) 0) // 「4バイトより何バイト多いか」がゼロバイトを超えている場合
{
return 4 - lOverByte; // 4から「何バイト多いか」引けば不要なデータのバイト数が算出される
}
// 上の条件に引っかからなかったということは不要なデータはゼロバイト
return 0;
}
//==========================================
// 関数 : BGR_to_RGB
// 目的 : BGRの順に並んでいる色情報をRGBの順に並べ替える
// 戻り値: なし
// 引数 : unsigned char * pbyRGBDatas RGB情報が格納されたメモリの先頭アドレス
// unsigned int uPixelNum 画像の総ピクセル数
//==========================================
void BGR_to_RGB(unsigned char * pbyRGBDatas, unsigned int uPixelNum)
{
// 実はBMPファイルは各ピクセルの色情報を Blue, Green, Red の順番に記録している
// しかしOpenGLの描画関数に渡すRGB情報は Red, Green, Blue の順でなければならない
// ゆえに、ここでは BGR の状態から RGB の状態に変換する処理を行う
unsigned int uRGBDatasByte = uPixelNum * 3/* R, G, B それぞれ1バイトずつで合計3バイト*/; // RGB情報のバイト数
unsigned int uPixelIndex; // 処理するピクセル(配列3つ分)の先頭インデックス
for (uPixelIndex = 0; uPixelIndex bEffective == FALSE)
{
if (pTexImage->pbyPixels)
free(pTexImage->pbyPixels);
free(pTexImage);
MessageBox(NULL, _T("この形式は対応していません"), _T("error"), MB_OK | MB_ICONSTOP);
return 0;
}
// テクスチャの作成
glGenTextures(1, &uTexID);
glBindTexture(GL_TEXTURE_2D, uTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (pTexImage->bEffective == TRUE)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
pTexImage->nWidth,
pTexImage->nHeight,
0, GL_RGB, GL_UNSIGNED_BYTE,
(void *)pTexImage->pbyPixels);
}
else
{
glDeleteTextures(1, &uTexID);
uTexID = 0;
}
if (pTexImage->pbyPixels)
free(pTexImage->pbyPixels);
free(pTexImage);
return uTexID;
}
//==========================================
// 関数 : ReleaseTexture
// 目的 : テクスチャデータの解放
// 戻り値: なし
// 引数 : GLuint uTexID テクスチャID
//==========================================
void ReleaseTexture(GLuint uTexID)
{
if (uTexID == 0)
return;
glDeleteTextures(1, &uTexID);
}
それでは、楽しいプログラミングライフを!