Guida introduttiva a Direct2D per Windows 8

Direct2D è un'API in modalità immediata e nativa per la creazione di grafica 2D. Questo argomento illustra come usare Direct2D per disegnare in windows::UI::Core::CoreWindow.

In questo argomento sono incluse le sezioni seguenti:

Disegno di un rettangolo semplice

Per disegnare un rettangolo usando GDI, è possibile gestire il messaggio WM_PAINT , come illustrato nel codice seguente.

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. 

Il codice per disegnare lo stesso rettangolo con Direct2D è simile: crea risorse di disegno, descrive una forma da disegnare, disegna la forma, quindi rilascia le risorse di disegno. Le sezioni che seguono descrivono in dettaglio ognuno di questi passaggi.

Passaggio 1: Includere l'intestazione Direct2D

Oltre alle intestazioni necessarie per l'applicazione, includere le intestazioni d2d1.h e d2d1_1.h.

Passaggio 2: Creare un ID2D1Factory1

Una delle prime operazioni eseguite da qualsiasi esempio Direct2D è la creazione di un OGGETTO ID2D1Factory1.

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

L'interfaccia ID2D1Factory1 è il punto di partenza per l'uso di Direct2D; usare un ID2D1Factory1 per creare risorse Direct2D.

Quando si crea una factory, è possibile specificare se è a thread singolo o multithread. Per altre informazioni sulle factory multithreading, vedere le osservazioni nella pagina di riferimento di ID2D1Factory. In questo esempio viene creata una factory a thread singolo.

In generale, l'applicazione deve creare la factory una sola volta e conservarla per tutta la durata dell'applicazione.

Passaggio 3: Creare un ID2D1Device e un ID2D1DeviceContext

Dopo aver creato una factory, usarla per creare un dispositivo Direct2D e quindi usare il dispositivo per creare un contesto di dispositivo Direct2D. Per creare questi oggetti Direct2D, devi avere un dispositivo Direct3D 11 , un dispositivo DXGI e una catena di scambio DXGI. Per informazioni sulla creazione dei prerequisiti necessari, vedi Dispositivi e Contesti di dispositivo .


    // 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 contesto di dispositivo è un dispositivo che può eseguire operazioni di disegno e creare risorse di disegno dipendenti dal dispositivo, ad esempio pennelli. Si usa anche il contesto di dispositivo per collegare un ID2D1Bitmap a una superficie DXGI da usare come destinazione di rendering. Il contesto del dispositivo può essere eseguito in diversi tipi di destinazioni.

Il codice qui dichiara le proprietà per la bitmap che collega a una catena di scambio DXGI che esegue il rendering in un CoreWindow. Il metodo ID2D1DeviceContext::CreateBitmapFromDxgiSurface ottiene una superficie Direct2D dalla superficie DXGI. In questo modo viene eseguito il rendering di qualsiasi elemento di cui viene eseguito il rendering sull'ID2D1Bitmap di destinazione nella superficie della catena di scambio.

Dopo aver creato la superficie Direct2D, usare il metodo ID2D1DeviceContext::SetTarget per impostarlo come destinazione di rendering attiva.

    // 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());

Passaggio 4: Creare un pennello

Analogamente a una factory, un contesto di dispositivo può creare risorse di disegno. In questo esempio il contesto di dispositivo crea un pennello.

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

Un pennello è un oggetto che disegna un'area, ad esempio il tratto di una forma o il riempimento di una geometria. Il pennello in questo esempio disegna un'area con un colore a tinta unita predefinito, nero.

Direct2D fornisce anche altri tipi di pennelli: pennelli sfumato per disegnare sfumature lineari e radiali, un pennello bitmap per disegnare con bitmap e motivi e a partire da Windows 8, un pennello immagine per disegnare con un'immagine sottoposta a rendering.

Alcune API di disegno forniscono penne per il disegno di contorni e pennelli per riempire le forme. Direct2D è diverso: non fornisce un oggetto penna, ma usa un pennello per disegnare contorni e riempire forme. Quando si disegna la struttura, utilizzare l'interfaccia ID2D1StrokeStyle o a partire da Windows 8'interfaccia ID2D1StrokeStyle1, con un pennello per controllare le operazioni di strozzamento del percorso.

Un pennello può essere usato solo con la destinazione di rendering che l'ha creata e con altre destinazioni di rendering nello stesso dominio di risorse. In generale, è consigliabile creare pennelli una sola volta e conservarli per la durata della destinazione di rendering che li ha creati. ID2D1SolidColorBrush è l'eccezione solitaria; poiché è relativamente economico da creare, è possibile creare un ID2D1SolidColorBrush ogni volta che si disegna un frame, senza alcun riscontro notevole sulle prestazioni. È anche possibile usare un singolo ID2D1SolidColorBrush e modificarne il colore o l'opacità ogni volta che lo usi.

Passaggio 5: Disegnare il rettangolo

Usare quindi il contesto del dispositivo per disegnare il rettangolo.

 
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);
);

Il metodo DrawRectangle accetta due parametri: il rettangolo da disegnare e il pennello da utilizzare per disegnare il contorno del rettangolo. Facoltativamente, è anche possibile specificare le opzioni larghezza tratto, motivo trattino, join di linea e estremità finale.

È necessario chiamare il metodo BeginDraw prima di eseguire comandi di disegno ed è necessario chiamare il metodo EndDraw dopo aver completato l'esecuzione dei comandi di disegno. Il metodo EndDraw restituisce un valore HRESULT che indica se i comandi di disegno hanno avuto esito positivo. In caso contrario, la funzione helper ThrowIfFailed genererà un'eccezione.

Il metodo IDXGISwapChain::P resent scambia la superficie del buffer con la superficie sullo schermo per visualizzare il risultato.

Codice di esempio

Il codice in questo argomento illustra gli elementi di base di un'applicazione Direct2D. Per brevità, l'argomento omette il framework dell'applicazione e il codice di gestione degli errori caratteristica di un'applicazione ben scritta.