DirectXプログラミング02 画像を表示する。

̃Gg[͂ĂȃubN}[Nɒlj

DirectXシリーズ第二回。
前回、開発環境整備を行ったので、今回はとにかく何かを画面に表示させたいと思います。
過去の記事「Windowsプログラミング03」で作成したコードを元に改造します。

改造内容

・Direct3D初期化処理の追加
 Direct3Dオブジェクト
 スプライトオブジェクト
 テクスチャオブジェクト
 の生成を行います。今のところ意味は分かりません。
・描画関数の追加
 bmpファイルを描画する処理を実施します。
・メッセージループに手を入れる
 キューにメッセージが入っていない場合は描画関数の処理を実施するようにする。
 すなわち、PeekMessage関数の戻り値が非0ならばメッセージハンドラにメッセージを渡し、
 0ならば描画関数をコールするようにします。

以下、ソースコード全体を掲載し、細部を解析していきます。

ソースコード全体

#include <windows.h>
#include <d3dx9.h>

LPDIRECT3D9 pD3d;
LPDIRECT3DDEVICE9 pDevice;
LPDIRECT3DTEXTURE9 pTexture;
LPD3DXSPRITE pSprite;

/*	プロトタイプ宣言	*/
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitD3d(HWND);
VOID DrawSprite();

/*	エントリ関数	*/
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szStr, INT iCmdShow)
{
	HWND hWnd = NULL;
	MSG msg;
	
	/*	ウィンドウの初期化	*/
	LPCWSTR szAppName = L"DirectXプログラミング02 画像を表示する。";
	WNDCLASSEX wndclass;
	wndclass.cbSize			= sizeof(wndclass);
	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= 0;
	wndclass.hInstance		= hInst;
	wndclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= szAppName;
	wndclass.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);
	RegisterClassEx(&wndclass);
	hWnd = CreateWindow(szAppName,
						szAppName,
						WS_OVERLAPPEDWINDOW,
						0,
						0,
						640,
						480,
						NULL,
						NULL,
						hInst,
						NULL);
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	
	/*	Direct3Dの初期化	*/
	if(FAILED(InitD3d(hWnd))){
		return 0;
	}
	/*	メッセージループ	*/
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message != WM_QUIT){
		if(PeekMessage( &msg,
						NULL,
						0U,
						0U,
						PM_REMOVE)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} else {
			DrawSprite();
		}
	}
	return(INT)msg.wParam;
}

