MFC Support for Direct2D – Part 5: Interoperability with GDI

There are two ways to combine Direct2D with Windows GDI API in the same application:

  1. Drawing Direct2D content to a GDI device context
  2. Drawing GDI content to a Direct2D GDI-compatible render target

Let’s see each one!

Drawing Direct2D content to a GDI device context

For this purpose, use ID2D1DCRenderTarget instead of ID2D1HwndRenderTarget interface. If using MFC shipped with Visual Studio 2015 or newer, then CDCRenderTarget wrapper class makes the programmer life easier. Here are the steps:

  1. In the WM_CREATE message handler call CWnd::EnableD2DSupport passing TRUE as second parameter. This way, the MFC framework creates a CD2DRenderTarget instead of a CHwndRenderTarget object.
  2. Map AFX_WM_DRAW2D registered messge.

  3. Finally, get the CDCRenderTarget* passed by MFC framework in LPARAM and enjoy.

Drawing GDI content to a Direct2D GDI-compatible render target

So far, MFC has not a wrapper class for ID2D1GdiInteropRenderTarget interface. Also, CWnd::EnableD2DSupport creates a CHwndRenderTarget which is not GDI-compatible. So, we must do it ourselves. Here is the sample code:

Demo projects

Download: Direct2D and GDI Interop Demo.zip (46)

The Visual C++ solution attached here has two simple projects showing the both Direct2D and GDI interoperatibily methods listed above.

Direct2D and GDI Interop - Demo Application

Direct2D and GDI Interop – Demo Application

 

Notes

  • can be observed that Direct2D drawing quality is higher than GDI drawing, because Direct2D is capable of rendering with antialiasing;
  • given the first note, my opinion is that GDI drawing has no much sense once using Direct2D but never know…

Resources and related articles

MFC Support for Direct2D – Part 4: Built-in Effects

Direct2D has built-in support for image processing like changing brightness or contrast, blurring, creating drop shadows, and so on. Basically, we can use for this purpose the CreateEffect and DrawImage methods of ID2D1DeviceContext interface. So far, there is no MFC wrapper class for ID2D1DeviceContext but that’s not so big issue. Once having a valid ID2D1RenderTarget instance (wrapped in CRenderTarget class) we can easily get the ID2D1DeviceContext interface by calling QueryInterface. No sweat!

Getting ID2D1DeviceContext interface in an MFC application

Or, a little bit easier, use CComQIPtr which calls QueryInterface for you.

Drawing an image using the Gaussian Blur built-in effect

Here is an example:

Just note that you should additionally include d2d1_1.h header and link your project to dxguid.lib. More details can be found in the attached demo project.

The demo project

Download: Gaussian Blur Effect demo.zip (42)

Gaussian Blur Effect - Demo Project

Notes

Resources and related articles

MFC Support for DirectWrite – Part 10: Outlined Text

In a previous article, I showed the basics of custom text rendering with DirectWrite (see MFC Support for DirectWrite – Part 7: A Step to Custom Rendering). So far so good but it just mimics the default text rendering. Let’s now modify the overridden IDWriteTextRenderer::DrawGlyphRun in order to draw outlined text.

Overridden IDWriteTextRenderer::DrawGlyphRun implementation

A method for drawing outlined text

Basically, the steps where the following:

  1. if pClientDrawingContext parameter is null then perform the default drawing;
  2. otherwhise, call _DrawOutlinedGlyphRun pasing an object that contains the brushes for text outline and fill (COutlinedTextEffect);
  3. create a path geometry (CD2DPathGeometry);
  4. instantiate a geometry sink that is used to populate the path geometry (CD2DGeometrySink);
  5. get IDWriteFontFace interface from DWRITE_GLYPH_RUN structure;
  6. call IDWriteFontFace::GetGlyphRunOutline, passing a bunch of parameters, most of them contained in DWRITE_GLYPH_RUN structure plus our geometry sink;
  7. close the geometry sink;
  8. translate the render target according to the glyph run baseline origin (baselineOriginX and baselineOriginY parameters of DrawGlyphRun);
  9. finally, call CRenderTarget::DrawGeometry and CRenderTarget::FillGeometry and…
  10. …do not forget to restore the initial render target transform.

You can find more details in the demo application attached here. Also you can have a look in the related articles mentioned at the bottom of this page.

Demo project

The demo project draws outlined text in order to make it readable over any background image.
DownloadOutlined Text Demo.zip (41)

Outlined Text demo project

Outlined Text demo project

Resources and related articles

MFC Support for DirectWrite – Part 9: Hit-Test

DirectWrite has hit-testing support that can be useful for showing a caret, making a selection, doing some action if the user chicks in a given text range, and so on. The hit-test methods of IDWriteTextLayout interface are HitTestPoint, HitTestTextPosition and HitTestTextRange. Let me show a simple example for each one.

Hit-testing a point

This example calls IDWriteTextLayout::HitTestPoint in the WM_LBUTTONDOWN message handler and keeps in mind the text position in which the user has clicked.

Hit-testing a text position

Further, use the previousy kept in mind text position and call IDWriteTextLayout::HitTestTextPosition when need to draw the caret.

Hit-testing a text range

And finally, here is an example of using IDWriteTextLayout::HitTestTextRange

It can be used, for example, to set the hand cursor when the mouse is moved over the given text range:

or can show some internet page when te user clicks on a “hyperlink”.

More details can be found in the demo examples attached to this article.

Demo projects

I’ve added the hit-test features to DirectWrite Static Control.
Download: Download: MFC Support for DirectWrite Demo (Part 9).zip (41)

MFC DirectWrite - Hit-Test Demo

MFC DirectWrite – Hit-Test Demo

Also here can be found a simpler application, only showing the DirectWrite hit-test features, to be easier understand: Simple DirectWrite Hit-Test Demo.zip (48)

Resources and related articles

MFC Support for Direct2D – Part 3: Multithreading

As shown in previous articles, we can enable MFC Direct2D support for a window by a call of CWnd::EnableD2DSupport.
Example:

So far so good as long as all windows which use Direct2D are running in the same thread (usually the application main thread). But let’s say we have more than one window with intensive rendering (e.g. some images slide show). In this case we would like to create each window in a separate thread. But this could cause the drawing to freeze or even application to crash. So, what should we do?

Create multi-threaded Direct2D factory

If step into MFC code starting with CWnd::EnableD2DSupport, we can notice the following:

  1. check if Direct2D and DirectWrite (kept in a global object of type _AFX_D2D_STATE) are already created;
  2. if not, call _AFX_D2D_STATE::InitD2D with default parameters D2D1_FACTORY_TYPE_SINGLE_THREADED and DWRITE_FACTORY_TYPE_SHARED.

Now, lets see the comments from D2D1_FACTORY_TYPE enumeration.

Also, let’s see what MSDN documentation states:

  • D2D1_FACTORY_TYPE_SINGLE_THREADED
    No synchronization is provided for accessing or writing to the factory or the objects it creates. If the factory or the objects are called from multiple threads, it is up to the application to provide access locking.

  • D2D1_FACTORY_TYPE_MULTI_THREADED
    Direct2D provides synchronization for accessing and writing to the factory and the objects it creates, enabling safe access from multiple threads.

Making the synchronization is not so handy so we have to find a way to create a Direct2D factory that uses multi-threaded model. Fortunately, that’s very easy by a single call of CWinApp::EnableD2DSupport.

That’s all. Hurray!

Demo application

Download: MFC Direct2D Multithreading Demo.zip (77)

The demo application can create multiple windows that perform image slideshow with Direct2D, each one in its own thread. Just push the button then select a folder containing image files.

MFC Direct2D Multithreading - Demo

MFC Direct2D Multithreading – Demo

 

Resources and related articles

MFC Support for DirectWrite – Part 8: Trimming

When using “classic” GDI functions i.e. CDC::DrawText, it’s no sweat to trim with ellipsis a single-line text when that text does not fit in the drawing rectangle width, by specifying DT_WORDBREAK flag. We cannot find a similar flag for CRenderTarget::DrawText or CRenderTarget::DrawTextLayout. However, trimming a text is also possible with DirectDraw. All we have to do is the following:

  1. call IDWriteFactory::CreateEllipsisTrimmingSign to create an inline object for trimming, using ellipsis as the omission sign;
  2. pass the created inline object to IDWriteTextFormat::SetTrimming.

Here is a simple code example in an MFC-based application:

Direct2D text trimming code sample

Demo project

Download: MFC Support for DirectWrite Demo (Part 8).zip (67)

The demo project contains sample code for all my DirectWrite-related articles. To demonstrate this one, in Trimming granularity combo, select “Character” or “Word”. Also select “No wrap” in Word wrapping combo then have fun.

MFC DirectWrite Demo Project

MFC DirectWrite Demo Project

 

Resources and related articles

Codexpert – 2016 Articles Summary

C++ Programming Language

Microsoft Libraries

Visual C++

See also