2011-08-22 96 views
0

我正在查看Xna框架遊戲類的源代碼,具體如何使它的繪製調用,我可以看到調用GraphicsDevice.Present()在 GraphicsDeviceManager.EndDraw(),但我可以沒有找到GraphicsDevice.BeginScene()或 GraphicsDevice.EndScene()的調用,即使在GraphicsDevice類本身中也沒有。任何人都知道他們如何處理這種情況Xna框架問題

+0

那麼,什麼是問題? –

回答

7

你沒有找到引用GraphicsDevice.Begin/EndScene()的原因是因爲不存在這些方法。 GraphicsDevice類是一個託管類,用於封裝XNA框架用戶所需的圖形功能;它不是一個一對一的本地IDirect3DDevice9接口映射。

我通過看你的意思是使用類似反射器的源代碼假設,並且我也假設你正在看代碼爲C#代碼。需要記住的一件事是,XNA框架的大部分都是用C++/CLI編寫的,因此當反映到C#時,結果可能會有些不可預知。

對於調用本機IDirect3DDevice9::BeginScene()IDirect3DDevice9::EndScene()的具體情況,您需要挖掘一點。

以下所有假設XNA 4.0。 3.1應該仍然是類似的。在Reflector中,您會注意到GraphicsDevice班有一個私人的bool_insideScene。如果你分析這個,你會看到它設置在各個位置,例如GraphicsDevice.DrawPrimitives()呼叫。這種方法的C#反射應設置這個構件用下面的代碼:

if (!this._insideScene) 
{ 
    **(((int*) this.pComPtr))[0xa4](this.pComPtr); 
    this._insideScene = true; 
} 

這裏的關鍵行是**(((int*) this.pComPtr))[0xa4](this.pComPtr);。如果你寫一個C++/CLI組件,包括適當的DirectX標題(d3d9.h)和呼叫BeginScene()上的IDirect3DDevice9(即pDevice->BeginScene())的實例,然後拆卸您在C#組件,就必須與上述相同的線。這就是本地呼叫的IL如何映射回C#,,但不可能在C#中編寫該行並編譯它

該代碼行本質上是一個原始的虛擬方法調用。你可以閱讀關於虛擬方法表here的更多信息,但是對於這種情況它的基本框架如下:對象的虛擬表指針是(依賴於編譯器,在這種情況下是true)本地對象中的第一個元素。 pComPtr是一個不安全的指向本地COM對象的指針。因此,取消引用pComPtr*pComPtr)會爲您提供指向虛擬方法表的指針。這裏的解體有些模糊,但是IL很清楚。接下來會發生什麼是0xa4被添加到虛擬方法表指針。要理解這一點,請記住本地數組只是指向數組的第一個元素的指針。一個對象的虛擬方法表是一個函數指針數組。 0xa4是十進制的164,意味着指針向前移動164個字節。由於庫是x86庫,指針長度爲4個字節。這意味着我們已經轉移到虛擬方法表(164/4 = 41)中的第41個方法。如果您看看d3d9.h(DirectX SDK的一部分)中的IDirect3DDevice9接口聲明,則會看到第41個方法是BeginScene。然後,該指針被解除引用,得到實際BeginScene方法,然後調用在(通常隱藏)this指針傳遞作爲第一(也是唯一的)參數(其中this對天然呼叫是this.pComPtr指針)。

您可以在專用的不安全的GraphicsDevice.Present()方法中看到類似的代碼,此時可抵消0xa8或功能42,即IDirect3DDevice9::EndScene()

因此,你可以看到GraphicsDevice正確確保任何繪圖完成之前BeginScene被調用,並且被稱爲本地IDirect3DDevice9::Present()方法之前EndScene被調用,但特意從XNA框架的用戶隱藏此功能。

+0

Geeze。很好的答案。 –

+0

令人印象深刻,就是這樣。我想問你一些問題,我試圖用native C++編寫一個遊戲編程框架,但我喜歡xna的工作方式,所以我正在試圖將相同的功能編碼到我的框架中。這是錯誤的,是否有任何法律影響?是的,我正在使用DotNetReflector – Yoss