ゲームプログラミングTips(5):DirectX Graphics(1)(基幹編)

 

2012年5月7日……前回の講座より、実に17日ぶりである。
実は毎回の講座を書くのは前の講座から一週間以内なのだが、日記をサボりがちなため連動して更新が遅れがちである。
……ううむ、どうしたらいいものか(´Д`)

 

1.DirectX Graphicsとは?

 DirectX Graphicsとはゲーム処理用API「DirectX」のグラフィックを扱うコンポーネントのことである。
 ……って、こんなこと別に書かなくても当然知ってるよね?(´Д`)
 詳しくはウィキペれ>[DirectX Graphics]

 

2.DirectX Graphicsのゲームプログラミングにおける活用事例

 Windows上で動作するゲームにおいて使わない事例はない、以上。
 ……いや、まあブラウザゲーとか例外を挙げていけばいくらでもあるんですがね(;´Д`)
 一般的なゲームプログラミングにおいては、気にする必要は無いし考えるだけ無駄というものである。

 

3.具体例(ヘッダ解説)

 本項では、俺が作ったDirectX Graphicsラッパークラスを掲載する。

/*************************************************
ファイル名:DX9AGraphic.h
作成者  :あびす
役割   :DirectX Graphicsラッパー
*************************************************/
/**
*	@file	DX9AGraphic.h
*	@brief	DirectX Graphicsのラッパークラス関係です。
*/
#ifndef DX9A_GRAPHICS_DX9AGRAPHIC_H
#define DX9A_GRAPHICS_DX9AGRAPHIC_H

namespace nsDX9A{
namespace nsGraphics{
namespace nsDX9AGraphic{

//文字列テクスチャ
/**
*	@brief	文字列テクスチャの情報が格納されている構造体です。 < br > 
*			ユーザーが使用する必要はありません。
*/
struct StringTexture{
/**
*	@brief	文字列テクスチャが最後に参照された時間です。
*/
	DWORD LastRefTime;																		//最後に参照された時間
/**
*	@brief	文字列テクスチャのサイズです(単位:バイト)
*/
	unsigned int Size;																		//テクスチャのサイズ
/**
*	@brief	文字列テクスチャの横幅です。
*/
	unsigned int Width;																		//テクスチャの横幅
/**
*	@brief	文字列テクスチャの縦幅です。
*/
	unsigned int Height;																	//テクスチャの縦幅
/**
*	@brief	文字列テクスチャです( < a href="http://msdn.microsoft.com/ja-jp/library/cc324033.aspx" target="_blank" > IDirect3DTexture9インターフェイス < /a > へのポインタ)
*/
	LPDIRECT3DTEXTURE9 Texture;																//テクスチャ
};

//DirectX Graphicsラッパー
/**
*	@brief	DirectX Graphicsのラッパークラスです。 < br > 
*			使用前に、必ずInitメソッドを実行してください。
*/
class DX9AGraphic{
/**
*	@brief	DX9AGraphicAccessor	クラスから本クラスのプライベートメンバにアクセス可能です。
*/
	friend class DX9AGraphicAccessor;														//フレンドクラス(アクセッサ)
public:
/**
*	@brief	デフォルトコンストラクタです。
*/
	DX9AGraphic();																			//デフォルトコンストラクタ
/**
*	@brief	デストラクタです。
*/
	~DX9AGraphic();																			//デストラクタ

	//初期化(必ず呼び出すこと)
/**
*	@brief	初期化を行います。 < br > 
*			使用前に、必ず実行してください。
*	@param	hInst					[in]インスタンスハンドルを指定します。
*	@param	WindowName				[in]ウインドウ名を指定します。
*	@param	WndProc					[in]メッセージ処理用コールバック関数を指定します。
*	@param	ScreenWidth				[in]ウインドウの横幅を指定します。
*	@param	ScreenHeight			[in]ウインドウの縦幅を指定します。
*	@param	StringTextureMaxSize	[in]文字列テクスチャの最大サイズを指定します(単位:バイト) < br > 
*									自動で拡張される場合があります。 < br > 
*									(例:StringTextureMaxSize = 5 * 1024(5KB)で使用中の文字列テクスチャ(6KB)が存在する場合、 < br > 
*									   StringTextureMaxSize = 6 * 1024(6KB)に自動で拡張されます)
*	@param	IsFullScreen			[in]フルスクリーンモードかを指定します。 < br > 
*									フルスクリーンモードにする場合はtrueを、ウインドウモードにする場合はfalseを指定します。
*	@param	UseDepthStencil			[in]深度/ステンシルバッファを使用するかを指定します。 < br > 
*									使用する場合はtrueを、使用しない場合はfalseを指定します。
*	@param	UseMultiSample			[in]フルシーンアンチエイリアシングを使用するかを指定します。 < br > 
*									使用する場合はtrueを、使用しない場合はfalseを指定します。
*	@param	hIcon					[in]大アイコンを指定します。
*	@param	hCursor					[in]マウスカーソルを指定します。
*	@param	hIconSm					[in]小アイコンを指定します。
*	@return	初期化が成功した場合はtrue、失敗した場合はfalseを返します。
*/
	bool Init(HINSTANCE hInst, LPCTSTR WindowName, WNDPROC WndProc, int ScreenWidth, int ScreenHeight, unsigned int StringTextureMaxSize, 
			  bool IsFullScreen = false, bool UseDepthStencil = false, bool UseMultiSample = false, HICON hIcon = NULL, HCURSOR hCursor = NULL, HICON hIconSm = NULL);

	//アイドル時の処理(必ず実行すること)
/**
*	@brief	アイドル時の処理を行います。 < br > 
*			メインループ中で、必ず実行してください。
*	@return	処理が成功した場合はtrue、失敗した場合はfalseを返します。
*/
	bool AppIdle();

	//ウインドウプロシージャ(必ず実行すること)
/**
*	@brief	ウインドウプロシージャ内での処理を行います。 < br > 
*			ウインドウプロシージャ内で、必ず実行してください。
*	@param	hWnd	[in]ウインドウプロシージャのhWndを指定します。 < br > 
*	@param	uMsg	[in]ウインドウプロシージャのuMsgを指定します。
*	@param	wParam	[in]ウインドウプロシージャのwParamを指定します。
*	@param	lParam	[in]ウインドウプロシージャのlParamを指定します。
*/
	void MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	//その他(初期化を済ませてから呼び出すこと)
/**
*	@brief	アクティブ状態かを取得します。
*	@return	アクティブ状態かを返します。 < br > 
*			アクティブ状態の場合はtrueを、アクティブ状態でない場合はfalseを返します。
*/
	bool IsActive() const;																	//アクティブ状態かを取得

/**
*	@brief	ウインドウハンドルを取得します。
*	@return	ウインドウハンドルを返します。
*/
	HWND GetHWND() const;																	//ウインドウハンドルを取得

/**
*	@brief	ウインドウの横幅を取得します。
*	@return	ウインドウの横幅を返します。
*/
	int GetScreenWidth() const;																//画面の横幅を取得
/**
*	@brief	ウインドウの縦幅を取得します。
*	@return	ウインドウの縦幅を返します。
*/
	int GetScreenHeight() const;															//画面の縦幅を取得
/**
*	@brief	フルスクリーンかを取得します。
*	@return	フルスクリーンかを返します。 < br > 
*			フルスクリーンモードの場合はtrueを、ウインドウモードの場合はfalseを返します。
*/
	bool GetFullScreen() const;																//フルスクリーンモードか否かを取得
/**
*	@brief	フルスクリーンかを設定します。
*	@param	IsFullScreen	[in]フルスクリーンかを指定します。 < br > 
*							フルスクリーンモードにする場合はtrueを、ウインドウモードにする場合はfalseを指定します。
*/
	bool SetFullScreen(bool IsFullScreen);													//フルスクリーンモードか否かを設定

/**
*	@brief	画面の消去を行います。
*	@param	Color	[in]塗り潰す色を < a href="http://msdn.microsoft.com/ja-jp/library/bb172518(v=vs.85).aspx" target="_blank" > D3DCOLOR < /a > で指定します。
*/
	void Clear(D3DCOLOR Color);																//画面を消去

/**
*	@brief	画面の更新を行います。
*/
	void Present();																			//画面を更新

/**
*	@brief	矩形の描画を行います。
*	@param	Rect		[in]矩形を < a href="http://msdn.microsoft.com/ja-jp/library/ms931125.aspx" target="_blank" > RECT < /a > で指定します。
*	@param	Color		[in]塗り潰す色を < a href="http://msdn.microsoft.com/ja-jp/library/bb172518(v=vs.85).aspx" target="_blank" > D3DCOLOR < /a > で指定します。
*	@param	Degree		[in]回転する角度を指定します(単位:度)
*	@param	BlendOp		[in]ブレンディング処理を < a href="http://msdn.microsoft.com/ja-jp/library/bb172509(VS.85).aspx" target="_blank" > D3DBLENDOP < /a > で指定します。
*	@param	SrcBlend	[in]転送元のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*	@param	DestBlend	[in]転送先のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*/
	void DrawRect(RECT Rect, D3DCOLOR Color, float Degree = 0.0f, D3DBLENDOP BlendOp = D3DBLENDOP_ADD, D3DBLEND SrcBlend = D3DBLEND_SRCALPHA, D3DBLEND DestBlend = D3DBLEND_INVSRCALPHA);
																							//矩形を描画
/**
*	@brief	文字列の描画を行います。
*	@param	Text		[in]文字列を指定します。
*	@param	x			[in]文字列の描画先のX座標を指定します。
*	@param	y			[in]文字列の描画先のY座標を指定します。
*	@param	Color		[in]文字列の色を < a href="http://msdn.microsoft.com/ja-jp/library/bb172518(v=vs.85).aspx" target="_blank" > D3DCOLOR < /a > で指定します。
*	@param	Font		[in]文字列のフォントを指定します。
*	@param	Size		[in]文字列のサイズを指定します。
*	@param	IsBold		[in]文字列が太字かを指定します。 < br > 
*						太字の場合はtrueを、太字でない場合はfalseを指定します。
*	@param	IsItalic	[in]文字列が斜体かを指定します。 < br > 
*						斜体の場合はtrueを、斜体でない場合はfalseを指定します。
*	@param	Degree		[in]回転する角度を指定します(単位:度)
*	@param	BlendOp		[in]ブレンディング処理を < a href="http://msdn.microsoft.com/ja-jp/library/bb172509(VS.85).aspx" target="_blank" > D3DBLENDOP < /a > で指定します。
*	@param	SrcBlend	[in]転送元のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*	@param	DestBlend	[in]転送先のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*/
	void DrawFreeText(const string& Text, int x, int y, D3DCOLOR Color, const string& Font, unsigned int Size, bool IsBold, bool IsItalic, float Degree = 0.0f, D3DBLENDOP BlendOp = D3DBLENDOP_ADD, D3DBLEND SrcBlend = D3DBLEND_SRCALPHA, D3DBLEND DestBlend = D3DBLEND_INVSRCALPHA);
																							//文字列を描画
/**
*	@brief	テクスチャの転送を行います。
*	@param	Texture		[in]対象のテクスチャを指定します。
*	@param	x			[in]テクスチャの描画先のX座標を指定します。
*	@param	y			[in]テクスチャの描画先のY座標を指定します。
*	@param	Color		[in]テクスチャの描画色を < a href="http://msdn.microsoft.com/ja-jp/library/bb172518(v=vs.85).aspx" target="_blank" > D3DCOLOR < /a > で指定します。
*	@param	SrcRect		[in]転送元矩形を < a href="http://msdn.microsoft.com/ja-jp/library/ms931125.aspx" target="_blank" > RECT < /a > で指定します。
*	@param	BlendOp		[in]ブレンディング処理を < a href="http://msdn.microsoft.com/ja-jp/library/bb172509(VS.85).aspx" target="_blank" > D3DBLENDOP < /a > で指定します。
*	@param	SrcBlend	[in]転送元のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*	@param	DestBlend	[in]転送先のブレンディングモードを < a href="http://msdn.microsoft.com/ja-jp/library/cc324307.aspx" target="_blank" > D3DBLEND < /a > で指定します。
*	@param	ScalingX	[in]拡大倍率(X方向)を指定します。
*	@param	ScalingY	[in]拡大倍率(Y方向)を指定します。
*	@param	Degree		[in]回転する角度を指定します(単位:度)
*/
	void GeneralBlt(LPDIRECT3DTEXTURE9 Texture, int x, int y, D3DCOLOR Color, const RECT* SrcRect, D3DBLENDOP BlendOp, D3DBLEND SrcBlend, D3DBLEND DestBlend, float ScalingX = 1.0f, float ScalingY = 1.0f, float Degree = 0.0f);
																							//汎用転送
private:
	HWND m_hWnd;																			//ウインドウハンドル
	HINSTANCE m_hInst;																		//インスタンスハンドル
	string m_ClassName;																		//ウインドウクラスの名前
	bool m_IsActive;																		//アクティブ状態か?
	bool m_IsBeginScene;																	//シーンが開始されているか?
	bool m_IsBeginSprite;																	//スプライトの描画が開始されているか?
	bool m_IsDeviceLost;																	//デバイスが消失しているか?
	int  m_ScreenWidth;																		//画面の横幅
	int  m_ScreenHeight;																	//画面の縦幅
	bool m_IsFullScreen;																	//フルスクリーンモードか?
	bool m_IsUseDepthStencil;																//深度/ステンシルバッファを使用するか?
	bool m_IsUseMultiSample;																//フルシーンアンチエイリアシングを使用するか?
	RECT m_WindowLastPos;																	//ウインドウの最後の位置

	void BeginScene();																		//描画を開始
	void EndScene();																		//描画を終了

	void BeginSprite();																		//スプライトの描画を開始
	void EndSprite();																		//スプライトの描画を終了

	bool InitApp(LPCTSTR WindowName, WNDPROC WndProc, HICON hIcon, HCURSOR hCursor, HICON hIconSm);
																							//アプリケーションを初期化
	bool InitD3D();																			//Direct3Dに管理されているオブジェクトを初期化
	bool SelectD3DDevice(UINT& Adapter, D3DDEVTYPE& Device);								//デバイスの設定を選択
	bool CheckDeviceCaps(D3DCAPS9* Caps);													//デバイスの能力をチェック
	bool SelectAdapterFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode);		//ディスプレイとバックバッファのフォーマットを調査
	bool SelectDepthStencilFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode);	//深度/ステンシルバッファのフォーマットを調査
	bool SelectRenderTextureFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode);	//レンダリングテクスチャのフォーマットを調査
	bool SelectMultiSampleType(UINT Adapter, D3DDEVTYPE Device);							//フルシーンアンチエイリアシングを調査
	bool SelectDisplayMode(UINT Adapter);													//ディスプレイモードを調査
	bool InitD3DObject();																	//Direct3Dに管理されていないオブジェクトを初期化

	bool CleanupD3DObject();																//Direct3Dに管理されていないオブジェクトの終了処理
	bool CleanupD3D();																		//Direct3Dに管理されているオブジェクトの終了処理
	bool CleanupApp();																		//アプリケーションの終了処理

	LPDIRECT3D9 m_pD3D;																		//Direct3D9オブジェクト
	LPDIRECT3DDEVICE9 m_pD3DDevice;															//Direct3DDevice9オブジェクト
	D3DPRESENT_PARAMETERS m_D3DParamNow;													//D3DPRESENT_PARAMETERS構造体(現在)
	D3DPRESENT_PARAMETERS m_D3DParamWin;													//D3DPRESENT_PARAMETERS構造体(ウインドウモード)
	D3DPRESENT_PARAMETERS m_D3DParamFull;													//D3DPRESENT_PARAMETERS構造体(フルスクリーンモード)
	D3DFORMAT m_FmtRenderTextureWin;														//レンダリングテクスチャのフォーマット(ウインドウモード)
	D3DFORMAT m_FmtRenderTextureFull;														//レンダリングテクスチャのフォーマット(フルスクリーンモード)

	LPD3DXSPRITE m_pD3DXSprite;																//スプライト
	LPDIRECT3DTEXTURE9 m_pDrawRect;															//矩形描画用テクスチャ

	unsigned int m_StringTextureNowSize;													//文字列テクスチャの合計サイズ
	unsigned int m_StringTextureMaxSize;													//文字列テクスチャの最大サイズ
	map < string, StringTexture >  m_StringTexture;												//文字列テクスチャ( < "テキスト_フォント_サイズ_その他", 文字列テクスチャ構造体 > )

	DX9AGraphic(const DX9AGraphic&);														//コピーコンストラクタ(禁止)
	DX9AGraphic& operator =(const DX9AGraphic&);											//代入演算子(禁止)
};

//DirectX Graphicsラッパーへのアクセッサ
/**
*	@brief	DX9AGraphic	クラスへのアクセッサクラスです。 < br > 
*			使用前に、必ずSetParentメソッドを実行してください。 < br > 
*			また、このクラス経由で	DX9AGraphic	クラスのプライベートメンバを操作するのは大変危険な行為です。 < br > 
*			それを理解し、十分注意した上で使用するようにしてください。
*/
class DX9AGraphicAccessor{
public:
/**
*	@brief	デフォルトコンストラクタです。
*/
	DX9AGraphicAccessor();																	//デフォルトコンストラクタ

/**
*	@brief	アクセス対象の	DX9AGraphic	クラスを設定します。
*	@param	Parent	[in]アクセス対象の	DX9AGraphic	クラスを指定します。
*/
	void SetParent(DX9AGraphic* Parent);													//親エンジンを設定

/**
*	@brief	 < a href="http://msdn.microsoft.com/ja-jp/library/cc324302.aspx" target="_blank" > IDirect3D9インターフェイスへのポインタ < /a > を取得します。
*	@return	 < a href="http://msdn.microsoft.com/ja-jp/library/cc324302.aspx" target="_blank" > IDirect3D9インターフェイスへのポインタ < /a > を返します。
*/
	LPDIRECT3D9 GetD3D9();																	//Direct3D9オブジェクトを取得
/**
*	@brief	 < a href="http://msdn.microsoft.com/ja-jp/library/cc372361.aspx" target="_blank" > ID3DXSpriteインターフェイスへのポインタ < /a > を取得します。
*	@return	 < a href="http://msdn.microsoft.com/ja-jp/library/cc372361.aspx" target="_blank" > ID3DXSpriteインターフェイスへのポインタ < /a > を返します。
*/
	LPD3DXSPRITE GetD3DXSprite();															//スプライトオブジェクトを取得
/**
*	@brief	 < a href="http://msdn.microsoft.com/ja-jp/library/cc324252.aspx" target="_blank" > IDirect3DDevice9インターフェイスへのポインタ < /a > を取得します。
*	@return	 < a href="http://msdn.microsoft.com/ja-jp/library/cc324252.aspx" target="_blank" > IDirect3DDevice9インターフェイスへのポインタ < /a > を返します。
*/
	LPDIRECT3DDEVICE9 GetD3D9Device();														//Direct3DDevice9オブジェクトを取得
private:
	DX9AGraphic* Outer;																		//親エンジンのアドレス

	DX9AGraphicAccessor(const DX9AGraphicAccessor&);										//コピーコンストラクタ(禁止)
	DX9AGraphicAccessor& operator =(const DX9AGraphicAccessor&);							//代入演算子(禁止)
};

//アクセッサを取得
/**
*	@brief	DX9AGraphicAccessor	クラスを取得します。
*	@param	Parent	[in]アクセス対象の	DX9AGraphic	クラスを指定します。
*	@return	DX9AGraphicAccessor	クラスへのポインタを返します。
*/
DX9AGraphicAccessor* GetDX9AGraphicAccessor(DX9AGraphic* Parent);

}
}
}

#endif

 ヘッダに対する解説では本クラスの使用方法を説明する。

 1.DX9AGraphicクラスのインスタンスを生成する
 2.Initメソッドを呼び出し、DirectX Graphicsの初期化を行う
 3.メッセージループ内でAppIdleメソッドを呼び出し、アイドル処理を行う
  (AppIdleメソッドの戻り値がfalseの場合はエラーを表示し終了処理を行う)
 4.ウインドウプロシージャ内でMsgProcメソッドを呼び出し、メッセージ処理を行う

具体例

DX9AGraphic g_DXProjectGraphics;

LRESULT CALLBACK MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
	g_DXProjectGraphics.MsgProc(hWnd, uMsg, wParam, lParam);
	switch(uMsg){
		case(WM_CLOSE):
			if(MessageBox(g_DXProjectGraphics.GetHWND(), "終了しますか?", "確認", MB_YESNO)==IDYES){
				DestroyWindow(g_DXProjectGraphics.GetHWND());
			}
			return(0);
			break;
		case(WM_DESTROY):
			PostQuitMessage(0);
			return(0);
			break;
		case(WM_SYSKEYDOWN):
			if(wParam==VK_MENU){
				return(0);
			}
			break;
	}
	return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){

	//DirectXを初期化
	if(!g_DXProjectGraphics.Init(hInstance, "アプリケーション名", MsgProc, 800, 600, 10 * 1024 * 1024, false)){
		MessageBox(g_DXProjectGraphics.GetHWND(), "DirectX Graphicsの初期化に失敗しました!", "エラー!", MB_OK | MB_ICONWARNING);
		return(0);
	}

	//メッセージループ
	MSG msg;
	do{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else{
			//アイドル処理
			if(!g_DXProjectGraphics.AppIdle()){
				//エラー:アプリケーションを終了
				MessageBox(g_DXProjectGraphics.GetHWND(), "消失したデバイスが復元できません!", "エラー!", MB_OK | MB_ICONWARNING);
				DestroyWindow(g_DXProjectGraphics.GetHWND());
			}
		}
	}while(msg.message!=WM_QUIT);

	return(static_cast < int > (msg.wParam));
}

 ……これだけである、というにはいささか複雑か(´Д`)

 では、以下にて具体的な説明を行っていく。
 ただしそれなりに長いソースであるため、なるべく説明は簡略に行う。 

