Direct2D在Windows 7中的使用介绍

Direct2D是微软在Windows 7中引入的一个硬件加速的图形API,它为应用程序提供了一种新的绘图方式。Direct2D的引入,使得图形渲染的性能得到了显著提升。在“Turbo Play”项目中,未使用Direct2D时,绘制屏幕需要28毫秒,而使用Direct2D后,绘制时间缩短到了不到1毫秒。

Direct2D的一个显著优点是它可以轻松地与GDI、GDI+或Direct3D结合使用。要使用Direct2D,需要Windows 7Release Candidate 1或更新的版本。请注意,这个示例在Beta 1或更早的版本中无法工作。

环境要求

要使用Direct2D,需要以下环境:

  • Windows 7Release Candidate 1或更新版本。
  • Windows 7 RC SDK。

Direct2D概述

Direct2D是一个ActiveX对象,它可以绘制到一个HWND或HDC。要实现这一点,需要按照以下步骤操作:

  1. 通过调用D2D1.DLL中的D2D1CreateFactory()来实例化一个ID2D1Factory。(建议使用LoadLibrary/GetProcAddress动态链接,以便代码可以在任何Windows版本上运行)。
  2. 调用ID2D1Factory::CreateHwndRenderTarget()来定位一个HWND,或者调用ID2D1Factory::CreateDCRenderTarget()来定位一个HDC。
  3. 使用返回的ID2D1RenderTarget接口进行绘制:
    1. 调用ID2D1RenderTarget::BeginDraw()。
    2. 绘制内容。
    3. 调用ID2D1RenderTarget::EndDraw()。

选择画刷进行绘制

以下函数创建了一个基于给定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)来书写的。步骤如下:

  1. 拥有IDWriteFactory(DWriteCreateFactory从DWRITE.DLL)。
  2. 通过调用IDWriteFactory::CreateTextFormat()并设置字体参数来设置字体,以获取IDWriteTextFormat*。(参见SetFont()函数)。
  3. 调用IDWriteTextFormat成员来设置格式 - 代码调用SetTextAlignment/SetParagraphAlignment来设置对齐方式。
  4. 调用ID2D1RenderTarget::DrawText。

代码

// 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.
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485