DXUT框架剖析(1)

http://www.cnblogs.com/flying_bat/archive/2008/05/17/1201301.html


DXUT(也稱sample framework)是建立在Direct3D API之上的Direct3D應用程序框架,有了DXUT這樣一個Direct3D程序框架,只需在這個框架的基礎上編寫相應的代碼,從而簡化了windows和Direct3D API的使用,可以高效地進行Direct3D程序設計。

生成一個Direct3D程序框架

第一步,運行Direct3D示例程序瀏覽器:

第二步,單擊"EmptyProject"中的"Installl Project"安裝工程:

第三步,在彈出的對話框中輸入新工程的名稱,修改該工程的創建路徑,單擊Install即可創建工程:

第四步,系統將自動完成工程的創建,然後彈出對話框詢問是否查看創建的工程文件夾中的內容:

若選擇是,則可以查看新創建的工程文件夾的內容:

使用Direct3D程序框架

通過上面的操作,Direct3D已經爲我們創建好了一個應用程序框架,該框架主要包括以下文件:

其中最主要的兩個文件是DXUT.h和DXUT.cpp。

除了上面這些通用文件外,Direct3D還生成了一個主程序文件,該文件的名字和工程名字相同,在此即是AppFrame.cpp。該文件主要由以下幾個回調函數構成:

bool CALLBACK IsD3D9DeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, 
									 bool bWindowed, void* pUserContext);
bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings* pDeviceSettings, void* pUserContext);
HRESULT CALLBACK OnD3D9CreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, 
									void* pUserContext);
HRESULT CALLBACK OnD3D9ResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, 
								   void* pUserContext);
void CALLBACK OnFrameMove(double fTime, float fElapsedTime, void* pUserContext);
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                          bool* pbNoFurtherProcessing, void* pUserContext );
void CALLBACK OnD3D9LostDevice( void* pUserContext );
void CALLBACK OnD3D9DestroyDevice( void* pUserContext );

函數名前使用"CALLBACK"表示聲明的是一個回調函數,也就是說,這是DXUT框架爲我們設置好的接口,DXUT框架將在合適的時機調用相應的回調函數。現在我們需要做的就是在這些回調函數中填寫相應的代碼完成所需要的功能。爲了使DXUT框架能夠調用這些回調函數,還需要在WinMain函數中爲DXUT框架設置這些回調函數,代碼如下:

    // Set the callback functions
    DXUTSetCallbackD3D9DeviceAcceptable(IsD3D9DeviceAcceptable);
    DXUTSetCallbackD3D9DeviceCreated(OnD3D9CreateDevice);
    DXUTSetCallbackD3D9DeviceReset(OnD3D9ResetDevice);
    DXUTSetCallbackD3D9FrameRender(OnD3D9FrameRender);
    DXUTSetCallbackD3D9DeviceLost(OnD3D9LostDevice);
    DXUTSetCallbackD3D9DeviceDestroyed(OnD3D9DestroyDevice);
    DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
    DXUTSetCallbackMsgProc(MsgProc);
    DXUTSetCallbackFrameMove(OnFrameMove);

DXUT框架程序的整個“生命週期”可劃分爲三個階段:啓動、運行和結束。

第一階段:啓動

DXUT框架依次執行IsD3D9DeviceAcceptable()、ModifyDeviceSettings()、OnD3D9CreateDevice()、OnD3D9ResetDevice()這4個函數。

在創建某個Direct3D渲染設備之前,如果需要對渲染設備的特徵進行檢查,查看設備是否支持需要的功能,可將檢查代碼寫在函數IsD3D9DeviceAcceptable()中。

在某個渲染設備創建之前,如果需要修改該渲染設備的設置,可將代碼寫在函數ModifyDeviceSettings()中。DXUT框架接下來就根據設置(或者是默認設置)創建最適合當前硬件的Direct3D渲染設備。例如,當硬件不支持某些功能時,可以通過使用參考設備進行模擬,設置使用參考設備代碼通常寫在該函數中。

DXUT框架創建了Direct3D設備之後,接下來會調用OnD3D9CreateDevice()回調函數,可在OnD3D9CreateDevice()回調函數中創建所有內存池類型爲D3DPOOL_MANAGED或D3DPOOL_SYSTEMMEM的資源。以類型D3DPOOL_MANAGED創建的設備由Direct3D系統代替管理(位於顯存或系統內存中),以類型D3DPOOL_SYSTEMMEM創建的設備位於系統內存中,在程序退出之前,這些資源常駐內存,不會出現設備丟失的現象。也就是說,以這兩種內存類型創建的資源不需要程序員進行管理。

