★ DirectX Class ★ * Chapter 05: 文字の表示 *
< 文字の表示について >
この章では文字の表示をやってみます。
地味ですが、かなり重要ですし、よく使います。
例えばゲームにおいて、HP、MP、キャラクター名、ダメージ、経験値、村人の話、スタッフロール、etc...
・・・と枚挙に暇がありません。
また、デバッグやFPSの表示等、開発段階で導入することにより、各種情報を可視化できて便利です。
< 準備 >
文字を表示するにも、今までと同様に文字用のクラス変数を宣言します。

LPD3DXFONT g_pFont = NULL;

そして、文字列用のクラスを作成します。
それは以下の関数を用いて実現できます。

HRESULT D3DXCreateFont(
  LPDIRECT3DDEVICE9 pDevice,
  INT Height,
  UINT Width,
  UINT Weight,
  UINT MipLevels,
  BOOL Italic,
  DWORD CharSet,
  DWORD OutputPrecision,
  DWORD Quality,
  DWORD PitchAndFamily,
  LPCTSTR pFacename,
  LPD3DXFONT * ppFont
);

たかが文字列されど文字列。
CreateWindowより引数多いよ・・・。

ということで重要なものだけ最低限の説明にします。

『pDevice』にはDirect3Dのデバイスへを指定します。
『Height』には文字の高さを指定します。
『Width』には文字の幅を指定します。
『pFacename』にはフォントの種類を指定します。"MS ゴシック"や"Courier New"等。
『ppFont』には先程宣言した文字列用クラス変数へのポインタを指定します。
あとは全部0で埋めましょう。
太字にしたり斜体にしたりできるようですが、よく分からなかったのと私には必要ないので知りません。
使いたい方は自分で調べてみてください。

実際には以下のように実行します。

D3DXCreateFont(
    g_pd3dDevice ,
    20 ,
    10 ,
    0 ,
    0 ,
    0 ,
    0 ,
    0 ,
    0 ,
    0 ,
    "Times New Roman" ,
    &g_pFont
);

また、アプリケーションの終了時には開放する必要があります。

g_pFont->Release();
< 描画 >
それでは実際に文字列を表示してみます。
文字列の表示は以下の関数によって実現できます。

INT DrawText(
  LPD3DXSPRITE pSprite,
  LPCTSTR pString,
  INT Count,
  LPRECT pRect,
  DWORD Format,
  D3DCOLOR Color
);

『pSprite』にはスプライトを指定します。
スプライトを作成していない場合、またスプライトを指定するのが面倒な場合には『 NULL 』を指定します。

『pString』には実際に表示したい文字列を指定します。
文字列配列へのポインタでも良いですし、直書きしてもかまいません。

『Count』には、表示する文字数を指定します。
pStringの最初から何文字かということです。『 -1 』を指定すると、pStringで指定した文字列が全て表示されます。

『pRect』にはRECT構造体へのポインタを指定します。
ウィンドウ上の、この構造体で指定された範囲に文字列が描画されます。
この範囲をはみ出す文字列は、はみ出した部分を描画しません。

『Format』フォーマットを指定します。
右寄せ、左寄せ、中央寄せ等、10種類以上の定数が用意されています。
詳しくは説明書をご覧ください。
特に指定しない場合は『 NULL 』を指定してください。

『Color』には描画する文字列の色を指定します。

実際には以下のように実行します。

g_pFont->DrawText(
  NULL ,
  "Test" ,
  -1 ,
  &rc ,
  NULL ,
  0xFF88FF88
);

この関数は、例によって描画の開始宣言から終了宣言の間に実行します。
< サンプル >
このサンプルを実行すると、クライアント領域に黄緑色の文章が表示されます。
描画の順番と実際の重なり順を比較してみてください。

ポイントはピンク色で示してあります。

//-----------------------------------------------------------------
//
//    DirectX 3D
//
//-----------------------------------------------------------------
#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;
LPD3DXFONT         g_pFont      = 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;
	}
	
	D3DXCreateFont( g_pd3dDevice , 20 , 10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , "Times New Roman" , &g_pFont );
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Cleanup Direct3D.
//-----------------------------------------------------------------
BOOL CleanupDirect3D()
{
	if ( g_pFont != NULL )
		g_pFont->Release();
	
	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()
{
	RECT rc;
	D3DXVECTOR3 center , position;
	
	g_pd3dDevice->Clear( 0 , NULL , D3DCLEAR_TARGET ,
	                     0x00000000 , 1.0f , 0 );
	
	g_pd3dDevice->BeginScene();
	
	rc.left   = 100;
	rc.top    = 100;
	rc.right  = 640;
	rc.bottom = 320;
	g_pFont->DrawText( NULL , "The DirectX is very cool, sexy and wild!\nHA HA HA!" , -1 , &rc , NULL , 0xFF88FF88 );
	
	g_pd3dDevice->EndScene();
	
	g_pd3dDevice->Present( NULL , NULL , NULL , NULL );
	
	return TRUE;
}

実行結果

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