Direct3D デバイスを取得する

DirectX の3Dデバイスを取得して、ウインドウを表示します。
Direct Draw が廃止されて、代わりに Sprite が使われるようになりました。
Sprite は基本的には三次元グラフィックスなので、3Dデバイスを取得しなければなりません。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの作成

  1. 事前に DirectX9 をインストールしてパスの設定を行って下さい。
    インストールは DirectX9 のインストール を参照して下さい。
    パスの設定は Windows Guide を参照して下さい。
  2. [ファイル][新規作成][プロジェクト]を選択すると新しいプロジェクトのウインドウが表示されます。
    [プロジェクトの種類]から[Visual C++ プロジェクト]を、[テンプレート]から[Win32 プロジェクト]を選択します。
    プロジェクト名は Main にして下さい。
    このとき、プロジェクトが格納される場所(フォルダーの名前)を覚えておいて下さい。

  3. [アプリケーションの設定]画面を表示して下さい。
    [Windows アプリケーション]と[空のプロジェクト]をチェックして下さい。
    完了ボタンをクリックすると Main のフォルダーが作成されてプロジェクトが構築されます。

  4. コンピュータ(マイ コンピュータ)を起動して、Main.cpp をプロジェクトのフォルダーに格納して下さい。
    Main.cpp の全ソースコードを、このページの後部に掲載しています。
    VC++ に戻って、プロジェクト/既存項目の追加から Main.cpp をプロジェクトに追加します。
    新しい項目の追加から Main.cpp を追加して、ソースコードをタイプする方法もあります。

  5. プロジェクト/Main のプロパティから文字セットを設定します。
    構成プロパティ/全般から文字セットをマルチバイト文字セットを使用するに設定して下さい。

  6. ビルドから実行を選ぶと、コンパイルに続いて実行が行われ、ウインドウが表示されます。
  7. フォルダーには沢山のファイルが作成されますが、Main.vcproj と Main.cpp 以外は削除しても、 再コンパイルすると自動的に作成されます。

