转载请注明出处:
Direct2D 是用于创建2D图形的本地即时模式应用程序接口。本文介绍如何在典型的Win32应用程序中运用Direct2D进行绘制。
本文包括以下内容:
- 绘制一个简单的矩形
- 第一步:包含 Direct2D 头文件
- 第二步:创建 ID2D1Factory
- 第三步:创建 ID2D1HwndRenderTarget
- 第四步:创建 Brush
- 第五步:画矩形
- 第六步:释放资源
- 创建一个简单的 Direct2D 应用程序
- 相关主题
绘制一个简单的矩形
switch(message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
// 获得绘制区域的大小.
RECT rc;
GetClientRect(
hwnd,
&rc
);
// 保存原始对象
HGDIOBJ original = NULL;
original = SelectObject(
ps.hdc,
GetStockObject(DC_PEN)
);
// 创建画笔.
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
// 选择画笔.
SelectObject(ps.hdc, blackPen);
// 绘制矩形.
Rectangle(
ps.hdc,
rc.left + 100,
rc.top + 100,
rc.right - 100,
rc.bottom - 100);
DeleteObject(blackPen);
// 恢复原始对象
SelectObject(ps.hdc, original);
EndPaint(hwnd, &ps);
}
return 0;
// ...处理其它消息.
要用 GDI 绘制一个矩形,需要捕获 WM_PAINT 消息,如下代码所示。
第一步:包含 Direct2D 头文件
除了Win32应用程序所需的头文件之外,还要包含 d2d1.h 头文件。
第二步:创建 ID2D1Factory
所有 Direct2D 例程的首要任务之一是创建一个ID2D1Factory。
ID2D1Factory* pD2DFactory = NULL;
HRESULT hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&pD2DFactory
);
ID2D1Factory接口是使用 Direct2D 的起点;使用 ID2D1Factory 创建 Direct2D 资源。创建 ID2D1Factory 时,可以指定它是多线程还是单线程。本例程创建一个单线程工厂。
通常,你的应用程序应该创建一次工厂并保存之直到应用程序结束。
第三步:创建ID2D1HwndRenderTarget
创建工厂之后,用它创建一个渲染目标。
// 获得绘制区域的大小.
RECT rc;
GetClientRect(hwnd, &rc);
// 创建 Direct2D 渲染目标
ID2D1HwndRenderTarget* pRT = NULL;
HRESULT hr = pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top ),
&pRT);
渲染目标是一个能完成绘图操作并能创建如画刷之类设备相关绘图资源的设备。不同类型的渲染目标渲染到不同设备上。上述例程使用 ID2D1HwndRenderTarget,它渲染到屏幕的某个区域。
如果可能,渲染目标使用GPU加速渲染操作并创建绘制资源。否则,渲染目标使用CPU处理渲染指令并创建资源。(创建渲染目标时可以通过D2D1_RENDER_TARGET_TYPE标记修改这种行为。)
CreateHwndRenderTarget 函数有三个参数。第一个参数,是一个 D2D1_RENDER_TARGET_PROPERTIES 结构,指明远程显示选项,是强制渲染目标渲染到软件还是硬件,并指明DPI。本例程用 D2D1::RenderTargetProperties 辅助函数来接收默认渲染目标属性。第二个参数,是一个 D2D1_HWND_RENDER_TARGET_PROPERTIES 结构,指明要渲染到哪个窗口的句柄、渲染目标的初始大小(像素)以及它的描述选项。本例程用D2D1::HwndRenderTargetProperties 辅助函数来指明一个窗口句柄和初始尺寸,并使用默认描述选项。第三个参数是渲染目标指针的地址。
当创建一个渲染目标并且硬件加速可用时,资源分配给计算机的GPU.通过创建一个渲染目标并尽可能久地保存它,有助于提升性能。应用程序要创建一次渲染目标,并保存它赶到程序结束或者收到D2DERR_RECREATE_TARGET 错误。当收到此错误时,需要重新创建渲染目标(包括它创建的任何资源)。
第四步:创建画刷
像工厂一样,渲染目标可以创建绘制资源。本例中用渲染目标创建一个画刷。
ID2D1SolidColorBrush* pBlackBrush = NULL;
if (SUCCEEDED(hr))
{
pRT->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
);
}
画刷是绘制一个区域的对象,就像形状的笔触或填充的几何对象。本例中的画刷用定义好的实心黑色来绘制一个区域。Direct2D 还提供了其实类型的画刷:渐变画刷用来绘制线性或径向渐变,位图画刷使用位图和图案进行绘制。有些绘图API提供绘制轮廓和填充形状的画笔。Direct2D 不一样:它不提供画笔,但使用画刷来绘制轮廓和填充形状。绘制轮廓时,使用ID2D1StrokeStyle 接口的画刷来控制描边路径操作。画刷只能由创建它的渲染目标使用或由同一资源区域的其它渲染目标使用。 通常,应该创建一次画刷并保存它直到创建它的渲染目标结束。但ID2D1SolidColorBrush是一个例外;因为创建它相对比较容易,你可以每次绘制一个框架时都创建一个ID2D1SolidColorBrush对象,而不会造成明显的性能损失。也可以只用一个ID2D1SolidColorBrush对象,每次使用它时改变它的颜色。
第五步:绘制矩形
接下来,用渲染目标来绘制矩形。
pRT->BeginDraw();
pRT->DrawRectangle(
D2D1::RectF(
rc.left + 100.0f,
rc.top + 100.0f,
rc.right - 100.0f,
rc.bottom - 100.0f),
pBlackBrush);
HRESULT hr = pRT->EndDraw();
DrawRectangle 函数接收两个参数:将要绘制的矩形,和用来绘制矩形外框的画刷。也可以指定笔触宽度、填充图案、线条结点以及结尾“帽子”等选项。发出任何绘制指令之前,必须先调用BeginDraw 函数,并且完成绘制后必须调用 EndDraw 函数。EndDraw 函数返回一个 HRESULT 修士,表明绘制是否成功。
第六步:释放资源
当没有更多框架要绘制或接收到D2DERR_RECREATE_TARGET 错误时,释放渲染目标和它创建的所有设备。
SafeRelease(pRT);
SafeRelease(pBlackBrush);
当应用程序使用完Direct2D资源时(例如程序将要退出时),释放Direct2D 工厂对象。
SafeRelease(pD2DFactory);
创建一个简单的Direct2D应用程序
本文中的代码展示了一个Direct2D应用程序的基本元素。简而言之,本文省略了应用程序框架和一个好的应用程序应有的容错处理代码。创建一个简单Direct2D应用程序的完整代码和较好设计原则的展示,请参阅 Creating a Simple Direct2D Application。