用 Direct2D 进行绘制

创建图形资源后,即可进行绘图。

绘制椭圆形

Circle 程序执行非常简单的绘制逻辑:

  1. 使用纯色填充背景。
  2. 绘制一个填充的圆。

圆形程序的屏幕截图。

由于呈现目标是窗口 (,而不是位图或其他屏幕外表面) ,因此绘制是为了响应 WM_PAINT 消息。 以下代码显示了 Circle 程序的窗口过程。

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_PAINT:
            OnPaint();
            return 0;

         // Other messages not shown...
    }
    return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

下面是绘制圆圈的代码。

void MainWindow::OnPaint()
{
    HRESULT hr = CreateGraphicsResources();
    if (SUCCEEDED(hr))
    {
        PAINTSTRUCT ps;
        BeginPaint(m_hwnd, &ps);
     
        pRenderTarget->BeginDraw();

        pRenderTarget->Clear( D2D1::ColorF(D2D1::ColorF::SkyBlue) );
        pRenderTarget->FillEllipse(ellipse, pBrush);

        hr = pRenderTarget->EndDraw();
        if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
        {
            DiscardGraphicsResources();
        }
        EndPaint(m_hwnd, &ps);
    }
}

ID2D1RenderTarget 接口用于所有绘图操作。 程序的 OnPaint 方法执行以下操作:

  1. ID2D1RenderTarget::BeginDraw 方法表示绘图的开始。
  2. ID2D1RenderTarget::Clear 方法使用纯色填充整个呈现目标。 颜色以 D2D1_COLOR_F 结构的形式提供。 可以使用 D2D1::ColorF 类初始化结构。 有关详细信息,请参阅 在 Direct2D 中使用颜色
  3. ID2D1RenderTarget::FillEllipse 方法使用指定的填充画笔绘制填充的椭圆。 椭圆由中心点和 x 和 y 半径指定。 如果 x 和 y-radii 相同,则结果为一个圆。
  4. ID2D1RenderTarget::EndDraw 方法指示此帧的绘图完成。 所有绘图操作都必须放在对 BeginDrawEndDraw 的调用之间。

BeginDrawClearFillEllipse 方法都具有 void 返回类型。 如果在执行任一方法期间发生错误,将通过 EndDraw 方法的返回值发出错误信号。 方法 CreateGraphicsResources主题创建 Direct2D 资源中显示。 此方法创建呈现目标和纯色画笔。

设备可能会缓冲绘图命令,并延迟执行它们,直到调用 EndDraw 。 可以通过调用 ID2D1RenderTarget::Flush 强制设备执行任何挂起的绘图命令。 但是,刷新可能会降低性能。

处理设备丢失

当你的程序正在运行时,你正在使用的图形设备可能会变得不可用。 例如,如果显示分辨率发生更改,或者用户删除显示适配器,设备可能会丢失。 如果设备丢失,则呈现器目标以及与设备关联的任何设备依赖资源也将变为无效。 Direct2D 通过从 EndDraw 方法返回错误代码D2DERR_RECREATE_TARGET来向丢失设备发出信号。 如果收到此错误代码,则必须重新创建呈现目标和所有依赖于设备的资源。

若要放弃资源,只需释放该资源的接口即可。

void MainWindow::DiscardGraphicsResources()
{
    SafeRelease(&pRenderTarget);
    SafeRelease(&pBrush);
}

创建资源可能是一项成本高昂的操作,因此不要为每个 WM_PAINT 消息重新创建资源。 创建一次资源,并缓存资源指针,直到资源因设备丢失而变得无效,或者直到不再需要该资源为止。

Direct2D 呈现循环

无论绘制什么内容,程序都应执行类似于以下内容的循环。

  1. 创建与设备无关的资源。
  2. 呈现场景。
    1. 检查是否存在有效的呈现器目标。 如果没有,请创建呈现目标和设备依赖资源。
    2. 调用 ID2D1RenderTarget::BeginDraw
    3. 发出绘图命令。
    4. 调用 ID2D1RenderTarget::EndDraw
    5. 如果 EndDraw 返回 D2DERR_RECREATE_TARGET,请放弃呈现目标和相关设备的资源。
  3. 每当需要更新或重绘场景时,重复步骤 2。

如果呈现目标为窗口,则每当窗口收到 WM_PAINT 消息时,将执行步骤 2。

此处所示的循环通过放弃依赖于设备的资源并在下一循环开始时重新创建它们来处理设备丢失, (步骤 2a) 。

下一步

DPI 和 Device-Independent 像素