ゲームプログラミング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なため、静的な割り当てが禁止されています。
* 必ず、動的な割り当て(new)でクラスを生成するようにしてください。
* また、本インターフェースにはReadメソッドが定義されていません。
* サブクラスで必ず実装するようにしてください(定義がないのは引数に制限を与えないためです) */ class IDraw2DReader{ protected: /** * @brief 仮想デストラクタです。 * * デストラクタがprotectedなため、静的な割り当てが禁止されています。
* 必ず、動的な割り当て(new)でクラスを生成するようにしてください。 */ virtual ~IDraw2DReader(){} //仮想デストラクタ(静的な割り当てを禁止) public: /** * @brief 本クラスを解体します。 */ virtual void Release() = 0; //解放 /** * @brief 本クラスがテクスチャを読み込み済みかを取得します。 * @return 本クラスがテクスチャを読み込み済みの場合はtrue、読み込み済みでない場合はfalseを返します。 */ virtual bool IsRead() const = 0; //読み込み済みか? /** * @brief テクスチャを取得します。 * @return テクスチャを返します。 */ virtual LPDIRECT3DTEXTURE9 GetTexture() = 0; //テクスチャを取得(1) /** * @brief テクスチャを取得します。 * @return テクスチャを返します。 */ virtual LPDIRECT3DTEXTURE9 GetTexture() const = 0; //テクスチャを取得(2) }; //グラフィックデータ読み込みクラス(2D) /** * @brief グラフィックデータ読み込みクラス(2D)です。 * * デストラクタがprotectedなため、静的な割り当てが禁止されています。
* 必ず、動的な割り当て(new)でクラスを生成するようにしてください。 */ class CDraw2DReader : public IDraw2DReader{ protected: /** * @brief デストラクタです。 * * デストラクタがprotectedなため、静的な割り当てが禁止されています。
* 必ず、動的な割り当て(new)でクラスを生成するようにしてください。 */ ~CDraw2DReader(); //デストラクタ(静的な割り当てを禁止) public: /** * @brief コンストラクタです。
* 所属する\link nsDX9A::nsGraphics::nsDX9AGraphic::DX9AGraphic DirectX Graphicsラッパークラス\endlinkと使用する\link nsDX9A::nsFile::nsFileReader::IFileReader ファイル入力クラス\endlink、
* ファイル名と抜き色を指定することで、生成時にテクスチャの読み込みをも行います。 * @param Outer [in]所属する\link nsDX9A::nsGraphics::nsDX9AGraphic::DX9AGraphic DirectX Graphicsラッパークラス\endlinkを指定します。 * @param FileReader [in]使用する\link nsDX9A::nsFile::nsFileReader::IFileReader ファイル入力クラス\endlinkを指定します。 * @param FileName [in]ファイル名を指定します。 * @param ColorKey [in]抜き色をD3DCOLORで指定します。 */ CDraw2DReader(DX9AGraphic* Outer, IFileReader* FileReader, const string& FileName = "", D3DCOLOR ColorKey = 0); //コンストラクタ(DirectX Graphicsラッパー、ファイル入力クラス、ファイル名、抜き色を指定) void Release(); //解放 /** * @brief テクスチャの読み込みを行います。 * @param FileName [in]ファイル名を指定します。 * @param ColorKey [in]抜き色をD3DCOLORで指定します。 * @return テクスチャの読み込みが成功した場合はtrue、失敗した場合はfalseを返します。 */ bool Read(const string& FileName, D3DCOLOR ColorKey = 0); //読み込み bool IsRead() const; //読み込み済みか? LPDIRECT3DTEXTURE9 GetTexture(); //テクスチャを取得(1) LPDIRECT3DTEXTURE9 GetTexture() const; //テクスチャを取得(2) private: IFileReader* m_FileReader; //ファイル入力クラス BYTE* m_TextureData; //テクスチャの生データ LPDIRECT3DTEXTURE9 m_Texture; //テクスチャ DX9AGraphic* m_Outer; //DirectX Graphicsラッパーへのアドレス CDraw2DReader(); //デフォルトコンストラクタ(禁止) CDraw2DReader(const CDraw2DReader&); //コピーコンストラクタ(禁止) CDraw2DReader& operator =(const CDraw2DReader&); //代入演算子(禁止) }; } } } #endif

 ヘッダに対する解説では、本クラスの使用方法ならびに実装技法を説明する。

 使用方法は簡単である。

 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関数がやや難解だがリファレンスに目を通せば十分だろう。

 

 

 

……以上で本項は終了である、お疲れ様でした(´Д`)
本項は箸休め的な内容である、特に難しいことはなくイディオムを理解すれば十分だろう。
あえてひとつ注目ポイントを書いておくと、本項では先に解説したファイル入出力クラスを用いている。
つまり、今後ファイルパックに対応したファイル入出力クラスを作成しても本クラスは問題なく使えるわけである。
上記の言葉のありがたみを理解できる人はよし、できない人は今後解説するファイルパックの項で理解してもらう予定である。

 

前へ                                        戻る                                     次へ