DirectX9によるテクスチャ描画

■バージョン

	DirectX
		DirectX9

	VisualStudio
		VisualStudio 2017

■サンプル

以下のリンクでサンプルをダウンロードできます。

	サンプル

■概要

DirectX9を使用してテクスチャの描画の方法を説明します。
テクスチャ描画は当然2Dゲームでは必須ですし、3DゲームでもUIなどは2Dで描画することになるので、
3Dゲームを作りたい人でも覚えておくべき内容です。

●知っておいたほうがいい知識
	このページを読むにあたり、知っておいたほうがいい知識は以下の内容です。

	・DirectGrphics基礎ポリゴン-テクスチャ座標

●描画概要
	テクスチャの描画はポリゴンを2枚用意して四角にしますdirectx_0011
	directx_0011

	この四角ポリゴンの4頂点に対してテクスチャ座標を指定することで
	画像が張り付けられます。

	directx_0012
	directx_0012

■ポリゴン情報をカスタマイズする

テクスチャを張り付けるためのポリゴンには座標を含めた様々な情報を設定します。
この情報は様々な用途で使用されることを想定されているために
開発側で設定を行うようになっています。
このような自分たちで作成した頂点構造を「CustomVertex(カスタムバーテックス)」と呼んでいます。

●設定情報
	情報のカスタマイズで設定できる情報はDirectX側で用意されおり、
	それ以外は使用できません。

	gmpg_0035
	gmpg_0035

●ポリゴン情報の宣言
	「●設定情報」の情報を使用してCustomVertexの宣言を行います。
	※宣言は構造体で行います。

	・例
		「頂点座標」「除算数」「テクスチャ座標」を使用することを宣言した構造体です。

		struct CUSTOM_VERTEX
		{
			// 頂点座標
			float x;
			float y;
			float z;

			// 除算数
			float rhw;

			// テクスチャ座標
			float tu;
			float tv;
		};

●DirectXへの通知
	作成したCustomVertexの構造情報は描画の際にDirectXに通知する必要があります。
	DirectGraphicsのDeviceに「SetFVF関数」を使用して構造情報を通知します。

	・通知用定数
		「頂点座標」や「テクスチャ座標」などの通知したい情報用の定数(D3DFVF_***)を
		DirectXが用意してくれているのそちらを使用します。

		・例
			頂点座標(除算数なし) => D3DFVF_XYZ
			頂点座標(除算数あり) => D3DFVF_XYZRHW
			テクスチャ座標 => D3DFVF_TEX1

	・設定方法
		SetFVFを使用して情報を設定する際は論理和「|」を使用して行います。

		・例
			SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1)

			上のように記述すると「座標(除算数あり)」と「テクスチャ座標」を
			使用したCustomVertexになっていることをDirectXに通知できます。

		・defineでまとめる
			通知設定は論理和を使用するので、一行が長くなってしまいます。
			この回避方法としてdefineを使用してまとめることで
			使用時の記述を短縮することができます。

			#define FVF_2D (D3DFVF_XYZRHW | D3DFVF_TEX1)

■テクスチャを読み込む

テクスチャを描画するには使用するテクスチャを読み込んでゲーム中に
使用可能状態にしておく必要があります。
DirectX9ではいくつかの読み込み関数が用意してあり
よく使用される関数は「D3DXCreateTextureFromFile」「D3DXCreateTextureFromFileEx」があります。
どちらも引数にファイル名を指定することで読み込み結果(成功、失敗)が返ります。
読み込んだテクスチャ情報は引数で指定した変数に格納されます。

●D3DXCreateTextureFromFile
	・関数名
		D3DXCreateTextureFromFile

	・戻り値
		HRESULT
			成功 => S_OK
			失敗 => E_FAILED

	・引数
		LPCSTR pSrcFile
			ファイル名(パス込み)

		LPDIRECT3DTEXTURE9 *ppTexture
			テクスチャポインタ(データ格納用)

	・内容
		指定したファイルを読み込む
		読み込んだ結果は戻り値で返り、テクスチャデータは引数の変数に格納される

●D3DXCreateTextureFromFileEx
	・関数名
		D3DXCreateTextureFromFileEx

	・備考
		今回は2D用として説明しますので一部の引数の説明は省きます。

	・戻り値
		HRESULT
			成功 => S_OK
			失敗 => E_FAILED

	・引数
		LPCSTR pSrcFile
			ファイル名(パス込み)

		UINT Width
			ファイルの横幅サイズ
			(0 or D3DX_DEFAULT ならDirectXが自動設定)

		UINT Height
			ファイルの縦幅サイズ
			(0 or D3DX_DEFAULT ならDirectXが自動設定)

		UINT MipLevels
			ミップマップのレベル
			(3Dで使用するが未使用の場合は0でいい)

		DWORD Usage
			テクスチャの使い方

		D3DFORMAT Format
			テクスチャのカラーフォーマットの設定

		D3DPOOL Pool
			テクスチャメモリの管理方法

		DWORD Filter
			フィルタリング方法

		DWORD MipFilter
			ミップマップのフィルタリング方法

		D3DCOLOR ColorKey
			抜き色の指定
			指定された色は透明色として扱われる

		D3DXIMAGE_INFO *pSrcInfo
			元の画像の情報が欲しい場合に使用する

		PALETTEENTRY *pPalette
			256色のカラーの場合のみカラーパレットが格納される

		LPDIRECT3DTEXTURE9 *ppTexture
			テクスチャポインタ(データ格納用)

	・内容
		指定したファイルを読み込む
		結果が戻り値で返ることやテクスチャデータは引数の変数に格納されることは
		変わらないが、D3DXCreateTextureFromFileとは異なり読み込むデータに対して
		細かな設定ができる

