Поделиться через


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

Direct2D — это API нативного кода для непосредственного режима, используемое для создания 2D-графики. В этом разделе показано, как использовать Direct2D для рисования в Windows::UI::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::Present меняет местами буферную поверхность с поверхностью экрана, чтобы отобразить результат.

Пример кода

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