Démarrage rapide direct2D pour Windows 8

Direct2D est une API de code natif en mode immédiat permettant de créer des graphiques 2D. Cette rubrique montre comment utiliser Direct2D pour dessiner vers un Windows::UI::Core::CoreWindow.

Cette rubrique contient les sections suivantes :

Dessin d’un rectangle simple

Pour dessiner un rectangle à l’aide de GDI, vous pouvez gérer le message WM_PAINT , comme indiqué dans le code suivant.

switch(message)
{

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);

            // Obtain the size of the drawing area.
            RECT rc;
            GetClientRect(
                hwnd,
                &rc
            );          

            // Save the original object
            HGDIOBJ original = NULL;
            original = SelectObject(
                ps.hdc,
                GetStockObject(DC_PEN)
            );

            // Create a pen.            
            HPEN blackPen = CreatePen(PS_SOLID, 3, 0);

            // Select the pen.
            SelectObject(ps.hdc, blackPen);

            // Draw a rectangle.
            Rectangle(
                ps.hdc, 
                rc.left + 100, 
                rc.top + 100, 
                rc.right - 100, 
                rc.bottom - 100);   

            DeleteObject(blackPen);

            // Restore the original object
            SelectObject(ps.hdc, original);

            EndPaint(hwnd, &ps);
        }
        return 0;

// Code for handling other messages. 

Le code pour dessiner le même rectangle avec Direct2D est similaire : il crée des ressources de dessin, décrit une forme à dessiner, dessine la forme, puis libère les ressources de dessin. Les sections qui suivent décrivent chacune de ces étapes en détail.

Étape 1 : Inclure l’en-tête Direct2D

En plus des en-têtes requis pour l’application, incluez les en-têtes d2d1.h et d2d1_1.h.

Étape 2 : Créer un ID2D1Factory1

L’une des premières choses que fait n’importe quel exemple Direct2D est de créer un ID2D1Factory1.

DX::ThrowIfFailed(
        D2D1CreateFactory(
            D2D1_FACTORY_TYPE_SINGLE_THREADED,
            __uuidof(ID2D1Factory1),
            &options,
            &m_d2dFactory
            )
        );

L’interface ID2D1Factory1 est le point de départ de l’utilisation de Direct2D ; utilisez un ID2D1Factory1 pour créer des ressources Direct2D.

Lorsque vous créez une fabrique, vous pouvez spécifier si elle est multithread ou monothread. (Pour plus d’informations sur les fabriques multithread, consultez les remarques sur la page de référence ID2D1Factory.) Cet exemple crée une fabrique à thread unique.

En général, votre application doit créer la fabrique une seule fois et la conserver pendant toute la durée de vie de l’application.

Étape 3 : Créer un ID2D1Device et un ID2D1DeviceContext

Après avoir créé une fabrique, utilisez-la pour créer un appareil Direct2D, puis utilisez l’appareil pour créer un contexte d’appareil Direct2D. Pour créer ces objets Direct2D, vous devez disposer d’un appareil Direct3D 11 , d’un appareil DXGI et d’une chaîne d’échange DXGI. Pour plus d’informations sur la création des prérequis nécessaires, consultez Appareils et contextes d’appareil.


    // Obtain the underlying DXGI device of the Direct3D11.1 device.
    DX::ThrowIfFailed(
        m_d3dDevice.As(&dxgiDevice)
        );

    // Obtain the Direct2D device for 2-D rendering.
    DX::ThrowIfFailed(
        m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
        );

    // And get its corresponding device context object.
    DX::ThrowIfFailed(
        m_d2dDevice->CreateDeviceContext(
            D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
            &m_d2dContext
            )
        );

Un contexte d’appareil est un appareil qui peut effectuer des opérations de dessin et créer des ressources de dessin dépendantes de l’appareil, telles que des pinceaux. Vous utilisez également le contexte de l’appareil pour lier un ID2D1Bitmap à une surface DXGI à utiliser comme cible de rendu. Le contexte de l’appareil peut s’afficher sur différents types de cibles.

Le code déclare ici les propriétés d’une bitmap qui est liée à une chaîne d’échange DXGI qui s’affiche sur un CoreWindow. La méthode ID2D1DeviceContext::CreateBitmapFromDxgiSurface obtient une surface Direct2D de la surface DXGI. Ainsi, tout ce qui est rendu à la cible ID2D1Bitmap est rendu à la surface de la chaîne d’échange.

