Une simple classe D3D10Renderer

Intro :

1211804249

Pour utiliser DirectX, il nous faut une classe D3D10Renderer afin d’initialiser le rendu graphique 3D.

Prérequis :

– Aucun

Explications :

Voici le code du fichier D3D10Renderer.h :

#ifndef D3D10_RENDERER_H
#define D3D10_RENDERER_H

#include <windows.h>
#include <d3dx10math.h>
#include <DxErr.h>

#include "Defines.h"
#include "Singleton.h"
#include "Types.h"

#include "InputManager.h"

#pragma comment(lib, "d3d10.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment(lib, "dxerr.lib")

class D3D10Renderer : public Singleton<D3D10Renderer>
{
public:
    D3D10Renderer(HWND hWnd);
    virtual ~D3D10Renderer();

    bool Initialize(bool bFullScreen);

    void Shutdown();

    void Render();

    ID3D10Device* GetDevice();

    uint32 GetViewportWidth();
    uint32 GetViewportHeight();
    
    void EnableZBuffer(bool bEnable);

    bool CreateSwapChain();
    bool CreateDepthStencilView();
    bool CreateRasterizerState();
    bool CreateDepthStencil();
    void CreateViewport();

    void UpdateWindowTitle();

    std::string Formater(const std::wstring& src);

    void SetFSAAMaximumLevel();

private:
    HWND m_hWnd;
    ID3D10Device* m_pd3dDevice;
    IDXGISwapChain* m_pSwapChain;        
    ID3D10RenderTargetView* m_pRenderTargetView;

    ID3D10Texture2D* m_pDepthStencil;
    ID3D10DepthStencilView* m_pDepthStencilView;
    ID3D10DepthStencilState* m_pDSState;
    ID3D10RasterizerState* m_pRasterizerState;

    uint32 m_iWidth;
    uint32 m_iHeight;

    bool m_bFullscreen;

    uint32 m_iFSAALevel;
};

#endif

 

Voici le code du fichier D3D10Renderer.cpp :

#include "D3D10Renderer.h"
#include "System.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

template<> D3D10Renderer* Singleton<D3D10Renderer>::ms_instance = nullptr;

D3D10Renderer::D3D10Renderer(HWND hWnd) :
m_hWnd(hWnd),
m_pd3dDevice(nullptr),
m_pSwapChain(nullptr),
m_pRenderTargetView(nullptr),
m_pDepthStencil(nullptr),
m_pDSState(nullptr),
m_pDepthStencilView(nullptr),
m_iWidth(0),
m_iHeight(0),
m_bFullscreen(false),
m_iFSAALevel(8)
{
}

D3D10Renderer::~D3D10Renderer()
{
    if (m_pd3dDevice)
    {
        m_pd3dDevice->ClearState();
    }

    SAFE_RELEASE(m_pRenderTargetView);
    SAFE_RELEASE(m_pSwapChain);
    SAFE_RELEASE(m_pd3dDevice);
}

bool D3D10Renderer::Initialize(bool bFullscreen)
{
    m_bFullscreen = bFullscreen;

    // Variable pour stocker l'état erreur / succès
    HRESULT hr = S_OK;;

    if (!CreateSwapChain())
    {
        return false;
    }

    // Créé le back buffer
    ID3D10Texture2D* pBackBuffer;
    hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
    if (FAILED(hr))
    {
        return false;
    }

    // Créé la render target
    hr = m_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &m_pRenderTargetView);
    pBackBuffer->Release();
    if (FAILED(hr))
    {
        return false;
    }

    if (!CreateDepthStencilView())
    {
        return false;
    }

    if (!CreateRasterizerState())
    {
        return false;
    }

    if (!CreateDepthStencil())
    {
        return false;
    }

    CreateViewport();

    ShowCursor(false);

    return true;
}

