在本文中,将探讨如何使用Direct2D绘制线条和基础形状。在开始之前,请确保已经了解了如何设置RenderTarget。如果对RenderTarget还不熟悉,请先阅读有关RenderTarget的文章,然后再回来阅读本文。
为了绘制形状,需要一个辅助函数CreateStrokeStyle()来创建ID2D1StrokeStyle,以定义笔刷的起点和终点样式。ID2D1StrokeStyle是一个设备无关的资源。在StrokeStyleProperties构造函数中,指定了起点、终点和虚线终点的样式为圆形,通过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()));
}
使用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());
设置笔刷颜色分别为红色和黄色。使用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());
圆角矩形在绘制块图时看起来更美观,因此经常使用它。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());
遗憾的是,Direct2D中没有绘制三角形的函数。可以使用ID2D1PathGeometry来创建所需的任何形状。GenTriangleGeometry()是一个辅助函数,用于创建三角形几何形状,然后进行绘制。创建ID2D1PathGeometry变量,然后使用CreatePathGeometry()。然后使用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;
if (SUCCEEDED(hr)) {
hr = FactorySingleton::GetGraphicsFactory()->CreatePathGeometry(m_pPathGeometry.ReleaseAndGetAddressOf());
if (SUCCEEDED(hr)) {
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());
可以使用绘制椭圆的函数来绘制圆形。在下面的代码中,创建了一个椭圆变量ell,它有一个中心点和x、y半径。使用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());