适用于 Windows 8 的 Direct2D 快速入门

Direct2D 是用于创建 2D 图形的本机代码即时模式 API。 本主题说明如何使用 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 图面以用作呈现目标。 设备上下文可以呈现到不同类型的目标。

此处的代码声明位图的属性,该位图链接到呈现到 CoreWindow 的 DXGI 交换链。 ID2D1DeviceContext::CreateBitmapFromDxgiSurface 方法从 DXGI 图面获取 Direct2D 图面。 这使得呈现到目标 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 应用程序的基本元素。 为简洁起见,本主题省略了编写良好的应用程序的特征的应用程序框架和错误处理代码。