●読み込みサイズの注意
	読み込まれた画像でサイズが2の累乗ではなかった場合、
	サイズより大きい2の累乗に自動で修正されます。

	・例
		500 * 500 のテクスチャを読み込んだ場合 => 512 * 512に変換

		640 * 200 のテクスチャを読み込んだ場合 => 1024 * 256に変換

●解放
	読み込まれたテクスチャが不要になった際はどこかのタイミングで
	必ずテクスチャの解放を行います。
	解放のタイミングは各シーンが終了した時やゲーム終了時に行われます。

	・解放関数
		LPDIRECT3DTEXTURE9インターフェースには解放関数として
		「Release関数」が用意されているので解放する場合はこちらを使用します。

		・例
			g_Texture.m_pTexture->Release();
			g_Texture.m_pTexture = NULL;

■ポリゴンを用意する

CustomVertexを宣言し、テクスチャの読み込みが終わったら描画するポリゴンの設定を行います。
四角形をポリゴンで作るためには4 or 6頂点が必要です。
4 or 6頂点となっているのはポリゴンの描画方法によって、必要数が変化するからです。
「TriangleList(トライアングルリスト)」が6頂点、「TriangleFan(トライアングルファン)」と
「TriangleStrip(トライアングルストリップ)」が4頂点です。

●TriangleList(トライアングルリスト)による設定
	トライアングルリストによる頂点設定は頂点3つのポリゴンを2つ用意します。
	DirectXの約束事として各ポリゴンの頂点設定は左回りで行う必要があります。

	directx_0013
	directx_0013

	・例
		struct CUSTOM_VERTEX
		{
			float x, y, z, rhw;
		};

		CUSTOM_VERTEX TriangleList[] =
		{
			// 1つ目のポリゴン
			{ 0.0f, 0.0f, 0.0f, 1.0f },
			{ 100.0f, 0.0f, 0.0f, 1.0f }, 
			{ 0.0f, 100.0f, 0.0f, 1.0f }, 

			// 2つ目のポリゴン
			{ 100.0f, 0.0f, 0.0f, 1.0f },
			{ 100.0f, 100.0f, 0.0f, 1.0f }, 
			{ 0.0f, 100.0f, 0.0f, 1.0f }, 
		};

●TriangleFan(トライアングルファン)による設定
	トライアングルファンによる頂点設定は頂点を4つ用意することで
	2つポリゴンが作成され、四角形が描画されます。
	こちらも頂点は左回りに設定を行います。
	どの頂点から始めても問題ありませんが、左上から設定することが多いです。

	directx_0014
	directx_0014

	・例
		struct CUSTOM_VERTEX
		{
			float x, y, z, rhw;
		};

		CUSTOM_VERTEX TriangleFan[] =
		{
			// 左上頂点
			{ 0.0f, 0.0f, 0.0f, 1.0f },
			// 右上頂点
			{ 100.0f, 0.0f, 0.0f, 1.0f }, 
			// 右下頂点
			{ 100.0f, 100.0f, 0.0f, 1.0f }, 
			// 左下頂点
			{ 0.0f, 100.0f, 0.0f, 1.0f }, 
		};


●TriangleStrip(トライアングルストリップ)による設定
	トライアングルストリップによる頂点設定は頂点を4つ用意することで
	2つポリゴンが作成され、四角形が描画されます。
	こちらも頂点は左回りに設定を行いますがトライアングルストリップは
	まず、1つのポリゴンを設定するために3つの頂点の設定を最初に行います。
	そして、4点で足りない頂点を追加することで2つのポリゴンが作成されます。

	directx_0015
	directx_0015

	・例
		struct CUSTOM_VERTEX
		{
			float x, y, z, rhw;
		};

		CUSTOM_VERTEX TriangleStrip[] =
		{
			// ポリゴンを作成
			// 左上頂点
			{ 0.0f, 0.0f, 0.0f, 1.0f },
			// 右上頂点
			{ 100.0f, 0.0f, 0.0f, 1.0f }, 
			// 左下頂点
			{ 0.0f, 100.0f, 0.0f, 1.0f }, 

			// 足りない頂点を追加
			// 右下頂点
			{ 100.0f, 100.0f, 0.0f, 1.0f }, 
		};

■テクスチャの設定

テクスチャを描画するために2つの設定を行う必要があります。
1つは「CustomVertexにテクスチャ座標を指定する」
もう1つは「DirectGraphicsに使用するテクスチャを指定する」です。
この2つの設定を四角形を描画する際に毎回行うことで
テクスチャが張り付けられた四角形が描画されます。