プログラムの説明

  1. #include では Windows.h, d3dx9.h, mmsystem.h を取り込んで下さい。
    mmsystem.h はマルチメディアタイマーを使用するときに必要です。
    #pragma でライブラリをリンクします。
    winmm.lib はマルチメディアタイマーを使用するときに必要です。
        /*********************************************/
        /*★ Direct3D デバイスを取得する   前田 稔 ★*/
        /*********************************************/
        #define     NAME    "Init Device"
        #include    <Windows.h>
        #include    <d3dx9.h>
        #include    <mmsystem.h>
    
        // ライブラリのリンク
        #pragma once
        #pragma comment(lib,"d3d9.lib")
        #pragma comment(lib,"d3dx9.lib")
        #pragma comment(lib,"dxguid.lib")
        #pragma comment(lib,"winmm.lib")
    
        // #define & 構造体の定義
        #define SAFE_RELEASE(x) if(x)  { x->Release(); x=NULL; } 
        
  2. HWND g_hWnd は幾つかの関数から参照するので、グローバル領域で定義しています。
    g_pD3D は Direct3D Object で g_pDEV を作成するために使用します。
    g_pDEV が描画環境の設定やモデルの描写に使用するデバイスです。
        // Global Area
        HWND                    g_hWnd = NULL;      // Window Handle
        LPDIRECT3D9             g_pD3D = NULL;      // Direct3D Object
        LPDIRECT3DDEVICE9       g_pDEV = NULL;      // 描写用デバイス
        
  3. WinMain() 関数では、ウインドウを生成した後で Init3DDev() で DirectX の初期化を行います。
    メッセージループでは PeekMessage() を使って、ループの中から描画関数 Draw() を呼び出します。
            ・・・
        if (!g_hWnd)  return FALSE;
    
        // DirectX Graphics の初期化
        if (FAILED(Init3DDev()))    return FALSE;
            ・・・
        // メッセージ・ループ
        ZeroMemory(&msg,sizeof(msg));
        while(msg.message!=WM_QUIT)
        {   if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {   TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else    Draw();     // レンダリングの処理
        }
        
  4. DirectX の初期化を行う Init3DDev() 関数です。
    DirectX の最初の難関がデバイスの取得です。
    ハード構成によってデバイスの制御も微妙に異なり、そのマシンに合ったデバイスを取得しなければなりません。
    今回は出来るだけ簡単な方法でデバイスを取得してみました。
    デバイスが取得出来れば、レンダリングステートパラメータとサンプラーステートパラメータを設定します。
    DirectX の初期化や HAL&HEL の説明は Back Buffer を取得して円を描画する を参照して下さい。
  5. DirectX ではメッセージループから直接 Draw() 関数が呼び出されます。
    D3DCOLOR_RGBA(0,0,0,0) がウインドウを塗りつぶす色(RGBA) です。
    例えばグレーで塗りつぶすときは D3DCOLOR_RGBA(100,100,100,0) になります。
    描画は BeginScene() で始めて EndScene() で終わります。
        HRESULT Draw(void)
        {
            //グレーで塗りつぶして消去
            g_pDEV->Clear(0,NULL,(D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER),D3DCOLOR_RGBA(80,80,80,0),1.0f,0);
            if (SUCCEEDED(g_pDEV->BeginScene()))
            {
                g_pDEV->EndScene();
            }
            g_pDEV->Present(NULL,NULL,NULL,NULL);
            return S_OK;
        }
        
  6. MsgProc() は WM_DESTROY: と ESC キーを検出してプログラムを終了するだけです。
        // ウィンドウ処理(自分で処理したときは 0 を返す)
        LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam)
        {
            switch(msg)
            {   case WM_DESTROY:
                    Cleanup();
                    PostQuitMessage(0);
                    break;
                case WM_KEYDOWN:
                    switch(wParam)
                    {   case VK_ESCAPE:
                            DestroyWindow(hWnd);
                            break;
                    }
                    break;
                    ・・・
        
  7. WM_DESTROY: から呼ばれる Cleanup() では、取得した Object を開放して下さい。
        // DirectX Graphics の終了処理
        void Cleanup(void)
        {   SAFE_RELEASE(g_pDEV);
            SAFE_RELEASE(g_pD3D);
        }
        
  8. Main.cpp の全ソースコードです。
    /**********************************************/
    /*★ Direct3D デバイスを取得する    前田 稔 ★*/
    /**********************************************/
    #define     NAME    "Init Device"
    #include    <Windows.h>
    #include    <d3dx9.h>
    #include    <mmsystem.h>
    
    // ライブラリのリンク
    #pragma once
    #pragma comment(lib,"d3d9.lib")
    #pragma comment(lib,"d3dx9.lib")
    #pragma comment(lib,"dxguid.lib")
    #pragma comment(lib,"winmm.lib")
    
    // #define & 構造体の定義
    #define SAFE_RELEASE(x) if(x)  { x->Release(); x=NULL; }
    
    // Global Area
    HWND                    g_hWnd = NULL;      // Window Handle
    LPDIRECT3D9             g_pD3D = NULL;      // Direct3D Object
    LPDIRECT3DDEVICE9       g_pDEV = NULL;      // 描写用デバイス
    
    // Function Prototype
    LRESULT CALLBACK    WndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam);
    
    HRESULT Init3DDev()
    {   D3DDISPLAYMODE          d3ddm;
        D3DPRESENT_PARAMETERS   d3dpp;
    
        if (NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION)))    return E_FAIL;
        if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))   return E_FAIL;
        ZeroMemory(&d3dpp,sizeof(d3dpp));
        d3dpp.Windowed                  = TRUE;                     // ウィンドウモード
        d3dpp.SwapEffect                = D3DSWAPEFFECT_DISCARD;    // 映像信号に同期してフリップする
        d3dpp.EnableAutoDepthStencil    = TRUE;                     // デプスバッファ(Zバッファ)とステンシルバッファを作成
        d3dpp.AutoDepthStencilFormat    = D3DFMT_D16;               // デプスバッファとして16bitを使う
        d3dpp.BackBufferFormat          = d3ddm.Format;             // カラーモードの指定
    
        if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,g_hWnd,
                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pDEV)))
            return E_FAIL;
    
        // レンダリングステートパラメータの設定
        g_pDEV->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);           // カリングを行わない
        g_pDEV->SetRenderState(D3DRS_ZENABLE, TRUE);                    // Zバッファを使用
        g_pDEV->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);           // αブレンドを行う
        g_pDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);      // αソースカラーの指定
        g_pDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);  // αデスティネーションカラーの指定
    
        // サンプラーステートパラメータの設定
        g_pDEV->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); // テクスチャU値の繰り返し設定
        g_pDEV->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); // テクスチャV値の繰り返し設定
        g_pDEV->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);  // テクスチャ拡大時の補間設定
        g_pDEV->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);  // テクスチャ縮小時の補間設定
    
        return S_OK;
    }
    
    // 画面の描画処理
    HRESULT Draw(void)
    {
        //グレーで塗りつぶして消去
        g_pDEV->Clear(0, NULL, (D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER), D3DCOLOR_RGBA(80,80,80,0), 1.0f, 0);
        if (SUCCEEDED(g_pDEV->BeginScene()))
        {
            g_pDEV->EndScene();
        }
        g_pDEV->Present(NULL,NULL,NULL,NULL);
        return S_OK;
    }
    
    // DirectX Graphics の終了処理
    void Cleanup(void)
    {
        SAFE_RELEASE(g_pDEV);
        SAFE_RELEASE(g_pD3D);
    }
    
    //★ WinMain()
    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
    {   MSG         msg;
    
        WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0,0, 
                          hInst,NULL,NULL,NULL,NULL,NAME,NULL
                        };
        if (!RegisterClassEx(&wc))  return FALSE;
    
        g_hWnd= CreateWindowEx(0,NAME,NAME,WS_OVERLAPPEDWINDOW,
                      CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
                      NULL,NULL,hInst,NULL);
        if (!g_hWnd)  return FALSE;
    
        // DirectX Graphics の初期化
        if (FAILED(Init3DDev()))    return FALSE;
    
        // ウインドウ表示
        ShowWindow(g_hWnd, SW_SHOWNORMAL);
        UpdateWindow(g_hWnd);
        // メッセージ・ループ
        ZeroMemory(&msg,sizeof(msg));
        while(msg.message!=WM_QUIT)
        {   if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {   TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else    Draw();     // レンダリングの処理
        }
    
        UnregisterClass(NAME, hInst);
        return  TRUE;
    }
    
    // ウィンドウ処理(自分で処理したときは 0 を返す)
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam)
    {
        switch(msg)
        {   case WM_DESTROY:
                Cleanup();
                PostQuitMessage(0);
                break;
            case WM_KEYDOWN:
                switch(wParam)
                {   case VK_ESCAPE:
                        DestroyWindow(hWnd);
                        break;
                }
                break;
            default:
                return DefWindowProc(hWnd, msg, wParam, lParam);
        }
        return 0;
    }
    

超初心者のプログラム入門(DirectX9 game program)