Partilhar via


Início rápido do Direct2D para Windows 8

O Direct2D é uma API de modo imediato de código nativo para a criação de gráficos 2D. Este tópico ilustra como usar o Direct2D para desenhar para 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 o Direct2D é semelhante: cria recursos de desenho, descreve uma forma para desenhar, desenha a forma e, em seguida, libera os recursos de desenho. As seções a seguir descrevem cada uma dessas etapas em detalhes.

Etapa 1: Incluir cabeçalho Direct2D

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 o Direct2D; use uma ID2D1Factory1 para criar recursos Direct2D.

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

Em geral, seu aplicativo deve criar a fábrica uma vez e mantê-la durante toda 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 permuta DXGI . Consulte Devices and Device Contexts 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 destino de renderização. O contexto do dispositivo pode renderizar para diferentes tipos de destinos.

O código aqui declara as propriedades para bitmap que se vincula a uma cadeia de permuta DXGI que renderiza 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 destino ID2D1Bitmap seja renderizada na superfície da cadeia de permuta.

Depois de ter a superfície Direct2D, use o método ID2D1DeviceContext::SetTarget para defini-la 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çado de uma forma ou o preenchimento de uma geometria. O pincel neste exemplo pinta uma área com uma cor sólida predefinida, preto.

O Direct2D também fornece outros tipos de pincéis: pincéis de gradiente para pintar gradientes lineares e radiais, um pincel de bitmap para pintar com bitmaps e padrões e, a partir do Windows 8, um pincel de imagem para pintar com uma imagem renderizada.

Algumas APIs de desenho fornecem canetas para desenhar contornos e pincéis para preencher formas. O Direct2D é diferente: não fornece um objeto de caneta, mas usa um pincel para desenhar contornos e preencher formas. Ao desenhar contornos, use a interface ID2D1StrokeStyle ou, a partir do Windows 8, a interface ID2D1StrokeStyle1, com um pincel para controlar as operações de traçado 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 mantê-los durante a vida útil do destino de renderização que os criou. ID2D1SolidColorBrush é a única exceção; como é relativamente barato criar, você pode criar um ID2D1SolidColorBrush toda vez que desenhar um quadro, sem qualquer impacto de desempenho percetível. Você também pode usar um único ID2D1SolidColorBrush e simplesmente alterar a sua cor ou opacidade sempre que precisar.

Passo 5: Desenhe 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étodoDrawRectangle usa dois parâmetros: o retângulo a ser desenhado e o pincel a ser usado para pintar o contorno do retângulo. Opcionalmente, você também pode especificar as opções de largura do traçado, padrão do traço, junção de linha e tampa final.

Você deve chamar o métodoBeginDraw antes de emitir qualquer comando 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 lançará uma exceção.

O método IDXGISwapChain::Present troca a superfície do buffer pela superfície no ecrã para exibir o resultado.

Código de exemplo

O código neste tópico mostra os elementos básicos de um aplicativo Direct2D. Por uma questão de brevidade, o tópico omite a estrutura do aplicativo e o código de tratamento de erros característicos de um aplicativo bem escrito.