DirectX の初期化


〜これさえあれば後は使いまわし〜




■今回は?

今回は、DirectX の初期化を行います。
ソースは、次のものです

今後、サンプルを作ったり、ゲームを作る時に、今回のファイルを元に作っていくことになると思います。
というか、今回のものを一度作ってしまえば、少々の変更でいろいろなことが出来ます。

■追加するオブジェクト

今回から、DirectX を使うので、それらの定義ファイルである、

#include <d3d8.h>
#include <d3dx8.h>

インクルードして下さい。
なお、今回のプロジェクトでは、すでに設定済みですが、d3d8.lib、d3dx8.lib、winmm.lib を [プロジェクト]-[設定]-[リンク]-[オブジェクト/ライブラリ モジュール(L)]に追加してください。

今回、次のものを静的変数に追加します。

static LPDIRECT3D8            s_lpD3D = NULL;
static LPDIRECT3DDEVICE8      s_lpD3DDEV = NULL;
static D3DPRESENT_PARAMETERS  s_d3dpp;

これらは、今回使用するインターフェースのポインタ等ですが、こんな物を使うんだと思って、 使っていく中で、おいおい分かっていけばいいのではないでしょうか。

■初期化関数

で、初期化関数です。InitD3D() にまとめました。
Winmain の CreateWindow で、ウィンドウを作成した後に呼び出します。
成功したら、ウィンドウの表示をして、メインループを回すようにします。
SUCCEEDED は HRESULT型の結果の成功、失敗を調べる関数です。 SUCCEEDED(hr) では、hr が S_OK の時に、成功と判定し、if 文は先に進みます。

    HWND hWnd = CreateWindow(..............);
    if(hWnd == NULL) return 0;
    
    if(SUCCEEDED(InitD3D(hWnd))){  // ★★★★★ Direct3D の初期化

        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);
        
        MSG msg;
        while (!s_end)
        {
            // .... メインループ処理
        }
    }

InitD3D() の流れは、

Direct3DCreate8 : Direct3D オブジェクトを作成
  ↓
s_d3dpp を 適当なフォーマットに設定
  ↓
CreateDevice : Direct3D デバイスの作成

になります。
s_d3dpp で、解像度を設定したり、Z バッファの設定をします。
今回は、CreateDevice で、T&L や シェーディングがハードウェアでできるかどうかトライしています。

実際の中身は、次のようになっています。

//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Direct3D の初期化
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Direct3D オブジェクトを作成
    if (NULL == (s_lpD3D = Direct3DCreate8(D3D_SDK_VERSION))){
        MessageBox(NULL,"Direct3D の作成に失敗しました。",CAPTION,MB_OK | MB_ICONSTOP);
        return E_FAIL;
    }

    // 現在の画面モードを取得
    D3DDISPLAYMODE d3ddm;
    if( FAILED( s_lpD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) return E_FAIL;

    // Direct3D 初期化パラメータの設定
    ZeroMemory(&s_d3dpp, sizeof(D3DPRESENT_PARAMETERS));

    s_d3dpp.BackBufferCount = 1;
    if (FULLSCREEN){
        s_d3dpp.Windowed = FALSE;
        s_d3dpp.BackBufferWidth = WIDTH;
        s_d3dpp.BackBufferHeight = HEIGHT;
    }else{
        s_d3dpp.Windowed = TRUE;
        s_d3dpp.BackBufferWidth = 0;
        s_d3dpp.BackBufferHeight = 0;
    }
    // ウインドウ : 現在の画面モードを使用
    s_d3dpp.BackBufferFormat = d3ddm.Format;
    s_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    s_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    s_d3dpp.hDeviceWindow = hWnd;
    // Z バッファの自動作成
    s_d3dpp.EnableAutoDepthStencil = TRUE;
    s_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
 
    // デバイスの作成 - T&L HAL
    if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
        // 失敗したので HAL で試行
        if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
            // 失敗したので REF で試行
            if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
                // 結局失敗した
                MessageBox(NULL,"Direct3D の初期化に失敗しました。",CAPTION,MB_OK | MB_ICONSTOP);
                return E_FAIL;
            }
        }
    }

    return S_OK;
}

■メインループ

さらに、メインループも追加します。
DirectX の描画は、BeginScene で始まり、EndScene で終わります。
BeginScene の前に、画面(とZバッファ)をきれいにするために塗りつぶしています。
イベントが無い時は、常に描画しますが、その描画対象は、 実際のディスプレイではありません。 常に画面で描いていると描いている途中が見えるので、見えないように、 描画用と表示用のメモリをビデオカードのメモリもしくはメインメモリに用意して、 描画し終わったら、現在表示している画面といれ替えます。 次は、今まで表示していたメモリ上に画面を作っています。

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
    // メッセージの処理
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}else{

    // ★★★★★ Direct3D の描画
    // バックバッファと Z バッファをクリア
    s_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
    // シーン開始
    s_lpD3DDEV->BeginScene();
    
    // ポリゴン描画などの処理
    
    // シーン終了
    s_lpD3DDEV->EndScene();
    if (FAILED(s_lpD3DDEV->Present(NULL,NULL,NULL,NULL)))
        s_lpD3DDEV->Reset(&s_d3dpp);// バックバッファをプライマリバッファにコピー

}

■後始末

最後に、使ったメモリーを開放します。
WinMain の一番最後に追加します。
今回は、Direct3DCreate8, CreateDevice で確保した、s_lpD3DDEV、s_lpD3DD のメモリを開放します。

    RELEASE(s_lpD3DDEV);
    RELEASE(s_lpD3D);

RELEASE はDirectX を使っている人なら、ほとんどの人が使っているマクロで、メモリの多重開放を防止します。
DirectX 系のオブジェクトは、RELEASE (その中の Release()) で開放することは覚えて置いてください。
なお、これは main.h にあります。





もどる

imagire@gmail.com