Direct2D:Windows 7 绘图中的硬件加速





5.00/5 (8投票s)
使用新的、基于 ActiveX 的硬件加速接口绘制您的向量。
引言
GDI+ 确实有很多功能,但速度有点慢。微软在 Windows 7 中引入了 Direct2D,这是一个具有硬件加速功能的 API,现在您可以将其用于应用程序。我第一次使用 Direct2D 是在我的 Turbo Play 项目中,如果没有它,绘制屏幕需要 28 毫秒。有了它,只需不到 1 毫秒!
Direct2D 的好处是可以轻松地与 GDI、GDI+ 或 Direct3D 结合使用。
您需要
- Windows 7 Release Candidate 1 或更高版本。请注意,此示例在 Beta 1 或更早版本中不起作用。
- Windows 7 RC SDK
#include <d2d1.h>
#include <d2d1helpers.h>
#include <dwrite.h>
(用于绘制文本)#include <wincodec.h>
(用于绘制图像)- MSDN 文档 Direct2D
概述
Direct2D 是一个 ActiveX 对象,可以绘制到 HWND
或 HDC
。 要使其工作,步骤如下
- 通过从 D2D1.DLL 创建
D2D1CreateFactory()
来实例化ID2D1Factory
(我建议您使用LoadLibrary
/GetProcAddress
动态链接到它,以便您的代码在任何 Windows 版本中运行)。 - 调用
ID2D1Factory :: CreateHwndRenderTarget()
以定位HWND
,或调用ID2D1Factory :: CreateDCRenderTarget()
以定位HDC
。 - 使用返回的
ID2D1RenderTarget
接口进行绘制- 调用
ID2D1RenderTarget::BeginDraw()
- 绘制内容
- 调用
ID2D1RenderTarget::EndDraw()
- 调用
选择画笔进行绘制
以下函数从给定的 ARGB 颜色创建一个 Direct2D 画笔
ID2D1SolidColorBrush* GetD2SolidBrush(ID2D1RenderTarget* pTR,unsigned long c)
{
if (!pRT)
return 0;
ID2D1SolidColorBrush* b = 0;
D2D1_COLOR_F cc;
cc.a = GetAValue(c)/255.0f;
if (cc.a == 0)
cc.a = 1.0f;
cc.r = GetRValue(c)/255.0f;
cc.g = GetGValue(c)/255.0f;
cc.b = GetBValue(c)/255.0f;
pRT->CreateSolidColorBrush(cc,&b);
return b;
}
绘制线条、矩形、椭圆
使用从 ID2D1RenderTarget
导出的函数,例如 DrawEllipse()
、DrawRectangle()
、DrawLine()
、FillEllipse()
和 FillRectangle()
。
绘制多边形
以下函数演示了如何从给定的一组 POINT*
创建多边形。 您只需创建一个路径几何体 (ID2DFactory :: CreatePathGeometry()
),打开它 (ID2D1PathGeometry::Open()
) 以获取其接收器,调用 ID2D1GeometrySink ::BeginFigure
,添加项目(线、直线、贝塞尔曲线等),调用 ID2D1GeometrySink::EndFigure()
,然后调用 ID2D1PathGeometry::Close()
,最后,将几何体对象传递给 ID2D1RenderTarget::DrawGeometry
。
void Polygon(POINT*p,int n,bool Close)
{
// Convert POINT to D2D1_POINT_2F
D2D1_POINT_2F* pt = new D2D1_POINT_2F[n];
for(int i = 0 ; i < n ; i++)
{
pt[i].x = (FLOAT)p[i].x;
pt[i].y = (FLOAT)p[i].y;
}
ID2D1SolidColorBrush* b = GetD2SolidBrush(c);
ID2D1PathGeometry* pg = 0;
ID2D1GeometrySink* pgs = 0;
pD2DFactory->CreatePathGeometry(&pg);
if (pg)
{
pg->Open(&pgs);
if (pgs)
{
D2D1_POINT_2F fb;
fb.x = (FLOAT)pt[0].x;
fb.y = (FLOAT)pt[0].y;
// Use D2D1_FIGURE_BEGIN_FILLED for filled
D2D1_FIGURE_BEGIN fg = D2D1_FIGURE_BEGIN_HOLLOW;
D2D1_FIGURE_END fe;
if (Close)
fe = D2D1_FIGURE_END_CLOSED;
else
fe = D2D1_FIGURE_END_OPEN;
pgs->BeginFigure(fb,fg);
for(int i = 1 ; i < n ; i++)
{
D2D1_POINT_2F fu;
fu.x = pt[i].x;
fu.y = pt[i].y;
pgs->AddLine(fu);
}
pgs->EndFigure(fe);
pgs->Close();
pgs->Release();
}
if (b)
pRT->DrawGeometry(pg,b,1);
pg->Release();
if (b)
b->Release();
delete[] pt;
}
绘制图像
Direct2D 从 Windows 图像组件加载位图。 以下简单函数将使用现有的 HBITMAP
(必须是 32 位!)进行绘制
void Image(int x1,int y1,HBITMAP hB,float Op = 1.0f);
{
BITMAP bo;
GetObject(hB,sizeof(bo),&bo);
WICBitmapAlphaChannelOption ao = WICBitmapUseAlpha;
IWICBitmap* wb = 0;
pImageFactory->CreateBitmapFromHBITMAP(hB,0,ao,&wb);
if (!wb)
return;
ID2D1Bitmap* b = 0;
pRT->CreateBitmapFromWicBitmap(wb,0,&b);
if (!b)
{
// Convert it
IWICFormatConverter* spConverter = 0;
pImageFactory->CreateFormatConverter(&spConverter);
if (spConverter)
{
spConverter->Initialize(wb,GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,NULL,0.f,
WICBitmapPaletteTypeMedianCut);
pRT->CreateBitmapFromWicBitmap(spConverter,0,&b);
spConverter->Release();
}
wb->Release();
}
if (b)
{
D2D1_RECT_F r;
r.left = (FLOAT)x1;
r.top = (FLOAT)y1;
r.right = (FLOAT)(x1 + bo.bmWidth);
r.bottom = (FLOAT)(y1 + bo.bmHeight);
pRT->DrawBitmap(b,r,Op);
b->Release();
}
}
绘制文本
Direct2D 中的文本是通过 DirectWrite
编写的(待续...),这是 Windows 7 中的另一个新的 Direct* API。 步骤如下
- 拥有
IDWriteFactory
(来自 DWRITE.DLL 的DWriteCreateFactory
)。 - 通过使用字体参数调用
IDWriteFactory::CreateTextFormat()
来设置字体,以获取IDWriteTextFormat*
。(请参阅我的SetFont()
函数。) - 调用
IDWriteTextFormat
成员来设置格式 - 我的代码调用SetTextAlignment
/SetParagraphAlignment
来设置对齐方式。 - 调用
ID2D1RenderTarget::DrawText
。
要测量文本尺寸,您必须创建 IDWriteTextLayout*
(IDWriteFactory::CreateTextLayout
),它表示格式化文本的属性(有关更多信息,请参阅我的 TextSize()
函数)。
代码
该代码是我跨平台绘图库的一部分,该库尚未完成(GDI/GDI+ 内容已从中删除,以专注于 D2D 代码)。 您可以使用 mydraw.h 函数
// Members
void Line(int x1,int y1,int x2,int y2,int th = 1,unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID);
void Rect(RECT&ar,int th = 1,unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID,bool Elp = false);
void FilledRect(RECT&ar,unsigned long c = AXRGB(0xFF,0,0,0),bool Elp = false);
void Polygon(POINT*p,int n,bool Close,int th = 1,
unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID);
void FilledPolygon(POINT*p,int n,bool Close,
unsigned long c = AXRGB(0xFF,0,0,0));
void Ellipse(RECT&ar,int th = 1,unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID);
void FilledEllipse(RECT&ar,unsigned long c = AXRGB(0xFF,0,0,0));
void Rect(int x1,int y1,int wi,int he,int th = 1,
unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID,bool Elp = false);
void Ellipse(int x1,int y1,int wi,int he,int th = 1,
unsigned long c = AXRGB(0xFF,0,0,0),
unsigned int PenStyle = PS_SOLID);
void FilledRect(int x1,int y1,int wi,int he,
unsigned long c = AXRGB(0xFF,0,0,0),bool Elp = false);
void FilledEllipse(int x1,int y1,int wi,int he,
unsigned long c = AXRGB(0xFF,0,0,0));
unsigned long TextSize(const wchar_t* txt,int l,
unsigned long al,unsigned long lal);
void DrawText(const wchar_t* txt,int l,int x,int y,int wi,int he,
unsigned long al,unsigned long lal,
unsigned long c = AXRGB(0xFF,0,0,0),int BreakMode = 1);
void DrawText(const wchar_t* txt,int l,RECT&,unsigned long al,
unsigned long lal,unsigned long c = AXRGB(0xFF,0,0,0),
int BreakMode = 1);
void SetFont(HFONT hF1);
void Image(int x1,int y1,LPWSTR fil,float Op = 1.0f);
void Image(int x1,int y1,HINSTANCE h,LPWSTR n,
LPWSTR typ = RT_BITMAP,float Op = 1.0f);
void Image(int x1,int y1,HBITMAP hB,float Op = 1.0f, bool HasAlpha = 0);
void Image(int x1,int y1,Gdiplus::Bitmap* b,bool HasAlpha = 0);
HRESULT LoadResourceImage(HINSTANCE h,PCWSTR resourceName,
PCWSTR resourceType,void**ppBitmap);
HRESULT LoadFileImage(const LPWSTR f,void**ppBitmap);
绘制内容。 加载 test32.sln 并编译它,然后从菜单中选择绘图模式。 还包括一个性能计数器。
待办事项...
- 添加 Direct2D、Direct3D、GDI+ 和 GDI 之间的互操作性
- 添加笔触
- 添加复杂的几何体
历史
- 08 - 5 - 2009:RC1 更新。
- 25 - 4 - 2009:首次发布。