Краткое руководство по Direct2D для Windows 8

Direct2D — это API прямого кода для создания двухD-графики. В этом разделе показано, как использовать Direct2D для рисования в Windows::UI::Core::CoreWindow.

Этот раздел состоит из следующих подразделов.

Рисование простого прямоугольника

Чтобы нарисовать прямоугольник с помощью GDI, можно обработать сообщение WM_PAINT , как показано в следующем коде.

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. 

Код для рисования одного прямоугольника с Direct2D аналогичен: он создает ресурсы рисования, описывает фигуру для рисования, рисует фигуру, а затем освобождает ресурсы рисования. В следующих разделах подробно описывается каждый из этих шагов.

Шаг 1. Включение заголовка Direct2D

В дополнение к заголовкам, необходимым для приложения, включите заголовки d2d1.h и d2d1_1.h.

Шаг 2. Создание ID2D1Factory1

Одна из первых вещей, которую делает любой пример Direct2D, — это создание ID2D1Factory1.

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

Интерфейс ID2D1Factory1 является отправной точкой для использования Direct2D; используйте ID2D1Factory1 для создания ресурсов Direct2D.

При создании фабрики можно указать, является ли она многопоточной или однопоточной. (Дополнительные сведения о многопоточных фабриках см. в примечаниях на странице справочника по ID2D1Factory.) В этом примере создается однопоточная фабрика.

Как правило, приложение должно создать фабрику один раз и сохранить ее в течение всего срока действия приложения.

Шаг 3. Создание ID2D1Device и ID2D1DeviceContext

После создания фабрики используйте ее для создания устройства Direct2D, а затем используйте устройство для создания контекста устройства Direct2D. Чтобы создать эти объекты Direct2D, необходимо иметь устройство Direct3D 11 , устройство DXGI и цепочку буферов DXGI. Сведения о создании необходимых компонентов см. в разделе Устройства и контексты устройств .


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

Контекст устройства — это устройство, которое может выполнять операции рисования и создавать зависимые от устройства ресурсы рисования, такие как кисти. Контекст устройства также используется для связывания ID2D1Bitmap с поверхностью DXGI для использования в качестве целевого объекта отрисовки. Контекст устройства может отображаться для различных типов целевых объектов.

Приведенный здесь код объявляет свойства растрового рисунка, который связывается с цепочкой буферов DXGI, которая отрисовывается в CoreWindow. Метод ID2D1DeviceContext::CreateBitmapFromDxgiSurface получает поверхность Direct2D из поверхности DXGI. Это делает его таким образом, что все, что отображается в целевом ID2D1Bitmap , отображается на поверхности цепочки буферов.

Получив поверхность Direct2D, используйте метод ID2D1DeviceContext::SetTarget , чтобы задать его в качестве активного целевого объекта отрисовки.

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

Шаг 4. Создание кисти

Как и в случае с фабрикой, контекст устройства может создавать ресурсы рисования. В этом примере контекст устройства создает кисть.

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

Кисть — это объект, который рисует область, например росчерк фигуры или заливку геометрии. Кисть в этом примере закрашивает область предопределенным сплошным цветом, черным цветом.

Direct2D также предоставляет другие типы кистей: градиентные кисти для рисования линейных и радиальных градиентов, точечные кисти для рисования точечными рисунками и узорами и, начиная с Windows 8, кисть изображения для рисования с отрисованным изображением.

Некоторые API рисования предоставляют ручки для рисования контуров и кисти для заполнения фигур. Direct2D отличается: он не предоставляет объект пера, но использует кисть для рисования контуров и заполнения фигур. При рисовании контуров используйте интерфейс ID2D1StrokeStyle или начиная с Windows 8 интерфейса ID2D1StrokeStyle1 с кистью для управления операциями поглаживания пути.

Кисть может использоваться только с целевым объектом отрисовки, который ее создал, и с другими целевыми объектами отрисовки в том же домене ресурсов. Как правило, кисти следует создавать один раз и сохранять их на протяжении всего времени существования созданного целевого объекта отрисовки. ID2D1SolidColorBrush является одиноким исключением; Так как создание является относительно недорогим, вы можете создавать ID2D1SolidColorBrush каждый раз при рисовании кадра без заметного снижения производительности. Вы также можете использовать один id2D1SolidColorBrush и просто изменять его цвет или прозрачность каждый раз при его использовании.

Шаг 5. Рисование прямоугольника

Затем используйте контекст устройства для рисования прямоугольника.

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

Метод DrawRectangle принимает два параметра: прямоугольник для рисования и кисть, используемая для рисования контура прямоугольника. При необходимости можно также указать ширину штриха, шаблон дефиса, соединение линий и конечный заголовок.

Перед выполнением команд рисования необходимо вызвать метод BeginDraw , а после завершения выполнения команд рисования — метод EndDraw . Метод EndDraw возвращает HRESULT , который указывает, были ли команды рисования успешными. В противном случае вспомогательная функция ThrowIfFailed вызовет исключение.

Метод IDXGISwapChain::P resent переключает буферную поверхность на поверхность на экране для отображения результата.

Пример кода

В коде в этом разделе показаны основные элементы приложения Direct2D. Для краткости в разделе пропускается платформа приложений и код обработки ошибок, характерный для правильно написанного приложения.