Direct2D是微软在Windows 7中引入的一个硬件加速的图形API,它为应用程序提供了一种新的绘图方式。Direct2D的引入,使得图形渲染的性能得到了显著提升。在“Turbo Play”项目中,未使用Direct2D时,绘制屏幕需要28毫秒,而使用Direct2D后,绘制时间缩短到了不到1毫秒。
Direct2D的一个显著优点是它可以轻松地与GDI、GDI+或Direct3D结合使用。要使用Direct2D,需要Windows 7Release Candidate 1或更新的版本。请注意,这个示例在Beta 1或更早的版本中无法工作。
要使用Direct2D,需要以下环境:
Direct2D是一个ActiveX对象,它可以绘制到一个HWND或HDC。要实现这一点,需要按照以下步骤操作:
以下函数创建了一个基于给定ARGB颜色的Direct2D画刷:
ID2D1SolidColorBrush* GetD2SolidBrush(ID2D1RenderTarget* pRT, 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 Imaging组件加载位图。以下简单函数将使用现有的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)来书写的。步骤如下:
// 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);
to draw stuff. Load test32.sln and compile it, and select the drawing mode from the menu. A performance counter is also included.