65.9K
CodeProject 正在变化。 阅读更多。
Home

Direct2D 教程 第 2 部分:基本形状

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2020年8月20日

CPOL

3分钟阅读

viewsIcon

21293

downloadIcon

552

关于绘制基本形状的 Direct2D 教程

目录

示例代码托管在 Github 上。

引言

在本文中,我们将探讨如何在 Direct2D 中绘制线条和基本形状。 本文的前提是设置 RenderTarget 的知识。 如果您不了解 RenderTarget 是什么,请先阅读 RenderTarget 文章,然后再回来阅读本文。

笔触样式

为了绘制形状,需要一个辅助函数 CreateStrokeStyle() 来创建 ID2D1StrokeStyle 以定义端点和连接样式。 ID2D1StrokeStyle 是一个与设备无关的资源。 在 StrokeStyleProperties 构造函数中,起始端点、结束端点和虚线端点的样式均为圆形,如 3 个 D2D1_CAP_STYLE_ROUND 参数所示。 指定的虚线端点样式未被使用,因为笔触样式没有任何虚线,由 D2D1_DASH_STYLE_SOLID 指定,并且线条连接样式为圆形,由 D2D1_LINE_JOIN_ROUND 指示。 读者可以通过修改 CreateStrokeStyle() 来尝试其他端点和连接样式。

ComPtr<ID2D1StrokeStyle> CD2DShapesDlg::CreateStrokeStyle()
{
    ComPtr<ID2D1StrokeStyle> strokeStyle;

    HR(FactorySingleton::GetGraphicsFactory()->CreateStrokeStyle(
        D2D1::StrokeStyleProperties(
            D2D1_CAP_STYLE_ROUND,
            D2D1_CAP_STYLE_ROUND,
            D2D1_CAP_STYLE_ROUND,
            D2D1_LINE_JOIN_ROUND,
            0.0f,
            D2D1_DASH_STYLE_SOLID,
            0.0f),
        nullptr,
        0,
        strokeStyle.GetAddressOf()
    ));

    return strokeStyle;
}

纯色画刷

使用 CreateSolidColorBrush() 创建用于笔触和填充的两个纯色画刷。 由于画刷是与设备相关的资源,因此应在 CreateDeviceResources() 内部创建它们。 它的颜色可以使用 SetColor() 成员函数动态更改,您稍后会看到。

void CD2DShapesDlg::CreateDeviceResources()
{
    HR(m_Target->CreateSolidColorBrush(ColorF(ColorF::Crimson),
        m_StrokeBrush.ReleaseAndGetAddressOf()));
    HR(m_Target->CreateSolidColorBrush(ColorF(ColorF::Yellow),
        m_FillBrush.ReleaseAndGetAddressOf()));
}

Line

Line

使用 DrawLine() 从一个起点和一个终点绘制一条线。 线条粗细指定为 8 像素。

m_StrokeBrush->SetColor(ColorF(ColorF::Black));

ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();

m_Target->DrawLine(
    Point2F(10.0f, 40.0f),
    Point2F(110.0f, 40.0f),
    m_StrokeBrush.Get(),
    8.0f,
    stroke.Get());

矩形

Rectangle

笔触画刷和填充画刷分别设置为红色和黄色。 使用一个 rect 变量来指定矩形边界。 矩形的轮廓使用 DrawRectangle() 绘制,并使用 FillRectangle() 填充黄色。 DrawRectangle() 的第三个参数是线条粗细,为 10 像素。

ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_RECT_F rect = RectF(10, 10, 210, 160);
m_Target->DrawRectangle(
    rect,
    m_StrokeBrush.Get(),
    16.0f,
    stroke.Get());

m_Target->FillRectangle(
    rect,
    m_FillBrush.Get());

圆角矩形

Rounded Rectangle

我经常使用圆角矩形来绘制文章中使用的框图,因为矩形看起来更美观。 Direct2D 的创建者也知道圆角矩形是一种常见的绘图原语,并决定为其用户提供这种便利。 使用一个 roundedRect 变量来指定矩形边界(来自 rect 变量),以及圆角的 x 和 y 半径。 轮廓和填充分别使用 DrawRoundedRectangle()FillRoundedRectangle() 完成。 DrawRoundedRectangle() 的第三个参数是线条粗细,为 10 像素。

ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_RECT_F rect = RectF(10, 10, 210, 160);

