★ DirectX Class ★ * Chapter 02: ウィンドウを作成する *
< ウィンドウの作成にあたって >
テスト段階では『WS_OVERLAPPEDWINDOW』のスタイルで良いです。
ウィンドウはそんな感じで普通に作ってください。
DirectXではGDI描画を行いませんので、描画に関しては通常のウィンドウズアプリケーションとは作り方が異なります。
< プリプロセッサ部 >
BCCでDirectXの三角関数等を扱うために、defineする必要があります。

#define sqrtf sqrt
#define sinf  sin
#define cosf  cos
#define sinf  sin

この三角関数はヘッダファイル内で使用されていますので、
ヘッダファイルをインクルードするよりも先に記述する必要があります。

そして、3Dの描画においては基本的に以下のヘッダを使用します。

#include <d3d9.h>
#include <d3dx9.h>

BCCにパスを通してあれば、フルパスを記述しなくてもインクルードできるはずです。

また、ライブラリを使用するにあたって、プリプロセッサでライブラリを指定する必要があります。

#pragma comment( lib , "d3d9.dll" );
#pragma comment( lib , "d3dx9.dll" );

これもパスを設定してあれば、フルパスを記述しなくてもインクルードできるはずです。
< グローバル変数 >
以下の型で定義される変数を宣言する必要があります。

LPDIRECT3D9
LPDIRECT3DDEVICE9

この講座では以下の宣言をし、今後この変数名で説明します。

LPDIRECT3D9       g_pD3D       = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
< Driect3D オブジェクトの作成 / デバイスの作成 >
オブジェクトは以下のプログラムで作成できます。

g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )

次にデバイスを作成しますが、デバイスの作成には『D3DPRESENT_PARAMETERS』という構造体を使用します。
この構造体に必要な情報を設定し、LPDIRECT3Dオブジェクトを利用してデバイスを作成します。

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory( &d3dpp , sizeof( d3dpp ) );
d3dpp.Windowed         = TRUE;
d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

g_pD3D->CreateDevice(
    D3DADAPTER_DEFAULT ,
    D3DDEVTYPE_HAL ,
    hWnd ,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
    &d3dpp ,
    &g_pd3dDevice );

尚、『 hWnd 』というのは親ウィンドウのハンドルです。

『D3DPRESENT_PARAMETERS』構造体の設定は簡単な気もしますが、
後にどんどん細かな設定をしていくことになります。
< 終了処理 >
アプリケーション終了時に、LPDIRECT3D9とLPDIRECT3DDEVICE9の開放処理を行わなければなりません。
Direct3Dのクラスは大抵『Reelase()』という関数を持っていますので、それを行えば大丈夫なはずです。

g_pd3dDevice->Release();
g_pD3D->Release();

ここで、開放の順番に注意してください。
LPDIRECT3DDEVICE9のクラスを先に解放します。
< 描画 >
Direct3Dによる描画の流れは以下のようになります。

   バックバッファのクリア
     ↓
   バックバッファへの描画開始
     ↓
   バックバッファへの描画
     ↓
   バックバッファへの描画終了
     ↓
   画面へ転送

バックバッファというのは目に見えない画面のことで、これを利用することによってちらつきを無くしたりすることができます。
私たちが見てる画面の後ろにそんなものが作られるんですよ。
ディスプレイの後ろを覗き込んだら見えるかもしれません。
バックバッファのクリアは以下の関数を使用します。

g_pd3dDevice->Clear( 0 ,
                     NULL ,
                     D3DCLEAR_TARGET ,
                     D3DCOLOR_XRGB( 0 , 0 , 0 ) ,
                     1.0f ,
                     0 );

今は丸暗記で結構です。
内部で使用されている関数に関して説明しておきますと、
『 D3DCOLOR_XRGB( 0 , 0 , 0 ) 』というのは背景を塗りつぶす色を指定しています。
各引数は赤、緑、青の値で、10進数0~255の間で指定します。
ここでは全部0を指定していますので、黒を指定したことになります。
また、この関数を使用せずに、『 0xFF000000 』のように直接16進数を指定することも可能です。
HTMLの指定とほぼ同じですが、HTMLが『RGB』なのに対し、Direct3Dでは『ARGB』を使用します。
『A』とはアルファ値(透明度)です。
画面のクリアで半透明はあまり使わないと思いますので、AはFF(完全不透明)で良いです。
『 D3DCOLOR_XRGB( 0 , 0 , 0 ) 』という関数はデフォルトで不透明にしてくれます。
次に、描画の開始と終了です。
描画の開始と終了には以下の関数を使用します。

g_pd3dDevice->BeginScene();
	
// ここへ実際の描画を行う

g_pd3dDevice->EndScene();

そして最後に、バックバッファから画面へと転送します。

g_pd3dDevice->Present( NULL , NULL , NULL , NULL );

バックバッファに描画されたものが実際に私たちの目に見えるのは、この関数が実行された瞬間です。
引数は丸暗記で全て『 NULL 』を指定すれば大丈夫です。ひゃっほう!
< ウィンドウズのメッセージ処理 >
ここも通常のウィンドウズアプリケーションとは大きく異なります。