17〜43行目

//文字列テクスチャ
/**
*	@brief	文字列テクスチャの情報が格納されている構造体です。
* ユーザーが使用する必要はありません。 */ struct StringTexture{ /** * @brief 文字列テクスチャが最後に参照された時間です。 */ DWORD LastRefTime; //最後に参照された時間 /** * @brief 文字列テクスチャのサイズです(単位:バイト) */ unsigned int Size; //テクスチャのサイズ /** * @brief 文字列テクスチャの横幅です。 */ unsigned int Width; //テクスチャの横幅 /** * @brief 文字列テクスチャの縦幅です。 */ unsigned int Height; //テクスチャの縦幅 /** * @brief 文字列テクスチャです(IDirect3DTexture9インターフェイスへのポインタ) */ LPDIRECT3DTEXTURE9 Texture; //テクスチャ };

 文字列テクスチャ構造体を定義している。
 DX9AGraphicクラスのユーザが知る必要はない。
 一応説明しておくと、DX9AGraphicクラス内では文字列テクスチャの管理を行っている。
 そのため各種情報の管理用に本構造体を定義し、DX9AGraphicクラス内で使用している。

92〜98行目

	//アイドル時の処理(必ず実行すること)
/**
*	@brief	アイドル時の処理を行います。
* メインループ中で、必ず実行してください。 * @return 処理が成功した場合はtrue、失敗した場合はfalseを返します。 */ bool AppIdle();

 AppIdleメソッドを宣言している。
 本メソッドは、メッセージループ内で呼び出すことで以下の処理を行っている。
 1.Direct3Dデバイス、D3Dオブジェクト(いずれもDirectX Graphicsの動作に必要なもの)の存在をチェックする
 2.文字列テクスチャの管理を行い、合計サイズが初期化時に指定した最大サイズを上回った場合は自動解放を行う
 3.消失したDirect3Dデバイス(ウインドウが非アクティブになるとDirect3Dデバイスは消失する)の復元をアクティブ時に試みる

100〜109行目

	//ウインドウプロシージャ(必ず実行すること)
/**
*	@brief	ウインドウプロシージャ内での処理を行います。
* ウインドウプロシージャ内で、必ず実行してください。 * @param hWnd [in]ウインドウプロシージャのhWndを指定します。
* @param uMsg [in]ウインドウプロシージャのuMsgを指定します。 * @param wParam [in]ウインドウプロシージャのwParamを指定します。 * @param lParam [in]ウインドウプロシージャのlParamを指定します。 */ void MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

 MsgProcメソッドを宣言している。
 本メソッドは、ウインドウプロシージャ内で呼び出すことで以下の処理を行っている。
 1.アクティブ状態かのフラグをセットしている
 2.アプリケーション終了時の処理を行っている

159〜203行目

/**
*	@brief	矩形の描画を行います。
*	@param	Rect		[in]矩形をRECTで指定します。
*	@param	Color		[in]塗り潰す色をD3DCOLORで指定します。
*	@param	Degree		[in]回転する角度を指定します(単位:度)
*	@param	BlendOp		[in]ブレンディング処理をD3DBLENDOPで指定します。
*	@param	SrcBlend	[in]転送元のブレンディングモードをD3DBLENDで指定します。
*	@param	DestBlend	[in]転送先のブレンディングモードをD3DBLENDで指定します。
*/
	void DrawRect(RECT Rect, D3DCOLOR Color, float Degree = 0.0f, D3DBLENDOP BlendOp = D3DBLENDOP_ADD, D3DBLEND SrcBlend = D3DBLEND_SRCALPHA, D3DBLEND DestBlend = D3DBLEND_INVSRCALPHA);
																							//矩形を描画
/**
*	@brief	文字列の描画を行います。
*	@param	Text		[in]文字列を指定します。
*	@param	x			[in]文字列の描画先のX座標を指定します。
*	@param	y			[in]文字列の描画先のY座標を指定します。
*	@param	Color		[in]文字列の色をD3DCOLORで指定します。
*	@param	Font		[in]文字列のフォントを指定します。
*	@param	Size		[in]文字列のサイズを指定します。
*	@param	IsBold		[in]文字列が太字かを指定します。
* 太字の場合はtrueを、太字でない場合はfalseを指定します。 * @param IsItalic [in]文字列が斜体かを指定します。
* 斜体の場合はtrueを、斜体でない場合はfalseを指定します。 * @param Degree [in]回転する角度を指定します(単位:度) * @param BlendOp [in]ブレンディング処理をD3DBLENDOPで指定します。 * @param SrcBlend [in]転送元のブレンディングモードをD3DBLENDで指定します。 * @param DestBlend [in]転送先のブレンディングモードをD3DBLENDで指定します。 */ void DrawFreeText(const string& Text, int x, int y, D3DCOLOR Color, const string& Font, unsigned int Size, bool IsBold, bool IsItalic, float Degree = 0.0f, D3DBLENDOP BlendOp = D3DBLENDOP_ADD, D3DBLEND SrcBlend = D3DBLEND_SRCALPHA, D3DBLEND DestBlend = D3DBLEND_INVSRCALPHA); //文字列を描画 /** * @brief テクスチャの転送を行います。 * @param Texture [in]対象のテクスチャを指定します。 * @param x [in]テクスチャの描画先のX座標を指定します。 * @param y [in]テクスチャの描画先のY座標を指定します。 * @param Color [in]テクスチャの描画色をD3DCOLORで指定します。 * @param SrcRect [in]転送元矩形をRECTで指定します。 * @param BlendOp [in]ブレンディング処理をD3DBLENDOPで指定します。 * @param SrcBlend [in]転送元のブレンディングモードをD3DBLENDで指定します。 * @param DestBlend [in]転送先のブレンディングモードをD3DBLENDで指定します。 * @param ScalingX [in]拡大倍率(X方向)を指定します。 * @param ScalingY [in]拡大倍率(Y方向)を指定します。 * @param Degree [in]回転する角度を指定します(単位:度) */ void GeneralBlt(LPDIRECT3DTEXTURE9 Texture, int x, int y, D3DCOLOR Color, const RECT* SrcRect, D3DBLENDOP BlendOp, D3DBLEND SrcBlend, D3DBLEND DestBlend, float ScalingX = 1.0f, float ScalingY = 1.0f, float Degree = 0.0f);

 DX9AGraphicクラスはDirectX Graphicsのラッパークラスだが、最低限の描画メソッドを実装している。
 これらのメソッドは普通に直接使用することも可能だが、主に他のクラスから呼ぶことを前提に実装している。

257〜258行目

	DX9AGraphic(const DX9AGraphic&);														//コピーコンストラクタ(禁止)
	DX9AGraphic& operator =(const DX9AGraphic&);											//代入演算子(禁止)

 コピーコンストラクタと代入演算子を「潰している」。
 本イディオムについては「Effective C++」を参照のこと。
 ……と書くと、あまりに不親切すぎるので一応解説しとく(´Д`)

 上記のようにヘッダにクラスのコピーコンストラクタと代入演算子の宣言を記述し、
 定義を記述しないでおくとクラスのコピーや代入を試みた際に「定義されてねーよボケ!」とコンパイラがエラーを吐く。
 つまり、「コピーも代入も暗黙的には行えない」クラスを本イディオムで作ることができる。コピーされるとまずいクラスの設計では非常に有用である。
 

261〜309行目

//DirectX Graphicsラッパーへのアクセッサ
/**
*	@brief	DX9AGraphic	クラスへのアクセッサクラスです。
* 使用前に、必ずSetParentメソッドを実行してください。
* また、このクラス経由で DX9AGraphic クラスのプライベートメンバを操作するのは大変危険な行為です。
* それを理解し、十分注意した上で使用するようにしてください。 */ class DX9AGraphicAccessor{ public: /** * @brief デフォルトコンストラクタです。 */ DX9AGraphicAccessor(); //デフォルトコンストラクタ /** * @brief アクセス対象の DX9AGraphic クラスを設定します。 * @param Parent [in]アクセス対象の DX9AGraphic クラスを指定します。 */ void SetParent(DX9AGraphic* Parent); //親エンジンを設定 /** * @brief IDirect3D9インターフェイスへのポインタを取得します。 * @return IDirect3D9インターフェイスへのポインタを返します。 */ LPDIRECT3D9 GetD3D9(); //Direct3D9オブジェクトを取得 /** * @brief ID3DXSpriteインターフェイスへのポインタを取得します。 * @return ID3DXSpriteインターフェイスへのポインタを返します。 */ LPD3DXSPRITE GetD3DXSprite(); //スプライトオブジェクトを取得 /** * @brief IDirect3DDevice9インターフェイスへのポインタを取得します。 * @return IDirect3DDevice9インターフェイスへのポインタを返します。 */ LPDIRECT3DDEVICE9 GetD3D9Device(); //Direct3DDevice9オブジェクトを取得 private: DX9AGraphic* Outer; //親エンジンのアドレス DX9AGraphicAccessor(const DX9AGraphicAccessor&); //コピーコンストラクタ(禁止) DX9AGraphicAccessor& operator =(const DX9AGraphicAccessor&); //代入演算子(禁止) }; //アクセッサを取得 /** * @brief DX9AGraphicAccessor クラスを取得します。 * @param Parent [in]アクセス対象の DX9AGraphic クラスを指定します。 * @return DX9AGraphicAccessor クラスへのポインタを返します。 */ DX9AGraphicAccessor* GetDX9AGraphicAccessor(DX9AGraphic* Parent);

 DX9AGraphicクラスのアクセッサクラス、ならびにアクセッサクラスの取得関数を定義している。
 ちなみにアクセッサクラスというのは、「触ると危険なメンバ」にアクセスするためのクラスのことである。
 あまり触らせたくない、だが触る必要があるメンバにアクセスさせる場合は個人的にはこうしておいた方が良い。
 何故なら一手間かけさせることで「危ないメンバ」であると認識しやすいし、grep等でアクセス箇所を特定するのも容易だからだ。

 ざっと説明はこんなところである。
 大分端折ったつもりなのだが、やはり長くなってしまった……(;´Д`)

 

4.具体例(ソース解説)

 次はソース解説である。

#include "stdafx.h"
#include "../index.h"
#include "DX9AGraphic.h"

namespace nsDX9A{
namespace nsGraphics{
namespace nsDX9AGraphic{

//デフォルトコンストラクタ
DX9AGraphic::DX9AGraphic(){
	m_hWnd = NULL;
	m_hInst = NULL;
	m_IsActive = false;
	m_IsBeginScene = false;
	m_IsBeginSprite = false;
	m_IsDeviceLost = false;
	m_ScreenWidth = 0;
	m_ScreenHeight = 0;
	m_IsFullScreen = false;
	m_IsUseDepthStencil = false;
	m_IsUseMultiSample = false;
	ZeroMemory(&m_WindowLastPos, sizeof(m_WindowLastPos));

	m_pD3D = NULL;
	m_pD3DDevice = NULL;
	ZeroMemory(&m_D3DParamNow, sizeof(m_D3DParamNow));
	ZeroMemory(&m_D3DParamWin, sizeof(m_D3DParamWin));
	ZeroMemory(&m_D3DParamFull, sizeof(m_D3DParamFull));
	m_FmtRenderTextureWin = D3DFMT_UNKNOWN;
	m_FmtRenderTextureFull = D3DFMT_UNKNOWN;

	m_pD3DXSprite = NULL;
	m_pDrawRect = NULL;

	m_StringTextureNowSize = 0;
	m_StringTextureMaxSize = 0;
}
//デストラクタ
DX9AGraphic::~DX9AGraphic(){
	CleanupApp();
}

//初期化(必ず実行すること)
bool DX9AGraphic::Init(HINSTANCE hInst, LPCTSTR WindowName, WNDPROC WndProc, int ScreenWidth, int ScreenHeight, unsigned int StringTextureMaxSize, 
					   bool IsFullScreen, bool UseDepthStencil, bool UseMultiSample, HICON hIcon, HCURSOR hCursor, HICON hIconSm){

	if(m_hInst){
		DX9AErrOut("Failed : DX9AGraphic::Init Already Initialized\n");
		return(false);
	}

	//メンバ変数を初期化
	m_hInst = hInst;
	m_ClassName = WindowName;
	m_ScreenWidth = ScreenWidth;
	m_ScreenHeight = ScreenHeight;
	m_IsFullScreen = IsFullScreen;
	m_IsUseDepthStencil = UseDepthStencil;
	m_IsUseMultiSample = UseMultiSample;
	m_WindowLastPos.top = 0;
	m_WindowLastPos.left = 0;
	m_WindowLastPos.right = ScreenWidth;
	m_WindowLastPos.bottom = ScreenHeight;
	m_StringTextureMaxSize = StringTextureMaxSize;

	//アプリケーションを初期化
	if(!InitApp(WindowName, WndProc, hIcon, hCursor, hIconSm)){
		DX9AErrOut("Failed : DX9AGraphic::Init InitApp\n");
		return(false);
	}

	//Direct3Dに管理されているオブジェクトを初期化
	if(!InitD3D()){
		DX9AErrOut("Failed : DX9AGraphic::Init InitD3D\n");
		return(false);
	}

	return(true);
}

//アイドル時の処理(必ず実行すること)
bool DX9AGraphic::AppIdle(){

	if(!m_pD3D || !m_pD3DDevice){
		if(m_pD3D){
			DX9AErrOut("Failed : DX9AGraphic::AppIdle No D3DDevice\n");
		}
		else{
			DX9AErrOut("Failed : DX9AGraphic::AppIdle No D3D\n");
		}
		return(false);
	}

	if(!m_IsActive){
		return(true);
	}

	//文字列テクスチャの管理
	DWORD Now = timeGetTime();
	map < string, StringTexture > ::iterator it;
	while(m_StringTextureNowSize > m_StringTextureMaxSize){
		it = m_StringTexture.begin();
		for(map < string, StringTexture > ::iterator it2=m_StringTexture.begin();it2!=m_StringTexture.end();it2++){
			if(Now-it2->second.LastRefTime > Now-it->second.LastRefTime){
				it = it2;
			}
			if(Now-it2->second.LastRefTime==Now-it->second.LastRefTime){
				if(it2->second.Size > it->second.Size){
					it = it2;
				}
			}
		}
		m_StringTextureNowSize -= it->second.Size;
		SAFE_RELEASE(it->second.Texture);
		m_StringTexture.erase(it);
	}

	//消失したデバイスの復元処理
	HRESULT hr;
	if(m_IsDeviceLost){

		//デバイス状態をチェック
		hr = m_pD3DDevice->TestCooperativeLevel();
		if(FAILED(hr)){

			if(hr==D3DERR_DEVICELOST){
				return(true);			//まだ失われている
			}
			if(hr!=D3DERR_DEVICENOTRESET){
				DX9AErrOut("Failed : DX9AGraphic::AppIdle Unknown Error\n");
				return(false);			//予期せぬエラー
			}

			//Direct3Dに管理されていないオブジェクトを開放
			CleanupD3DObject();

			//復元を試みる
			hr = m_pD3DDevice->Reset(&m_D3DParamNow);
			if(FAILED(hr)){
				if(hr==D3DERR_DEVICELOST){
					return(true);		//まだ失われている
				}
				else{
					DX9AErrOut("Failed : DX9AGraphic::AppIdle Reset\n");
					return(false);		//復元に失敗
				}
			}

			//Direct3Dに管理されていないオブジェクトを再取得
			if(!InitD3DObject()){
				DX9AErrOut("Failed : DX9AGraphic::AppIdle InitD3DObject\n");
				return(false);
			}

		}

		//復元に成功
		m_IsDeviceLost = false;

	}

	//チェック
	hr = m_pD3DDevice->TestCooperativeLevel();
	if(FAILED(hr)){
		if(hr==D3DERR_DEVICELOST){
			m_IsDeviceLost = true;
		}
		else{
			DX9AErrOut("Failed : DX9AGraphic::AppIdle TestCooperativeLevel Failed\n");
			return(false);
		}
	}

	return(true);
}

//ウインドウプロシージャ(必ず呼び出すこと)
void DX9AGraphic::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
	switch(uMsg){
		case(WM_ACTIVATE):
			m_IsActive = (LOWORD(wParam)!=0);
			break;
		case(WM_DESTROY):
			CleanupD3DObject();
			CleanupD3D();
			break;
	}
	UNREFERENCED_PARAMETER(hWnd);
	UNREFERENCED_PARAMETER(lParam);
}

//その他(初期化を済ませてから呼び出すこと)

//アクティブ状態かを取得
bool DX9AGraphic::IsActive() const{
	return(m_IsActive);
}

//ウインドウハンドルを取得
HWND DX9AGraphic::GetHWND() const{
	return(m_hWnd);
}

//画面の横幅を取得
int DX9AGraphic::GetScreenWidth() const{
	return(m_ScreenWidth);
}
//画面の縦幅を取得
int DX9AGraphic::GetScreenHeight() const{
	return(m_ScreenHeight);
}
//フルスクリーンモードか否かを取得
bool DX9AGraphic::GetFullScreen() const{
	return(m_IsFullScreen);
}
//フルスクリーンモードか否かを設定
bool DX9AGraphic::SetFullScreen(bool IsFullScreen){
	if(m_IsFullScreen!=IsFullScreen){

		m_IsFullScreen = IsFullScreen;

		CleanupD3DObject();

		if(m_IsFullScreen){
			m_D3DParamNow = m_D3DParamFull;
			GetWindowRect(m_hWnd, &m_WindowLastPos);
		}
		else{
			m_D3DParamNow = m_D3DParamWin;
		}

		HRESULT hr = m_pD3DDevice->Reset(&m_D3DParamNow);
		if(FAILED(hr)){
			if(hr==D3DERR_DEVICELOST){
				m_IsDeviceLost = true;
			}
			else{
				DestroyWindow(m_hWnd);
			}
			DX9AErrOut("Failed : DX9AGraphic::SetFullScreen() Reset\n");
			return(false);
		}

		if(!InitD3DObject()){
			DX9AErrOut("Failed : DX9AGraphic::SetFullScreen() InitD3DObject\n");
			DestroyWindow(m_hWnd);
			return(false);
		}

		if(m_IsFullScreen){
			SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
		}
		else{
			SetWindowLong(m_hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE);
			SetWindowPos(m_hWnd, HWND_NOTOPMOST, m_WindowLastPos.left, m_WindowLastPos.top, 
						 m_WindowLastPos.right - m_WindowLastPos.left, m_WindowLastPos.bottom - m_WindowLastPos.top, SWP_SHOWWINDOW);
		}

	}
	return(true);
}

//画面を消去
void DX9AGraphic::Clear(D3DCOLOR Color){
	m_pD3DDevice->Clear(0, NULL, m_IsUseDepthStencil ? D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL : D3DCLEAR_TARGET, Color, 1.0f, 0);
}

//画面を更新
void DX9AGraphic::Present(){
	EndSprite();
	EndScene();
	m_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

//矩形を描画
void DX9AGraphic::DrawRect(RECT Rect, D3DCOLOR Color, float Degree, D3DBLENDOP BlendOp, D3DBLEND SrcBlend, D3DBLEND DestBlend){
	RECT SrcRect = {0, 0, 1, 1};
	float ScalingX = static_cast < float > (Rect.right-Rect.left);
	float ScalingY = static_cast < float > (Rect.bottom-Rect.top);
	GeneralBlt(m_pDrawRect, Rect.left, Rect.top, Color, &SrcRect, BlendOp, SrcBlend, DestBlend, ScalingX, ScalingY, Degree);
}
//文字列を描画
void DX9AGraphic::DrawFreeText(const string& Text, int x, int y, D3DCOLOR Color, const string& Font, unsigned int Size, bool IsBold, bool IsItalic, float Degree, D3DBLENDOP BlendOp, D3DBLEND SrcBlend, D3DBLEND DestBlend){
	//内部関数用クラス
	class InnerFunction{
	public:
		//GetGlyphOutline用にエンコード
		static void EncodeText(const string& Src, wstring& Dest){
			Dest.clear();
			for(unsigned int i=0;Src[i]!='\0';){
				unsigned int ChByte = ((Src[i] >= static_cast < char > (0x81) && Src[i] <= static_cast < char > (0x9F)) || 
									  (Src[i] >= static_cast < char > (0xE0) && Src[i] <= static_cast < char > (0xFF))) ? 2 : 1;
				Dest.push_back(ChByte==2 ? static_cast < BYTE > (Src[i]) * 256 + static_cast < BYTE > (Src[i+1]) : static_cast < BYTE > (Src[i]));
				i += ChByte;
			}
		}
		//論理和コピー
		static void* memcpy_or(void* s1, const void* s2, size_t n){
			register BYTE* ss1;
			register const BYTE* ss2;
			for(ss1=reinterpret_cast < BYTE* > (s1), ss2=reinterpret_cast < const BYTE* > (s2);n!=0;n--){
				*ss1++ |= *ss2++;
			}
			return(s1);
		}
	};

	//空文字列の場合
	if(Text==""){
		return;
	}
	//空文字列でない場合
	else{
		//テキスト(描画時に利用)を生成
		char KeyText[1024] = {0};
		sprintf(KeyText, "%s_%s_%d_%d", Text.c_str(), Font.c_str(), Size, (IsBold ? 1 : 0)+(IsItalic ? 2 : 0));

		//GetGlyphOutline用にエンコード
		wstring Text2;
		InnerFunction::EncodeText(Text, Text2);

		//文字列テクスチャが存在しない場合は作成する
		if(m_StringTexture.find(KeyText)==m_StringTexture.end()){

			//フォントの作成
			LOGFONT LF = {Size, 0, 0, 0, (IsBold ? FW_BOLD : 0), (IsItalic ? TRUE : FALSE), 0, 0,
						  SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, ""};
			strcpy(LF.lfFaceName, Font.c_str());
			HFONT hFont;
			if((hFont = CreateFontIndirect(&LF))==0){
				DX9AErrOut("Failed : DX9AGraphic::DrawFreeText() CreateFontIndirect\n");
				return;
			}

			//デバイスコンテキストを取得
			HDC hDC = GetDC(NULL);
			HFONT OldFont = reinterpret_cast < HFONT > (SelectObject(hDC, hFont));

			//テクスチャのサイズを取得→確保
			TEXTMETRIC TM;
			GLYPHMETRICS GM;
			UINT TexWidth = 0, TexHeight = 0;
			CONST MAT2 Mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
			GetTextMetrics(hDC, &TM);
			TexHeight += TM.tmHeight;
			for(unsigned int i=0;Text2[i]!=L'\0';i++){
				if(Text2[i]==L'\n'){
					TexHeight += TM.tmHeight;
				}
				else{
					GetGlyphOutline(hDC, Text2[i], GGO_METRICS, &GM, 0, NULL, &Mat);
					TexWidth += GM.gmCellIncX;
				}
			}
			if(IsItalic){
				TexWidth += Size / 4;
			}
			unsigned int cnt;
			UINT TmpTexWidth = TexWidth, TmpTexHeight = TexHeight;
			for(cnt=0;pow(2.0f, static_cast < float > (cnt)) < TexWidth;cnt++);	TexWidth = static_cast < UINT > (pow(2.0f, static_cast < float > (cnt)));
			for(cnt=0;pow(2.0f, static_cast < float > (cnt)) < TexHeight;cnt++);	TexHeight = static_cast < UINT > (pow(2.0f, static_cast < float > (cnt)));
			m_StringTexture.insert(pair < string, StringTexture > (KeyText, StringTexture()));
			if(FAILED(D3DXCreateTexture(m_pD3DDevice, TexWidth, TexHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &(m_StringTexture.find(KeyText)->second.Texture)))){
				DX9AErrOut("Failed : DX9AGraphic::DrawFreeText() D3DXCreateTexture\n");
				SelectObject(hDC, OldFont);
				DeleteObject(hFont);
				ReleaseDC(NULL, hDC);
				return;
			}

			//フォントビットマップ取得→テクスチャに書き込み
			DWORD Alpha, Color;
			D3DLOCKED_RECT LockedRect;
			BYTE* p = new BYTE[4 * TexWidth * TexHeight];
			int Base_X = 0, Base_Y = 0, Bmp_W, Bmp_H, Ofs_X, Ofs_Y;
			if(FAILED(m_StringTexture.find(KeyText)->second.Texture->LockRect(0, &LockedRect, NULL, D3DLOCK_DISCARD))){
				DX9AErrOut("Failed : DX9AGraphic::DrawFreeText() LockRect\n");
				SelectObject(hDC, OldFont);
				DeleteObject(hFont);
				ReleaseDC(NULL, hDC);
				SAFE_DELETE_ARRAY(p);
				return;
			}
			FillMemory(LockedRect.pBits , LockedRect.Pitch * TexHeight, 0);
			for(unsigned int i=0;Text2[i]!=L'\0';i++){
				if(Text2[i]==L'\n'){
					Base_X = 0;
					Base_Y += TM.tmHeight;
				}
				else{
					GetGlyphOutline(hDC, Text2[i], GGO_METRICS, &GM, 0, NULL, &Mat);
					if(Text2[i]!=32/* 半角スペース */ && Text2[i]!=33088/* 全角スペース */){
						GetGlyphOutline(hDC, Text2[i], GGO_GRAY8_BITMAP, &GM, 4 * TexWidth * TexHeight, p, &Mat);
						Bmp_W = GM.gmBlackBoxX + (4 - (GM.gmBlackBoxX % 4)) % 4;
						Bmp_H = GM.gmBlackBoxY;
						Ofs_X = GM.gmptGlyphOrigin.x;
						Ofs_Y = TM.tmAscent - GM.gmptGlyphOrigin.y;
						for(int Y=0;Y < static_cast < int > (GM.gmBlackBoxY);Y++){
							for(int X=0;X < static_cast < int > (GM.gmBlackBoxX);X++){
								Alpha = (255 * p[Bmp_W * Y + X]) / 64;
								Color = 0x00ffffff | (Alpha << 24);
								InnerFunction::memcpy_or((BYTE*)LockedRect.pBits+LockedRect.Pitch*(Base_Y+Ofs_Y+Y)+4*(Base_X+Ofs_X+X), &Color, sizeof(Color)); 
							}
						}
					}
					Base_X += GM.gmCellIncX;
				}
			}
			m_StringTexture.find(KeyText)->second.Texture->UnlockRect(0);
			SAFE_DELETE_ARRAY(p);

			//文字列テクスチャの情報を設定
			m_StringTexture.find(KeyText)->second.Size = 4 * TexWidth * TexHeight;
			m_StringTexture.find(KeyText)->second.Width = TmpTexWidth;
			m_StringTexture.find(KeyText)->second.Height = TmpTexHeight;

			//文字列テクスチャのサイズ > 文字列テクスチャの最大サイズなら、文字列テクスチャの最大サイズを拡張する
			if(m_StringTexture.find(KeyText)->second.Size > m_StringTextureMaxSize){
				m_StringTextureMaxSize = m_StringTexture.find(KeyText)->second.Size;
			}

			//文字列テクスチャの合計サイズを増加
			m_StringTextureNowSize += m_StringTexture.find(KeyText)->second.Size;

			//後始末
			SelectObject(hDC, OldFont);
			DeleteObject(hFont);
			ReleaseDC(NULL, hDC);

		}

		//文字列を描画
		RECT SrcRect = {0, 0, m_StringTexture.find(KeyText)->second.Width, m_StringTexture.find(KeyText)->second.Height};
		GeneralBlt(m_StringTexture.find(KeyText)->second.Texture, x, y, Color, &SrcRect, BlendOp, SrcBlend, DestBlend, 1.0, 1.0, Degree);

		//文字列テクスチャの最後に参照された時間を更新
		m_StringTexture.find(KeyText)->second.LastRefTime = timeGetTime();

	}

}
//汎用転送
void DX9AGraphic::GeneralBlt(LPDIRECT3DTEXTURE9 Texture, int x, int y, D3DCOLOR Color, const RECT* SrcRect, D3DBLENDOP BlendOp, D3DBLEND SrcBlend, D3DBLEND DestBlend, float ScalingX, float ScalingY, float Degree){
	if(Texture){
		BeginScene();
		BeginSprite();
		//マトリックスを設定
		//変換行列初期化
		D3DXMATRIX Mat;
		D3DXMatrixIdentity(&Mat);
		//拡大処理
		D3DXMATRIX Scaling;
		D3DXMatrixScaling(&Scaling, ScalingX, ScalingY, 1.0f);
		//回転処理(中心点:スプライトの中心座標)
		D3DXMATRIX Rotation, t1, t2;
		float ox = SrcRect ? static_cast < float > (SrcRect->right - SrcRect->left) * ScalingX / 2.0f : 0.0f;
		float oy = SrcRect ? static_cast < float > (SrcRect->bottom - SrcRect->top) * ScalingY / 2.0f : 0.0f;
		D3DXMatrixTranslation(&t1, -ox, -oy, 0.0f);
		D3DXMatrixRotationZ(&Rotation, D3DXToRadian(Degree));
		D3DXMatrixTranslation(&t2, ox, oy, 0.0f);
		Rotation = t1 * Rotation * t2;
		//移動処理
		D3DXMATRIX Translation;
		D3DXMatrixTranslation(&Translation, static_cast < float > (x), static_cast < float > (y), 0.0f);
		//行列を合成
		Mat = Scaling * Rotation * Translation;
		//トランスフォームステートを設定
		m_pD3DXSprite->SetTransform(&Mat);
		//レンダリングステートを設定
		m_pD3DDevice->SetRenderState(D3DRS_BLENDOP, BlendOp);
		m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, SrcBlend);
		m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, DestBlend);
		//転送
		m_pD3DXSprite->Draw(Texture, SrcRect, NULL, NULL, Color);
		m_pD3DXSprite->Flush();
	}
}

//描画を開始
void DX9AGraphic::BeginScene(){
	if(!m_IsBeginScene){
		m_pD3DDevice->BeginScene();
		m_IsBeginScene = true;
	}
}
//描画を終了
void DX9AGraphic::EndScene(){
	if(m_IsBeginScene){
		m_pD3DDevice->EndScene();
		m_IsBeginScene = false;
	}
}

//スプライトの描画を開始
void DX9AGraphic::BeginSprite(){
	if(!m_IsBeginSprite){
		m_pD3DXSprite->Begin(D3DXSPRITE_ALPHABLEND);
		m_IsBeginSprite = true;
	}
}
//スプライトの描画を終了
void DX9AGraphic::EndSprite(){
	if(m_IsBeginSprite){
		m_pD3DXSprite->End();
		m_IsBeginSprite = false;
	}
}

//アプリケーションを初期化
bool DX9AGraphic::InitApp(LPCTSTR WindowName, WNDPROC WndProc, HICON hIcon, HCURSOR hCursor, HICON hIconSm){

	//ウインドウクラスを設定
	WNDCLASSEX wc = { sizeof(wc), CS_CLASSDC, WndProc, 0, 0, m_hInst,
					  hIcon, hCursor, NULL, NULL, WindowName, hIconSm};
	if(!RegisterClassEx(&wc)){
		DX9AErrOut("Failed : DX9AGraphic::InitApp() RegisterClassEx\n");
		return(false);
	}

	//ウインドウを生成
	RECT WindowRect = {0};
	RECT DesktopRect = {0};
	GetWindowRect(GetDesktopWindow(), &DesktopRect);
	AdjustWindowRect(&m_WindowLastPos, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, FALSE);
	m_WindowLastPos.bottom -= m_WindowLastPos.top;
	m_WindowLastPos.right -= m_WindowLastPos.left;
	m_WindowLastPos.left = (DesktopRect.right - m_WindowLastPos.right) / 2;
	m_WindowLastPos.top = (DesktopRect.bottom - m_WindowLastPos.bottom) / 2;
	m_WindowLastPos.bottom += m_WindowLastPos.top;
	m_WindowLastPos.right += m_WindowLastPos.left;
	if(m_IsFullScreen){
		//フルスクリーンモード
		WindowRect.top = 0;
		WindowRect.left = 0;
		WindowRect.right = m_ScreenWidth;
		WindowRect.bottom = m_ScreenHeight;
	}
	else{
		//ウインドウモード
		WindowRect.top = m_WindowLastPos.top;
		WindowRect.left = m_WindowLastPos.left;
		WindowRect.right = m_WindowLastPos.right - m_WindowLastPos.left;
		WindowRect.bottom = m_WindowLastPos.bottom - m_WindowLastPos.top;
	}
	m_hWnd = CreateWindow(WindowName, WindowName, m_IsFullScreen ? WS_POPUP : WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
						  WindowRect.left, WindowRect.top, WindowRect.right, WindowRect.bottom, NULL, NULL, m_hInst, NULL);
	if(!m_hWnd){
		DX9AErrOut("Failed : DX9AGraphic::InitApp() CreateWindow\n");
		return(false);
	}

	ShowWindow(m_hWnd, SW_SHOW);
	UpdateWindow(m_hWnd);
	return(true);
}
//Direct3Dに管理されているオブジェクトを初期化
bool DX9AGraphic::InitD3D(){

	//Direct3D9オブジェクトを初期化
	m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if(!m_pD3D){
		DX9AErrOut("Failed : DX9AGraphic::InitD3D() Direct3DCreate9\n");
		return(false);
	}

	//デバイスの設定を選択
	UINT Adapter;
	D3DDEVTYPE Device;
	if(!SelectD3DDevice(Adapter, Device)){
		DX9AErrOut("Failed : DX9AGraphic::InitD3D() SelectD3DDevice\n");
		return(false);
	}

	//Direct3DDevice9オブジェクトを初期化
	if(m_IsFullScreen){
		m_D3DParamNow = m_D3DParamFull;
	}
	else{
		m_D3DParamNow = m_D3DParamWin;
	}

	/*	↓CheckDeviceCapsメソッドの変更に伴いこちらも変更
	if(FAILED(m_pD3D->CreateDevice(Adapter, Device, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
		if(FAILED(m_pD3D->CreateDevice(Adapter, Device, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
			DX9AErrOut("Failed : DX9AGraphic::InitD3D() CreateDevice\n");
			return(false);
		}
	}
	*/
	if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
		if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
			if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
				if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
					DX9AErrOut("Failed : DX9AGraphic::InitD3D() CreateDevice\n");
					return(false);
				}
			}
		}
	}
	/*	↑CheckDeviceCapsメソッドの変更に伴いこちらも変更	*/

	//ビューポートを設定
	D3DVIEWPORT9 vp;
	vp.X = 0;
	vp.Y = 0;
	vp.Width = m_D3DParamNow.BackBufferWidth;
	vp.Height = m_D3DParamNow.BackBufferHeight;
	vp.MinZ = 0.0f;
	vp.MaxZ = 1.0f;
	if(FAILED(m_pD3DDevice->SetViewport(&vp))){
		DX9AErrOut("Failed : DX9AGraphic::InitD3D() SetViewport\n");
		return(false);
	}

	//テクスチャを初期化
	if(FAILED(D3DXCreateTexture(m_pD3DDevice, 2, 2, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pDrawRect))){
		DX9AErrOut("Failed : DX9AGraphic::InitD3D() D3DXCreateTexture\n");
		return(false);
	}
	else{
		D3DLOCKED_RECT LockedRect;
		if(FAILED(m_pDrawRect->LockRect(0, &LockedRect, NULL, D3DLOCK_DISCARD))){
			if(FAILED(m_pDrawRect->LockRect(0, &LockedRect, NULL, 0))){
				DX9AErrOut("Failed : DX9AGraphic::InitD3D() LockRect\n");
				return(false);
			}
		}
		D3DCOLOR RectColor = D3DCOLOR_ARGB(255, 255, 255, 255);
		for(int y=0;y < 2;y++){
			for(int x=0;x < 2;x++){
				memcpy(reinterpret_cast < BYTE* > (LockedRect.pBits)+LockedRect.Pitch*y+4*x, &RectColor, sizeof(RectColor));
			}
		}
		m_pDrawRect->UnlockRect(0);
	}

	//スプライトを初期化
	if(FAILED(D3DXCreateSprite(m_pD3DDevice, &m_pD3DXSprite))){
		DX9AErrOut("Failed : DX9AGraphic::InitD3D() D3DXCreateSprite\n");
		return(false);
	}

	return(true);
}
//デバイスの設定を選択
bool DX9AGraphic::SelectD3DDevice(UINT& Adapter, D3DDEVTYPE& Device){

	HRESULT hr;

	//アダプタを選択
	Adapter = D3DADAPTER_DEFAULT;

	//デバイスの能力を取得
	D3DCAPS9 Caps;
	//HALデバイスをチェック
	Device = D3DDEVTYPE_HAL;
	hr = m_pD3D->GetDeviceCaps(Adapter, Device, &Caps);
	if(FAILED(hr) || !CheckDeviceCaps(&Caps)){
		DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() GetDeviceCaps HAL\n");

		//REFデバイスをチェック
		Device = D3DDEVTYPE_REF;
		hr = m_pD3D->GetDeviceCaps(Adapter, Device, &Caps);
		if(FAILED(hr) || !CheckDeviceCaps(&Caps)){
			DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() GetDeviceCaps REF\n");
			return(false);
		}

	}

	//現在のディスプレイのフォーマットなどを取得
	D3DDISPLAYMODE DMode;
	if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DMode))){
		DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() GetAdapterDisplayMode\n");
		return(false);
	}

	//ディスプレイとバックバッファのフォーマットを調査
	if(!SelectAdapterFormat(Adapter, Device, DMode)){
		DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() SelectAdapterFormat\n");
		return(false);
	}

	//深度/ステンシルバッファのフォーマットを調査
	if(m_IsUseDepthStencil){
		if(!SelectDepthStencilFormat(Adapter, Device, DMode)){
			DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() SelectDepthStencilFormat\n");
			return(false);
		}
	}

	//レンダリングテクスチャのフォーマットを調査
	if(!SelectRenderTextureFormat(Adapter, Device, DMode)){
		DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() SelectRenderTextureFormat\n");
		return(false);
	}

	//フルシーンアンチエイリアシングを調査
	if(m_IsUseMultiSample){
		if(!SelectMultiSampleType(Adapter, Device)){
			DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() SelectMultiSampleType\n");
			return(false);
		}
	}

	//ディスプレイモードを調査
	if(!SelectDisplayMode(Adapter)){
		DX9AErrOut("Failed : DX9AGraphic::SelectD3DDevice() SelectDisplayMode\n");
		return(false);
	}

	return(true);
}
//デバイスの能力をチェック
bool DX9AGraphic::CheckDeviceCaps(D3DCAPS9* Caps){
	/*	↓EeePC等の低スペックPCで無意味にREFに切り替えられてしまう原因、とりあえずはコメントアウトで対応!
	//プリミティブ数
	if(Caps->MaxPrimitiveCount < 0xFFFF){
		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() MaxPrimitiveCount < 0xFFFF\n");
		return(false);
	}
	//インデックス数
	if(Caps->MaxVertexIndex < 0xFFFF){
		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() MaxVertexIndex < 0xFFFF\n");
		return(false);
	}
	//頂点シェーダバージョン
	if(Caps->VertexShaderVersion < D3DVS_VERSION(1, 1)){
		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() VertexShaderVersion < D3DVS_VERSION(1, 1)\n");
		return(false);
	}
	//ピクセルシェーダバージョン
	if(Caps->PixelShaderVersion < D3DVS_VERSION(1, 1)){
		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() PixelShaderVersion < D3DVS_VERSION(1, 1)\n");
		return(false);
	}
		↑EeePC等の低スペックPCで無意味にREFに切り替えられてしまう原因、とりあえずはコメントアウトで対応!	*/
	UNREFERENCED_PARAMETER(Caps);
	return(true);
}
//ディスプレイとバックバッファのフォーマットを調査
bool DX9AGraphic::SelectAdapterFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode){

	HRESULT hr = S_OK;

	//希望するフォーマット
	D3DFORMAT FmtDisplay[] = FMT_DISPLAY;

	//ウインドウモード
	m_D3DParamWin.BackBufferCount = 1;
	m_D3DParamWin.SwapEffect = D3DSWAPEFFECT_DISCARD;
	m_D3DParamWin.hDeviceWindow = m_hWnd;
	m_D3DParamWin.Windowed = TRUE;
	m_D3DParamWin.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	m_D3DParamWin.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	for(int i=0;i < sizeof(FmtDisplay)/sizeof(FmtDisplay[0]);i++){
		hr = m_pD3D->CheckDeviceType(Adapter, Device, DMode.Format, FmtDisplay[i], TRUE);
		if(SUCCEEDED(hr)){
			m_D3DParamWin.BackBufferFormat = FmtDisplay[i];
			break;
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectAdapterFormat() CheckDeviceType Window\n");
		return(false);
	}

	//フルスクリーンモード
	m_D3DParamFull.BackBufferCount = 1;
	m_D3DParamFull.SwapEffect = D3DSWAPEFFECT_DISCARD;
	m_D3DParamFull.hDeviceWindow = m_hWnd;
	m_D3DParamFull.Windowed = FALSE;
	m_D3DParamFull.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	m_D3DParamFull.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

	for(int i=0;i < sizeof(FmtDisplay)/sizeof(FmtDisplay[0]);i++){
		hr = m_pD3D->CheckDeviceType(Adapter, Device, FmtDisplay[i], FmtDisplay[i], FALSE);
		if(SUCCEEDED(hr)){
			m_D3DParamFull.BackBufferFormat = FmtDisplay[i];
			break;
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectAdapterFormat() CheckDeviceType FullScreen\n");
		return(false);
	}

	return(true);
}
//深度/ステンシルバッファのフォーマットを調査
bool DX9AGraphic::SelectDepthStencilFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode){

	HRESULT hr = S_OK;

	//希望するフォーマット
	D3DFORMAT FmtDepthStencil[] = FMT_DEPTHSTENCIL;

	//ウインドウモード
	for(int i=0;i < sizeof(FmtDepthStencil)/sizeof(FmtDepthStencil[0]);i++){
		hr = m_pD3D->CheckDeviceFormat(Adapter, Device, DMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, FmtDepthStencil[i]);
		if(SUCCEEDED(hr)){
			hr = m_pD3D->CheckDepthStencilMatch(Adapter, Device, DMode.Format, m_D3DParamWin.BackBufferFormat, FmtDepthStencil[i]);
			if(SUCCEEDED(hr)){
				m_D3DParamWin.EnableAutoDepthStencil = TRUE;
				m_D3DParamWin.AutoDepthStencilFormat = FmtDepthStencil[i];
				break;
			}
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectDepthStencilFormat() Window\n");
		return(false);
	}

	//フルスクリーンモード
	for(int i=0;i < sizeof(FmtDepthStencil)/sizeof(FmtDepthStencil[0]);i++){
		hr = m_pD3D->CheckDeviceFormat(Adapter, Device, m_D3DParamFull.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, FmtDepthStencil[i]);
		if(SUCCEEDED(hr)){
			hr = m_pD3D->CheckDepthStencilMatch(Adapter, Device, m_D3DParamFull.BackBufferFormat, m_D3DParamFull.BackBufferFormat, FmtDepthStencil[i]);
			if(SUCCEEDED(hr)){
				m_D3DParamFull.EnableAutoDepthStencil = TRUE;
				m_D3DParamFull.AutoDepthStencilFormat = FmtDepthStencil[i];
				break;
			}
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectDepthStencilFormat() FullScreen\n");
		return(false);
	}

	return(true);
}
//レンダリングテクスチャのフォーマットを調査
bool DX9AGraphic::SelectRenderTextureFormat(UINT Adapter, D3DDEVTYPE Device, D3DDISPLAYMODE DMode){

	HRESULT hr = S_OK;

	//希望するフォーマット
	D3DFORMAT FmtRenderTexture[] = FMT_RENDERTEXTURE;

	//ウインドウモード
	m_FmtRenderTextureWin = D3DFMT_UNKNOWN;
	for(int i=0;i < sizeof(FmtRenderTexture)/sizeof(FmtRenderTexture[0]);i++){
		hr = m_pD3D->CheckDeviceFormat(Adapter, Device, DMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, FmtRenderTexture[i]);
		if(SUCCEEDED(hr)){
			if(m_D3DParamWin.EnableAutoDepthStencil==TRUE){
				hr = m_pD3D->CheckDepthStencilMatch(Adapter, Device, DMode.Format, FmtRenderTexture[i],	m_D3DParamWin.AutoDepthStencilFormat);
				if(SUCCEEDED(hr)){
					m_FmtRenderTextureWin = FmtRenderTexture[i];
					break;
				}
			}
			else{
				m_FmtRenderTextureWin = FmtRenderTexture[i];
				break;
			}
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectRenderTextureFormat() Window\n");
		return(false);
	}

	//フルスクリーンモード
	m_FmtRenderTextureFull = D3DFMT_UNKNOWN;
	for(int i=0;i < sizeof(FmtRenderTexture)/sizeof(FmtRenderTexture[0]);i++){
		hr = m_pD3D->CheckDeviceFormat(Adapter, Device, m_D3DParamFull.BackBufferFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, FmtRenderTexture[i]);
		if(SUCCEEDED(hr)){
			if(m_D3DParamFull.EnableAutoDepthStencil==TRUE){
				hr = m_pD3D->CheckDepthStencilMatch(Adapter, Device, m_D3DParamFull.BackBufferFormat, FmtRenderTexture[i],	m_D3DParamFull.AutoDepthStencilFormat);
				if(SUCCEEDED(hr)){
					m_FmtRenderTextureFull = FmtRenderTexture[i];
					break;
				}
			}
			else{
				m_FmtRenderTextureFull = FmtRenderTexture[i];
				break;
			}
		}
	}
	if(FAILED(hr)){
		DX9AErrOut("Failed : DX9AGraphic::SelectRenderTextureFormat() FullScreen\n");
		return(false);
	}

	return(true);
}
//フルシーンアンチエイリアシングを調査
bool DX9AGraphic::SelectMultiSampleType(UINT Adapter, D3DDEVTYPE Device){

	//希望するフォーマット
	D3DMULTISAMPLE_TYPE MST[] = TYPE_MULTISAMPLE;

	//ウインドウモード
	for(int i=0;i < sizeof(MST)/sizeof(MST[0]);i++){
		if(FAILED(m_pD3D->CheckDeviceMultiSampleType(Adapter, Device, m_D3DParamWin.BackBufferFormat, TRUE, MST[i], NULL))){
			continue;
		}
		if(m_D3DParamWin.EnableAutoDepthStencil==TRUE){
			if(FAILED(m_pD3D->CheckDeviceMultiSampleType(Adapter, Device, m_D3DParamWin.AutoDepthStencilFormat, TRUE, MST[i], NULL))){
				continue;
			}
		}
		m_D3DParamWin.MultiSampleType = MST[i];
		m_D3DParamWin.MultiSampleQuality = 0;
		break;
	}

	//フルスクリーンモード
	for(int i=0;i < sizeof(MST)/sizeof(MST[0]);i++){
		if(FAILED(m_pD3D->CheckDeviceMultiSampleType(Adapter, Device, m_D3DParamFull.BackBufferFormat, FALSE, MST[i], NULL))){
			continue;
		}
		if(m_D3DParamFull.EnableAutoDepthStencil==TRUE){
			if(FAILED(m_pD3D->CheckDeviceMultiSampleType(Adapter, Device, m_D3DParamFull.AutoDepthStencilFormat, FALSE, MST[i], NULL))){
				continue;
			}
		}
		m_D3DParamFull.MultiSampleType = MST[i];
		m_D3DParamFull.MultiSampleQuality = 0;
		break;
	}

	return(true);
}
//ディスプレイモードを調査
bool DX9AGraphic::SelectDisplayMode(UINT Adapter){

	//ウインドウモード(調査不要)

	//フルスクリーンモード
	int level = INT_MAX;
	D3DDISPLAYMODE DMode = {0, 0, 0, D3DFMT_UNKNOWN};
	int Num = m_pD3D->GetAdapterModeCount(Adapter, m_D3DParamFull.BackBufferFormat);

	for(int i=0;i < Num;i++){
		//ディスプレイモードの列挙
		D3DDISPLAYMODE DM;
		m_pD3D->EnumAdapterModes(Adapter, m_D3DParamFull.BackBufferFormat, i, &DM);
		int l = abs(m_ScreenWidth - static_cast < int > (DM.Width)) + abs(m_ScreenHeight - static_cast < int > (DM.Height));
		if(l < level){
			//より適切なモードを選択
			DMode = DM;
			level = l;
		}
	}
	if(DMode.Format==D3DFMT_UNKNOWN){
		DX9AErrOut("Failed : DX9AGraphic::SelectDisplayMode()\n");
		return(false);
	}

	m_D3DParamFull.BackBufferWidth = DMode.Width;
	m_D3DParamFull.BackBufferHeight = DMode.Height;

	return(true);
}
//Direct3Dに管理されていないオブジェクトを初期化
bool DX9AGraphic::InitD3DObject(){
	//スプライトの管理
	if(m_pD3DXSprite){
		m_pD3DXSprite->OnResetDevice();
	}
	//レンダリングステートを設定
	//Zバッファ
	m_pD3DDevice->SetRenderState(D3DRS_ZENABLE, m_D3DParamNow.EnableAutoDepthStencil ? D3DZB_TRUE : D3DZB_FALSE);
	//マルチサンプリング
	m_pD3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, m_D3DParamNow.MultiSampleType!=D3DMULTISAMPLE_NONE ? TRUE : FALSE);

	return(true);
}

//Direct3Dに管理されていないオブジェクトの終了処理
bool DX9AGraphic::CleanupD3DObject(){
	if(m_pD3DXSprite){
		m_pD3DXSprite->OnLostDevice();
	}

	return(true);
}
//Direct3Dに管理されているオブジェクトの終了処理
bool DX9AGraphic::CleanupD3D(){
	for(map < string, StringTexture > ::iterator it=m_StringTexture.begin();it!=m_StringTexture.end();it++){
		SAFE_RELEASE(it->second.Texture);
	}
	SAFE_RELEASE(m_pDrawRect);
	SAFE_RELEASE(m_pD3DXSprite);
	SAFE_RELEASE(m_pD3DDevice);
	SAFE_RELEASE(m_pD3D);

	return(true);
}
//アプリケーションの終了処理
bool DX9AGraphic::CleanupApp(){
	UnregisterClass(m_ClassName.c_str(), m_hInst);

	return(true);
}



//デフォルトコンストラクタ
DX9AGraphicAccessor::DX9AGraphicAccessor(){
	Outer = NULL;
}

//親エンジンを設定
void DX9AGraphicAccessor::SetParent(DX9AGraphic* Parent){
	Outer = Parent;
}

//Direct3D9オブジェクトを取得
LPDIRECT3D9 DX9AGraphicAccessor::GetD3D9(){
	return(Outer->m_pD3D);
}
//スプライトオブジェクトを取得
LPD3DXSPRITE DX9AGraphicAccessor::GetD3DXSprite(){
	return(Outer->m_pD3DXSprite);
}
//Direct3DDevice9オブジェクトを取得
LPDIRECT3DDEVICE9 DX9AGraphicAccessor::GetD3D9Device(){
	return(Outer->m_pD3DDevice);
}



//アクセッサ
static DX9AGraphicAccessor DX9ASingletonDX9AGraphicAccessor;
//アクセッサを取得
DX9AGraphicAccessor* GetDX9AGraphicAccessor(DX9AGraphic* Parent){
	DX9ASingletonDX9AGraphicAccessor.SetParent(Parent);
	return(&DX9ASingletonDX9AGraphicAccessor);
}

}
}
}

 コメントも付けているしググれば大体分かると思うが、一応いくつか補足しておく。

