TOP

ABOUT

PROGRAM

DIALY







テクスチャを読み込む!!(3)

 1.はじめに…
 今回は,Windows Bitmapファイル(*.bmp)の読み込みについてやってみます。
BMPもモノクロ,16色,256色,24Bit,32Bitと色々と種類はあるのですが,おそらくほとんどの方は24ビットBMPファイルを使うと思うので24Bitのみを対象として説明します。




 2.BMPファイルフォーマット
 BMPファイルフォーマットについて以下のサイトに詳しく書いてあるのでそちらの方を参照してください。
http://www.kk.iij4u.or.jp/~kondo/bmp/



 3.ファイルの読み込み
ファイルの読み込みに大事なのは前回も言ったとおり,画像の幅と高さ,ビット数,ピクセルデータです。
画像の幅・高さはBITMAPINFOHEADER構造体のbiWidthとbiHeightに格納されます,ビット数は今回24ビットのみを取り扱うという前提なので24bitで固定にしておきます。もし,24Bitと32Bitの両方を取扱いたい場合にはBITMAPINFORHEADERのbiBitCountの値が24か32かを調べて処理するといいと思います。
BMPファイルもTGAと同じようにヘッダー部が終わるとデータ部(54バイト以降)がくるようになっているので,ヘッダー部を読み取ったあとはfread()で一気にピクセルデータを読み込みます。その後,読み取ったデータはBGRの順になっているので,RGBに変換してやります。
読み取りにつかうクラスはBMPLoader.hで以下のように定義しています。
//
// include
//
#include <iostream>
#include <GL/glut.h>
using namespace std;


/////////////////////////////////////////////////////////////////////////
//  BMPImage class
/////////////////////////////////////////////////////////////////////////
class BMPImage
{
protected:
    GLuint imageSize;
    GLubyte *imageData;
    GLenum format;
    GLuint internalFormat;
    GLuint width;
    GLuint height;
    GLuint bpp;

public:
    GLuint ID;
    BMPImage();
    ~BMPImage();
    bool ReadBMP(const char *filename);
    GLuint Load(const char *filename);
};
ヘッダーで宣言したクラスの中身は以下のような感じでBMPLoader.cppで定義してあります。
//
// include
//
#include <fstream>
#include <windows.h>
#include "BMPLoader.h"
using namespace std;


//////////////////////////////////////////////////////////////////////////
//  BMPImage class
//////////////////////////////////////////////////////////////////////////


//-----------------------------------------------------------------------------------------------------
//  ReadBMP
//  Desc : BMPファイルの読み込み
//-----------------------------------------------------------------------------------------------------
bool BMPImage::ReadBMP(const char *filename)
{
    FILE *fp;

    BITMAPINFOHEADER bitmapInfoHeader;
    BITMAPFILEHEADER header;
    GLubyte temp = 0;

    // ファイルを開く
    if ( (fp = fopen(filename, "rb")) == NULL )
    {
        cout << "Error : 指定されたファイルが開けません\n";
        cout << "File Name : " << filename << endl;
        return false;
    }

    // ヘッダー情報の読み取り
    fread(&header, sizeof(BITMAPFILEHEADER), 1, fp);

    // ファイルチェック
    if ( header.bfType != 0x4d42 )
    {
        cout << "Error : Bitmapファイルではありません\n";
        fclose(fp);
        return false;
    }

    // ヘッダー情報の読み取り
    fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);

    // 幅と高さを取得
    width = bitmapInfoHeader.biWidth;
    height = bitmapInfoHeader.biHeight;

    if ( bitmapInfoHeader.biSizeImage == 0 )
    {
        bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3;
    }

    fseek(fp, header.bfOffBits, SEEK_SET);

    // データサイズを決定し,メモリを確保
    imageSize = bitmapInfoHeader.biSizeImage;
    imageData = new GLubyte [imageSize];

    // エラーチェック
    if ( !imageData )
    {
        cout << "Error : メモリが確保できませんでした\n";
        delete [] imageData;
        fclose(fp);
        return false;
    }

    // ピクセルデータの読み込み
    fread(imageData, 1, bitmapInfoHeader.biSizeImage, fp);

    // BGR → RGBに変換
    for ( int i=0; i<(int)imageSize; i+=3 )
    {
        temp = imageData[i+0];
        imageData[i+0] = imageData[i+2];
        imageData[i+2] = temp;
    }

    // ファイルを閉じる
    fclose(fp);

    return true;
}

//-----------------------------------------------------------------------------------------------------
//  Load
//  Desc : BMPファイルを読み込み,テクスチャを生成
//-----------------------------------------------------------------------------------------------------
GLuint BMPImage::Load(const char *filename)
{
    if ( !ReadBMP(filename) )
        return 0;

    glGenTextures(1, &ID);

    glBindTexture(GL_TEXTURE_2D, ID);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, width, height, format, GL_UNSIGNED_BYTE, imageData );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    if ( imageData )
    {
        delete [] imageData;
        imageData = NULL;
    }
    return ID;
}

ここで注意してほしいのは,windows.hをインクルードしている点です。読み込みに使用しているBIMAPINFOHEADER構造体などはwindows.hで定義されているので気をつけてください。
もし,「Windowsに依存するの嫌だ!」というひとは,#include の一行を消して,読み込みに使用しているBITMAPINFOHEADERなどの構造体を自分でファイルに定義してあげれば,windows.hをインクルードしなくても読み込みができると思います。


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2005 Professional Editionを用いています。