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
- 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; // ... };
- 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; }
- 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)); } }
- 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)); }
- 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); } }
- 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 (246)
Resources and related articles
- MSDN: MFC Classes Added for Visual Studio 2010 SP1
- Codexpert blog: MFC Support for Direct2D – Part 2
- Codexpert blog: Using Direct2D for Rendering WIC Bitmap Sources