Direct2D入门 一. 资源管理(Resource management) 和Direct3D一样,Direct2D程序需要处理设 备丢失(Device lost)问题。Direct2D中的资源分为设备独立资源(Device independent resource)和设备依赖资源(Device dependent resource)。 设备独立资源包括: ID2D1DrawingStateBlock ID2D1Factory ID2D1Geometry 和由此继承而来的接口 ID2D1GeometrySink and ID2D1SimplifiedGeometrySink ID2D1StrokeStyle 设备依赖资源包括: ID2D1Brush 和由此继承而来的接口 ID2D1Layer ID2D1RenderTarget 和由此继承而来的接口 其他资源 具体参见:http://msdn.microsoft.com/en-us/library/dd756757(v=VS.85).aspx 二. Direct2D程序的结构 在程序初始化函数处创建设备独立资源,如ID2D1Factory,IDWriteFactory等; 创建设备依赖资源,如果运行过程中出现设备丢失,需要重新创建; 响应WM_PAINT消息,在OnPaint()或OnDraw()等处,用创建的资源Render; 响应WM_SIZE消息,在OnSize()处调用ID2D1RenderTarget::Resize(); 响应WM_ERASEBKGND,在OnEraseBkgnd()处返回FALSE,阻止GDI重绘客户区背景色,设置背景色的工作交给Direct2D在Render时设置,否则在Resize时会出现窗口闪烁的问题; 退出程序前,清理资源。 为提高程序的性能,尽量减少资源的创建和销毁操作,将能够重复利用的资源接口变量申明为View类的成员变量。 三. Direct2D demo 一个简单的MFC程序,用于演示Direct2D程序的结构和一些简单绘图操作。 1.Direct2D prerequisite D2dPrerequisite.h,包含一些编译Direct2D程序所需要用到的头文件,lib库文件,帮助宏和预处理指令: 1: //D2dPrerequisite.h 2: #pragma once 3: 4: ////////////////////////////////////////////////////////////////////////// 5: //Header files and lib files for Direct2D and DirectWrite 6: #include <d2d1.h> //Direct2D,for normal rendering task 7: #include <d2d1helper.h> 8: #include <dwrite.h> //DirectWrite,for drawing text 9: #include <wincodec.h> //Windows imaging component,for image decoding 10: 11: #pragma comment(lib,"d2d1.lib") 12: #pragma comment(lib,"dwrite.lib") 13: #pragma comment(lib,"windowscodecs.lib") 14: 15: ////////////////////////////////////////////////////////////////////////// 16: //Helper template for resource releasing 17: template<class Interface> 18: inline void SafeRelease(Interface **ppInterfaceToRelease) 19: { 20: if (*ppInterfaceToRelease != NULL) 21: { 22: (*ppInterfaceToRelease)->Release(); 23: (*ppInterfaceToRelease) = NULL; 24: } 25: } 26: 27: #ifndef Assert 28: #if defined( DEBUG ) || defined( _DEBUG ) 29: #define Assert(b) do {if (!(b)) {OutputDebugStringA("Assert: " #b "\n");}} while(0) 30: #else 31: #define Assert(b) 32: #endif //DEBUG || _DEBUG 33: #endif 34: 35: #ifndef HINST_THISCOMPONENT 36: EXTERN_C IMAGE_DOS_HEADER __ImageBase; 37: #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) 38: #endif 2.View类中的成员变量: 1: //View.h 2: private: 3: //Direct2D interface 4: ID2D1Factory* m_pD2d1Factory; 5: ID2D1HwndRenderTarget* m_pHwndRenderTarget; 6: ID2D1SolidColorBrush* m_pSolidColorBrush; 7: ID2D1LinearGradientBrush* m_pLinearGradientBrush; 8: ID2D1RadialGradientBrush* m_pRadialGradientBrush; 9: 10: //DirectWrite interface 11: IDWriteFactory* m_pDWriteFactory; 12: IDWriteTextFormat* m_pTextFormat; 3.创建设备独立资源 1: //View.cpp 2: BOOL CBasicView::CreateDeviceIndependentResource() 3: { 4: HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&m_pD2d1Factory); 5: ASSERT(hr == S_OK); 6: 7: if (SUCCEEDED(hr)) 8: { 9: hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, 10: __uuidof(m_pDWriteFactory), 11: reinterpret_cast<IUnknown**>(&m_pDWriteFactory)); 12: ASSERT(hr == S_OK); 13: } 14: 15: //Create TextFormat object with IDWriteFactory 16: if (SUCCEEDED(hr)) 17: { 18: const CString fontName = _T("Verdana"); 19: const FLOAT fontSize = 32.0f; 20: hr = m_pDWriteFactory->CreateTextFormat( 21: fontName, 22: NULL, 23: DWRITE_FONT_WEIGHT_NORMAL, 24: DWRITE_FONT_STYLE_NORMAL, 25: DWRITE_FONT_STRETCH_NORMAL, 26: fontSize, 27: L"", //locale 28: &m_pTextFormat 29: ); 30: ASSERT(hr == S_OK); 31: if (SUCCEEDED(hr)) 32: { 33: //Center alignment vertically and horizontally 34: m_pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); 35: m_pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); 36: } 37: } 38: return (hr == S_OK); 39: } 4.创建设备依赖资源 1: //View.cpp 2: BOOL CBasicView::CreateDeviceDependentResource() 3: { 4: ASSERT(m_pD2d1Factory != NULL); 5: if (m_pHwndRenderTarget != NULL) //There is no need to create render target 6: return TRUE; 7: 8: RECT rc; 9: GetClientRect(&rc); 10: D2D1_SIZE_U size = SizeU(rc.right-rc.left,rc.bottom-rc.top); 11: HRESULT hr = m_pD2d1Factory->CreateHwndRenderTarget( 12: RenderTargetProperties(), 13: HwndRenderTargetProperties(m_hWnd,size),//Bind the HwndRenderTarget to view window 14: &m_pHwndRenderTarget); 15: ASSERT(hr == S_OK); 16: if (SUCCEEDED(hr)) 17: { 18: //Create solid color brush 19: hr = m_pHwndRenderTarget->CreateSolidColorBrush( 20: ColorF(ColorF::LightGreen), 21: &m_pSolidColorBrush); 22: ASSERT(hr == S_OK); 23: 24: //Create gradient stops collection, 25: //used by linear gradient brush or radial gradient brush 26: ID2D1GradientStopCollection* pGradientStops = NULL; 27: D2D1_GRADIENT_STOP stops[2]; 28: stops[0].color = ColorF(ColorF::Yellow); 29: stops[0].position = 0.0f; 30: stops[1].color = ColorF(ColorF::Red); 31: stops[1].position = 1.0f; 32: HRESULT hr = m_pHwndRenderTarget->CreateGradientStopCollection( 33: stops, 34: 2, 35: D2D1_GAMMA_2_2, 36: D2D1_EXTEND_MODE_CLAMP, 37: &pGradientStops); 38: ASSERT(hr == S_OK); 39: 40: //Create linear gradient brush 41: hr = m_pHwndRenderTarget->CreateLinearGradientBrush( 42: LinearGradientBrushProperties(Point2F(210,110),Point2F(290,190)), 43: pGradientStops, 44: &m_pLinearGradientBrush); 45: ASSERT(hr == S_OK); 46: 47: //Create radial gradient brush 48: hr = m_pHwndRenderTarget->CreateRadialGradientBrush( 49: RadialGradientBrushProperties(Point2F(350,150),Point2F(0,0),50,50), 50: pGradientStops, 51: &m_pRadialGradientBrush); 52: ASSERT(hr == S_OK); 53: 54: SafeRelease(&pGradientStops); 55: } 56: 57: return (hr == S_OK); 58: } 5.Render 1: //View.cpp 2: void CBasicView::Render() 3: { 4: ASSERT(m_pD2d1Factory != NULL); 5: if (!m_pHwndRenderTarget) //Render target need to be recreated 6: { 7: //Recreate device dependent resource 8: BOOL succeeded = CreateDeviceDependentResource(); 9: if (!succeeded) 10: return; 11: } 12: 13: const D2D1_COLOR_F redColor = ColorF(ColorF::Red); 14: const D2D1_COLOR_F greenColor = ColorF(ColorF::Green); 15: const D2D1_COLOR_F blueColor = ColorF(ColorF::Blue); 16: const D2D1_COLOR_F yellowColor = ColorF(ColorF::Yellow); 17: const D2D1_COLOR_F pinkColor = ColorF(ColorF::Pink); 18: const D2D1_COLOR_F lightBlue = ColorF(ColorF::LightBlue); 19: const D2D1_COLOR_F lightGreen = ColorF(ColorF::LightGreen); 20: 21: m_pHwndRenderTarget->BeginDraw(); 22: m_pHwndRenderTarget->Clear(ColorF(ColorF::White)); //Clear the background 23: 24: //Draw line 25: //We can set the color and opacity of solid color brush at any time, 26: //so there is no need to create brushes for different colors 27: m_pSolidColorBrush->SetColor(redColor); 28: D2D1_POINT_2F startPoint = Point2F(10,10); 29: D2D1_POINT_2F endPoint = Point2F(90,90); 30: m_pHwndRenderTarget->DrawLine(startPoint,endPoint,m_pSolidColorBrush,5.0); 31: 32: //Draw rectangle 33: m_pSolidColorBrush->SetColor(greenColor); 34: D2D1_RECT_F rect = RectF(110,10,190,90); 35: m_pHwndRenderTarget->DrawRectangle(rect,m_pSolidColorBrush,4.0f); 36: 37: //Draw rounded rectangle 38: m_pSolidColorBrush->SetColor(blueColor); 39: rect = RectF(210,10,290,90); 40: D2D1_ROUNDED_RECT roundedRect = RoundedRect(rect,10,10); 41: m_pHwndRenderTarget->DrawRoundedRectangle(roundedRect,m_pSolidColorBrush,3.0f); 42: 43: //Draw ellipse 44: m_pSolidColorBrush->SetColor(redColor); 45: D2D1_POINT_2F center = D2D1::Point2F(350,50); 46: D2D1_ELLIPSE ellipse = D2D1::Ellipse(center,40,30); 47: m_pHwndRenderTarget->DrawEllipse(ellipse,m_pSolidColorBrush,3.0f); 48: 49: //Fill rectangle 50: m_pSolidColorBrush->SetColor(pinkColor); 51: rect = RectF(10,110,90,190); 52: m_pHwndRenderTarget->FillRectangle(rect,m_pSolidColorBrush); 53: 54: //Fill rounded rectangle 55: m_pSolidColorBrush->SetColor(blueColor); 56: m_pSolidColorBrush->SetOpacity(0.3f); 57: rect = RectF(110,110,190,190); 58: roundedRect = RoundedRect(rect,20,20); 59: m_pHwndRenderTarget->FillRoundedRectangle(roundedRect,m_pSolidColorBrush); 60: 61: //Fill rectangle with linear gradient brush 62: rect = RectF(210,110,290,190); 63: m_pHwndRenderTarget->FillRectangle(rect,m_pLinearGradientBrush); 64: 65: //Fill ellipse with gradient brush 66: ellipse = D2D1::Ellipse(Point2F(350,150),40,40); 67: m_pHwndRenderTarget->FillEllipse(ellipse,m_pRadialGradientBrush); 68: 69: //Draw text with a linear gradient brush 70: const CString text = _T("Text drawed with Direct2D & DWrite!"); 71: rect = RectF(20,210,380,290); 72: m_pHwndRenderTarget->DrawTextW( 73: text, 74: text.GetLength(), 75: m_pTextFormat, 76: rect, 77: m_pLinearGradientBrush); 78: 79: HRESULT hr = m_pHwndRenderTarget->EndDraw(); 80: 81: if (hr == D2DERR_RECREATE_TARGET) //Render target need to be recreated 82: { 83: //Discard all device dependent resources, 84: //and recreate them in the next render procedure 85: DiscardDeviceDependentResource(); 86: } 87: } 6. 销毁设备依赖资源,以备下次Render时再次创建 1: //View.cpp 2: void CBasicView::DiscardDeviceDependentResource() 3: { 4: SafeRelease(&m_pRadialGradientBrush); 5: SafeRelease(&m_pLinearGradientBrush); 6: SafeRelease(&m_pSolidColorBrush); 7: SafeRelease(&m_pHwndRenderTarget); 8: } 7.Resize 1: //View.cpp 2: void CBasicView::Resize(int width,int height) 3: { 4: if (m_pHwndRenderTarget) 5: { 6: m_pHwndRenderTarget->Resize(SizeU(width,height)); 7: } 8: } 四. 程序运行结果

评论