D3D的初始化

要開始D3D編程,首先是要初始化D3D環境,SDK文檔的tutorial將整個過程分爲幾部html

  1. 建立一個窗體
  2. 初始化D3D
    • 獲取IDirect3D9的指針
    • 檢查設備的性能、對API的支持能力
    • 初始化D3DPRESENT_PARAMETERS
    • 使用D3DPRESENT_PARAMETER的參數建立IDirectDDevice9
  3. 處理消息
  4. 渲染&顯示場景
  5. 關閉D3D,退出程序

  1. 建立窗體
    以前說過,D3D程序是在一個windows窗體的客戶區進行繪製,D3D至關於畫筆的話,這個窗體就是畫布,因此在初始化D3D以前首先要有一個窗體,根據簡單的Windows API編程回顧的內容,建立一個簡單窗體並不難。
    • 定義窗口類
    WNDCLASS wclass;
    • 註冊窗口類
    RegisterClass(&wclass);
    • 建立窗口
    CreateWindow(...);
  2. 初始化D3D
    一旦建立好了窗體,就能夠在這個基礎上進一步去初始化D3D,建立D3D設備,以在窗體這個畫布上進行繪圖,初始化D3D的過程能夠分爲四部。
    • 獲取IDirect3D9的指針,遊戲開發中最經常使用的就是COM配合DirectX技術,這兒IDirect3D9就是一個表示D3D9的COM接口,所以不能直接使用C++的new操做符
    LPDIRECT3D9 g_pD3D9;    //IDirect3D9 *g_pD3D9;
    g_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
    • 檢查設備性能,對API的支持程度(如硬件TnL,這個是比較老的固定功能流水線中所採用的一些東西,現代的可編程流水線已經見不着了)
    //以硬件TnL爲例
    D3DCAPS9 d3dcap;
    int hwTnL = 0;
    g_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps);
    if(caps.Devcaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
        hwTnL = D3DCREATE_HARDWARE_VERTEXPROCESSING;
    else
        hwTnL = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    • 創建一個D3DPRESENT_PARAMETERS
    D3DPRESENT_PARAMETERS d3dpp;
    //按需設置d3dpp的各種屬性
    • 創建D3D設備
    g_pD3D9->CreateDevice(D3DADAPTER,
                          D3DDEVTYPE,
                          HWND, BEHAVIOR_FLAGS
                          D3DPRESENT_PARAMETERS*,
                          IDirect3DDevice9 **);

    至此,D3D的初始化就完成了編程

  3. 處理消息
    就如簡單的Windows API編程回顧中所述,遊戲程序多數不是事件驅動的,於是能夠使用PeekMessage處理消息windows

    MSG msg;
    while(PeekMessage(&msg, 0, 0, 0, 0))
    {
        if(msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    //Game Codes
  4. 渲染&顯示場景
    • 清除後臺緩存,將後臺緩存置爲所設定的顏色,將深度或模板緩存設置爲須要的值
    //IDirect3DDevice9::Clear
    g_pD3DDEV9->Clear(DWORD Count, const D3DRECT *pRects,
                      DWORD flags, D3DCOLOR Color, float Z, DWORD Stencil);
    • 向後臺緩存繪製場景
    g_pD3DDEV9->BeginScene();
    //Render Codes
    g_pD3DDEV9->EndScene();
    • 提交下一幀後臺緩存,僅僅是提交,尚未顯示
    //IDirect3DDevice9::Present
    g_pD3DDEV9->Present(0,0,0,0);
  5. 關閉D3D,退出程序
    退出程序不困難,但以前要先關閉D3D。以前說了g_pD3D9和g_pD3DDEV9是兩個COM接口指針,而COM不能夠使用C++的new/delete操做符來建立和銷燬,因此須要手動的來釋放一下
g_pD3D9->Release();
g_pD3D9 = NULL;
g_pD3DDEV9->Release();
g_pD3DDEV9 = NULL;

至此,整個D3D程序流程就結束了

所有代碼以下緩存

#include <windows.h>
#include <d3d9.h>
#include <strsafe.h>

#pragma comment(lib, "d3d9.lib")


LPDIRECT3D9         g_pD3D9;
LPDIRECT3DDEVICE9   g_pD3D9dev;

HWND hMain;

bool initWinApp(HINSTANCE hInstance, int iCmdShow);
LRESULT CALLBACK MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

HRESULT D3DInit(HWND hWnd);
void D3DRender();
void D3DCleanup();


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmd, int iCmdShow)
{
    if( !initWinApp(hInstance, iCmdShow) )
    {
        ::MessageBox(0, TEXT("initWinApp Failed!"), TEXT("ERROR"), MB_OK);
        return 0;
    }

    if( SUCCEEDED(D3DInit(hMain)) )
    {
        ::ShowWindow(hMain, iCmdShow);
        ::UpdateWindow(hMain);

        MSG msg;
        while( PeekMessage(&msg, 0, 0, 0, 0 ) )
        {
            if( msg.message == WM_QUIT )
                break;
            msg.message = WM_PAINT;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    D3DCleanup();
    UnregisterClass(L"D3DInit", hInstance);
    return 0;


}

bool initWinApp(HINSTANCE hInstance, int iCmdshow)
{
    WNDCLASS wc;
    wc.style        = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc  = MsgProc;
    wc.cbClsExtra   = 0;
    wc.cbWndExtra   = 0;
    wc.hInstance    = hInstance;
    wc.hIcon        = ::LoadIcon(0, IDI_APPLICATION);
    wc.hCursor      = ::LoadCursor(0, IDC_ARROW);
    wc.hbrBackground= static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH));
    wc.lpszMenuName = 0;
    wc.lpszClassName= TEXT("D3DInit");

    if( !RegisterClass(&wc) )
    {
        ::MessageBox(0, TEXT("RegisterClass Failed!"), TEXT("ERROR"), MB_OK);
        return false;
    }

    if( (hMain = CreateWindow(TEXT("D3DInit"), TEXT("D3DInit"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL)) == NULL)
    {
        ::MessageBox(0, TEXT("CreateWindow Failed!"), TEXT("ERROR"), MB_OK);
        return false;
    }

    return true;
}

HRESULT D3DInit(HWND hWnd)
{
    //acquire pointer to IDirect3D9
    if( (g_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL )
    {
        ::MessageBox(0, TEXT("Direct3DCreate Failed!"), TEXT("ERROR"), MB_OK);
        return E_FAIL;
    }

    //Check Device Capabilities, here we check the hardware TnL support
    D3DCAPS9 caps;
    g_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
    int hardwareTnL = 0;
    if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
        hardwareTnL = D3DCREATE_HARDWARE_VERTEXPROCESSING;
    else
        hardwareTnL = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    //setup D3DPRESENT_PARAMETERS which defines the behavior of the D3D app 
    D3DPRESENT_PARAMETERS d3dpp;
    d3dpp.BackBufferWidth           = 800;
    d3dpp.BackBufferHeight          = 600;
    d3dpp.BackBufferCount           = 2;
    d3dpp.BackBufferFormat          = D3DFMT_A8R8G8B8;
    d3dpp.MultiSampleType           = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality        = 0;
    d3dpp.SwapEffect                = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow             = hMain;
    d3dpp.Windowed                  = 1;
    d3dpp.EnableAutoDepthStencil    = TRUE;
    d3dpp.AutoDepthStencilFormat    = D3DFMT_D24S8;
    d3dpp.Flags                     = 0;
    d3dpp.FullScreen_RefreshRateInHz= D3DPRESENT_RATE_DEFAULT;
    d3dpp.PresentationInterval      = D3DPRESENT_INTERVAL_IMMEDIATE;

    //Create D3D device
    if( FAILED(g_pD3D9->CreateDevice(D3DADAPTER_DEFAULT,
                                    D3DDEVTYPE_HAL,
                                    hWnd,
                                    hardwareTnL,
                                    &d3dpp,
                                    &g_pD3D9dev)) )
    {
        MessageBox(0, TEXT("CreateDevice Failed"), TEXT("ERROR"), MB_OK);
        return E_FAIL;
    }

    return S_OK;
}

LRESULT CALLBACK MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch( msg )
    {
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        D3DRender();
        ValidateRect(hWnd, NULL);
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

void D3DRender()
{
    //Set BackBuffer
    g_pD3D9dev->Clear(0, NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB( 0, 255, 0 ), 1.0f, 0 );

    //Render in this section
    if( SUCCEEDED(g_pD3D9dev->BeginScene()) )
    {
        g_pD3D9dev->EndScene();
    }

    //Present BackBuffer
    g_pD3D9dev->Present(NULL, NULL, NULL, NULL);
}

void D3DCleanup()
{
    if( g_pD3D9dev != NULL )
    {
        g_pD3D9dev->Release();
    }
    if( g_pD3D9 != NULL )
    {
        g_pD3D9->Release();
    }
}
相關文章
相關標籤/搜索