98〜116行目

	//文字列テクスチャの管理
	DWORD Now = timeGetTime();
	map < string, StringTexture > ::iterator it;
	while(m_StringTextureNowSize > m_StringTextureMaxSize){
		it = m_StringTexture.begin();
		for(map < string, StringTexture > ::iterator it2=m_StringTexture.begin();it2!=m_StringTexture.end();it2++){
			if(Now-it2->second.LastRefTime > Now-it->second.LastRefTime){
				it = it2;
			}
			if(Now-it2->second.LastRefTime==Now-it->second.LastRefTime){
				if(it2->second.Size > it->second.Size){
					it = it2;
				}
			}
		}
		m_StringTextureNowSize -= it->second.Size;
		SAFE_RELEASE(it->second.Texture);
		m_StringTexture.erase(it);
	}

 アイドル時に文字列テクスチャの管理を行っている。
 もう少し詳しく説明すると、現在の総合計サイズ>Initメソッドの引数で指定した最大サイズの場合に、
 最後に参照された時間が最も古く最もサイズの大きいテクスチャから順に自動で解放するようになっている。

284〜306行目

	//内部関数用クラス
        	class InnerFunction{
        	public:
        		//GetGlyphOutline用にエンコード
        		static void EncodeText(const string& Src, wstring& Dest){
        			Dest.clear();
        			for(unsigned int i=0;Src[i]!='\0';){
        				unsigned int ChByte = ((Src[i] >= static_cast < char > (0x81) && Src[i] <= static_cast < char > (0x9F)) ||
        									  (Src[i] >= static_cast < char > (0xE0) && Src[i] <= static_cast < char > (0xFF))) ? 2 : 1;
        				Dest.push_back(ChByte==2 ? static_cast < BYTE > (Src[i]) * 256 + static_cast < BYTE > (Src[i+1]) : static_cast < BYTE > (Src[i]));
        				i += ChByte;
        			}
        		}
        		//論理和コピー
        		static void* memcpy_or(void* s1, const void* s2, size_t n){
        			register BYTE* ss1;
        			register const BYTE* ss2;
        			for(ss1=reinterpret_cast < BYTE* > (s1), ss2=reinterpret_cast < const BYTE* > (s2);n!=0;n--){
        				*ss1++ |= *ss2++;
        			}
        			return(s1);
        		}
        	};

 DrawFreeTextメソッド内でローカル関数を定義している。
 ローカル関数とは、関数内で定義した関数のことである。
 C++では関数内関数を定義することはできないが、関数内クラスを定義することはできる。
 よって、ローカル関数を実現するには関数内クラスを定義しstatic関数で実装すればよい。
 何故そこまでしてローカル関数を定義しているのか、以下にその理由を箇条書きで記してみる。
 1.複雑な処理であるため一部を関数化したい
 2.だが呼び出し元が限られている(DrawFreeTextメソッドのみ)ので名前空間を汚染したくない
 上記のような理由である、長いソースコードを書かざるをえない場合に役立つのではないかと個人的には思う。