void D3D10Renderer::Render()
{
    __int64 cntsPerSec = 0;
    QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec);

    __int64 currTimeStamp = 0;
    QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp);

    static __int64 prevTimeStamp = currTimeStamp;

    float secsPerCnt = 1.0f / (float)cntsPerSec;   

    float fTimeSinceLastFrame = (currTimeStamp - prevTimeStamp) * secsPerCnt;

    static float afClearColor[4] = {0.85f, 1.0f, 1.0f, 1.0f}; 

    // Efface la surface de rendu
    m_pd3dDevice->ClearDepthStencilView(m_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0 );
    m_pd3dDevice->ClearRenderTargetView(m_pRenderTargetView, afClearColor);

    UpdateWindowTitle();

    m_pSwapChain->Present(0, 0);

    prevTimeStamp = currTimeStamp;
}

ID3D10Device* D3D10Renderer::GetDevice()
{
    return m_pd3dDevice;
}

uint32 D3D10Renderer::GetViewportWidth()
{
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

    m_pSwapChain->GetDesc(&swapChainDesc);

    return swapChainDesc.BufferDesc.Width;
}

uint32 D3D10Renderer::GetViewportHeight()
{
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

    m_pSwapChain->GetDesc(&swapChainDesc);

    return swapChainDesc.BufferDesc.Height;
}

void D3D10Renderer::EnableZBuffer(bool bEnable)
{
    D3D10_DEPTH_STENCIL_DESC pDesc;

    m_pDSState->GetDesc(&pDesc);
    pDesc.DepthEnable = bEnable;

    m_pd3dDevice->OMSetDepthStencilState(m_pDSState, 1);
}

void D3D10Renderer::CreateViewport()
{
    // Création du viewport
    D3D10_VIEWPORT vp;

    vp.Width = m_iWidth;
    vp.Height = m_iHeight;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;

    m_pd3dDevice->RSSetViewports( 1, &vp );
}

bool D3D10Renderer::CreateSwapChain()
{
    // Rectangle 2D pour les dimensions de la fenêtre
    RECT rc;

    // On obtient les dimensions de la fenêtre courante
    GetClientRect(m_hWnd, &rc);
    // Largeur de la fenêtre
    m_iWidth = rc.right - rc.left;
    // Hauteur de la fenêtre
    m_iHeight = rc.bottom - rc.top;

    // Paramètres de création du device
    UINT createDeviceFlags = 0;

    // Permet d'afficher les éventuelles erreurs de la création du device
    createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;

    // Création de la Swap Chain
    // c'est-à-dire création du front buffer et du back buffer
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 1;
    // Taille de la surface en pixels
    sd.BufferDesc.Width = m_iWidth;
    sd.BufferDesc.Height = m_iHeight;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    // Format des couleurs
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 0;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    // L'handle de la fenêtre que l'on va afficher dessus
    sd.OutputWindow = m_hWnd;
    sd.SampleDesc.Count = m_iFSAALevel;
    sd.SampleDesc.Quality = 0;
    // Fenêtré ou non
    sd.Windowed = !m_bFullscreen;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    // On créé le device DirectX 10 et la Swap Chain
    HRESULT hr = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags,
                                               D3D10_SDK_VERSION, &sd, &m_pSwapChain, &m_pd3dDevice);
    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }

    SetFSAAMaximumLevel();

    return true;
}

void D3D10Renderer::SetFSAAMaximumLevel()
{
    HRESULT hr = S_OK;
    UINT maxQualityLevel = 1;
    for (uint32 iSampleCount = 1; iSampleCount <= D3D10_MAX_MULTISAMPLE_SAMPLE_COUNT; iSampleCount++)
    {
        hr = m_pd3dDevice->CheckMultisampleQualityLevels(
            DXGI_FORMAT_R8G8B8A8_UNORM, iSampleCount, &maxQualityLevel);

        if (hr != S_OK)
        {
            fastprint(Formater(L"CheckMultisampleQualityLevels a échoué."));
        }
                                 
        if (maxQualityLevel > 0)
        {
            fastprint("MSAA " << iSampleCount << Formater(L"X supportée par la carte vidéo avec ") <<
                maxQualityLevel << Formater(L" niveau(x) de qualité."));
        }
    }
}