DXUT框架在調用OnD3D9CreateDevice()回調函數之後,將調用OnD3D9ResetDevice()回調函數。我們可在函數OnD3D9ResetDevice()中創建所有內存池類型爲D3DPOOL_DEFAULT的資源,這一類資源將儘可能存放在顯存中,這樣可以提高程序的運行速度。但是,這類資源在程序運行時會出現設備丟失的現象,因此需要程序員自己管理。在設備丟失時釋放它的內存,當設備恢復時重新爲它分配內存。此外,觀察變換矩陣和投影變換矩陣以及在整個程序運行期間保持不變的渲染狀態通常也在該回調函數中設置。

如果性能不是很重要,使用D3DPOOL_MANAGED內存類型資源永遠是一種安全的選擇。

第二階段:運行

DXUT框架調用回調函數MsgProc()處理各類消息,並在空閒時間反覆調用OnFrameMove()和OnFrameRender()兩個函數進行場景渲染。

在每一幀中,程序爲實現對場景的刷新,爲用戶輸入的響應而編寫的代碼通常寫在函數OnFrameMove()中,例如設置世界變換矩陣實現物體的運動,它相當於“update”的性質,真正進行渲染的代碼寫在函數OnFrameRender()中。

需要說明的是,在應用程序運行期間,當Direct3D設備變爲丟失狀態時,DXUT框架會調用OnD3D9LostDevice()函數,釋放所有在回調函數OnD3D9ResetDevice()中創建的設備資源。也就是說,這時釋放的資源都是D3DPOOL_DEFAULT類型的。當Direct3D設備從丟失狀態恢復時,DXUT框架會調用回調函數OnD3D9ResetDevice()重新創建所有類型爲D3DPOOL_DEFAULT的資源。也就是說,在程序運行時,如果出現設備丟失現象,OnD3D9LostDevice()和OnD3D9ResetDevice()這一對函數就需要分別調用一次。

第三階段:退出

在退出程序時,DXUT框架會依次調用OnD3D9LostDevice()和OnD3D9DestroyDevice()回調函數,在函數OnD3D9LostDevice()中釋放由函數OnD3D9ResetDevice()創建的資源,在函數OnD3D9DestroyDevice()中釋放由函數OnD3D9CreateDevice()創建的資源。

AppFrame.cpp的全部代碼如下:

#include "DXUT.h"
#include "resource.h"
//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false.
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D9DeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
bool bWindowed, void* pUserContext)
{
// Typically want to skip back buffer formats that don't support alpha blending
    IDirect3D9* pD3D = DXUTGetD3D9Object();
/*
    HRESULT CheckDeviceFormat(
      UINT Adapter,
      D3DDEVTYPE DeviceType,
      D3DFORMAT AdapterFormat,
      DWORD Usage,
      D3DRESOURCETYPE RType,
      D3DFORMAT CheckFormat
    );
    /*/
if(FAILED(pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
            D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat)))
    {
return false;
    }
return true;
}
//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings* pDeviceSettings, void* pUserContext)
{
return true;
}
//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9CreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext)
{
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT)
// or that are tied to the back buffer size.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9ResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext)
{
return S_OK;
}
//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used.
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove(double fTime, float fElapsedTime, void* pUserContext)
{
}
//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;
// Clear the render target and the zbuffer
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 5, 5, 5), 1.0f, 0) );
// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        V( pd3dDevice->EndScene() );
    }
}
//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing, void* pUserContext )
{
return 0;
}
//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
}
//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
}
//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// Set the callback functions
    DXUTSetCallbackD3D9DeviceAcceptable(IsD3D9DeviceAcceptable);
    DXUTSetCallbackD3D9DeviceCreated(OnD3D9CreateDevice);
    DXUTSetCallbackD3D9DeviceReset(OnD3D9ResetDevice);
    DXUTSetCallbackD3D9FrameRender(OnD3D9FrameRender);
    DXUTSetCallbackD3D9DeviceLost(OnD3D9LostDevice);
    DXUTSetCallbackD3D9DeviceDestroyed(OnD3D9DestroyDevice);
    DXUTSetCallbackDeviceChanging(ModifyDeviceSettings);
    DXUTSetCallbackMsgProc(MsgProc);
    DXUTSetCallbackFrameMove(OnFrameMove);
// TODO: Perform any application-level initialization here
// Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit( true, true ); // Parse the command line and show msgboxes
    DXUTSetHotkeyHandling( true, true, true );  // handle the default hotkeys
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"AppFrame Sample" );
    DXUTCreateDevice( true, 640, 480 );
// Start the render loop
    DXUTMainLoop();
// TODO: Perform any application-level cleanup here
return DXUTGetExitCode();
}

運行效果圖:

下載示例工程

我最擅長從零開始創造世界,所以從來不怕失敗,它最多也就讓我一無所有。
發佈了4 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章