582〜600行目

	/*	↓CheckDeviceCapsメソッドの変更に伴いこちらも変更
        	if(FAILED(m_pD3D->CreateDevice(Adapter, Device, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        		if(FAILED(m_pD3D->CreateDevice(Adapter, Device, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        			DX9AErrOut("Failed : DX9AGraphic::InitD3D() CreateDevice\n");
        			return(false);
        		}
        	}
        	*/
        	if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        		if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        			if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        				if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &m_D3DParamNow, &m_pD3DDevice))){
        					DX9AErrOut("Failed : DX9AGraphic::InitD3D() CreateDevice\n");
        					return(false);
        				}
        			}
        		}
        	}
        	/*	↑CheckDeviceCapsメソッドの変更に伴いこちらも変更	*/

 本来はコメントアウトの内容通り、ハードウェアアクセラレーションでのデバイス作成→ソフトウェアアクセラレーションでのデバイス作成を試みていた。
 それを、ハードウェアアクセラレーションでのデバイス作成を3回試みてソフトウェアアクセラレーションでのデバイス作成を試みるよう一時的に変更している。
 理由は、コメントアウトの内容だとEee PCなどの低価格ミニノートパソコンでDirect3DデバイスがHALデバイスではなくREFデバイスで作成されてしまうからである。
 本来は、こんな対症療法的なコメントアウトでお茶を濁すのではなくきちんとしたコードを書くべきなのだが……実は、本コンテンツを書くまで見直しを忘れてたのである(´Д`)

714〜740行目

//デバイスの能力をチェック
        bool DX9AGraphic::CheckDeviceCaps(D3DCAPS9* Caps){
        	/*	↓EeePC等の低スペックPCで無意味にREFに切り替えられてしまう原因、とりあえずはコメントアウトで対応!
        	//プリミティブ数
        	if(Caps->MaxPrimitiveCount<0xFFFF){
        		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() MaxPrimitiveCount<0xFFFF\n");
        		return(false);
        	}
        	//インデックス数
        	if(Caps->MaxVertexIndex<0xFFFF){
        		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() MaxVertexIndex<0xFFFF\n");
        		return(false);
        	}
        	//頂点シェーダバージョン
        	if(Caps->VertexShaderVersion < D3DVS_VERSION(1, 1)){
        		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() VertexShaderVersion < D3DVS_VERSION(1, 1)\n");
        		return(false);
        	}
        	//ピクセルシェーダバージョン
        	if(Caps->PixelShaderVersion < D3DVS_VERSION(1, 1)){
        		DX9AErrOut("Failed : DX9AGraphic::CheckDeviceCaps() PixelShaderVersion < D3DVS_VERSION(1, 1)\n");
        		return(false);
        	}
        	/*	↑EeePC等の低スペックPCで無意味にREFに切り替えられてしまう原因、とりあえずはコメントアウトで対応!	*/
        	UNREFERENCED_PARAMETER(Caps);
        	return(true);
        }

 コメントアウトの理由は582〜600行目と同じ、本来は定数化なりマクロ化なりで対応してコメントアウトで誤魔化すべきではない。
 いやぁ、仮に誰も見ていなかったとしてもこうして書いていると自分の過ちがぼろぼろと漏れ出してきますなぁ(;´Д`)

