Click here to Skip to main content
12,635,816 members (25,122 online)
Click here to Skip to main content
Add your own
alternative version

Stats

66.1K views
1.5K downloads
31 bookmarked
Posted

Direct2D: Hardware Acceleration in Windows 7 Plotting

, 10 May 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Draw your vectors using a new, ActiveX based hardware accelerated interface.

Introduction

GDI+ has many features all right, but it is somewhat slow. Microsoft introduced Direct2D in Windows 7, a featured hardware-accelerated API that you can now use for applications. My first usage of Direct2D was in my Turbo Play project, which without it takes 28ms to draw screen. With it, it takes < 1 ms!

The good thing about Direct2D is that it can be easily combined with GDI, GDI+, or Direct3D.

You Need

Overview

Direct2D is an ActiveX object that can draw to an HWND or to an HDC. For this to work, the steps are:

  • Instantiate an ID2D1Factory by creating D2D1CreateFactory() from D2D1.DLL (I suggest you link to this dynamically using LoadLibrary/GetProcAddress so your code runs in any Windows version).
  • Call ID2D1Factory :: CreateHwndRenderTarget() to target an HWND, or call ID2D1Factory :: CreateDCRenderTarget() to target an HDC.
  • Use the returned ID2D1RenderTarget interface to draw:
    • Call ID2D1RenderTarget::BeginDraw()
    • Draw stuff
    • Call ID2D1RenderTarget::EndDraw()

Selecting a Brush to Draw

The following function creates a Direct2D Brush from a given ARGB color:

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;
}

Draw Lines, Rectangles, Ellipses

Use the functions exported from ID2D1RenderTarget, like DrawEllipse(), DrawRectangle(), DrawLine(), FillEllipse(), and FillRectangle().

Draw Polygons

The following function demonstrates how to create a polygon from a given set of POINT*s. You simply create a path geometry (ID2DFactory :: CreatePathGeometry()), open it (ID2D1PathGeometry::Open()) to get its sink, call ID2D1GeometrySink ::BeginFigure, add items (Line, Lines, Bezier curves etc.), call ID2D1GeometrySink::EndFigure(), then ID2D1PathGeometry::Close(), and finally, you pass the geometry object to 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;
    }

Draw Images

Direct2D loads a bitmap from a Windows Imaging component. The simple function below will use an existing HBITMAP (which must be a 32-bit one!) to draw:

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();
    }
}

Draw Text

Text in Direct2D is written through DirectWrite (to be continued...), another new Direct* API in Windows 7. The steps are:

  • Have the IDWriteFactory (DWriteCreateFactory from DWRITE.DLL).
  • Set the font by calling IDWriteFactory::CreateTextFormat() with font parameters, to get the IDWriteTextFormat*. (See my SetFont() function.)
  • Call IDWriteTextFormat members to set the format - my code calls SetTextAlignment/SetParagraphAlignment to set the alignment.
  • Call ID2D1RenderTarget::DrawText.

To measure the text dimensions, you have to create IDWriteTextLayout* (IDWriteFactory::CreateTextLayout) which represents the formatted text's attributes (for more, see my TextSize() function).

The Code

The code is part of my cross-platform drawing library, which is not complete (GDI/GDI+ stuff has been stripped from it to focus on the D2D code). You can use the mydraw.h functions:

// 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.

Todo...

  • Add interoperability between Direct2D, Direct3D , GDI+, and GDI
  • Add brush strokes
  • Add complex geometry

History

  • 08 - 5 - 2009: Update for RC1.
  • 25 - 4 - 2009: First release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

I 've a PhD in Digital Signal Processing and I specialize in Pro Audio applications.

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Pro

Comments and Discussions

 
QuestionDirect2D isn't rendering your IMG Pin
Sukar7-Jun-12 9:56
memberSukar7-Jun-12 9:56 
AnswerRe: Direct2D isn't rendering your IMG Pin
Michael Chourdakis7-Jun-12 11:04
memberMichael Chourdakis7-Jun-12 11:04 
Questiondoes it work just on windows 7? Pin
druscelli7-May-12 1:00
memberdruscelli7-May-12 1:00 
AnswerRe: does it work just on windows 7? Pin
Michael Chourdakis7-May-12 1:08
memberMichael Chourdakis7-May-12 1:08 
GeneralRe: does it work just on windows 7? Pin
druscelli7-May-12 1:12
memberdruscelli7-May-12 1:12 
GeneralRe: does it work just on windows 7? Pin
Michael Chourdakis7-May-12 1:16
memberMichael Chourdakis7-May-12 1:16 
GeneralRe: does it work just on windows 7? Pin
druscelli7-May-12 1:52
memberdruscelli7-May-12 1:52 
QuestionAre you sure about this? Pin
maryanny4-Dec-09 8:28
membermaryanny4-Dec-09 8:28 
QuestionHow to add Textbox? Pin
sebastiansony119665-Aug-09 2:33
membersebastiansony119665-Aug-09 2:33 
AnswerRe: How to add Textbox? Pin
Michael Chourdakis5-Aug-09 3:39
memberMichael Chourdakis5-Aug-09 3:39 
GeneralRe: How to add Textbox? Pin
sebastiansony119666-Aug-09 0:45
membersebastiansony119666-Aug-09 0:45 
Generalmain.rc(10): error RC2135: file not found: x86.manifest Pin
tyjiang11-Jul-09 16:07
membertyjiang11-Jul-09 16:07 
GeneralRe: main.rc(10): error RC2135: file not found: x86.manifest Pin
Michael Chourdakis12-Jul-09 7:07
memberMichael Chourdakis12-Jul-09 7:07 
GeneralRe: main.rc(10): error RC2135: file not found: x86.manifest ---- This content has been removed. Pin
Jo su hyeon30-Jan-12 20:07
memberJo su hyeon30-Jan-12 20:07 
GeneralRe: main.rc(10): error RC2135: file not found: x86.manifest ---- This content has been removed. Pin
Michael Chourdakis30-Jan-12 21:00
memberMichael Chourdakis30-Jan-12 21:00 
QuestionWindows 7 Pin
Paul Selormey10-May-09 17:25
memberPaul Selormey10-May-09 17:25 
AnswerRe: Windows 7 Pin
Paul Selormey11-May-09 16:21
memberPaul Selormey11-May-09 16:21 
GeneralRe: Windows 7 Pin
Michael Chourdakis11-May-09 21:27
memberMichael Chourdakis11-May-09 21:27 
GeneralRe: Windows 7 Pin
Paul Selormey11-May-09 21:50
memberPaul Selormey11-May-09 21:50 
GeneralRe: Windows 7 Pin
Michael Chourdakis12-May-09 3:11
memberMichael Chourdakis12-May-09 3:11 
GeneralRe: Windows 7 Pin
Paul Selormey12-May-09 3:37
memberPaul Selormey12-May-09 3:37 
GeneralRe: Windows 7 Pin
Michael Chourdakis12-May-09 6:24
memberMichael Chourdakis12-May-09 6:24 
GeneralRe: Windows 7 Pin
Paul Selormey12-May-09 10:38
memberPaul Selormey12-May-09 10:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.161208.2 | Last Updated 10 May 2009
Article Copyright 2009 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid