その13 DirectX用デバッグ文字表示
DirectXのサンプルやゲーム等を作っていつも「いー!」っと思うのがデバッグ文字の表示です。DirectXで文字を表示させるのって意外と面倒なんです。もっと「printf」並に簡単にデバッグ文字を表示させたい!そう思い1ヘッダー1cppでデバッグ文字を表示できるDebugFontクラスを作りました。ただし「ASCII文字限定」です。日本語は出せません。デバッグ表示ってそれで十分だったリします。
アプリケーション開始時にinitializeメソッドを呼んでおけば、実質あとはDebugFont::print(***)だけでデバッグ文字がガンガン出ます(^-^)。
名前 | バージョン | 公開日 | |
デバッグフォント文字表示クラス | 1.00 | 2011. 6. 3 |
○ 定義
名前空間 | ヘッダー | .cpp |
OX | oxdebugfont.h | oxdebugfont_dx9.cpp |
※ヘッダーと.cppの名前が違うので注意してください。
○ デバッグフォント文字表示クラスメソッド
公開メンバメソッド | 説明 | 使い方 | 備考 |
~DebugFont() | デストラクタ | - | - |
static bool initialize(void *device, unsigned maxStrNum, unsigned maxWorkingBufferSize); | 初期化 | OX::DebugFont::initialize(g_pD3DDev, 2500, 1024); | リソースやワーキングメモリの初期化を行います。これはアプリケーションが開始されてゲームループに入る前に一度だけ呼び出します。このメソッドを呼び出す前に外のメソッドを呼び出してはいけません。 deviceにはIDirect3DDevice9オブジェクトを渡して下さい。void*型になっているのは汎用性を考慮しているためです。maxStrNumは一度に描画する最大文字数です。各種バッファサイズに直結するのであまり大きくしない方がメモリに優しいです。maxWorkingBufferSizeは1回のprintメソッド呼び出しでの最大表示文字数です。指定分のメモリをアプリケーションが終了するまで確保します。 |
static bool print(int x, int y, unsigned color, const char *format, ...); static bool print(int x, int y, unsigned color, Option &option, const char *format, ...); |
デバッグ文字を追加 | OX::DebugFont::print(50, 100, 0xff00ffff, "Count = %d", count); | 表示するデバッグ文字を追加します。x, yはスクリーン座標位置、colorは表示色をARGBで指定します。formatはprintfと同じ書式が使えます。 optionはDebugFont::Option構造体で指定した方法で文字列を表示する拡張機能です。単純なデバッグ表示は上のprint、クリッピングやアラインメントなどを使いたい場合は下のprintメソッドを使用します。 |
static bool draw(void *device); | 描画 | OX::DebugFont::draw(g_pD3DDev); | ストックしたデバッグ文字を描画します。これはストックしたすべての文字を一度に描画するため、ゲームループ内で毎フレーム1回呼ぶだけで十分です。 deviceにはIDirect3DDevice9オブジェクトを渡します。内部ではアルファブレンドとカリングのみ一時的に設定されますが、メソッドを抜ける時に元に戻されます。 |
static void clear() | バッファ位置を戻す | OX::DebugFont::clear(); | デバッグ文字をストックしている配列の書き込みバッファ位置を0に戻します。このメソッドはdrawメソッドの後ゲームループの最後で必ず一度呼んで下さい。呼び忘れるとデバッグ文字がバッファに貯まり、最大文字数を超えると追加ができなくなってしまいます。 |
static void terminate(); | 終了処理 | OX::DebugFont::terminate(); | 内部のリソースをすべて解放します。アプリケーションが終了する前に一度呼んで下さい。 |
○ Option構造体
struct Option {
enum Align {
LEFT, RIGHT, CENTER
};
bool clip;
int clipWidth;
Align align;
Option() : clip(), clipWidth(), align(LEFT) {}
};
拡張的なデバッグ表示を行う時に指定します。Alignは指定位置に対して左寄せ、右寄せ及び中央寄せ描画を行います。clipをtrueにするとclipWidthに指定した幅で自動折り返しになります。
○ バージョンレポート
v1.00 (2011. 6. 3)
初出
○ 使用例
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include "oxdebugfont.h"
TCHAR gName[100] = _T("デバッグ文字表示テスト");
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
if(mes == WM_DESTROY || mes == WM_CLOSE ) {PostQuitMessage(0); return 0;}
return DefWindowProc(hWnd, mes, wParam, lParam);
}
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// アプリケーションの初期化
MSG msg; HWND hWnd;
WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
if(!RegisterClassEx(&wcex))
return 0;
RECT r = {0, 0, 640, 480};
::AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, hInstance, NULL)))
return 0;
// Direct3Dの初期化
LPDIRECT3D9 g_pD3D;
LPDIRECT3DDEVICE9 g_pD3DDev;
if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;
D3DPRESENT_PARAMETERS d3dpp = {640,480,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0};
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) ) {
g_pD3D->Release();
return 0;
}
// 初期化
// ループ前に一度だけ呼び出します。
OX::DebugFont::initialize(g_pD3DDev, 2500, 1024);
ShowWindow(hWnd, nCmdShow);
int count = 0;
// メッセージ ループ
do{
if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){
DispatchMessage(&msg);
}
// Direct3Dの処理
count++;
g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,96), 1.0f, 0 );
g_pD3DDev->BeginScene();
// デバッグ表示
// グローバルなクラスなのでどこからでも呼べます!
OX::DebugFont::print(50, 100, 0xff00ffff, "OX TUKURO- : http://marupeke296.com", count);
OX::DebugFont::print(70, 130, 0xffffffff, "This is a test of debug texts. Counter = %d. Pi = %f", count, 3.141592f);
// 拡張表示
OX::DebugFont::Option option;
option.clip = true;
option.clipWidth = 120;
// 右寄せ
option.align = OX::DebugFont::Option::RIGHT;
OX::DebugFont::print(70, 150, 0xffffff00, option, "Clipping and Alignment: w = %d, Right alignment.", option.clipWidth);
// 左寄せ
option.align = OX::DebugFont::Option::LEFT;
OX::DebugFont::print(70, 220, 0xffffff00, option, "Clipping and Alignment: w = %d, Left alignment.", option.clipWidth);
// 中央寄せ
option.align = OX::DebugFont::Option::CENTER;
OX::DebugFont::print(70, 290, 0xffffff00, option, "Clipping and Alignment: w = %d, Center alignment.", option.clipWidth);
// 描画
OX::DebugFont::draw(g_pD3DDev);
g_pD3DDev->EndScene();
g_pD3DDev->Present( NULL, NULL, NULL, NULL );
// バッファ位置をクリア
// ※クリアしないといずれ溢れて文字を追加できなくなります(オーバーランはしません)
OX::DebugFont::clear();
}while(msg.message != WM_QUIT);
// 終了処理
// ※DebugFontのデストラクタでも呼ばれますが、先に呼んでおいた方が確実です
OX::DebugFont::terminate();
g_pD3DDev->Release();
g_pD3D->Release();
return 0;
}
○ 技術的なお話
このデバッグフォントのリソースはdebugfont_dx9.cppの中にがりっとハードコーディングされています。よってヘッダーと.cppをプロジェクトに追加するだけでデバッグ文字を表示できます。フォントリソースが入っている.cppはおよそ70KBで、アプリケーションが存在する間メモリに常駐されます。このフォントリソースの作成にはAngelCodeのBitmap Font Generatorを利用しました。大変素晴らしいツールです(オフィシャルページはこちら)。
DebugFontクラスの描画の仕組みは、実はフォントリソースさえあればどんな文字でもちゃんと描画する事ができます(ただしUnicode変換が必要になります)。「デバッグ文字が気に入らねぇ」「もっと沢山の文字や記号を表示させられるようにしたい」という場合はリソースを更新すれば良いのですが・・・独自フォーマットなのでちょっと難しいかもしれません(^-^;。すみません・・・。ご希望があれば出来る範囲でリソースファイルを作って公開致します。