Direct2D教程(二)来看D2D世界中的Hello,World
引子
任何一門語言的第一個(gè)教程幾乎都是Hello,world。我們也不例外,但是這里不是教大家打印Hello,world,而是編寫一個(gè)簡(jiǎn)單的D2D繪制程序,讓大家對(duì)Direct2D的程序結(jié)構(gòu)及編程方法有一個(gè)基本的認(rèn)識(shí)。下面我們來看如何一步一步繪制一個(gè)矩形。
基本概念
在開始之前,還是先介紹一些基本的概念,有助于大家理解程序,這些概念包括,Brush(畫刷),Render target(渲染目標(biāo)),Geometry(幾何圖形),它們會(huì)貫穿整個(gè)教程,所以越早介紹越好,對(duì)于有Windows GDI基礎(chǔ)的人來說,理解這些概念很容易。沒有基礎(chǔ)的也沒關(guān)系,我們可以先了解一下,隨著學(xué)習(xí)的深入,會(huì)有更加深刻的認(rèn)識(shí)。
Brush
Brush-畫刷,畫刷是繪圖的工具,它管理圖形的顏色,虛實(shí),畫刷可以繪制幾何圖形,也可以繪制位圖。
Render target
Render target-渲染目標(biāo)(姑且這么翻譯吧)是繪制的場(chǎng)所,其實(shí)這就是一個(gè)surface,一個(gè)表面,再具體點(diǎn)就是一塊內(nèi)存,可以是顯存,也可能是系統(tǒng)內(nèi)存。所有的繪圖操作都在這里完成。
Geometry, Bitmap, Text
Geometry-幾何圖形,Bitmap-位圖, Text-文本。這三者是要繪制的內(nèi)容,幾何圖形包括矩形,圓角矩形,橢圓等,當(dāng)然Direct2D除了可以繪制幾何圖形之外,還可繪制位圖和文本,D2D沒有提供加載位圖的接口,所以對(duì)位圖的加載都是使用WIC來實(shí)現(xiàn)的。而對(duì)文本的繪制則是通過DirectWrite來實(shí)現(xiàn)的,DirectWrite在分類上屬于D2D,但是目前已經(jīng)獨(dú)立成一個(gè)組件了。為了便于理解以上三者之間的關(guān)系,大家可以想象一個(gè)畫家,他在作畫的時(shí)候,都需要那些東西呢?第一,他需要一支畫筆用來繪制,這相當(dāng)于上面的畫刷,第二,他需要一張紙或者一張畫布用來承載繪制的東西,這就是上面的Render target,最后,他想畫什么呢?山水?花鳥?亦或是人物?這就是繪制的內(nèi)容,相當(dāng)于上面的幾何圖形,位圖或者文本。
Resource
在Direct2D中主要有兩種資源,一是設(shè)備無關(guān)的資源,另一個(gè)是設(shè)備相關(guān)的資源。所謂設(shè)備無關(guān),是指該資源不與特定的硬件渲染設(shè)備相關(guān)聯(lián),所以設(shè)備無關(guān)的資源都分配在CPU中,而設(shè)備相關(guān)是指該資源與特定的渲染硬件相關(guān)聯(lián),比如當(dāng)硬件加速可用時(shí),使用GPU渲染,否則使用CPU渲染。
設(shè)備無關(guān)的資源
- ID2D1DrawingStateBlock
- ID2D1Factory
- ID2D1Geometry及繼承自它的接口
- ID2D1GeometrySink和ID2D1SimplifiedGeometrySink
- ID2D1StrokeStyle
除了ID2D1RenderTarget之外,所有使用ID2D1Factory創(chuàng)建的資源都是設(shè)備無關(guān)的。
設(shè)備相關(guān)的資源
- ID2D1Brush及繼承自它的接口
- ID2D1Layer
- ID2D1RenderTarget及繼承自它的接口
一般來說,使用ID2D1RenderTarget創(chuàng)建的資源都是設(shè)備相關(guān)的。
程序框架
一個(gè)簡(jiǎn)單的D2D程序大致包含下面三個(gè)核心函數(shù)。
1 創(chuàng)建資源(CreateResources) - 設(shè)備無關(guān)的資源可以一次性創(chuàng)建,永久使用,而設(shè)備相關(guān)的資源則需要隨著設(shè)備改變而相應(yīng)的改變。
2 渲染(Render) - 響應(yīng)WM_PAINT消息進(jìn)行繪制。
3 清理資源(Cleanup) - DX是基于COM的,所有COM對(duì)象在使用完畢時(shí),都要釋放。
為了便于大家理解,我畫了一張圖,這個(gè)圖簡(jiǎn)單描述了D2D程序的基本渲染流程。
需要說明的是,Direct2D的渲染時(shí)機(jī)與D3D有些不同,D3D是在沒有消息處理時(shí)進(jìn)行渲染,而D2D則是響應(yīng)WM_PAINT消息進(jìn)行渲染。下面的代碼中會(huì)有詳細(xì)的解釋。
代碼
添加頭文件
除了Win32編程需要的頭文件(比如Windows.h)之外,任何D2D程序都需要頭文件d2d1.h。
#include?<windows.h>#include?<D2D1.h>
聲明全局變量
首先我們需要一個(gè)ID2D1Factory*類型的對(duì)象,也就是D2D工廠接口,這個(gè)接口是所有D2D程序的起始點(diǎn),幾乎所有的D2D資源都是由這個(gè)接口創(chuàng)建的,其次我們需要一個(gè)渲染的場(chǎng)所,也就是Render Target,在D2D中有多種類型的Render Target,這里我們選擇ID2D1HwndRenderTarget類型,用來在窗口中進(jìn)行渲染。最后我們定義一個(gè)畫刷,用來繪制圖形,這里選擇固定顏色的畫刷,即ID2D1SolidColorBrush。?
ID2D1Factory*?pD2DFactory?=?NULL ;?//?Direct2D factoryID2D1HwndRenderTarget*?pRenderTarget?=?NULL;?? //?Render target
ID2D1SolidColorBrush*?pBlackBrush?=?NULL ;?//?A black brush, reflect the line color
RECT rc ;?//?Render area
HWND g_Hwnd ;?//?Window handle
創(chuàng)建D2D工廠
接下來創(chuàng)建D2D工廠對(duì)象,有了這個(gè)對(duì)象才能創(chuàng)建后續(xù)的資源,這個(gè)函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是工廠的類型,這里只有單線程和多線程兩類,如果是單線程的話,意味著D2D不會(huì)為所創(chuàng)建的工廠的對(duì)象以及由這個(gè)對(duì)象創(chuàng)建的子對(duì)象提供同步機(jī)制,也就是說,如果有多個(gè)線程訪問了這個(gè)資源,那么需要自己提供同步機(jī)制。如果是多線程類型,那么D2D會(huì)為你提供同步機(jī)制。第二個(gè)參數(shù)用來接收創(chuàng)建的工廠。
HRESULT hr ;hr?=?D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,?&pD2DFactory) ;
if?(FAILED(hr))
{
MessageBox(hWnd,?"Create D2D factory failed!",?"Error",?0) ;
return?;
}
創(chuàng)建Render target
有了工廠對(duì)象以后,開始創(chuàng)建RenderTarget,CreateHwndRenderTarget函數(shù)有三個(gè)參數(shù),第一個(gè)參數(shù)是Render target屬性,包括渲染模式,象素格式,DPI等,D2D提供了一個(gè)函數(shù)D2D1::RenderTargetProperties(),可以用來生成默認(rèn)的屬性,我們這里直接使用這個(gè)函數(shù)。第二個(gè)參數(shù)是Hwnd類型的Render target屬性,它包含三個(gè)參數(shù),第一個(gè)是窗口句柄,第二個(gè)是Render target的大小,第三個(gè)參數(shù)是Present選項(xiàng),這個(gè)參數(shù)有個(gè)默認(rèn)值,這里我們使用它的默認(rèn)值。CreateHwndRenderTarget函數(shù)的最后一個(gè)參數(shù)用來接收創(chuàng)建的Render target。
//?Create a Direct2D render targethr?=?pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,?
D2D1::SizeU(rc.right?-?rc.left,rc.bottom?-?rc.top)
),?
&pRenderTarget
) ;
if?(FAILED(hr))
{
MessageBox(hWnd,?"Create render target failed!",?"Error",?0) ;
return?;
}
創(chuàng)建畫刷
有了Render target,再使用函數(shù)CreateSolidColorBrush創(chuàng)建畫刷,這里創(chuàng)建一個(gè)固定顏色的畫刷,第一個(gè)參數(shù)是畫刷的顏色,第二個(gè)參數(shù)接收創(chuàng)建的畫刷,畫刷的顏色就是繪制線條所用的顏色,比如這里創(chuàng)建一個(gè)紅色的畫刷,那么后面繪制的矩形就是紅色的。
//?Create a brushhr?=?pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),
&pBlackBrush
) ;
if?(FAILED(hr))
{
MessageBox(hWnd,?"Create brush failed!",?"Error",?0) ;
return?;
}
繪制矩形
萬事俱備,只欠渲染!渲染的代碼很簡(jiǎn)單,首先調(diào)用CreateD2DResource函數(shù)來創(chuàng)建資源,這是個(gè)自定義函數(shù),用來創(chuàng)建資源,比如Render target,畫刷之類的,該函數(shù)包含了上面提到的代碼。繪制的代碼要放在BeginDraw和EndDraw函數(shù)之間,調(diào)用Clear函數(shù)可以將Render target清除為指定的背景色。DrawRectangle函數(shù)用來繪制矩形,它有兩個(gè)參數(shù),第一個(gè)是被繪制的矩形,第二個(gè)是繪制所用的畫刷。函數(shù)EndDraw的返回值標(biāo)識(shí)了渲染是否成功。
VOID DrawRectangle(){
CreateD2DResource(g_Hwnd) ;
pRenderTarget->BeginDraw() ;
//?Clear background color white
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
//?Draw Rectangle
pRenderTarget->DrawRectangle(
D2D1::RectF(100.f,?100.f,?500.f,?500.f),
pBlackBrush
);
HRESULT hr?=?pRenderTarget->EndDraw() ;
if?(FAILED(hr))
{
MessageBox(NULL,?"Draw failed!",?"Error",?0) ;
return?;
}
清理資源
最后,在程序退出時(shí),清理程序資源,每個(gè)COM對(duì)象都有一個(gè)Release方法,用來釋放自己,這里我們定義一個(gè)宏來釋放COM對(duì)象。
VOID Cleanup(){
SAFE_RELEASE(pRenderTarget) ;
SAFE_RELEASE(pBlackBrush) ;
SAFE_RELEASE(pD2DFactory) ;
}
釋放COM對(duì)象的宏。
#define?SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}效果圖如下
代碼下載
Happy Coding
== THE END ==
總結(jié)
以上是生活随笔為你收集整理的Direct2D教程(二)来看D2D世界中的Hello,World的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vs2008 C++创建和调用标准DLL
- 下一篇: JM8.5中的7种宏块模式问题 - zh