Direct2D入门

一. 资源管理(Resource management)

和Direct3D一样,Direct2D程序需要处理设备丢失(Device lost)问题。Direct2D中的资源分为设备独立资源(Device independent resource)和设备依赖资源(Device dependent resource)。

设备独立资源包括:

设备依赖资源包括:

具体参见:http://msdn.microsoft.com/en-us/library/dd756757(v=VS.85).aspx

二. Direct2D程序的结构

  1. 在程序初始化函数处创建设备独立资源,如ID2D1Factory,IDWriteFactory等;
  2. 创建设备依赖资源,如果运行过程中出现设备丢失,需要重新创建;
  3. 响应WM_PAINT消息,在OnPaint()或OnDraw()等处,用创建的资源Render;
  4. 响应WM_SIZE消息,在OnSize()处调用ID2D1RenderTarget::Resize();
  5. 响应WM_ERASEBKGND,在OnEraseBkgnd()处返回FALSE,阻止GDI重绘客户区背景色,设置背景色的工作交给Direct2D在Render时设置,否则在Resize时会出现窗口闪烁的问题;
  6. 退出程序前,清理资源。

为提高程序的性能,尽量减少资源的创建和销毁操作,将能够重复利用的资源接口变量申明为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: }

四. 程序运行结果

ScreenShot00072

posted on 2010-04-28 16:49  wudong  阅读(11587)  评论(0编辑  收藏  举报

导航