Introduction à DirectX 10 – Fenêtrage – partie 1

Intro :

Ceci constitue une introduction à la version 10 de DirectX.

DirectX est une interface entre le programmeur et la carte graphique.

Dans cette partie je vais vous apprendre à l’initialiser de manière rudimentaire.

Prérequis :

Savoir programmer en C++.

Première partie :

Création de la fenêtre de rendu.

Explications :

Pensez à configurer les chemins d’accès du SDK de DirectX  dans VC++ ! Si vous ne savez pas comment faire : lire ce tutoriel.

On a besoin d’utiliser une fonction qui boucle à chaque fois que l’application reçoit
un message :

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


Ensuite créez un fichier System.cpp et un fichier System.h où vous mettrez les fonctions que je vous énoncerai.

Voici le fichier System.h :


#ifndef SYSTEM_H
#define SYSTEM_H

#include "Defines.h"
#include "D3D10Renderer.h"

class System

{
public:
    System();
    virtual ~System();

    bool Initialize();
    void Shutdown();
    bool Frame();
    bool Run();

    HRESULT SetupTheWindow();
    void DestroyTheWindow();

private:
    // Objet qui gère le rendu de DirectX
    D3D10Renderer* m_pRenderer;
    LPCWSTR m_sApplicationName;
    HINSTANCE m_hInstance;
    HWND m_Hwnd;
    bool m_bFullScreen;
};

#endif

Dans le fichier System.cpp. On initialise d’abord une fenêtre Windows ; voici la fonction pour l’initialiser :


HRESULT System::SetupTheWindow()
{
    // Détermine la résolution de l'écran.
    unsigned int iScreenWidth  = GetSystemMetrics(SM_CXSCREEN);
    unsigned int iScreenHeight = GetSystemMetrics(SM_CYSCREEN);

    // Structure de la classe à configurer
    WNDCLASSEX wcex;

    // Taille de la structure WNDCLASSEX
    wcex.cbSize = sizeof( WNDCLASSEX );

    // Style de la classe
    wcex.style = CS_HREDRAW | CS_VREDRAW;

    // Pointeur de la fonction de boucle de fenêtre (Callback)
    wcex.lpfnWndProc = WndProc;

    // Inutile à comprendre
    wcex.cbClsExtra = 0;

    // Inutile à comprendre
    wcex.cbWndExtra = 0;

    // Obtention de l'instance de cette application
    wcex.hInstance = m_hInstance;

    // Icone de la fenêtre
    wcex.hIcon = LoadIcon(NULL, IDI_WINLOGO);

    // Icone du pointeur de la souris
    wcex.hCursor = LoadCursor( NULL, IDC_ARROW );

    // Inutile à comprendre
    wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );

    // Inutile à comprendre
    wcex.lpszMenuName = NULL;

    // Nom de la classe enregistrée
    wcex.lpszClassName = m_sApplicationName;

    wcex.hIconSm = wcex.hIcon;

    DEVMODE dmScreenSettings;

    if(m_bFullScreen)
    {
        ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings));

        dmScreenSettings.dmSize       = sizeof (dmScreenSettings);
        dmScreenSettings.dmPelsWidth  = (unsigned long) iScreenWidth;
        dmScreenSettings.dmPelsHeight = (unsigned long) iScreenHeight;
        dmScreenSettings.dmBitsPerPel = 32;            
        dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
    }

    if (!RegisterClassEx(&wcex))
        return E_FAIL;

    // Créé la fenêtre
    RECT rc = { 0, 0, 640, 480 };
    AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
    m_Hwnd = CreateWindow(m_sApplicationName, m_sApplicationName, WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, m_hInstance,
                          NULL);
    if (!m_Hwnd)
        return E_FAIL;

    ShowWindow(m_Hwnd, SW_SHOW);

    SetForegroundWindow(m_Hwnd);
    SetFocus(m_Hwnd);

    return S_OK;
}

 

Toujours dans System.cpp, la fonction pour détruire la fenêtre :


void System::DestroyTheWindow()
{
    // Change les paramètres d'affichage si l'on quitte le mode plein écran
    if(m_bFullScreen)
    {
        ChangeDisplaySettings(NULL, 0);
    }

    // Détruit la fenêtre.
    DestroyWindow(m_Hwnd);
    m_Hwnd = NULL;

    // Détruit l'instance de l'application
    UnregisterClass(m_sApplicationName, m_hInstance);
    m_hInstance = NULL;
}

 

La fonction pour initialiser la fenêtre et le Renderer de DirectX 10 :


bool System::Initialize()
{
    SetupTheWindow();

    m_pRenderer = new D3D10Renderer(m_Hwnd);
    bool bSucess = m_pRenderer->Initialize(m_bFullScreen);

    if (!bSucess)
    {
        MessageBoxA(NULL, "Erreur d'initialisation de DirectX !", "Erreur", MB_ICONHAND | MB_OK);
        return false;
    }

    return true;
}

 

 


 

La fonction WinMain est dans le fichier Main.cpp et est implémentée de cette façon :

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    System* pSystem = new System();

    bool bSucess = pSystem->Initialize();

    if (bSucess)
    {
        pSystem->Run();
    }

    pSystem->Shutdown();

    SAFE_DELETE(pSystem);

    return 0;
}

 


 

Ensuite créez un fichier D3D10Renderer.cpp et un fichier D3D10Renderer.h où vous mettrez les fonctions que je vous énoncerai.


bool D3D10Renderer::Initialize(bool bFullScreen)
{
    HRESULT hr = S_OK;;
    RECT rc;

    GetClientRect(m_hWnd, &rc);
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;

#ifdef _DEBUG
    createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
#endif
    // Une swap chain représente en fait le back buffer
    // et le front buffer (principe nommé double buffering)
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 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 = m_hWnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = !bFullScreen;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags,
                                        D3D10_SDK_VERSION, &sd, &m_pSwapChain, &m_pd3dDevice);
    if (FAILED(hr))
        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, NULL, &m_pRenderTargetView);
    pBackBuffer->Release();
    if (FAILED(hr))
        return false;

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

    // Création du viewport
    D3D10_VIEWPORT vp;
    vp.Width = width;
    vp.Height = height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    m_pd3dDevice->RSSetViewports( 1, &vp );

    
    return true;
}

 

La fonction pour afficher le rendu :


void D3D10Renderer::Render()
{
    float afClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; 

    m_pd3dDevice->ClearRenderTargetView(m_pRenderTargetView, afClearColor);
    m_pSwapChain->Present(1, 0);
}

 

Résumé :

Nous avons affiché une fenêtre prête à recevoir le rendu de DirectX.

fenetre

Voici l’archive du code complet pour cette partie : DirectX 10 Tutoriel – Partie 1.zip

Voilà le code et les explications pour initialiser la fenêtre de DirectX 10.
Il reste beaucoup de choses à intégrer pour faire un jeu mais vous saurez au moins comment intégrer DirectX 10.

Références :

– https://takinginitiative.wordpress.com/directx10-tutorials/

– http://www.rastertek.com/tutdx10.html

– DirectX SDK June 2010 Documentation Samples

Laisser un commentaire

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