/*	ウィンドウプロシージャ	*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	switch(iMsg){
		case WM_DESTROY :
			PostQuitMessage(0);
		break;
		case WM_KEYDOWN :
			switch((CHAR)wParam){
				case VK_ESCAPE:
				PostQuitMessage(0);
				break;
			}
		break;
	}
	return DefWindowProc(hWnd, iMsg, wParam, lParam);
}

/*	Direct3Dの初期化	*/
HRESULT InitD3d(HWND hWnd)
{
	/*	Direct3Dオブジェクトの生成	*/
	if(NULL == (pD3d = Direct3DCreate9(D3D_SDK_VERSION))){
		MessageBox(0, L"Direct3Dの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	/*	Direct3Dデバイスオブジェクトの生成	*/
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferFormat	= D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount	= 1;
	d3dpp.SwapEffect		= D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed			= TRUE;
	if(FAILED(pD3d->CreateDevice(	D3DADAPTER_DEFAULT,
									D3DDEVTYPE_HAL,
									hWnd,
									D3DCREATE_MIXED_VERTEXPROCESSING,
									&d3dpp,
									&pDevice))){
		MessageBox(0, L"HALモードでDirect3Dデバイスを作成できませんnREFモードで再試行します", NULL, MB_OK);
		if(FAILED(pD3d->CreateDevice(D3DADAPTER_DEFAULT,
									 D3DDEVTYPE_REF,
									 hWnd,
									 D3DCREATE_MIXED_VERTEXPROCESSING,
									 &d3dpp,
									 &pDevice))){
			 MessageBox(0, L"DIRECT3Dデバイスの作成に失敗しました", NULL, MB_OK);
			 return E_FAIL;
		}
	}
	/*	テクスチャオブジェクトの生成	*/
	if(FAILED(D3DXCreateTextureFromFileEx(pDevice,
										  L"Sprite.jpg",
										  200,
										  149,
										  0,
										  0,
										  D3DFMT_UNKNOWN,
										  D3DPOOL_DEFAULT,
										  D3DX_FILTER_NONE,
										  D3DX_DEFAULT,
										  0xFF000000,
										  NULL,
										  NULL,
										  &pTexture))){
		MessageBox(0, L"テクスチャの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	/*	スプライトオブジェクトの作成	*/
	if(FAILED(D3DXCreateSprite(	pDevice,
								&pSprite
								))){
		MessageBox(0, L"スプライトの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	return S_OK;
}
/*	スプライトの描画	*/
void DrawSprite()
{
	pDevice->Clear(	0,
					NULL,
					D3DCLEAR_TARGET,
					D3DCOLOR_XRGB(100,100,100),
					1.0f,
					0);
	if(SUCCEEDED(pDevice->BeginScene())){
		RECT rect = {0, 0, 200, 149};
		D3DXVECTOR3 vec3Center(0,0,0);
		D3DXVECTOR3 vec3Position(220,170,0);
		pSprite->Begin(D3DXSPRITE_ALPHABLEND);
		pSprite->Draw( pTexture,
					   &rect,
					   &vec3Center,
					   &vec3Position,
					   0xFFFFFFFF);
		pSprite->End();
		pDevice->EndScene();
	}
	pDevice->Present(NULL,
					 NULL,
					 NULL,
					 NULL);
}

ソースコード解析

さっそく解析していきましょう。
過去の記事「Windowsプログラミング03」で
扱ったコードと同等の個所については省略します。

インクルードとDirect3Dオブジェクトへのポインタ宣言

#include <windows.h>
#include <d3dx9.h>

LPDIRECT3D9 pD3d;
LPDIRECT3DDEVICE9 pDevice;
LPDIRECT3DTEXTURE9 pTexture;
LPD3DXSPRITE pSprite;

・Direct3Dを使うコードでは、d3dx9.hのインクルードが必要とのこと。
・いきなり、知らない型の宣言が、、、、
 それぞれ、以下らしいです。

LPDIRECT3D9 pD3d Direct3Dオブジェクトへのポインタ
LPDIRECT3DDEVICE9 pDevice Direct3Dデバイスオブジェクトへのポインタ
LPDIRECT3DTEXTURE9 pTexture Direct3Dテクスチャオブジェクトへのポインタ
LPD3DXSPRITE pSprite Direct3Dスプライトオブジェクトへのポインタ

 ひとまず以下のように、そんなものか程度に解釈しておきます。
イ) Direct3Dオブジェクト     …Direct3D全体の機能をもってるのか?
ロ) Direct3Dデバイスオブジェクト …グラフィックボード等のデバイスに関する機能を担当している?
ハ) Direct3Dテクスチャオブジェクト…テクスチャって、ポリゴンの表面に張る絵のことですよね?
   Direct3Dスプライトオブジェクト…絵を表示する機能担当?
イからロ、ロからハが生成されるっぽいです。

初期化関数コールと描画関数コール

	
	/*	Direct3Dの初期化	*/
	if(FAILED(InitD3d(hWnd))){
		return 0;
	}
	/*	メッセージループ	*/
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message != WM_QUIT){
		if(PeekMessage( &msg,
						NULL,
						0U,
						0U,
						PM_REMOVE)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} else {
			DrawSprite();
		}
	}

メッセージループに入る前に初期化関数をコールしています。
メッセージループでは、メッセージがない場合、
すなわちPeekMessage関数の戻り値が0ならば描画関数をコールするようにしています。

初期化関数の内容

/*	Direct3Dの初期化	*/
HRESULT InitD3d(HWND hWnd)
{
	/*	Direct3Dオブジェクトの生成	*/
	if(NULL == (pD3d = Direct3DCreate9(D3D_SDK_VERSION))){
		MessageBox(0, L"Direct3Dの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	/*	Direct3Dデバイスオブジェクトの生成	*/
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferFormat	= D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount	= 1;
	d3dpp.SwapEffect		= D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed			= TRUE;
	if(FAILED(pD3d->CreateDevice(	D3DADAPTER_DEFAULT,
									D3DDEVTYPE_HAL,
									hWnd,
									D3DCREATE_MIXED_VERTEXPROCESSING,
									&d3dpp,
									&pDevice))){
		MessageBox(0, L"HALモードでDirect3Dデバイスを作成できませんnREFモードで再試行します", NULL, MB_OK);
		if(FAILED(pD3d->CreateDevice(D3DADAPTER_DEFAULT,
									 D3DDEVTYPE_REF,
									 hWnd,
									 D3DCREATE_MIXED_VERTEXPROCESSING,
									 &d3dpp,
									 &pDevice))){
			 MessageBox(0, L"DIRECT3Dデバイスの作成に失敗しました", NULL, MB_OK);
			 return E_FAIL;
		}
	}
	/*	テクスチャオブジェクトの生成	*/
	if(FAILED(D3DXCreateTextureFromFileEx(pDevice,
										  L"Sprite.jpg",
										  249,
										  149,
										  0,
										  0,
										  D3DFMT_UNKNOWN,
										  D3DPOOL_DEFAULT,
										  D3DX_FILTER_NONE,
										  D3DX_DEFAULT,
										  0xFF000000,
										  NULL,
										  NULL,
										  &pTexture))){
		MessageBox(0, L"テクスチャの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	/*	スプライトオブジェクトの作成	*/
	if(FAILED(D3DXCreateSprite(	pDevice,
								&pSprite
								))){
		MessageBox(0, L"スプライトの作成に失敗しました", L"", MB_OK);
		return E_FAIL;
	}
	return S_OK;
}

以下の流れのようです。
①Direct3Dオブジェクト生成
■Direct3DCreate9関数を読んでるだけですね。
■戻り値がDirect3Dオブジェクトへのポインタになるようです。
 
②Direct3Dデバイスオブジェクト生成
■①で生成したDirect3Dオブジェクトが持つCreateDeviceメソッドを呼んでいます。
■引数にD3DPRESENT_PARAMETERS型の変数を渡す必要があるので事前に初期化しているようです。
・D3DPRESENT_PARAMETERS型について

BackBufferFormat フロントバッファとバックバッファの切り替えて画面を更新しているらしいが、
バックバッファの方の表示形式を指定するらしい。
D3DFMT_UNKNOWNでいいらしい。
BackBufferCount バックバッファの数。1でいいらしい。
SwapEffect フリップ(フロントバッファとバックバッファの切り替え)の形態を指定するらしい。D3DSWAPEFFECT_DISCARDでいいらしい。
Windowed TRUE : ウィンドウモード
FALSE : フルスクリーンモード
※フルスクリーンにするには、以下に変更する必要があるらしい。

D3DDISPLAYMODE DMode;
pD3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DMode);
d3dpp.BackBufferFormat	= DMode.Format;
d3dpp.BackBufferWidth	= 640;
d3dpp.BackBufferHeight	= 480;
d3dpp.BackBufferCount	= 1;
d3dpp.SwapEffect		= D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed			= FALSE;

■生成されたDirect3Dデバイスオブジェクトは&pDeviceに格納されるようです。
■引数の指定内容について
 深追いせず、こんなものか程度に留めておきます^^;
 気が向いたら追記予定。
・D3DADAPTER_DEFAULT
 ビデオカードが複数搭載されていない限りこれでいいらしい。
・D3DDEVTYPE_HAL
 ハードウェアかソフトウェアで表示を実現するが、高速な方(ハードウェア)を選択。
・D3DCREATE_MIXED_VERTEXPROCESSING
 ?
③Direct3Dテクスチャオブジェクト生成
■D3DXCreateTextureFromFileEx
Sprite.jpgを読み込んで&pTextureにDirect3Dテクスチャオブジェクトとして格納するらしい。
プロトタイプ宣言は以下。こちらもあまり深追いはしない^^;

HRESULT D3DXCreateTextureFromFileEx(
  LPDIRECT3DDEVICE9 pDevice,
  LPCTSTR pSrcFile,
  UINT Width,
  UINT Height,
  UINT MipLevels,
  DWORD Usage,
  D3DFORMAT Format,
  D3DPOOL Pool,
  DWORD Filter,
  DWORD MipFilter,
  D3DCOLOR ColorKey,
  D3DXIMAGE_INFO * pSrcInfo,
  PALETTEENTRY * pPalette,
  LPDIRECT3DTEXTURE9 * ppTexture
);

・D3DCOLOR ColorKey
 カラーキーあるいは抜け色と呼ばれるらしい。
 0xFF000000は、RGB(00,00,00)つまり黒の透明度(アルファ値)を0xffに設定する意味らしい。
 アルファ値が0xffだと完全に透明になるので、
 黒背景に絵が載っている画像を表示させると絵の回りは表示されなくなるようだ。
④Direct3Dスプライトオブジェクト生成
■D3DXCreateSprite関数にDirect3Dデバイスオブジェクトへのポインタを渡すと、
 Direct3Dスプライトオブジェクトへのポインタに格納してくれるようですね。

描画関数の内容

/*	スプライトの描画	*/
void DrawSprite()
{
	pDevice->Clear(	0,
					NULL,
					D3DCLEAR_TARGET,
					D3DCOLOR_XRGB(100,100,100),
					1.0f,
					0);
	if(SUCCEEDED(pDevice->BeginScene())){
		RECT rect = {0, 0, 200, 149};
		D3DXVECTOR3 vec3Center(0,0,0);
		D3DXVECTOR3 vec3Position(270,170,0);
		pSprite->Begin(D3DXSPRITE_ALPHABLEND);
		pSprite->Draw( pTexture,
					   &rect,
					   &vec3Center,
					   &vec3Position,
					   0xFFFFFFFF);
		pSprite->End();
		pDevice->EndScene();
	}
	pDevice->Present(NULL,
					 NULL,
					 NULL,
					 NULL);
}

■pDevice->Clear
・描画前に画面をクリアしている。
・D3DCOLOR_XRGB(100,100,100)はクリアする色(ここでは灰色)を指定している。
■pDevice->BeginScene()
・描画処理の前に必ずコールする
■pSprite->Begin
■pSprite->Draw

HRESULT Draw(
  LPDIRECT3DTEXTURE9 pTexture,
  CONST RECT * pSrcRect,
  CONST D3DXVECTOR3 * pCenter,
  CONST D3DXVECTOR3 * pPosition,
  D3DCOLOR Color
);

・D3DXVECTOR3とは?
 3次元ベクトルを格納する型らしい。
 D3DXVECTOR3 vec3Center…描画開始ピクセル用(スプライト画像のどの部分から描画するか)
 D3DXVECTOR3 vec3Position…位置(ウィンドウ内のスクリーン座標)情報用
・D3DCOLOR Color
 元のビットマップをどのような透明度と色合いで表示させるかの指定。
 0xFFFFFFFF指定でそのままの色合いで表示する。
■pSprite->End()
■pDevice->EndScene()
・描画処理が終了したら必ずコールする
■pDevice->Present
・フリップさせる(バックバッファとフロントバッファを切り替える)。

動作画面

directx02_window

次回は、キーボード入力に対応させ、絵を移動させてみたいと思います。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です