在博客園里,系統的Direct2D的教程比較少,只有“萬一”寫了一個關於Direct2D的系列(Delphi 2009)。於是,仿照其系列,寫一個在VS下的Direct2D系列教程。
博客園中的高手還是有不少的,在寫本系列教程的過程中,也會把碰到的問題或疑惑一一貼出來,期待高手的解答。以使得大家共同提高。
什么是Direct2D
一言以蔽之,就是Windows 7平台上的一個2D圖形API,可以提供高性能,高質量的2D渲染。大多數人對Direct2D可能都比較陌生,以至於我之前在論壇上提到這個詞的時候,有人竟然說你是不是寫錯了?可能大家比較熟悉的是Direct3D,因為D3D已經是當前游戲界的主流應用。在過去,3D世界是OpenGL與DirectX二分天下,但是由於OpenGL發展十分滯后,而且沒有一個像微軟這樣強大的后台支柱,所以逐漸被DirectX所超越。回過頭來說2D,過去Windows上的2D程序還主要基於GDI和GDI+,遺憾的是這兩者都是軟件實現,而Direct2D則不同,它基於Direct3D,所以能夠使用硬件加速功能,能更大程度的發揮硬件特性,創建高性能,高質量的2D圖形,這些圖形包括幾何圖形,如矩形,橢圓等。還有位圖,文本。而且更方便的是,Direct2D與GDI,GDI+和D3D都是可以交互的。
Direct2D運行需求
要開發和使用Direct2D程序,系統必須是Windows 7,Windows Vista SP2, Windows Server 2008 R2或者Windows Server 2008 SP2,這樣的系統需求無疑會稍稍阻礙Direct2D前進的步伐,雖然Vista和Windows 7已經推出有一段時間了,但是不可否認的是,仍然有很多人在使用XP系統。甚至是Win2K。但是新技術的普及是不可阻礙的,相信不久的將來,Direct2D將會成為2D圖形世界的主流。
VS2010下的Direct2D的運行庫
首先在Windows® API Code Pack for Microsoft® .NET Framework上下載Windows API Code Pack 1.1.zip
解壓后,在\Windows API Code Pack 1.1\binaries\DirectX目錄下有兩個子文件夾"x64"、"x86"。分別代表着64位、32位下的運行庫。
在自己的項目中引用x86下的Microsoft.WindowsAPICodePack.DirectX.dll文件。就可以進行Direct2D開發了。
下面是用VB2010寫的Direct2D的示例類。
Imports Microsoft.WindowsAPICodePack.DirectX
Public Class clsDirect2DSample
Private _d2DFactory As Direct2D1. D2DFactory
Private _renderTarget As Direct2D1. RenderTarget
Public Sub New()
_d2DFactory = Direct2D1. D2DFactory.CreateFactory()
End Sub
Public Sub CreateDeviceResource(Target As Control)
If _renderTarget Is Nothing Then
_renderTarget = _d2DFactory.CreateHwndRenderTarget( _
New Direct2D1. RenderTargetProperties, _
New Direct2D1. HwndRenderTargetProperties( _
Target.Handle, _
New Direct2D1. SizeU(Target.Width, Target.Height), _
Direct2D1. PresentOptions.None) _
)
End If
End Sub
Public Sub Render()
If Not _renderTarget Is Nothing Then
_renderTarget.BeginDraw()
Dim E As New Direct2D1. Ellipse( New Direct2D1. Point2F(50, 50), 30, 40)
Dim B As Direct2D1. SolidColorBrush = _renderTarget.CreateSolidColorBrush( New Direct2D1. ColorF(0, 1, 0))
_renderTarget.DrawEllipse(E, B, 4)
_renderTarget.EndDraw()
End If
End Sub
End Class
首先引入Microsoft.WindowsAPICodePack.DirectX命名空間,實際上還可以更進一步引入Direct2D1命名空間。只是為了區分某些類是在Direct2D下還是在原本的System下,沒有引入Direct2D1命名空間。凡是在類前有Direct2D1前綴的說明該類是在Direct2D1命名空間下。
從上面的代碼可以看出,要想使用Direct2D,得分下面幾步走
1、創建D2DFactory,相當於Direct2D的總管類,必須首先被創建。在類的初始化函數中,用CreateFactory函數創建D2DFactory。該函數有3個重載方式,在以后的文章有機會再詳細介紹
2、創建RenderTarget,相當於GDI+中的Graphics類,只有在創建后,才能進行后面的繪圖操作。在本例中,用D2DFactory類的CreateHwndRenderTarget方法創建一個和指定句柄Hwnd綁定的RenderTarget。在該方法中有兩個參數:RenderTargetProperties類,設置RenderTarget的一些屬性(DPI等,在該類重載初始化函數中可以設置);HwndRenderTargetProperties類設置綁定的Hwnd的屬性(Hwnd、寬、高等屬性)
3、在完成上面兩步后,可以開始繪圖操作了。為了演示方便,把所有的繪圖操作放在Render函數中。在Render函數中,先調用RenderTarget類的BeginDraw方法,表示要開始繪圖了,再調用RenderTarget類的EndDraw方法表示繪圖結束。Direct2D會把結果繪制到綁定的設備上
本例中,在Render函數中,先創建了一個Ellipse對象(橢圓),再創建一個SolidColorBrush對象(純色筆刷),然后用RenderTarget類的DrawEllipse方法繪制一個橢圓。三個參數分別表示:橢圓、筆刷、線寬。
同時,在WinForm中,有下面的代碼。把Panel1作為綁定的控件,傳給示例類,並在該空間的Paint事件中調用示例類的Render方法
Public Class Form1
Private _D As clsDirect2DSample
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
_D = New clsDirect2DSample
_D.CreateDeviceResource(Me.Panel1)
End Sub
Private Sub Panel1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
_D.Render()
End Sub
End Class
下圖是程序運行的結果
在Windows API Code Pack的官網上,有Windows API Code Pack的Visual Basic的示例代碼,只不過比較簡單,而且是WPF的示例代碼。有興趣的可以去看看。
注意:如果直接運行的話,會出現紅色大叉,表示運行錯誤。在項目屬性中勾選調試中的“啟用非托管代碼調試”。會出現下面的對話框
在網友Launcher提示下,按照“混合模式程序集是針對“v2.0.50727”版的運行時生成的,在沒有配置其他信息的情況下,無法在 4.0 運行時中加載該程序集。”一文中給出的解決方案,解決上面的錯誤。
解決方案是:在項目根目錄下,新建app.config文件,並包含到項目中,在其中打上如下的內容
<? xml version =" 1.0" ?>
< configuration >
< startup useLegacyV2RuntimeActivationPolicy =" true" >
< supportedRuntime version =" v4.0" sku = " .NETFramework,Version=v4.0" />
< supportedRuntime version =" v2.0.50727" />
</ startup >
</ configuration >
接下來,把調試中遇到的三個問題寫在下方。希望網友不吝賜教
問題一:引入64位的DLL,在運行時會出錯。
在引入64位的DLL后,運行的時候就會出錯。是在新建項目的時候,有什么設置不對么?之前的MediaInfo的64位DLL也是同樣的問題。機器和操作系統都是64位的。
問題二:在窗口界面出現后,用別的窗口覆蓋一下再顯示,等於重新調用了一次Render。可是第二次的效果圖和第一次的效果相差好多,鋸齒明顯了很多。在Render函數中,並沒寫設置鋸齒的代碼,為何同樣的代碼兩次執行的效果不一致。下圖是第二次的效果圖。(可是如果第一次效果圖出來后,最小化窗口,再恢復,也等於調用一次Render函數,效果還是和原來一樣好)
問題三:在首次運行的時候,會彈出對話框,找尋h文件(或者是cpp文件),沒找到會直接報錯。此時,到Debug目錄下,運行一遍程序后,上述的現象消失了。后面在多次運行,也不會問詢文件了