746〜747、796〜797行目

	//希望するフォーマット
        	D3DFORMAT FmtDisplay[] = FMT_DISPLAY;
	//希望するフォーマット
        	D3DFORMAT FmtDepthStencil[] = FMT_DEPTHSTENCIL;
	//希望するフォーマット
        	D3DFORMAT FmtRenderTexture[] = FMT_RENDERTEXTURE;
	//希望するフォーマット
        	D3DMULTISAMPLE_TYPE MST[] = TYPE_MULTISAMPLE;

 上記ソースコードにおける定数は、別のヘッダファイルにて以下のように定義されている。

//DirectX Graphics
        //希望するフォーマット(必ず希望順で並べること)
        /**
        *	@brief	ディスプレイならびにバックバッファの希望です。
        *
        *			必ず希望順で並べてください。
        */
        #define FMT_DISPLAY				{D3DFMT_X8R8G8B8, D3DFMT_X1R5G5B5, D3DFMT_R5G6B5}
        /**
        *	@brief	深度/ステンシルバッファの希望です。
        *
        *			必ず希望順で並べてください。
        */
        #define FMT_DEPTHSTENCIL		{D3DFMT_D24S8}
        /**
        *	@brief	レンダリングテクスチャの希望です。
        *
        *			必ず希望順で並べてください。
        */
        #define FMT_RENDERTEXTURE		{D3DFMT_X8R8G8B8, D3DFMT_X1R5G5B5, D3DFMT_R5G6B5}
        /**
        *	@brief	フルシーンアンチエイリアシングの希望です。
        *
        *			必ず希望順で並べてください。
        */
        #define TYPE_MULTISAMPLE		{D3DMULTISAMPLE_4_SAMPLES, D3DMULTISAMPLE_3_SAMPLES, D3DMULTISAMPLE_2_SAMPLES, D3DMULTISAMPLE_NONMASKABLE}

 見れば分かるとおり、定数の配列を定義している。
 あとは配列をforループで回して、要素を順に使用可能か確認すればフォーマットの設定を行えるわけだ。
 こういうことはconstやinlineでは(多分)できない、プリプロセッサであるマクロの面目躍如といったところだろう。

 とりあえずざっとした説明を行ってみた、APIなどの説明は省略(ググれば分かるさ!)
 個人的にプログラミングのTipsを語る上で重要なのは、APIの解説よりは「何故そんな形で実装しているのか?」だと思う。
 前者はMSDNなりAPIの解説を行っているページに行けば簡単に分かることだが、後者は当人が説明しない限り絶対に分からない。
 なので、今後もこういった書き方をしていく予定である。1行1行に解説を加えるようなことをするのは、めんどいしね!(それが本音か)

 

 

 

……以上で本項は終了である、お疲れ様でした(´Д`)
次回はちょっと浮気をしてファイルIO周りの解説を行う予定、でもって再びDirectX Graphicsに戻る予定である。

 

前へ                                        戻る                                     次へ