const D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect(
    rect,
    10.f,
    10.f
);

m_Target->DrawRoundedRectangle(
    roundedRect,
    m_StrokeBrush.Get(),
    16.0f,
    stroke.Get());

m_Target->FillRoundedRectangle(
    roundedRect,
    m_FillBrush.Get());

三角形

Triangle

不幸的是,Direct2D 中没有绘制三角形的函数。 我们可以随时使用 ID2D1PathGeometry 来创建我们想要的任何形状。 GenTriangleGeometry() 是一个辅助函数,用于创建然后绘制的三角形几何图形。 ID2D1PathGeometry 变量使用 CreatePathGeometry() 创建。 然后,该 ID2D1PathGeometry 变量 m_pPathGeometry 用于打开 ID2D1GeometrySink 变量 pSink。 在 pSink 上调用 BeginFigure() 以指定第一个点和要填充的绘图。 使用来自 2 个点的 AddLine 添加 2 个线段图元。 D2D1_FIGURE_END_CLOSED 告诉 EndFigure() 用一条线闭合第一个点和最后一个点。 如果您已经通过指定最后一个点与第一个点相同来自己闭合了第一个点和最后一个点,并且您可能不希望 EndFigure() 在它们之间绘制一条线,则应指定 D2D1_FIGURE_END_OPEN

ComPtr<ID2D1PathGeometry> CD2DShapesDlg::GenTriangleGeometry
      (D2D1_POINT_2F pt1, D2D1_POINT_2F pt2, D2D1_POINT_2F pt3)
{
    ID2D1GeometrySink* pSink = NULL;
    HRESULT hr = S_OK;
    ComPtr<ID2D1PathGeometry> m_pPathGeometry;
    // Create a path geometry.
    if (SUCCEEDED(hr))
    {
        hr = FactorySingleton::GetGraphicsFactory()->CreatePathGeometry
                               (m_pPathGeometry.ReleaseAndGetAddressOf());

        if (SUCCEEDED(hr))
        {
            // Write to the path geometry using the geometry sink.
            hr = m_pPathGeometry->Open(&pSink);

            if (SUCCEEDED(hr))
            {
                pSink->BeginFigure(
                    pt1,
                    D2D1_FIGURE_BEGIN_FILLED
                );

                pSink->AddLine(pt2);


                pSink->AddLine(pt3);

                pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

                hr = pSink->Close();
            }
            SafeRelease(&pSink);
        }
    }
    return m_pPathGeometry;
}

三角形的轮廓和填充分别使用 DrawGeometry()FillGeometry() 绘制。

ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
ComPtr<ID2D1PathGeometry> geometry = GenTriangleGeometry(
    Point2F(110, 10), Point2F(210, 140), Point2F(10, 140));
m_Target->DrawGeometry(
    geometry.Get(),
    m_StrokeBrush.Get(),
    16.0f,
    stroke.Get());

m_Target->FillGeometry(
    geometry.Get(),
    m_FillBrush.Get());

Circle

可以使用椭圆绘制函数绘制一个圆。 在下面的代码中,使用一个中心点和 x 和 y 半径创建一个椭圆变量 ell。 圆的轮廓和填充分别使用 DrawEllipse()FillEllipse() 绘制。

ComPtr<ID2D1StrokeStyle> stroke = CreateStrokeStyle();
const D2D1_ELLIPSE ell = Ellipse(Point2F(100.0f, 100.0f), 90, 90);
m_Target->DrawEllipse(
    ell,
    m_StrokeBrush.Get(),
    16.0f,
    stroke.Get());

m_Target->FillEllipse(
    ell,
    m_FillBrush.Get());

历史

  • 2021 年 1 月 5 日:将所有颜色更新为深红色和黄色,以及更大的形状。
  • 2020 年 8 月 22 日:为了最佳实践,将画刷创建放入 CreateDeviceResource()
  • 2020 年 8 月 20 日:首次发布

系列中的其他文章

© . All rights reserved.