ゲームプログラミングTips(7):DirectX Graphics(2)(読み込み編)
2012年9月17日……前回の講座より、実に約4ヶ月ぶりである。
実際にこの講座を書いたのは実は前回の講座と同日(5月14日)だが、諸事情により公開が遅れた次第……こ、今後は頑張ります(;´Д`)
1.DirectX Graphicsとは?(Part2)
基幹編で解説したから要らんでしょ(´Д`)
2.DirectX Graphicsのゲームプログラミングにおける活用事例(Part2)
以下同文……というのもつまらないので、少しだけ。
基幹編では、DirectX Graphicsやウィンドウの初期化等について解説を行った。
今回の内容はその発展系で、画像ファイルの読み込みについて解説を行っていく。
3.具体例(ヘッダ解説)
本項では、俺が作ったグラフィックデータ読み込みクラスを掲載する。
/************************************************* ファイル名:IDraw2DReader.h 作成者 :あびす 役割 :グラフィックデータ読み込みクラス(2D) *************************************************/ /** * @file IDraw2DReader.h * @brief グラフィックデータ読み込みクラス(2D)関係です。 */ #ifndef DX9A_GRAPHICS_IDRAW2DREADER_H #define DX9A_GRAPHICS_IDRAW2DREADER_H namespace nsDX9A{ namespace nsGraphics{ namespace nsIDraw2DReader{ //グラフィックデータ読み込みクラス(2D)(インターフェース) /** * @brief グラフィックデータ読み込みクラス(2D)のインターフェースです。 * * デストラクタがprotectedなため、静的な割り当てが禁止されています。 |
ヘッダに対する解説では、本クラスの使用方法ならびに実装技法を説明する。
使用方法は簡単である。
1.インスタンスをnewで生成する
2.コンストラクタまたはReadメソッドで画像ファイルを読み込む
3.GetTextureメソッドで画像ファイルから生成したテクスチャを取得できる
4.Releaseメソッドでインスタンスを解体する
具体例 DX9AGraphic* g_DX9AG = new DX9AGraphic(); //DirectX Graphicsラッパークラス CDraw2DReader* A = new CDraw2DReader(g_DX9AG, new CFileReader(), "1.bmp", 0); //グラフィックデータ読み込みクラス(2D)(1) CDraw2DReader* B = new CDraw2DReader(g_DX9AG, new CFileReader()); //グラフィックデータ読み込みクラス(2D)(2) B->Read("1.bmp", 0); A->GetTexture(); B->GetTexture(); A->Release(); B->Release(); g_DX9AG->Release(); |
……これだけである、特に変なところはない筈だ。
では、以下にて具体的な説明を行っていく。
ただし、なるべく説明は簡略に行う。
ヘッダの説明
何故2Dだけなの?3Dは?
はいはいへぼプログラマで悪うござんしたさーせん('A`)
真面目に答えると、今のところ3Dゲームを作る予定がない(かつ技術もない)からである。
IDraw2DReaderクラスの仮想デストラクタがprotectedなのは何故?
これは、動的生成(=newでの生成)を強制したかったからである。
仮想デストラクタをprotectedにしておくと、継承クラスのデストラクタはprotected以上にせざるをえない。
そしてユーザーが継承クラスを静的に生成しようと試みた場合、コンパイラがコンパイルエラーを発生させてくれる。
それは、コンパイラがスコープの終わり際で静的生成されたインスタンスのprotectedなデストラクタを呼ぶからである。
それに対し、動的生成したインスタンスはスコープ自体が存在しない。つまり、コンパイルエラーを引き起こさないわけだ。
Releaseメソッドの意味は?
上記で、動的生成を強制するために仮想デストラクタをprotectedにしたと書いた。
だがそうするとひとつ問題が生じてしまう、deleteでの解体を試みるとコンパイルエラーが発生してしまうのだ。
解決策はReleaseメソッドを用意しその中でdelete(this)を呼び出すこと、Releaseメソッド内での解体はエラーが発生しない。
Readメソッドをインターフェースで定義していないのは?
コメントにもあるとおり、引数を自由にさせるためである。
読み込み元によって、引数が変化する可能性があるためこうしている。
4.具体例(ソース解説)
次はソース解説である。
#include "stdafx.h" #include "../index.h" #include "IDraw2DReader.h" namespace nsDX9A{ namespace nsGraphics{ namespace nsIDraw2DReader{ //コンストラクタ(DirectX Graphicsラッパー、ファイル入力クラス、ファイル名、抜き色を指定) CDraw2DReader::CDraw2DReader(DX9AGraphic* Outer, IFileReader* FileReader, const string& FileName, D3DCOLOR ColorKey){ m_FileReader = FileReader; m_TextureData = NULL; m_Texture = NULL; m_Outer = Outer; if(FileName!=""){ Read(FileName, ColorKey); } } //デストラクタ(静的な割り当てを禁止) CDraw2DReader::~CDraw2DReader(){ SAFE_RELEASE(m_Texture); SAFE_DELETE_ARRAY(m_TextureData); SAFE_DELETE(m_FileReader); } //解放 void CDraw2DReader::Release(){ delete(this); } //読み込み bool CDraw2DReader::Read(const string& FileName, D3DCOLOR ColorKey){ if(!m_FileReader){ DX9AErrOut("Failed : CDraw2DReader::Read FileReader Not Exists\n"); return(false); } if(!m_FileReader->fopen(FileName.c_str(), "rb")){ DX9AErrOut("Failed : CDraw2DReader::Read File Not Found(%s)\n", FileName.c_str()); return(false); } SAFE_RELEASE(m_Texture); SAFE_DELETE_ARRAY(m_TextureData); long FileSize = m_FileReader->fsize(); m_TextureData = new BYTE[FileSize]; m_FileReader->fread(m_TextureData, FileSize, 1); m_FileReader->fclose(); return(SUCCEEDED(D3DXCreateTextureFromFileInMemoryEx(GetDX9AGraphicAccessor(m_Outer)->GetD3D9Device(), m_TextureData, FileSize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, ColorKey, NULL, NULL, &m_Texture))); } //読み込み済みか? bool CDraw2DReader::IsRead() const{ return(m_Texture!=NULL); } //テクスチャを取得(1) LPDIRECT3DTEXTURE9 CDraw2DReader::GetTexture(){ return(m_Texture); } //テクスチャを取得(2) LPDIRECT3DTEXTURE9 CDraw2DReader::GetTexture() const{ return(m_Texture); } } } } |
特に難しいことは行っていない、あえて言えばD3DXCreateTextureFromFileInMemoryEx関数がやや難解だがリファレンスに目を通せば十分だろう。
……以上で本項は終了である、お疲れ様でした(´Д`)
本項は箸休め的な内容である、特に難しいことはなくイディオムを理解すれば十分だろう。
あえてひとつ注目ポイントを書いておくと、本項では先に解説したファイル入出力クラスを用いている。
つまり、今後ファイルパックに対応したファイル入出力クラスを作成しても本クラスは問題なく使えるわけである。
上記の言葉のありがたみを理解できる人はよし、できない人は今後解説するファイルパックの項で理解してもらう予定である。