Condividi tramite


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 un Windows::UI::Core::CoreWindow.

Questo argomento contiene 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 seguenti 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 consiste nel creare un ID2D1Factory1.

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

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

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

In generale, l'applicazione deve creare la factory una sola volta e conservarla per 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, è necessario disporre di un dispositivo Direct3D 11 , un dispositivo DXGI e una catena di scambio DXGI . Vedi Dispositivi e contesti di dispositivo per informazioni sulla creazione dei prerequisiti necessari.


    // 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. Puoi anche usare il contesto del dispositivo per collegare un ID2D1Bitmap a una superficie DXGI da usare come destinazione di rendering. Il contesto del dispositivo può effettuare il rendering verso diversi tipi di obiettivi.

Il codice qui dichiara le proprietà della bitmap che si collega a un DXGI swap chain che esegue il rendering in un CoreWindow. Il metodo ID2D1DeviceContext::CreateBitmapFromDxgiSurface ottiene una superficie Direct2D dalla superficie DXGI. In questo modo, qualsiasi elemento renderizzato nella destinazione ID2D1Bitmap viene trasferito sulla superficie della catena di swap.

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

Come una factory, un contesto di dispositivo può creare risorse di disegno. In questo esempio il contesto del 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 modelli e a partire da Windows 8, un pennello immagine per disegnare con un'immagine sottoposta a rendering.

Alcune API di disegno forniscono penne per disegnare contorni e pennelli per riempire le forme. Direct2D è diverso: non fornisce un oggetto penna, ma usa un pennello per disegnare contorni e riempire le forme. Quando si tracciano contorni, usa l'interfaccia ID2D1StrokeStyle, o a partire da Windows 8 l'interfaccia ID2D1StrokeStyle1, con un pennello per controllare le operazioni di stroking 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, dovresti creare i pennelli una sola volta e conservarli per tutta la durata della destinazione di rendering che li ha creati. ID2D1SolidColorBrush è l'unica eccezione; poiché è a basso costo da creare, è possibile creare un ID2D1SolidColorBrush ogni volta che si disegna un fotogramma, senza alcun impatto percepibile 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 la larghezza del tratto, il motivo del trattino, la giunzione linea e le opzioni di cap 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 HRESULT che indica se i comandi di disegno sono stati eseguiti con successo. Se non ha successo, la funzione helper ThrowIfFailed genererà un'eccezione.

Il metodo IDXGISwapChain::Present 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.