通过ID2D1HwndRenderTarget,可以轻松地画作各种样式的长方形和椭圆形:
#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();
}
通过运行在高中学过的一些数学知识,可以轻易绘制出一些其它有意思的图形:
#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),因此,一旦定义,将无法更改。以下是几何图形组件的一些基本应用:
#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方法中定义:
#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还可以使用圆弧:
#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),来绘制出一些更加有意思的图形:
#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();
}