bool D3D10Renderer::CreateDepthStencilView()
{
    HRESULT hr = S_OK;

    D3D10_TEXTURE2D_DESC descDepth;
    ZeroMemory(&descDepth, sizeof(descDepth));
    descDepth.Width = m_iWidth;
    descDepth.Height = m_iHeight;
    descDepth.MipLevels = 1;
    descDepth.ArraySize = 1;
    descDepth.Format = DXGI_FORMAT_D32_FLOAT;
    descDepth.SampleDesc.Count = m_iFSAALevel;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D10_USAGE_DEFAULT;
    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;

    hr = m_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &m_pDepthStencil);

    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }
        
    D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;
    descDSV.Format = descDepth.Format;

    if (m_iFSAALevel > 1)
    {
        descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2DMS;
    }
    else
    {
        descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
    }

    descDSV.Texture2D.MipSlice = 0;

    hr = m_pd3dDevice->CreateDepthStencilView(m_pDepthStencil, &descDSV, &m_pDepthStencilView);

    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }

    m_pd3dDevice->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);

    return true;
}

bool D3D10Renderer::CreateRasterizerState()
{
    D3D10_RASTERIZER_DESC rasterizerState;

    rasterizerState.CullMode = D3D10_CULL_NONE;
    rasterizerState.FillMode = D3D10_FILL_SOLID;
    rasterizerState.FrontCounterClockwise = true;
    rasterizerState.DepthBias = false;
    rasterizerState.DepthBiasClamp = 0;
    rasterizerState.SlopeScaledDepthBias = 0;
    rasterizerState.DepthClipEnable = true;
    rasterizerState.ScissorEnable = false;
    rasterizerState.MultisampleEnable = true;
    rasterizerState.AntialiasedLineEnable = true;

    HRESULT hr = m_pd3dDevice->CreateRasterizerState(&rasterizerState, &m_pRasterizerState);    

    m_pd3dDevice->RSSetState(m_pRasterizerState);

    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }

    return true;
}

bool D3D10Renderer::CreateDepthStencil()
{
    D3D10_DEPTH_STENCIL_DESC pDesc;

    pDesc.DepthEnable = true;
    pDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
    pDesc.DepthFunc = D3D10_COMPARISON_LESS;
    pDesc.StencilEnable = true;
    pDesc.StencilReadMask = 0xFF;
    pDesc.StencilWriteMask = 0xFF;
    pDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
    pDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;
    pDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
    pDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
    pDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
    pDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_DECR;
    pDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
    pDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

    HRESULT hr = m_pd3dDevice->CreateDepthStencilState(&pDesc, &m_pDSState);

    if (FAILED(hr))
    {
        ShowMessageBoxDXError(hr);
        return false;
    }

    m_pd3dDevice->OMSetDepthStencilState(m_pDSState, 1);

    return true;
}

FPSCamera* D3D10Renderer::GetCamera()
{
    return m_pCamera;
}

void D3D10Renderer::OnKeyPressed(const KeyEvent& arg)
{
    if (arg.keyCode == VK_ESCAPE)
    {
        SYSTEM->Quit();
    }
}

void D3D10Renderer::OnKeyReleased(const KeyEvent& arg)
{
}

void D3D10Renderer::UpdateWindowTitle()
{
    static char buffer[256];
    D3DXVECTOR3 camPos = D3DXVECTOR3(1.0f, 1.0f, 1.0f);

    sprintf(buffer, "Position de la caméra : X = %.2f Y = %.2f Z = %.2f", camPos.x, camPos.y, camPos.z);
 
    // On met à jour le titre de la fenêtre
    SetWindowTextA(m_hWnd, buffer);
}

std::string D3D10Renderer::Formater(const std::wstring& src)
{
    char outString[512];
    CharToOemW(src.c_str(), outString);
 
    return std::string(outString);
}

 

Résumé :

Nous avons présenté les deux fichiers nécessaire à l’initialiser du rendu graphique de DirectX !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *