MFC Support for Direct2D – Part 1

A few time ago, I begun writing a series of wrapper classes to make easier the using of Direct2D interfaces. Meanwhile, I discovered that MFC Library, beginning with Visual Studio 2010 SP1, offers an excelent built-in support. That’s pretty cool!
So, let’s use Direct2D (D2D) MFC classes for making a simple image viewer.

Image viewer using Direct2D MFC classes

  1. In the view’s class definition, add data members for render target and Direct2D bitmap.
    #pragma once
    #include <memory>
    
    class CDemoView : public CScrollView
    {
        CHwndRenderTarget m_renderTarget;
        std::shared_ptr<CD2DBitmap> m_spBitmap;
        // ...
    };
    
  2. Create the render target in the view’s WM_CREATE message handler.
    int CDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        if (CScrollView::OnCreate(lpCreateStruct) == -1)
            return -1;
    
        HRESULT hr = m_renderTarget.Create(m_hWnd);
        return SUCCEEDED(hr) ? 0 : -1;    
    }
    
  3. In the view’s WM_SIZE message handler resize the render target.
    void CDemoView::OnSize(UINT nType, int cx, int cy)
    {
        CScrollView::OnSize(nType, cx, cy);
    
        if(m_renderTarget.IsValid())
        {
            m_renderTarget.Resize(CD2DSizeU(cx, cy));
        }
    }
    
  4. Override CView::OnUpdate and load the bitmap from the current document’s file.
    void CDemoView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
    {
        CDemoDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
    
        if(nullptr != m_spBitmap)
        {
            m_spBitmap->Destroy();
        }
        CSize sizeImage(100, 100);
    
        const CString& strFile = pDoc->GetPathName();
        if(! strFile.IsEmpty())
        {
            m_spBitmap = std::make_shared<CD2DBitmap>(&m_renderTarget, strFile);
            HRESULT hr = m_spBitmap->Create(&m_renderTarget);
            if(m_spBitmap->IsValid())
            {
                CD2DSizeF size = m_spBitmap->GetSize();
                sizeImage.SetSize(static_cast<int>(size.width), static_cast<int>(size.height));
            }
        }
       SetScrollSizes(MM_TEXT, sizeImage);
       ScrollToPosition(CPoint(0, 0));
    }
    
  5. Prevent painintg in WM_ERASEBKGND message handler.
    BOOL CDemoView::OnEraseBkgnd(CDC* pDC)
    {
        if(m_renderTarget.IsValid() && m_spBitmap->IsValid())
        {
            return TRUE; // all drawing is made in WM_PAINT handler
        }
        else
        {
            return CScrollView::OnEraseBkgnd(pDC);
        }
    }
    
  6. Finally, override CView::OnDraw and draw the bitmap.
    void CDemoView::OnDraw(CDC* pDC)
    {
    	if(m_renderTarget.IsValid())
        {
            // initiate drawing on render target
            m_renderTarget.BeginDraw();
            // clear background using white color
            D2D1_COLOR_F color = {1.f, 1.f, 1.f, 1.f}; // r, g, b, a
            m_renderTarget.Clear(color);
            if((nullptr != m_spBitmap) && m_spBitmap->IsValid())
            {
                // apply translation transform according to view's scroll position
                CPoint point = GetScrollPosition();
                D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation((float)-point.x, (float)-point.y);
                m_renderTarget.SetTransform(matrix);
                // draw the bitmap
                CD2DSizeF size = m_spBitmap->GetSize();
                m_renderTarget.DrawBitmap(m_spBitmap.get(), CD2DRectF(0, 0, size.width, size.height));
            }
            // ends drawing operations 
            HRESULT hr = m_renderTarget.EndDraw();
            // if the render target has been lost, then recreate it
            if(D2DERR_RECREATE_TARGET == hr)
            {
                m_renderTarget.ReCreate(m_hWnd);
            }
        }
    }
    

Notes

  • CD2DBitmap::Create uses WIC (Windows Imaging Component) interfaces, so beside common image formats like BMP, JPEG, GIF, PNG, and TIFF, can deal also with any other image format for which a WIC-compliant decoder is installed in system.
  • Next article will show an even easier mode of using Direct2D MFC support.

Demo project

Download: Image Viewer - Using Direct2D MFC Classes.zip (1921 downloads)

Using Direct2D MFC Classes - Demo Project
Using Direct2D MFC Classes – Demo Project

Resources and related articles

1 thought on “MFC Support for Direct2D – Part 1”

  1. Hi
    It’s useful guide but this line always returns S_FALSE

    HRESULT hr = m_renderTarget.Create(m_hWnd);

    Why?

    PS Even in your sample project.

    Reply

Leave a Comment