1. 程式人生 > >Directx11入門之D3D程式初始化

Directx11入門之D3D程式初始化

初始化的程式在書中第四章講解比較清楚,文章Directx11學習筆記【三】 第一個D3D11程式已經把書中內容做了大致翻譯,因此不再贅述。以下從原文複製了一些內容與整合後的程式碼。

在先前的解決方案中新建一個新的Win32專案FirstD3D11Demo。在寫程式碼之前,我們必須先新增dx11所需要的庫。為了連結dx庫,右鍵專案選擇屬性->vc++目錄,在包含目錄中新增你所安裝的SDK根目錄\Include,在庫目錄中新增 根目錄\lib\x86(或x64),在連結器->輸入的附加依賴項中新增d3d11.lib、d3dx11.lib、dxerr.lib。

#include <windows.h>
#include <d3d11.h>
#include <DxErr.h>
#include <D3DX11.h>

HINSTANCE g_hInstance = NULL;
HWND g_hWnd = NULL;
LPCWSTR g_name = L"FirstD3D11Demo";
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;                //驅動型別
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;            //特徵等級    
ID3D11Device *g_pd3dDevice = NULL;                                    //裝置
ID3D11DeviceContext *g_pImmediateContext = NULL;                    //裝置上下文
IDXGISwapChain *g_pSwapChain = NULL;                                //交換鏈
ID3D11RenderTargetView *g_pRenderTargetView = NULL;                    //要建立的檢視


HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void Render();

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
    if (FAILED(InitWindow(hInstance, nShowCmd)))
        return 0;
    if (FAILED(InitDevice()))
    {
        CleanupDevice();
        return 0;
    }
    MSG msg;
    ZeroMemory(&msg, sizeof(MSG));
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else//渲染
        {
            Render();
        }
    }
    CleanupDevice();
    return static_cast<int>(msg.wParam);
}

HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
    WNDCLASSEX wcex;
    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wcex.hIconSm = wcex.hIcon;
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = g_name;
    wcex.lpszMenuName = NULL;
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    if (!RegisterClassEx(&wcex))
        return E_FAIL;

    g_hInstance = hInstance;
    RECT rc{ 0,0,640,480 };
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
    g_hWnd = CreateWindowEx(WS_EX_APPWINDOW, g_name, g_name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, g_hInstance, NULL);
    if (!g_hWnd)
        return E_FAIL;

    ShowWindow(g_hWnd, nCmdShow);

    return S_OK;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wPararm, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wPararm, lParam);
    }
    return 0;
}

//建立裝置及交換鏈
HRESULT InitDevice()
{
    HRESULT hResult = S_OK;//返回結果

    RECT rc;
    GetClientRect(g_hWnd, &rc);//獲取視窗客戶區大小
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    //驅動型別陣列
    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE
    };
    UINT numDriverTypes = ARRAYSIZE(driverTypes);

    //特徵級別陣列
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0
    };
    UINT numFeatureLevels = ARRAYSIZE(featureLevels);

    //交換鏈
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(DXGI_SWAP_CHAIN_DESC));//填充
    sd.BufferCount = 1;                              //我們只建立一個後緩衝(雙緩衝)因此為1
    sd.BufferDesc.Width = width;
    sd.BufferDesc.Height = height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = g_hWnd;
    sd.SampleDesc.Count = 1;                      //1重取樣
    sd.SampleDesc.Quality = 0;                      //取樣等級
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;      //常用引數
    sd.Windowed = TRUE;                              //是否全屏

    for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; ++driverTypeIndex)
    {
        g_driverType = driverTypes[driverTypeIndex];
        hResult = D3D11CreateDeviceAndSwapChain(
            NULL,                                //預設圖形介面卡
            g_driverType,                        //驅動型別
            NULL,                                //實現軟體渲染裝置的動態庫控制代碼,如果使用的驅動裝置型別是軟體裝置則不能為NULL
            createDeviceFlags,                    //建立標誌,0用於遊戲釋出,一般D3D11_CREATE_DEVICE_DEBUG允許我們建立可供除錯的裝置,在開發中比較有用
            featureLevels,                        //特徵等級
            numFeatureLevels,                    //特徵等級數量
            D3D11_SDK_VERSION,                    //sdk版本號
            &sd,
            &g_pSwapChain,
            &g_pd3dDevice,
            &g_featureLevel,
            &g_pImmediateContext
        );
        if (SUCCEEDED(hResult))
            break;
    }
    if (FAILED(hResult))
        return hResult;

    //建立渲染目標檢視
    ID3D11Texture2D *pBackBuffer = NULL;
    //獲取後緩衝區地址
    hResult = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    if (FAILED(hResult))
        return hResult;

    //建立目標檢視
    hResult = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
    //釋放後緩衝
    pBackBuffer->Release();
    if (FAILED(hResult))
        return hResult;

    //繫結到渲染管線
    g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);

    //設定viewport
    D3D11_VIEWPORT vp;
    vp.Height = (FLOAT)height;
    vp.Width = (FLOAT)width;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports(1, &vp);

    return S_OK;
}

void Render()
{
    float ClearColor[4] = { 0.5f, 0.1f, 0.2f, 1.0f }; //red,green,blue,alpha
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);
    g_pSwapChain->Present(0, 0);
}

void CleanupDevice()
{
    if (g_pImmediateContext)
        g_pImmediateContext->ClearState();
    if (g_pSwapChain)
        g_pSwapChain->Release();
    if (g_pRenderTargetView)
        g_pRenderTargetView->Release();
    if (g_pImmediateContext)
        g_pImmediateContext->Release();
    if (g_pd3dDevice)
        g_pd3dDevice->Release();
}