Direct2D 几何图形
通过ID2D1HwndRenderTarget,可以轻松地画作各种样式的长方形和椭圆形:
View Code
#include "Precompiled.h" #include "DesktopWindow.h" D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1StrokeStyle> m_style; void CreateDeviceIndependentResources() { } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } void Draw() { m_target->Clear(COLOR_BLUE); auto size = m_target->GetSize(); auto offset = 50.0f; auto rect = RectF( offset, offset, size.width - offset, size.height - offset ); D2D1_ROUNDED_RECT rounded = { rect, 200.0f, 200.0f }; D2D1_POINT_2F center = { size.width / 2.0f, size.height / 2.0 }; D2D1_ELLIPSE ellipse = { center, center.x - offset, center.y - offset }; m_brush->SetColor(COLOR_WHITE); m_brush->SetOpacity(1.0f); m_target->FillRectangle(rect, m_brush.Get()); m_brush->SetColor(COLOR_BLACK); m_brush->SetOpacity(0.5f); m_target->DrawRectangle(rect, m_brush.Get(), 20.0f); m_target->DrawRoundedRectangle(rounded, m_brush.Get(), 40.0f); m_brush->SetColor(COLOR_YELLOW); m_target->DrawEllipse(ellipse, m_brush.Get(), 20.0f); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }
通过运行在高中学过的一些数学知识,可以轻易绘制出一些其它有意思的图形:
View Code
#include "Precompiled.h" #include "DesktopWindow.h" #include <cmath> D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_RED = { 1.0f, 0.0f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1StrokeStyle> m_style; void CreateDeviceIndependentResources() { } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } D2D1_POINT_2F EllipsePoint(D2D1_ELLIPSE const & ellipse, float angle) { const float pi = 3.1415926f; D2D1_POINT_2F point = { ellipse.point.x + ellipse.radiusX * cos(angle * pi / 180.0f), ellipse.point.y + ellipse.radiusY * sin(angle * pi / 180.0f), }; return point; } void Draw() { m_target->Clear(COLOR_BLACK); auto size = m_target->GetSize(); auto offset = 50.0f; auto rect = RectF( offset, offset, size.width - offset, size.height - offset ); D2D1_ROUNDED_RECT rounded = { rect, 200.0f, 200.0f }; D2D1_POINT_2F center = { size.width / 2.0f, size.height / 2.0f }; D2D1_ELLIPSE ellipse = { center, center.x - offset, center.y - offset }; m_brush->SetColor(COLOR_WHITE); m_target->FillEllipse(ellipse, m_brush.Get()); m_brush->SetColor(COLOR_RED); m_target->DrawEllipse(ellipse, m_brush.Get(), 40.0f); m_target->DrawLine( EllipsePoint(ellipse, 135), EllipsePoint(ellipse, 315), m_brush.Get(), 40.0f); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }
可以定义一些D2D1中的几何图形组件(ID2D1***Geometry),来简化绘制流程。注意,几何图形组件是独立于设备的资源(DeviceIndependentResources),因此只需要在CreateDeviceIndependentResources方法中定义即可。另外,几何图形组件是不可更改的(immutable),因此,一旦定义,将无法更改。以下是几何图形组件的一些基本应用:
View Code
#include "Precompiled.h" #include "DesktopWindow.h" D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_RED = { 1.0f, 0.0f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1RectangleGeometry> m_rect; ComPtr<ID2D1RoundedRectangleGeometry> m_rounded; ComPtr<ID2D1EllipseGeometry> m_ellipse; void CreateDeviceIndependentResources() { D2D1_RECT_F rect = { 100.0f, 100.0f, 600.0f, 400.0f }; D2D1_ROUNDED_RECT rounded = { rect, 40.0f, 40.0f }; D2D1_ELLIPSE ellipse = { { 350.0f, 250.0f }, 250.0f, 150.f, }; m_factory->CreateRectangleGeometry(rect, m_rect.GetAddressOf()); m_factory->CreateRoundedRectangleGeometry(rounded, m_rounded.GetAddressOf()); m_factory->CreateEllipseGeometry(ellipse, m_ellipse.GetAddressOf()); } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } void Draw() { m_target->Clear(COLOR_BLUE); auto size = m_target->GetSize(); m_brush->SetOpacity(0.5f); m_brush->SetColor(COLOR_WHITE); m_target->DrawGeometry(m_rect.Get(), m_brush.Get(), 40.0f); m_brush->SetColor(COLOR_RED); m_target->DrawGeometry(m_rounded.Get(), m_brush.Get(), 20.0f); m_brush->SetColor(COLOR_YELLOW); m_target->DrawGeometry(m_ellipse.Get(), m_brush.Get()); m_target->FillGeometry(m_ellipse.Get(), m_brush.Get()); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }
可以使用路径几何图形(ID2D1PathGeometry),来定义更加复杂的图形,ID2D1PathGeometry是独立于设备的资源,因此只需在CreateDeviceIndependentResources方法中定义:
View Code
#include "Precompiled.h" #include "DesktopWindow.h" D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_RED = { 1.0f, 0.0f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1PathGeometry> m_path; void CreateDeviceIndependentResources() { m_factory->CreatePathGeometry(m_path.GetAddressOf()); ComPtr<ID2D1GeometrySink> sink; m_path->Open(sink.GetAddressOf()); // 使用BEGIN_HOLLOW将不会填充多边形 sink->BeginFigure(Point2F(50.0f, 50.0f), D2D1_FIGURE_BEGIN_HOLLOW); sink->AddLine(Point2F(250.0f, 50.0f)); D2D1_POINT_2F points[] = { { 250.0f, 250.0f }, { 50.0f, 250.0f } }; sink->AddLines(points, _countof(points)); // 如果使用END_OPEN,则不会绘制最后一条边 sink->EndFigure(D2D1_FIGURE_END_OPEN); // 可以绘制多个图形 sink->BeginFigure(Point2F(300.0f, 50.0f), D2D1_FIGURE_BEGIN_FILLED); D2D1_POINT_2F points2[] = { { 500.0f, 50.0f }, { 550.0f, 250.0f }, { 350.0f, 250.0f }, }; sink->AddLines(points2, _countof(points2)); sink->EndFigure(D2D1_FIGURE_END_CLOSED); sink->Close(); } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } void Draw() { m_target->Clear(COLOR_BLUE); m_brush->SetColor(COLOR_YELLOW); m_target->FillGeometry(m_path.Get(), m_brush.Get()); m_brush->SetColor(COLOR_RED); m_target->DrawGeometry(m_path.Get(), m_brush.Get(), 10.0f); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }
注意定义的不同可以让图形也不同。
除了路径组成的多边形外,Geometry还可以使用圆弧:
View Code
#include "stdafx.h" #include "DesktopWindow.h" D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_RED = { 1.0f, 0.0f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1PathGeometry> m_arc1; ComPtr<ID2D1PathGeometry> m_arc2; ComPtr<ID2D1PathGeometry> m_arc3; ComPtr<ID2D1PathGeometry> m_arc4; D2D1_POINT_2F m_begin; D2D1_POINT_2F m_end; void BuildPath(ComPtr<ID2D1PathGeometry>& path, D2D1_SWEEP_DIRECTION direction, D2D1_ARC_SIZE size) { D2D1_ARC_SEGMENT arc = { m_end, { 100.0f, 100.0f }, 0.0f, direction, size }; m_factory->CreatePathGeometry(path.ReleaseAndGetAddressOf()); ComPtr<ID2D1GeometrySink> sink; path->Open(sink.GetAddressOf()); sink->BeginFigure(m_begin, D2D1_FIGURE_BEGIN_FILLED); sink->AddArc(arc); sink->EndFigure(D2D1_FIGURE_END_OPEN); sink->Close(); } void BuildPaths() { BuildPath(m_arc1, D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, D2D1_ARC_SIZE_LARGE); BuildPath(m_arc2, D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, D2D1_ARC_SIZE_SMALL); BuildPath(m_arc3, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_LARGE); BuildPath(m_arc4, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL); } void CreateDeviceIndependentResources() { m_begin = Point2F(100.0f, 60.0f); m_end = Point2F(200.0f, 210.0f); BuildPaths(); } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } void Draw() { m_target->Clear(COLOR_BLUE); m_brush->SetOpacity(1.0f); m_brush->SetColor(COLOR_RED); m_target->DrawGeometry(m_arc1.Get(), m_brush.Get(), 5.0f); m_target->DrawGeometry(m_arc2.Get(), m_brush.Get(), 5.0f); m_brush->SetColor(COLOR_WHITE); m_target->DrawGeometry(m_arc3.Get(), m_brush.Get(), 5.0f); m_target->DrawGeometry(m_arc4.Get(), m_brush.Get(), 5.0f); m_brush->SetColor(COLOR_BLACK); m_target->DrawLine(m_begin, m_end, m_brush.Get(), 3.0f); m_brush->SetOpacity(0.5f); m_brush->SetColor(COLOR_YELLOW); m_target->FillEllipse(Ellipse(m_begin, 8.0f, 8.0f), m_brush.Get()); m_brush->SetColor(COLOR_YELLOW); m_target->FillEllipse(Ellipse(m_end, 8.0f, 8.0f), m_brush.Get()); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }
可以使用贝兹尔曲线(Bezier),来绘制出一些更加有意思的图形:
View Code
#include "stdafx.h" #include "DesktopWindow.h" D2D1_COLOR_F const COLOR_BLUE = { 0.26f, 0.56f, 0.87f, 1.0f }; D2D1_COLOR_F const COLOR_WHITE = { 1.0f, 1.0f, 1.0f, 1.0f }; D2D1_COLOR_F const COLOR_BLACK = { 0.0f, 0.0f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f, 1.0f }; D2D1_COLOR_F const COLOR_RED = { 1.0f, 0.0f, 0.0f, 1.0f }; struct SampleWindow : DesktopWindow<SampleWindow> { ComPtr<ID2D1SolidColorBrush> m_brush; ComPtr<ID2D1PathGeometry> m_path; D2D1_POINT_2F m_c1; D2D1_POINT_2F m_c2; D2D1_POINT_2F start; D2D1_POINT_2F end; void CreateDeviceIndependentResources() { m_factory->CreatePathGeometry(m_path.GetAddressOf()); ComPtr<ID2D1GeometrySink> sink; m_path->Open(sink.GetAddressOf()); start = Point2F(100.0f, 600.0f); end = Point2F(900.0f, 600.0f); m_c1 = Point2F(50.0f, 50.0f); m_c2 = Point2F(600.0f, 50.0f); sink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED); sink->AddBezier(BezierSegment(m_c1, m_c2, end)); sink->EndFigure(D2D1_FIGURE_END_OPEN); sink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED); D2D1_QUADRATIC_BEZIER_SEGMENT quad[] = { { { 400.0f, 0.0f }, { 400.0f, 300.0f } }, { { 400.0f, 600.0f}, end } }; sink->AddQuadraticBeziers(quad, _countof(quad)); sink->EndFigure(D2D1_FIGURE_END_OPEN); sink->Close(); } void CreateDeviceResources() { m_target->CreateSolidColorBrush(COLOR_WHITE, m_brush.ReleaseAndGetAddressOf()); } void Draw() { m_target->Clear(COLOR_BLUE); m_brush->SetColor(COLOR_WHITE); m_target->FillEllipse(Ellipse(m_c1, 5.0f, 5.0f), m_brush.Get()); m_target->FillEllipse(Ellipse(m_c2, 5.0f, 5.0f), m_brush.Get()); m_target->FillEllipse(Ellipse(Point2F(400.0f, 0.0f), 5.0f, 5.0f), m_brush.Get()); m_target->FillEllipse(Ellipse(Point2F(400.0f, 300.0f), 5.0f, 5.0f), m_brush.Get()); m_target->FillEllipse(Ellipse(Point2F(400.0f, 600.0f), 5.0f, 5.0f), m_brush.Get()); m_target->DrawGeometry(m_path.Get(), m_brush.Get(), 3.0f); m_brush->SetColor(COLOR_RED); m_target->DrawLine(start, m_c1, m_brush.Get(), 1.0f); m_target->DrawLine(end, m_c2, m_brush.Get(), 1.0f); m_target->DrawLine(start, Point2F(400.0f, 0.0f), m_brush.Get(), 1.0f); m_target->DrawLine(Point2F(400.0f, 0.0f), Point2F(400.0f, 300.0f), m_brush.Get(), 1.0f); m_target->DrawLine(Point2F(400.0f, 300.0f), Point2F(400.0f, 600.0f), m_brush.Get(), 1.0f); m_target->DrawLine(Point2F(400.0f, 600.0f), end, m_brush.Get(), 1.0f); } }; int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { SampleWindow window; window.Run(); }