1つの画像ファイルに複数の画像を載せるには?

この章で使用するプログラムおよび画像ファイル

今までのテクスチャ

前ページの復習だが、DirectX Graphicsでは、テクスチャ画像の左上座標を原点として、横方向をtu、縦方向をtvとし、それぞれ0.0〜1.0の浮動小数点(実数)で表現する。つまり、右下座標のテクスチャ座標はtu=1.0、tv=1.0である。

例えば32×32ピクセルのポリゴンにテクスチャを貼り付けたいとき、ポリゴンの頂点A,B,C,Dそれぞれにtu、tvの値を指定することになる。

上図のようにポリゴンの頂点A,B,C,Dそれぞれに該当するテクスチャのtu、tvの値を設定すると、次の値になる。

この場合、複数のキャラクタを作成したい場合、1つのキャラクタ画像ごとに1つのファイルを作成し、必要に応じて複数のテクスチャを用意しなければならない。

複数の画像を1つのファイルで管理したい

ここで、テクスチャ画像の頂点情報に注目して欲しい。テクスチャ画像の大きさがいくつであろうと、頂点座標の範囲は必ず0.0から1.0の間である。ということは、例えば縦と横にそれぞれ2つ、計4つの画像を同じ大きさで配置した画像ファイルを作成した場合、左上のキャラクタをポリゴンに貼り付けるには次のように考えればよい。

上図の場合、ポリゴンの頂点A,B,C,Dそれぞれにテクスチャ画像の左上のキャラクタのtu、tvを設定すると、次の値になる。

同じように、左上のキャラクタのtu、tvを設定すると、次の値になる。

これらのことから、同じ大きさのキャラクタ画像であれば1つのファイルにまとめることができることが分かる。

実際のプログラム

では実際に、複数のキャラクタを配置した画像ファイルを用意し、それぞれのキャラクタが表示されるプログラムを作成する。用意した画像ファイルは次のようになっている。

同じ大きさの画像を横に4つ並べた。この場合、tuの値は0.25ずつ増加し、tvの値は変わらないことが分かる。

tu、tvの情報は頂点情報の初期化時に設定しているので、その時に1つ目のポリゴンなら0.25に、2つ目のポリゴンなら0.5に・・・とセットすればよいが、テクスチャに用意されているキャラクタの総数と表示する画像の順番によって、tuの値を求めることができる。今回は4つのキャラクタを用意しているので、次のような式で求めることができる。

頂点情報を初期化する関数はInitVertex()である。よって、この関数の引数に表示したいキャラクタの順番を与えれば、初期化関数内でtuの値を計算できることが分かる。

初期化処理関数

//----------------------------------------------------------------------------------------
// 関数名 : InitVertex() 
// 機能概要: 頂点データを格納する
//----------------------------------------------------------------------------------------
void InitVertex(LPTLVERTEX v, float x1, float y1, float x2, float y2, int no)
{
    float width;

    // 画像ファイルに配置したキャラクタの数により、幅の値を求める
    width = 1.0f / (float)CHARACTER_MAX;

    //頂点配列をゼロクリア
    ZeroMemory(v, sizeof(TLVERTX));
    //---頂点A1のデータ定義
    v[0].x      =  x1;                         // 頂点X座標
    v[0].y      =  y1;                         // 頂点Y座標
    v[0].z      =  0.0f;                       // 頂点Z座標
    v[0].rhw    =  1.0f;                       // 2Dを扱うときの値
    v[0].tu     =  width * (float)no;          // テクスチャのX座標
    v[0].tv     =  0.0f;                       // テクスチャのY座標
    v[0].color  =  D3DCOLOR_XRGB(255,255,255); // 頂点色
    //---頂点A2のデータ定義
    v[1].x      =  x2;
    v[1].y      =  y1;
    v[1].z      =  0.0f;
    v[1].rhw    =  1.0f;
    v[1].tu     =  width * (float)(no + 1);
    v[1].tv     =  0.0f;
    v[1].color  =  D3DCOLOR_XRGB(255,255,255);
    //---頂点A3のデータ定義
    v[2].x      =  x2;
    v[2].y      =  y2;
    v[2].z      =  0.0f;
    v[2].rhw    =  1.0f;
    v[2].tu     =  width * (float)(no + 1);
    v[2].tv     =  1.0f;
    v[2].color  =  D3DCOLOR_XRGB(255,255,255);
    //---頂点A4のデータ定義
    v[3].x      =  x1;
    v[3].y      =  y2;
    v[3].z      =  0.0f;
    v[3].rhw    =  1.0f;
    v[3].tu     =  width * (float)no;
    v[3].tv     =  1.0f;
    v[3].color  =  D3DCOLOR_XRGB(255,255,255);
}

《解説》

初期化処理関数の実行

//-----------------------------------------------------------------------------
// 関数名 : StartInit()
// 機能概要: スタート画面初期化処理
//-----------------------------------------------------------------------------
void StartInit(void)
{
    //--------------------------------------------------- 各変数の初期化
    // スタート画面で使用するテクスチャの作成
    CreateStartTexture();
    // 頂点データを格納する
    InitVertex(VertexDataTbl[0], 100.0f, 100.0f, 300.0f, 300.0f, 0);
    InitVertex(VertexDataTbl[1], 250.0f, 50.0f, 450.0f, 250.0f, 1);
    InitVertex(VertexDataTbl[2], 300.0f, 200.0f, 500.0f, 400.0f, 2);
    InitVertex(VertexDataTbl[3], 350.0f, 250.0f, 550.0f, 450.0f, 3);

    //--------------------------------------------------- フレームナンバーセット
    g_FrameNo = START_FRAME;

}

《解説》

※上記修正を行い、1枚のビットマップファイル内にある各キャラクタが、それぞれのポリゴンに貼り付けられて表示されることを確認すること。


BACK(複数のキャラクタを表示する) NEXT(テクスチャサイズの最大(参考))