●テクスチャ座標
	テクスチャ座標は名前の通り、テクスチャの位置を指定するための座標情報のことです。
	座標は縦0.0~1.0、横0.0~1.0で指定します。
	これはテクスチャのサイズは128 * 256や512 * 512などバラバラで統一されていません。
	このままでは座標指定がやりにくいので指定をしやすいように縦、横のサイズを
	1.0として統一されています。

●CustomVertexにテクスチャ座標を指定する
	テクスチャを頂点に設定するためにはCustomVertexに情報の追加が必要です。
	情報はテクスチャ1枚につき「テクスチャ座標のX座標とY座標」が必要で、
	これはどちらもfloat型で指定します。

	・宣言例
		struct CUSTOM_VERTEX
		{
			float x, y, z, rhw;
			
			// テクスチャ座標(横)
			float tu;
			// テクスチャ座標(縦)
			float tv;
		};

	・uv
		テクスチャ座標ではX軸をu、Y軸をvとすることが一般的で、
		「UV座標」と呼ばれています。
		これは、ベクトルの成分をu,vで示すことが多く、位置座標のXとYと区別するために
		使われているといわれており、様々な参考書、サイトでもテクスチャ座標は
		u、vで書かれています。

	・指定例
		以下のコードはトライアングルファンでテクスチャ座標の指定を行った例です。

		・使用テクスチャ
			directx_0030
			directx_0030

		・テクスチャ座標
			左上 => 0.0, 0.0
			右上 => 0.5, 0.0
			右下 => 0.5, 0.5
			左下 => 0.0, 0.5

		・コード
			struct CUSTOM_VERTEX
			{
				float x, y, z, rhw;
				
				// テクスチャ座標(横)
				float tu;
				// テクスチャ座標(縦)
				float tv;
			};

			CUSTOM_VERTEX TriangleFan[] =
			{
				// 左上頂点
				{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
				// 右上頂点
				{ 100.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.0f }, 
				// 右下頂点
				{ 100.0f, 100.0f, 0.0f, 1.0f, 0.5f, 0.5f }, 
				// 左下頂点
				{ 0.0f, 100.0f, 0.0f, 1.0f, 0.0f, 0.5f }, 
			};

		・結果
			directx_0031
			directx_0031


●DirectGraphicsに使用するテクスチャを指定する
	テクスチャ座標の指定を行ったら、次はDirectGraphicsに使用するテクスチャの指定します。
	設定にはDirectGraphicsDeviceの「SetTexture関数を使用します。
	このテクスチャ指定はテクスチャ付きのポリゴンを1つ描画する毎に行います。
	1フレームで100回描画する場合指定処理を100回行うということです。
	これは使用するテクスチャが複数あった場合に、間違って意図しないテクスチャが
	貼り付けられないようにするために行っています。
	※慣れてきたら毎回しなくてもいい方法を選択しても問題ありませんが、
	 はじめはテクスチャ描画の毎で設定したほうがいいかと。

	・関数詳細
		SetTexture

		戻り値:
			HRESULT
				S_OK => 成功
				E_FAILED => 失敗

		引数:
			第一
				DWORD Stage
					テクスチャステージ番号
					(一枚目は0で問題ない)

			第二
				LPDIRECT3DTEXTURE9 pTexture
					使用するテクスチャのポインタ

		内容:
			テクスチャステージにテクスチャを設定する
			この設定はDrawPrimitiveUpなどの関数の前に使用しておく必要があり
			次のSetTextureが実行されるまでは設定がそのまま使用される

■描画方法

テクスチャ描画はDirectGraphicsDeviceのBeginとEndの間で行います。
描画で使用する関数は「DrawPrimitiveUPを使います。

●DrawPrimitiveUP
	DrawPrimitiveUpはポリゴンを描画する関数です。
	DirectX9の2Dゲームではだいたいこの関数で2Dオブジェクトの描画を行っています。

	・関数詳細
		・名前
			DrawPrimitiveUp

		・戻り値
			HRESULT
				S_OK => 成功
				E_FAILED => 失敗
		・引数
			D3DPRIMITIVETYPE PrimitiveType,
				プリミティブの種類を指定する
				(D3DPT_TRIANGLELISTやD3DPT_TRIANGLEFANなど)

			UINT PrimitiveCount
				プリミティブの数
				(描画するポリゴン数)
				
			const void *pVertexStreamZeroData
				描画するカスタムバーテックスのポインタ

			UINT VertexStreamZeroStride
				カスタムバーテックスのサイズ

		・内容
			引数で指定した情報からポリゴンを描画する

●例
	// CustomVertexの指定
	GetDirectGraphicsDevice()->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);

	// テクスチャの指定
	GetDirectGraphicsDevice()->SetTexture(0, g_Texture.m_pTexture);

	// ポリゴンの描画
	GetDirectGraphicsDevice()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 
							2, 
							bg, 
							sizeof(CUSTOM_VERTEX));