início rápido do Direct2D para Windows 8

Direct2D é uma API de código nativo e modo imediato para criar gráficos 2D. Este tópico ilustra como usar Direct2D para desenhar em um Windows::UI::Core::CoreWindow.

Este tópico contém as seguintes seções:

Desenhando um retângulo simples

Para desenhar um retângulo usando GDI, você pode manipular a mensagem WM_PAINT , conforme mostrado no código a seguir.

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. 

O código para desenhar o mesmo retângulo com Direct2D é semelhante: ele cria recursos de desenho, descreve uma forma a ser desenhada, desenha a forma e libera os recursos de desenho. As seções a seguir descrevem cada uma dessas etapas em detalhes.

Etapa 1: incluir Direct2D cabeçalho

Além dos cabeçalhos necessários para o aplicativo, inclua os cabeçalhos d2d1.h e d2d1_1.h.

Etapa 2: Criar um ID2D1Factory1

Uma das primeiras coisas que qualquer exemplo Direct2D faz é criar um ID2D1Factory1.

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

A interface ID2D1Factory1 é o ponto de partida para usar Direct2D; use um ID2D1Factory1 para criar recursos Direct2D.

Ao criar uma fábrica, você pode especificar se ela é multi-ou de thread único. (Para obter mais informações sobre fábricas multi-threaded, consulte os comentários na página de referência ID2D1Factory.) Este exemplo cria uma fábrica de thread único.

Em geral, seu aplicativo deve criar a fábrica uma vez e retê-la durante a vida útil do aplicativo.

Etapa 3: Criar um ID2D1Device e um ID2D1DeviceContext

Depois de criar uma fábrica, use-a para criar um dispositivo Direct2D e, em seguida, use o dispositivo para criar um contexto de dispositivo Direct2D. Para criar esses objetos Direct2D, você deve ter um dispositivo Direct3D 11, um dispositivo DXGI e uma cadeia de troca DXGI. Consulte Dispositivos e Contextos de Dispositivo para obter informações sobre como criar os pré-requisitos necessários.


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

Um contexto de dispositivo é um dispositivo que pode executar operações de desenho e criar recursos de desenho dependentes do dispositivo, como pincéis. Você também usa o contexto do dispositivo para vincular um ID2D1Bitmap a uma superfície DXGI para usar como um destino de renderização. O contexto do dispositivo pode renderizar para diferentes tipos de destinos.

O código aqui declara as propriedades do bitmap que se vinculam a uma cadeia de troca DXGI que é renderizada para um CoreWindow. O método ID2D1DeviceContext::CreateBitmapFromDxgiSurface obtém uma superfície Direct2D da superfície DXGI. Isso faz com que qualquer coisa renderizada para o ID2D1Bitmap de destino seja renderizada para a superfície da cadeia de troca.

Depois de ter a superfície Direct2D, use o método ID2D1DeviceContext::SetTarget para defini-lo como o destino de renderização ativo.

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

Etapa 4: Criar um pincel

Como uma fábrica, um contexto de dispositivo pode criar recursos de desenho. Neste exemplo, o contexto do dispositivo cria um pincel.

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

Um pincel é um objeto que pinta uma área, como o traço de uma forma ou o preenchimento de uma geometria. O pincel neste exemplo pinta uma área com uma cor sólida predefinida, preto.

Direct2D também fornece outros tipos de pincéis: pincéis de gradiente para pintar gradientes lineares e radiais, um pincel de bitmap para pintura com bitmaps e padrões, e começando em Windows 8, um pincel de imagem para pintura com uma imagem renderizada.

Algumas APIs de desenho fornecem canetas para contornos de desenho e pincéis para preencher formas. Direct2D é diferente: ele não fornece um objeto de caneta, mas usa um pincel para desenhar contornos e preencher formas. Ao desenhar estruturas de tópicos, use a interface ID2D1StrokeStyle ou começando no Windows 8 interface ID2D1StrokeStyle1, com um pincel para controlar as operações de acariciamento de caminho.

Um pincel só pode ser usado com o destino de renderização que o criou e com outros destinos de renderização no mesmo domínio de recurso. Em geral, você deve criar pincéis uma vez e retê-los durante a vida útil do destino de renderização que os criou. ID2D1SolidColorBrush é a exceção solitária; porque é relativamente barato criar, você pode criar um ID2D1SolidColorBrush sempre que desenhar um quadro, sem nenhum impacto perceptível no desempenho. Você também pode usar um único ID2D1SolidColorBrush e apenas alterar sua cor ou opacidade sempre que usá-lo.

Etapa 5: Desenhar o retângulo

Em seguida, use o contexto do dispositivo para desenhar o retângulo.

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

O método DrawRectangle usa dois parâmetros: o retângulo a ser desenhado e o pincel a ser usado para pintar a estrutura de tópicos do retângulo. Opcionalmente, você também pode especificar as opções largura do traço, padrão de traço, junção de linha e limite final.

Você deve chamar o método BeginDraw antes de emitir comandos de desenho e deve chamar o método EndDraw depois de terminar de emitir comandos de desenho. O método EndDraw retorna um HRESULT que indica se os comandos de desenho foram bem-sucedidos. Se não for bem-sucedida, a função auxiliar ThrowIfFailed gerará uma exceção.

O método IDXGISwapChain::P resent troca a superfície do buffer pela superfície da tela para exibir o resultado.

Código de exemplo

O código neste tópico mostra os elementos básicos de um aplicativo Direct2D. Para resumir, o tópico omite a estrutura do aplicativo e o código de tratamento de erros que são características de um aplicativo bem escrito.