MSG msg;

while( msg.message != WM_QUIT ){
	if ( PeekMessage( &msg , NULL , 0 , 0 , PM_REMOVE ) ){
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}else{
		// ここで、描画その他ゲームに必要な処理をする。
	}
	Sleep( 1 );
}

これで描画の基盤ができました。
< サンプル >
このサンプルを実行すると、クライアント領域が真っ黒なウィンドウが作成されます。

//-----------------------------------------------------------------
//
//    DirectX 3D Sample Program.
//
//-----------------------------------------------------------------
#define sqrtf sqrt
#define sinf  sin
#define cosf  cos
#define tanf  tan

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

#pragma comment( lib , "d3d9.dll" );
#pragma comment( lib , "d3dx9.dll" );



//-----------------------------------------------------------------
//    Grobal Variables.
//-----------------------------------------------------------------
LPDIRECT3D9       g_pD3D       = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;



//-----------------------------------------------------------------
//    Prototypes.
//-----------------------------------------------------------------
HWND    InitApp( HINSTANCE , int );
BOOL    InitDirect3D( HWND );
BOOL    CleanupDirect3D();
BOOL    RenderDirect3D();
LRESULT CALLBACK WndProc( HWND , UINT , WPARAM , LPARAM );



//-----------------------------------------------------------------
//    Main.
//-----------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst , HINSTANCE hPrevinst , LPSTR nCmdLine , int nCmdShow )
{
	MSG msg;
	HWND hWnd;
	
	hWnd = InitApp( hInst , nCmdShow );
	if ( !hWnd ) return FALSE;
	
	if ( !InitDirect3D( hWnd ) ) return FALSE;
	
	while( msg.message != WM_QUIT ){
		if ( PeekMessage( &msg , NULL , 0 , 0 , PM_REMOVE ) ){
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}else{
			RenderDirect3D();
		}
		Sleep( 1 );
	}
	
	return msg.wParam;
}



//-----------------------------------------------------------------
//    Initialize Application.
//-----------------------------------------------------------------
HWND InitApp( HINSTANCE hInst , int nCmdShow )
{
	WNDCLASS wc;
	HWND hWnd;
	char szClassName[] = "Direct3D Test";
	
	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance     = hInst;
	wc.hCursor       = LoadCursor( NULL , IDC_ARROW );
	wc.hIcon         = LoadIcon( NULL , IDI_APPLICATION );
	wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpszClassName = szClassName;
	wc.lpszMenuName  = NULL;
	wc.lpfnWndProc   = WndProc;
	wc.cbWndExtra    = 0;
	wc.cbClsExtra    = 0;
	if ( !RegisterClass( &wc ) ) return FALSE;
	
	hWnd = CreateWindow( szClassName , "Direct3D Test" , WS_OVERLAPPEDWINDOW ,
	                     CW_USEDEFAULT , CW_USEDEFAULT , 640 , 480,
	                     NULL , NULL , hInst , NULL );
	if ( !hWnd ) return FALSE;
	
	ShowWindow( hWnd , nCmdShow );
	UpdateWindow( hWnd );
	
	return hWnd;
}



//-----------------------------------------------------------------
//    Initialize Direct3D.
//-----------------------------------------------------------------
BOOL InitDirect3D( HWND hWnd )
{
	D3DPRESENT_PARAMETERS d3dpp;
	HRESULT hr;
	
	if ( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ){
		MessageBox( hWnd , "Can't create Direct3D." , "Error" , MB_OK );
		return FALSE;
	}
	ZeroMemory( &d3dpp , sizeof( d3dpp ) );
	d3dpp.Windowed         = TRUE;
	d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	
	hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
	                           D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
	                           &d3dpp , &g_pd3dDevice );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create device." , "Error" , MB_OK );
		return FALSE;
	}
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Cleanup Direct3D.
//-----------------------------------------------------------------
BOOL CleanupDirect3D()
{
	if ( g_pd3dDevice != NULL )
		g_pd3dDevice->Release();
	
	if ( g_pD3D != NULL )
		g_pD3D->Release();
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Window Proc.
//-----------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd , UINT msg , WPARAM wp , LPARAM lp )
{
	switch( msg ){
		case WM_DESTROY:
			CleanupDirect3D();
			PostQuitMessage( 0 );
			break;
		default:
			return DefWindowProc( hWnd , msg , wp , lp );
	}
	
	return 0L;
}



//-----------------------------------------------------------------
//    Render Direct3D.
//-----------------------------------------------------------------
BOOL RenderDirect3D()
{
	g_pd3dDevice->Clear( 0 , NULL , D3DCLEAR_TARGET ,
	                     D3DCOLOR_XRGB( 0 , 0 , 0 ) , 1.0f , 0 );
	
	g_pd3dDevice->BeginScene();
	
	// Render.
	
	g_pd3dDevice->EndScene();
	
	g_pd3dDevice->Present( NULL , NULL , NULL , NULL );
	
	return TRUE;
}

実行結果

クリックすると実物大で表示されます。
執筆: 2008/05/05 (MON)