Introduction à DirectX 10 – Redimensionner la fenêtre de rendu – partie 6

directx9c

Intro :

Dans une application DirectX, l’utilisateur peut vouloir redimensionner la fenêtre à sa guise ou passer le jeu en mettre en mode plein écran.

Il faut implémenter et coder cette fonctionnalité.

Prérequis :

– Avoir suivi la cinquième partie de ce tutoriel.

Sixième partie :

Redimensionnement et plein écran de la fenêtre de rendu.

Explications :

Avant tout, juste pour énoncer un petit point  mis à part :

L’appel à D3D11DeviceContext::ClearState réinitialise par défaut toutes les configurations du contexte d’affichage (remet à zéro les shaders, les inputs layout, les viewports, etc..)

 


 

Avec les interfaces DXGI* on peut obtenir les informations sur la carte graphique :


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

    uint32 iNumModes;

    IDXGIFactory* pDXGIFactory = nullptr;
    IDXGIAdapter* pDXGIAdapter = nullptr;
    IDXGIOutput* pDXGIAdapterOutput = nullptr;

    DXGI_MODE_DESC* pDisplayModeList = nullptr;

    DXGI_ADAPTER_DESC adapterDesc;

    // Créée une interface métier "factory" DirectX
    hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pDXGIFactory);

    HR_FAILED_RETURN_FALSE(hr);

    // Utilise la "factory"
    hr = pDXGIFactory->EnumAdapters(0, &pDXGIAdapter);

    HR_FAILED_RETURN_FALSE(hr);

    // Enumère l'adpatateur principal de l'écran
    hr = pDXGIAdapter->EnumOutputs(0, &pDXGIAdapterOutput);

    HR_FAILED_RETURN_FALSE(hr);

    // Obtient le nombre de modes d'affichage qui corresppond à DXGI_FORMAT_R8G8B8A8_UNORM  
    hr = pDXGIAdapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &iNumModes, nullptr);

    HR_FAILED_RETURN_FALSE(hr);

    /* Créé une liste qui détient tous les modes d'affichage possibles pour cette carte graphique et
       le format d'affichage */
    pDisplayModeList = new DXGI_MODE_DESC[iNumModes];

    if (!pDisplayModeList)
    {
        return false;
    }

    // Remplie la précédente structure
    hr = pDXGIAdapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &iNumModes, pDisplayModeList);
    
    HR_FAILED_RETURN_FALSE(hr);

    /* On parcourt tous les modes d'affichages possibles
       et on trouve celui qui correspond à la taille spécifiée
       en paramètre ; puis on enregistre le numérateur et le dénominateur
       du taux de rafraichissement de l'écran
    */
    for (uint32 i = 0; i < iNumModes; i++)
    {
        if (pDisplayModeList[i].Width == (uint32)m_iWidth)
        {
            if (pDisplayModeList[i].Height == (uint32)m_iHeight)
            {
                m_iNumerator = pDisplayModeList[i].RefreshRate.Numerator;
                m_iDenominator = pDisplayModeList[i].RefreshRate.Denominator;
            }
        }

        DXGI_MODE_DESC desc = pDisplayModeList[i];

        // On vérifie que ce mode n'a pas déjà été ajouté
        bool bAlreadyExist = false;
        for (uint32 i = 0; i < m_modes.size(); i++)
        {
            if (m_modes[i].Width == desc.Width &&
                m_modes[i].Height == desc.Height)
            {
                bAlreadyExist = true;
                break;
            }
        }

        if (!bAlreadyExist)
        {
            m_modes.push_back(desc);
        }
    }

    hr = pDXGIAdapter->GetDesc(&adapterDesc);

    HR_FAILED_RETURN_FALSE(hr);

    // On enregistre la taille de la mémoire vidéo en mégabytes
    m_iVideoCardMemory = (adapterDesc.DedicatedVideoMemory / 1024 / 1024);

    size_t iStringLength = 0;
    // Convertie le nom la carte vidéo dans une chaîne de caractères
    int iError = wcstombs_s(&iStringLength, m_sVideoCardDescription, 128, adapterDesc.Description, 128);

    if (iError != 0)
    {
        return false;
    }

    // On supprime les objets dont a plus besoin !
    SAFE_DELETE_ARRAY(pDisplayModeList);

    SAFE_RELEASE(pDXGIAdapterOutput);
    SAFE_RELEASE(pDXGIAdapter);
    SAFE_RELEASE(pDXGIFactory);

    return true;
}

 

Voici le programme de cet article une fois compilé et lancé :

fullscreen

 

La fonction qui redimensionne les buffers :


bool D3D10Renderer::ResizeSwapChain(const size_t iWidth, const size_t iHeight)
{
    /* On décharge les précédents objets de rendu */
    SAFE_RELEASE(m_pRenderTargetView);
    SAFE_RELEASE(m_pDepthStencilView);

    HRESULT hr = S_OK;
    hr = m_pSwapChain->ResizeBuffers(2, iWidth, iHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0);

    HR_FAILED_RETURN_FALSE(hr);

    m_iWidth = iWidth;
    m_iHeight = iHeight;

    /* Puis on les recréer */
    CreateRenderTarget();
    CreateDepthStencilView();

    //m_pCube->SetLens()
    SetViewport();

    return true;
}

 

La fonction qui gère les entrées clavier :

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

        if (m_bFullscreen)
        {
            ResizeSwapChain(m_iWidth, m_iHeight);
        }

        m_pSwapChain->SetFullscreenState(m_bFullscreen, nullptr);
    }
    else if (arg.keyCode == VK_F2)
    {
        static uint32 iMode = 0;

        // Largeur de la fenêtre
        uint32 iWidth = m_modes[iMode].Width;
        // Hauteur de la fenêtre
        uint32 iHeight = m_modes[iMode].Height;

        ResizeSwapChain(iWidth, iHeight);

        RECT rc;

        GetWindowRect(m_hWnd, &rc);

        SetWindowPos(m_hWnd, 0, rc.left, rc.top, iWidth, iHeight, SWP_SHOWWINDOW);

        iMode++;

        if (iMode >= m_modes.size())
        {
            iMode = 0;
        }
    }
}

 

Résumé :

Depuis DirectX 10 il est plus facile et aisé de changer de résolution et de passer en mode plein écran.

Voici les fichiers source – Partie 6

Références :

– https://msdn.microsoft.com/en-us/library/windows/desktop/ff476389%28v=vs.85%29.aspx

– https://msdn.microsoft.com/en-us/library/windows/desktop/bb174577%28v=vs.85%29.aspx

Laisser un commentaire

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