Une fois que vous avez la surface Direct2D, utilisez la méthode ID2D1DeviceContext::SetTarget pour la définir comme cible de rendu active.

    // Now we set up the Direct2D render target bitmap linked to the swapchain. 
    // Whenever we render to this bitmap, it will be directly rendered to the 
    // swapchain associated with the window.
    D2D1_BITMAP_PROPERTIES1 bitmapProperties = 
        BitmapProperties1(
            D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
            PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
            m_dpi,
            m_dpi
            );

    // Direct2D needs the dxgi version of the backbuffer surface pointer.
    ComPtr<IDXGISurface> dxgiBackBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
        );

    // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
    DX::ThrowIfFailed(
        m_d2dContext->CreateBitmapFromDxgiSurface(
            dxgiBackBuffer.Get(),
            &bitmapProperties,
            &m_d2dTargetBitmap
            )
        );

    // So now we can set the Direct2D render target.
    m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());

Étape 4 : Créer un pinceau

Comme une fabrique, un contexte d’appareil peut créer des ressources de dessin. Dans cet exemple, le contexte de l’appareil crée un pinceau.

ComPtr<ID2D1SolidColorBrush> pBlackBrush;
DX::ThrowIfFailed(
   m_d2dContext->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black),
        &pBlackBrush
        )
);

Un pinceau est un objet qui peint une zone, comme le trait d’une forme ou le remplissage d’une géométrie. Le pinceau de cet exemple peint une zone avec une couleur unie prédéfinie, noire.

Direct2D fournit également d’autres types de pinceaux : des pinceaux dégradés pour peindre des dégradés linéaires et radials, un pinceau bitmap pour la peinture avec des bitmaps et des motifs et, à partir de Windows 8, un pinceau d’image pour la peinture avec une image rendue.

Certaines API de dessin fournissent des stylets pour les contours de dessin et des pinceaux pour remplir des formes. Direct2D est différent : il ne fournit pas d’objet stylet, mais utilise un pinceau pour dessiner des contours et remplir des formes. Lorsque vous dessinez des contours, utilisez l’interface ID2D1StrokeStyle ou, à partir de Windows 8 l’interface ID2D1StrokeStyle1, avec un pinceau pour contrôler les opérations de caressement de chemin.

Un pinceau ne peut être utilisé qu’avec la cible de rendu qui l’a créé et avec d’autres cibles de rendu dans le même domaine de ressources. En général, vous devez créer des pinceaux une seule fois et les conserver pendant toute la durée de vie de la cible de rendu qui les a créés. ID2D1SolidColorBrush est la seule exception ; Étant donné qu’il est relativement peu coûteux à créer, vous pouvez créer un ID2D1SolidColorBrush chaque fois que vous dessinez un cadre, sans aucun impact notable sur les performances. Vous pouvez également utiliser un seul ID2D1SolidColorBrush et modifier simplement sa couleur ou son opacité chaque fois que vous l’utilisez.

Étape 5 : Dessiner le rectangle

Ensuite, utilisez le contexte de l’appareil pour dessiner le rectangle.

 
m_d2dContext->BeginDraw();

m_d2dContext->DrawRectangle(
    D2D1::RectF(
        rc.left + 100.0f,
        rc.top + 100.0f,
        rc.right - 100.0f,
        rc.bottom - 100.0f),
        pBlackBrush);

DX::ThrowIfFailed(
    m_d2dContext->EndDraw()
);

DX::ThrowIfFailed(
    m_swapChain->Present1(1, 0, &parameters);
);

La méthode DrawRectangle prend deux paramètres : le rectangle à dessiner et le pinceau à utiliser pour peindre le contour du rectangle. Si vous le souhaitez, vous pouvez également spécifier les options de largeur de trait, de tiret, de jointure de ligne et d’extrémité.

Vous devez appeler la méthode BeginDraw avant d’émettre des commandes de dessin, et vous devez appeler la méthode EndDraw une fois que vous avez terminé d’émettre des commandes de dessin. La méthode EndDraw retourne une valeur HRESULT qui indique si les commandes de dessin ont réussi. Si elle échoue, la fonction d’assistance ThrowIfFailed lève une exception.

La méthode IDXGISwapChain::P resent permute la surface de mémoire tampon avec la surface à l’écran pour afficher le résultat.

Exemple de code

Le code de cette rubrique montre les éléments de base d’une application Direct2D. Par souci de concision, la rubrique omet l’infrastructure d’application et le code de gestion des erreurs caractéristiques d’une application bien écrite.