65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2009年4月25日

CPOL

3分钟阅读

viewsIcon

107575

downloadIcon

1951

使用新的、基于 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 对象,可以绘制到 HWNDHDC。 要使其工作,步骤如下

  • 通过从 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.DLLDWriteCreateFactory)。
  • 通过使用字体参数调用 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:首次发布。
Direct2D:Windows 7 中的硬件加速绘图 - CodeProject - 代码之家
© . All rights reserved.