Intro :
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 !

