8:Direct3D 9の扱い方
3D処理もサウンド処理もゲーム処理もCPUにすべての処理を任せていたら、CPUのパワーがいくらあっても足りません。サウンド処理はサウンド処理専用の、3D処理は3D処理専用のハードウェアに任せるのが一番です。その専用ハードウェアにCPUを介せずダイレクトに命令をアクセスする技術、それがDirectXです。プロジェクト発足当時は「マンハッタン・プロジェクト」とよばれ、ロゴマークにはキノコ雲を彷彿とさせるイメージが採用されていたのですが、ゲーム市場のお得意先である日本が嫌悪感を示しかねないとの理由で「DirectX」に改称された経緯があります(豆知識)。#include <dxerr.h>
#include <d3d9.h>
#include <d3dx9.h>


では第7回で作成した完成したプログラムの「CreateWindow」の次の行あたりに。次のコードを付け足します。これはDirect3Dの基盤データを作成するもので、取得に成功すればIDirect3D9のポインタが、失敗すればNULLが返されます。
// Direct3Dオブジェクトを生成
LPDIRECT3D9 m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if(m_pD3D == NULL){
DXTRACE_MSG(_T("DirectXDeviceの初期化に失敗しました"));
return false;
}
// 細かい画面モードの設定
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp)); // 構造体の中身を0で初期化
d3dpp.Windowed = TRUE;
// ウィンドウモード(FALSEならフルスクリーン状態になる)
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
// ディスプレイドライバに最も効率的な方法を選択させる
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// バックグラウンド描画の方法はシステムに任せる
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// 描画更新の指示があり次第、待たずにすぐ更新
//D3Dデバイスオブジェクトの作成
LPDIRECT3DDEVICE9 m_pD3Ddevice;
if(FAILED(m_pD3D->CreateDevice(
D3DADAPTER_DEFAULT, // プライマリディスプレイに描画
D3DDEVTYPE_HAL, // グラフィックボードの利用を優先して処理を行う
hWnd, // 表示するウィンドウ(CreateWindowで取得したハンドル)
D3DCREATE_MIXED_VERTEXPROCESSING,
// グラフィックボードの利用を優先して頂点処理を行う
&d3dpp, // 画面モードの状態を格納した構造体
&m_pD3Ddevice // 格納するIDirect3DDevice9へのポインタ
)))
{
DXTRACE_MSG(_T("3DDeviceの初期化に失敗しました"));
return false;
}
// アルファブレンドの設定
m_pD3Ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
// 描画先にある画像に対するブレンド方法を指定
// D3DBLEND_SRCALPHAでアルファ値による描画をできるようなる
m_pD3Ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
// 描画元の画像に対するブレンド方法を指定
// D3DBLEND_INVSRCALPHAで画像の状態にあわせて描画先画像のアルファ値が変わるようになる
m_pD3Ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
// アルファブレンドを有効にする
//スプライトオブジェクトの作成
LPD3DXSPRITE m_pSprite;
if(FAILED(D3DXCreateSprite(m_pD3Ddevice, &m_pSprite)))
{
DXTRACE_MSG(_T("SpriteObjectの作成に失敗しました"));
return 0;
}
new
で作成したオブジェクトはdelete
で削除する必要があるように、作成したDirect3D関連のオブジェクトは最後には必ずRelease()で解放しなくてはなりません。たいていのオブジェクトにはRelease()メソッドが用意されているので、解放の処理をマクロ化しておくとよいでしょう。
#define RELEASE(x) {if(x) x->Release();}
RELEASE(m_pSprite);
RELEASE(m_pD3Ddevice);
RELEASE(m_pD3D);
#include <tchar.h>
#include <windows.h>
#include <dxerr9.h>
#include <d3d9.h>
#include <d3dx9.h>
#define RELEASE(x) {if(x) x->Release();}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
PostQuitMessage(NULL);
break;
default:
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
return (0);
}
int APIENTRY _tWinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpszCmdLine, int nCmdShow)
{
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
wc.hIcon = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc; //イベント処理関数を連結
wc.lpszClassName = _T("Game");
wc.lpszMenuName = NULL;
wc.style = NULL;
if(RegisterClass(&wc) == NULL){
return 0;
}
HWND hWnd = CreateWindow(
wc.lpszClassName,
_T("クラスまみれのゲームプログラミング入門"),
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, hInstance, NULL );
LPDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if(pD3D == NULL){
DXTRACE_MSG(_T("DirectXDeviceの初期化に失敗しました"));
return 0;
}
D3DDISPLAYMODE d3ddm;
if(FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
{
DXTRACE_MSG(_T("DirectX3DDeviceの初期化に失敗しました"));
return 0;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
LPDIRECT3DDEVICE9 pD3Ddevice;
if(FAILED(pD3D->CreateDevice(
D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,&pD3Ddevice)))
{
DXTRACE_MSG(_T("3DDeviceObjectの初期化に失敗しました"));
return 0;
}
pD3Ddevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
pD3Ddevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
pD3Ddevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
LPD3DXSPRITE pSprite;
if(FAILED(D3DXCreateSprite(pD3Ddevice, &pSprite)))
{
DXTRACE_MSG(_T("SpriteObjectの作成に失敗しました"));
return 0;
}
ShowWindow(hWnd, nCmdShow);
MSG msg;
while(TRUE){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
// 画像のクリア
pD3Ddevice->Clear( 0, NULL, D3DCLEAR_TARGET ,
D3DCOLOR_XRGB(0,0,64), 1.0f, 0 );
// ディスプレイに表示
pD3Ddevice->Present( NULL, NULL, NULL, NULL );
Sleep(10);
}
}
RELEASE(pSprite);
RELEASE(pD3Ddevice);
RELEASE(pD3D);
return 0;
}