DXUT編程指南.

DXUT設計指南

    DXUT是一個建立在Direct3D API之上的,被大部分Direct3D指南和例子所使用的層。 它的目標是創建Direct3D例子、原型、工具,更容易的建立堅固、專業的遊戲。

·           DXUT概觀

·           初始化DXUT

·           使用基於DXUT的程序窗口

·           使用DXUT設備

·           使用DXUT主循環

·           處理DXUT的錯誤

·           DXUT高級設備選擇

·           DXUT高級功能

 

 

See also: DXUT參考.

 

 

 

DXUT概觀

本主題提供對DXUT概觀的高級介紹。

·         概觀

·         特點

·         侷限性

·         啓動一個新工程

·         DirectX April 2005 SDKDXUT的改進

·         DirectX Summer 2003 SDK以來DXUT的變化

概觀

DXUT框架的設計是爲了幫助開發者在創建窗口、設備,處理窗口消息和設備事件時,更有效率(消耗較少的時間)

 

這是使用該框架的應用程序的主函數:

INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )

{

    // 設置回調函數,這些函數允許DXUT通知應用程序更換設備,用戶輸入和窗口消息。

    // 回調函數是可選的,因此你要做的僅是設置你感興趣的事件的回調函數。

    DXUTSetCallbackDeviceCreated( OnCreateDevice );

    DXUTSetCallbackDeviceReset( OnResetDevice );

    DXUTSetCallbackDeviceLost( OnLostDevice );

    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );

 

    DXUTSetCallbackFrameRender( OnFrameRender );

    DXUTSetCallbackFrameMove( OnFrameMove );

 

    // 初始化DXUT並創建想要的Win32窗口和應用程序的Direct3D設備。調用這些

// 可選函數中的每一個,此外它們允許你設置幾個選項來控制框架的行爲。

    DXUTInit( TRUE, TRUE, TRUE );

    DXUTCreateWindow( L"BasicHLSL" );

    DXUTCreateDevice( D3DADAPTER_DEFAULT, TRUE, 640, 480 );

 

    // 通過DXUT來處理消息循環並分派渲染調用。當在空閒時間和處理窗口消息的

// 時間間隔時,框架將調用OnFrameMoveOnFrameRender回調函數。

    DXUTMainLoop();

    return DXUTGetExitCode();

}

在例子代碼中,框架做了大部分的工作。它創建窗口、設備,處理主消息循環,當應用程序事件觸發時,提供相應的回調函數,例如:在設備重置或渲染每幀時。DXUT框架是組件化的,應用程序可以使用框架的全部功能或部分功能。

這個設計指南的其他部分詳細的包括了這些步驟,並着重於應用程序可選擇的控制或可替代的步驟。

更詳細的語法和函數的使用,回調函數,結構,列舉和常量等信息可以在DXUT參考中找到。

特點

爲了幫助你創建一個應用程序,框架提供下列服務:

·           簡單的窗口和設備的創建。

·           設備事件 (created, reset, lost, destroyed) 和窗口事件 (messages, keyboard, mouse)的通知。

·           窗口模式與全屏模式之間的轉換, 硬件設備和軟件設備之間的轉換。

·           精確的計時器。

·           命令行支持和自動化測試。

·           使用對話框或API的設備選擇。

·           一套紋理化的GUI控件,包括一個可使用輸入法編輯器的編輯框。

·           各種擴展類,例如簡單的攝像機類型。

侷限性

爲了便於使用,框架只支持綁定一個設備的窗口。需要同時使用多個設備,或顯示多個Direct3D窗口的高級程序,是本框架不支持的,大部分類型的應用程序將能夠使用本框架來實現。

啓動一個新工程

最簡單的方法,啓動一個使用新的Visual Studio .NET中的DXUT開發的項目:

1.       啓動例子瀏覽器(SampleBrowser.exe),在下面位置找到DirectX SDK(SDK root)/Samples/SampleBrowser/

2.       在例子瀏覽器裏,選擇一個已有的Direct3D 例子項目,將從這開始。

3.       點擊 “安裝項目”("Install Project")鏈接,然後拷貝Visual Studio .NET項目文件到一個新的本地目錄。

4.       你可以給項目重命名,這時瀏覽器將根據提供的新工程名,去更改相應的文件和源代碼。

DirectX April 2005 SDKDXUT的改進

基於用戶的反潰, DXUT框架在DirectX April 2005 SDK中進行了改進更新。下面是主要的差異和改進的列表。

·         DXUTSetCallback*系列的函數使用void*類型的參數pUserContext來傳參給回調函數.這允許回調函數從應用程序接受類指針那樣的context.

·         框架的GUI部分現在是可選的,並且從核心框架中分離出來了。CDXUTDialogResourceManager 的創建和接口化現在只有在應用程序想要使用框架GUI的時候才起作用。

·         應用程序可以阻止通過返回一個bool類型的LPDXUTCALLBACKMODIFYDEVICESETTINGS函數來進行設備更改。如果返回false,框架將繼續使用現有設備而不是更改爲新設備。例如在默認情況下,在多個顯示器的機器上將一個窗口從一個顯示器拖到另一個顯示器時,框架將會更換設備。但是如果應用程序不能使用其他設備,它必須能夠阻止這種變換並且使用現有的設備。這個回調現在可以使用DXUTSetCallbackDeviceChanging設定,獨立於CreateDevice函數。

·        傳0,寬和高給DXUTCreateDevice函數現在可以創建和客戶窗口相同大小的後備緩衝。

·        如果最後一個設備是D3DDEVTYPE_REF,DXUTGetExitCode將會返回11。

DirectX Summer 2003 SDK以來DXUT的變化

The new framework is significantly redesigned from DXUT that shipped in the DirectX Summer 2003 SDK Update. The following is a list of major differences and improvements.

·         Flat API design. The new framework is a set of global functions that more clearly define how the application interacts with the framework.

·         Clearer naming. The device, frame, and message events have been renamed to be more easily understood.

·         Modular. An application can use only parts of the framework if desired. An application can use the framework to create its own window or its own device, or it can use its own main loop.

·         Better device selection. The application can fully customize the presentation parameters or behavior flags before creating the device. The new framework also has a more advanced algorithm for finding valid device settings.

·         Toggling between hal and reference devices (see Device Types). Built-in toggling support is available, and toggling can be bound to a keystroke for simplified debugging.

·         Better error handling. Error handling and macros can be used by the application to display error message boxes immediately if an API is called incorrectly.

·         Better multiple-monitor support. If this feature is enabled, the new framework will automatically change devices if the window is moved to a different monitor.

·         GUI controls. A set of textured GUI controls features an IME-enabled edit box for use in samples, prototypes, and professional games.

·         No dialog dependency onGDI. Unlike the previous framework, the new framework does not require anyGDI dialog resources in the application.

·         Late binding with DirectX. Late binding verifies that the required DirectX version is installed on the system.

·         Unicode support. The new framework supports Unicode. Windows NT-based operating systems natively support Unicode, which means that ANSI calls need to be converted to Unicode. With this and better international support, Unicode is the better choice because it will result in better performance on these operating systems. For Windows 98 and Windows Millennium Edition (Windows Me) systems, consider using the Microsoft Layer for Unicode (MSLU).

·         Documentation. The framework library functions in the Dxut.h header are documented; see DXUT Reference.

 

初始化DXUT

使用DXUT的第一步是初始化。可以簡單的用DXUTInit 函數:

HRESULT DXUTInit (

         BOOL bParseCommandLine     = TRUE,

         BOOL bHandleDefaultHotkeys = TRUE,

         BOOL bShowMsgBoxOnError    = TRUE

);

你將在應用程序的 WinMain 函數開始後不遠的地方調用DXUTInit如果DXUTInit沒有在應用程序中調用,它將使用默認的參數在框架中自動調用。

如果第一個參數bParseCommandLineTRUE,框架將對命令行參數做出響應。例如,運行BasicHLSL Sample執行下列命令行參數:

BasicHLSL.exe -windowed -width:600 -height:600

DXUT框架將嘗試執行這些窗口設定,對於命令行支持參數的全部列表,請查看DXUTInit函數部分的幫助。

第二個參數bHandleDefaultHotkeys通知DXUT框架對一些預先執行的擊鍵做出響應,例如:ALT+ENTER。再說一次,全部的列表請查看DXUTInit函數部分的幫助。如果這個參數爲FALSE,程序將不做響應。

最後一個參數bShowMsgBoxOnError,當框架發現一個錯誤時,顯示一個消息框。設置它爲FALSE則運行自動測試或完全由用戶經驗控制的專業程序。

 

 

使用基於DXUT的程序窗口

你的程序可以只使用一個新的DXUT函數,來處理大部分窗口管理的任務。

·         創建窗口

·         使用你自己的窗口

創建窗口

創建一個Direct3D應用程序窗口包括下列步驟:

1.       定義一個響應窗口的消息。

2.       創建。

3.       使用。

4.       使用。

這些步驟如果沒做正確將會引起bugs。雖然它對於一個Direct3D程序員來說,這可能很沒勁,但卻是每個程序所必需的。DXUT框架使用DXUTCreateWindow函數來簡單化這個過程:

HRESULT DXUTCreateWindow(

    const WCHAR *strWindowTitle = L"Direct3D Window",

    HINSTANCE hInstance         = NULL,

    HICON hIcon                 = NULL,

    HMENU hMenu                 = NULL,

    INT x                       = CW_USEDEFAULT,

    INT y                       = CW_USEDEFAULT

);

所有參數都是可選的:

·         strWindowTitle是窗口標題,也顯示在任務欄,它表示工程名稱。

·         hInstance是應用程序實例的句柄。大部分程序的默認值爲NULL

·         hIcon是應用程序的圖標。如果爲NULL,則應用程序的可執行文件裏包含的第一個圖標將被使用,所以NULL值也能很好的工作。

·         hMenu 處理菜單,如果想的話可以設置它,大部分遊戲無論無何不能使用標準菜單,但作爲替代,可以用自己定製的遊戲類界面來創建它們。

·         最後2個參數描述窗口位置。如果應用程序運行在全屏模式,則忽視這2個參數。

最簡單的調用方法,程序可以像下面這樣調用DXUTCreateWindow

DXUTCreateWindow( L"My New Game" );

只用一個參數來調用這個函數,strWindowTitle將促使DXUT框架去創建窗口,並自動處理重要的窗口消息。如果需要重新取得窗口的句柄,可以調用DXUTGetHWND

如果想讓程序響應窗口消息,可以用DXUTSetCallbackMsgProc 去設置回調函數:

void DXUTSetCallbackMsgProc( LPDXUTCALLBACKMSGPROC pCallbackMsgProc,

  void* pUserContext = NULL );

PCallbackMsgProc參數是一個LPDXUTCALLBACKMSGPROC類型的回調函數,下面是定義:

LRESULT CALLBACK FUNCTION MsgProc(

    HWND   hWnd,

    UINT   uMsg,

    WPARAM wParam,

    LPARAM lParam,

    BOOL*  pbNoFurtherProcessing,

    void*  pUserContext

    )

{

    return 0;

}

在這個回調函數裏,程序不需要去響應任何消息,因爲所有重要的消息將被DXUT框架處理。爲了阻止DXUT框架處理消息,應用程序可以設置*pbNoFurtherProcessingTRUE。(查看LPDXUTCALLBACKMSGPROC),然而,當使用這個設置時要小心,因爲它可能會阻止DXUT框架的正確行爲。

使用自己的窗口

如果你想讓程序去創建自己的窗口,並且和框架一起使用,而不是讓DXUT處理窗口的操作,那麼你可以使用DXUTSetWindow函數:

HRESULT DXUTSetWindow(

    HWND hWndFocus,

    HWND hWndDeviceFullScreen,

    HWND hWndDeviceWindowed,

    BOOL bHandleMessages = TRUE

);

這個函數帶有3個窗口句柄,它們是完全相同的,除非程序在窗口模式和全屏模式中使用不同的窗口。當應用程序因按ALT+TAB、鼠標點擊、或其他用戶輸入,而轉到後臺時,將提供焦點窗口的句柄通知給Direct3D應用程序應該經常傳遞焦點窗口的句柄給DXUTSetWindow函數,不管它創建多少個Direct3D設備。

除了用一個窗口初始化框架之外,應用程序需要用窗口消息通知框架,窗口接收有序的消息給正確的框架行爲處理。如果框架創建了窗口,窗口消息是自動處理的。否則,應用程序可以使用DXUTStaticWndProc函數,從內部的窗口WindowProc回調函數傳遞窗口消息給框架,下面是定義:

LRESULT CALLBACK DXUTStaticWndProc(

    HWND hWnd,

    UINT uMsg,

    WPARAM wParam,

    LPARAM lParam

);

如果你不想讓應用程序使用DXUTStaticWndProc,你可以交替複製在函數中的功能,儘管它是不被推薦的。

 

 

使用DXUT設備

使用最新版的DXUT創建DirectX設備。它可以代替你用應用程序直接創建設備,而框架的其他功能仍然可用。

·         創建設備

·         選擇最佳設備設定

·         更改可用的設備設定

·         軟件頂點處理 Fallback to Software Vertex Processing

·         使用你自己的設備

創建設備

下面是用標準的Direct3D方法創建設備,CreateDevice

HRESULT CreateDevice(

    UINT                  Adapter,

    D3DDEVTYPE            DeviceType,

    HWND                  hFocusWindow,

    DWORD                 BehaviorFlags,

    D3DPRESENT_PARAMETERS *pPresentationParameters,

    IDirect3DDevice9      **ppReturnedDeviceInterface

);

 


這個方法需要正確的adapter(適配器),設備類型(hal or reference),窗口句柄,行爲標記(軟件/硬件頂點處理和其他設備標記),和一個表達參數(一個D3DPRESENT_PARAMETERS結構的參數)。此外,D3DPRESENT_PARAMETERS結構有衆多成員,它們是:特定的後備緩存區設置,採樣器設備,swap效果,窗口模式,深度模版緩存區設置,刷新速度等等。

給所有這些參數選擇有效的設定就是個挑戰,那麼DXUT框架的DXUTCreateDevice函數簡化了這一過程:

HRESULT DXUTCreateDevice(

    UINT AdapterOrdinal  = D3DADAPTER_DEFAULT,

    BOOL bWindowed       = TRUE,

    INT nSuggestedWidth  = 640,

    INT nSuggestedHeight = 480,

    LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable     = NULL,

    LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = NULL

);

 

 

 

 

 

 

 

 

 

大多數基本用法是很簡單的,使用默認的參數調用函數:

DXUTCreateDevice();

 

對於這個簡單的調用,框架創建設備的默認設定,它可以工作在大部分情況下。下面是設備創建的默認設定:

Direct3D創建標記

描述

DXUTCreateDevice的默認值

AdapterFormat parameter of CheckDeviceFormat

適配器表面格式

Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits.

Adapter parameter of IDirect3D9::CreateDevice

顯示適配器的序號

D3DADAPTER_DEFAULT

D3DPRESENT_PARAMETERS. BackBufferCount

後備緩衝區數量

2, indicating triple buffering.

D3DPRESENT_PARAMETERS. BackBufferFormat

緩衝區格式

Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits.

D3DPRESENT_PARAMETERS. AutoDepthStencilFormat

設備將創建表面的深度緩衝區格式

D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise.

The DeviceType parameter of IDirect3D9::CreateDevice

設備的列舉類型

D3DDEVTYPE_HAL if available, otherwise D3DDEVTYPE_REF or failure code if neither is available.

D3DPRESENT_PARAMETERS. MultiSampleQuality

品質級別

MultiSampleQuality = 0, indicating multisampling is disabled.

D3DPRESENT_PARAMETERS. Flags

Presentation parameters flags.

D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL

D3DPRESENT_PARAMETERS. PresentationInterval

Presentation interval.

D3DPRESENT_INTERVAL_IMMEDIATE for windowed mode, or D3DPRESENT_INTERVAL_DEFAULT for full-screen mode.

D3DPRESENT_PARAMETERS. FullScreen_RefreshRateInHz

顯示器的刷新速度

0, indicating windowed mode.

D3DPRESENT_PARAMETERS. BackBufferWidth and .BackBufferHeight

顯示模式

640 x 480 pixels for windowed mode, or the desktop resolution for full-screen mode.

D3DPRESENT_PARAMETERS. AutoDepthStencilFormat

設備將創建表面的模版緩衝區格式

D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise.

D3DPRESENT_PARAMETERS. SwapEffect

交換效果.

D3DSWAPEFFECT_DISCARD

BehaviorFlags parameter of IDirect3D9::CreateDevice

頂點處理標記

D3DCREATE_HARDWARE_VERTEXPROCESSING if supported, otherwise D3DCREATE_SOFTWARE_VERTEXPROCESSING.

D3DPRESENT_PARAMETERS. Windowed

窗口或全屏模式

true, indicating windowed mode.

hFocusWindow parameter of CreateDevice

處理創建的窗口 (查看使用基於DXUT的程序窗口).

hWndFocus parameter of DXUTSetWindow

D3DPRESENT_PARAMETERS. hDeviceWindow

設備窗口的處理

hWndDeviceFullScreen or hWndDeviceWindowed parameters of DXUTSetWindow

D3DPRESENT_PARAMETERS. EnableAutoDepthStencil

深度/模版緩衝區的創建標記

true.

 

比使用一個設備創建很多默認設定更好的方法是,應用程序能夠通過傳遞給CreateDevice函數的參數來使設備應用更多的控制。例如,你可能通過SuggestedWidthnSuggestedHeight參數改變窗口的尺寸:

DXUTCreateDevice(

    D3DADAPTER_DEFAULT,

    false,

    1024,

    768,

    NULL,

    NULL,

    NULL

);

爲了取得更多的控制,應用程序可以使用2個可選的回調函數: LPDXUTCALLBACKISDEVICEACCEPTABLELPDXUTCALLBACKMODIFYDEVICESETTINGS.

選擇最佳設備設定

你可以在程序裏使用IsDeviceAcceptable回調函數來幫助框架選擇佳的設備設定,請看下列代碼:

bool CALLBACK IsDeviceAcceptable(

D3DCAPS9*     pCaps,

D3DFORMAT     AdapterFormat,

D3DFORMAT     BackBufferFormat,

bool          bWindowed,

void*         pUserContext )

{

    // TODO: 可接受的設定返回true,否則返回false

    return true;

}

這個回調函數的原型是LPDXUTCALLBACKISDEVICEACCEPTABLE。框架爲下列5個設定中每個唯一有效的組合,一次性的調用這個函數:

D3DDEVTYPE DeviceType;

UINT       AdapterOrdinal;

D3DFORMAT  AdapterFormat;

D3DFORMAT  BackBufferFormat;

bool       Windowed;

注意:適配器序號和設備類型不直接傳遞給回調函數,而是分別的傳遞,D3DCAPS9結構中的設備類型(DeviceType)和設備序號(AdapterOrdinal)成員。

在這個回調函數裏,應用程序可以拒絕它不支持的或接受任何組合。舉個例子,程序可以使用下列代碼拒絕16-bit格式的後備緩衝區,並且讓所有設備不支持像素着色器ps_2_0以下的版本:

bool CALLBACK IsDeviceAcceptable(

    D3DCAPS9*     pCaps,

    D3DFORMAT     AdapterFormat,

    D3DFORMAT     BackBufferFormat,

    bool          bWindowed )

{

    if( pCaps->PixelShaderVersion < D3DPS_VERSION(2,0) )

             return false;

    if( BackBufferFormat == D3DFMT_X1R5G5B5 || BackBufferFormat == D3DFMT_R5G6B5 )

        return false;

    return true;

}

回調函數調用設定中每個唯一的組合以後,框架隊列保存可接受的組合並選擇他們中最好的之一。排名較高的組合包括下面這些:

·         D3DDEVTYPE_HAL, 爲了取得硬件的加速度。

·         如果程序在全屏模式下顯示,框架默認的格式是與桌面適配器匹配的,所以從窗口向全屏的模式轉換是很快的。如果桌面顯示模式小於32bits時會觸發異常,在這種情況下框架默認D3DFMT_X8R8G8B8格式

·         後備緩衝區格式,它與適配器格式相匹配。

對於這些選擇的設定中最高級別的組合,行爲標記和表達參數在創建設備時仍然是必需的,對於這些設定,Direct3D使用上表所示的默認值。

修改可用的設備設定

應用程序可以修改框架的可選項,使用第2個回調函數:ModifyDeviceSettings,類似下面這樣:

bool CALLBACK ModifyDeviceSettings(

    DXUTDeviceSettings* pDeviceSettings,

    const D3DCAPS9*     pCaps )

{

    // TODO: Include device creation requirements here. 

    // 創建設備返回true,保持當前設備返回false

    return true;

}

 

這個回調函數的方法原型是:LPDXUTCALLBACKMODIFYDEVICESETTINGSDXUTDeviceSettings結構在框架中是這樣定義的:

struct DXUTDeviceSettings

{

    UINT       AdapterOrdinal;

    D3DDEVTYPE DeviceType;

    D3DFORMAT  AdapterFormat;

    DWORD      BehaviorFlags;

    D3DPRESENT_PARAMETERS pp;

};

 

這個結構包括了創建設備所需要的所有東西(除了窗口句柄),假定早就創建了窗口句柄。框架用有效的值填充這個結構,並允許程序通過ModifyDeviceSettings回調函數去更改設備(創建選擇的設備)

在這個回調函數中程序可以更改行爲標記,像DXUTDeviceSettings結構中的表達參數一樣好用。如果應用程序在回調函數裏沒有更改任何東西,設備將創建成功。然而,任何設備設定的更改都需要應用程序對設備的支持,否則設備創建可能會失敗。

 

例如,如果應用程序需要一個D3DFMT_D24S8格式的深度模版,將檢查設備是否支持它,使用下面的代碼:

bool CALLBACK ModifyDeviceSettings(

    DXUTDeviceSettings* pDeviceSettings,

    const D3DCAPS9*     pCaps )

{

    IDirect3D9* pD3D = DXUTGetD3DObject();

    if( SUCCEEDED( pD3D->CheckDeviceFormat(

                 pDeviceSettings->AdapterOrdinal,

                 pDeviceSettings->DeviceType,

                 pDeviceSettings->AdapterFormat,

                 D3DUSAGE_DEPTHSTENCIL,

                 D3DRTYPE_SURFACE,

                 D3DFMT_D24S8 ) ) )

    {

             if( SUCCEEDED( pD3D->CheckDepthStencilMatch(

                     pDeviceSettings->AdapterOrdinal,

                     pDeviceSettings->DeviceType,

                     pDeviceSettings->AdapterFormat,

                     pDeviceSettings->pp.BackBufferFormat,

                     D3DFMT_D24S8 ) ) )

         {

                 pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;

         }

    }

   

    return true;

}

 

作爲替代, 回調函數也可以使用框架的CD3DEnumeration 對象去檢查是否支持D3DFMT_D24S8格式:

bool CALLBACK ModifyDeviceSettings(

    DXUTDeviceSettings* pDeviceSettings,

    const D3DCAPS9*     pCaps )

{

    CD3DEnumeration *pEnum = DXUTGetEnumeration();

    CD3DEnumDeviceSettingsCombo *pCombo;

        

    pCombo = pEnum->GetDeviceSettingsCombo( pDeviceSettings );

        

    if( pCombo->depthStencilFormatList.Contains( D3DFMT_D24S8 ) )

        pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;

       

    return true;

}

應用程序更改設備設定後,框架用新的設定創建設備。

這個回調函數返回bool值。如果應用程序返回TRUE,框架將創建標準設備。如果返回FALSE,如果有設備存在的話,框架不更改設備,保持當前的設備。這樣就允許應用程序拒絕框架的請求(更改應用程序所不支持的設備)。例如,在一個多顯示器的結構裏,默認在顯示器間拖曳窗口將導致框架更改設備,然而如果應用程序不能使用另一個設備,它必須能夠拒絕更改,並繼續使用當前的設備。

軟件頂點處理

如果我在硬件上創建一個Direct3D設備,它支持硬件像素處理,但不支持硬件頂點處理,那麼你需要設置行爲標記。在IsDeviceAcceptable回調函數裏,爲了確保正確的回調給軟件頂點處理,當IsDeviceAcceptable回調函數裏不能拒絕基於頂點着色器版本的設備時,你要採取防備措施;並確保行爲標記在ModifyDeviceSettings回調函數裏被正確的調用。這裏有一個例子:

bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings,

                                    const D3DCAPS9* pCaps )

{

    // 如果設備不支持硬件的T&L 或硬件的頂點着色器版本1.1,那麼轉換到SWVP(軟件頂點處理).

    if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||

         pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )

    {

        pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    }

    else // 支持

    {

        pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;

    }

   

    return true;

}

 

使用你自己的設備

你可以不必依賴框架創建Direct3D設備,替代的方法是,用程序自己創建設備,並且傳遞它給框架使用。類似的方法是應用程序可以覆蓋框架的window creation設定。用所有想要的設定簡單的創建一個設備,然後調用DXUTSetDevice函數使框架能夠在設備上進行渲染。

注意    如果應用程序創建了獨立於框架的設備,在主循環執行完畢之後清除資源時,程序必須釋放設備接口。

 

 

使用DXUT主循環

在窗口和設備創建後,程序需要使用主循環(調用一個渲染循環或消息循環)來響應窗口消息。更新並渲染場景,處理設備事件。程序可以自己實現主循環,也使用DXUT實現。回調函數的註冊允許DXUT去處理設備、框架和事件消息。

進入主消息循環

要使用框架的主循環,簡單的調用DXUTMainLoop,唯一的參數設置爲NULL

儘管用框架去處理消息循環相當容易,對於一些高級程序,定製主循環是更好的設計。使用DXUTMainLoop函數定製的主循環是可能的,但需要在程序中寫更多的代碼,下面是例子代碼:

INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )

{

    DXUTSetCallbackDeviceCreated( OnCreateDevice );

    DXUTSetCallbackDeviceReset( OnResetDevice );

    DXUTSetCallbackDeviceLost( OnLostDevice );

    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );

    DXUTSetCallbackFrameRender( OnFrameRender );

    DXUTSetCallbackFrameMove( OnFrameMove );

 

    DXUTInit( TRUE, TRUE, TRUE );

    DXUTCreateWindow( L"BasicHLSL" );

    DXUTCreateDevice( D3DADAPTER_DEFAULT, TRUE, 640, 480 );

 

    // ------------------------------------------------

    // 定製主循環

    HWND hWnd = DXUTGetHWND();

    BOOL bGotMsg;

    MSG  msg;

    msg.message = WM_NULL;

    PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

 

    while( WM_QUIT != msg.message )

    {

        // 使用PeekMessage(),因爲我們使用空閒時間渲染場景

             bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );

        

             if( bGotMsg )

             {

                 // 轉換並分派消息

                 if( 0 == TranslateAccelerator( hWnd, NULL, &msg ) )

                 {

                          TranslateMessage( &msg );

                      DispatchMessage( &msg );

                 }

         }

             else

         {

                 // 在空閒時間渲染一幀 (沒有消息則等待ing)

                 DXUTRender3DEnvironment();

         }

}

// 定製主循環結束

    // ------------------------------------------------

    return DXUTGetExitCode();

}

在這個例子代碼中,程序調用DXUTRender3DEnvironment函數來進行每幀的更新、渲染場景和處理設備事件。在程序中完全的複製這個函數是可行的,但我們不推薦這樣做。

處理事件

該框架使用回調函數機制來實現程序對事件的響應。應用程序只需要註冊或設置一個框架的函數指針,當事件觸發時框架將調用這個函數。框架不需要註冊所有回調函數,因此應用程序僅釋放因需要而註冊的回調函數就行了。在DirectX April 2005 SDK中,回調函數從void* pUserContext類型的函數中傳遞一個void* pUserContext來完成回調。這樣允許回調函數接收應用程序的上下文,例如類的指針。在框架中觸發的3種類型的事件:

·           設備事件

·           框架事件

·           消息事件

 

設備事件

當應用程序在渲染Direct3D設備時,設備的丟棄(lost)是有可能的。導致這樣事情的發生有很多原因,比如當用戶按ALT+TAB鍵離開全屏程序時,當用戶按CTRL+ALT+DEL,或者當用戶運行其他全屏的3D應用程序時。當調用特定的函數時,例如Present這時就會返回一個D3DERR_DEVICELOST值,這時Direct3D API會通知應用程序。

當設備丟棄時,釋放所有Direct3D對象是應用程序的責任,但當設備丟棄時就不可挽回了,例如在D3DPOOL_DEFAULT類型的內存中創建的對象。如果對象沒有被釋放,那麼它從丟棄的狀態返回時,設備將不能重置(reset)

當設備丟棄時應用程序必須等待。當設備返回時,程序必須調用Reset,並重新創建所有設備對象,重置設備將無法找回丟棄的設備對象。

使用DXUT框架,在程序中使用回調函數去處理不同的事件是很簡單的:設備更改,創建,重置,丟棄或釋放。當設備丟棄時框架將會記錄下來,當它從丟棄狀態返回時框架將全部重置設備。框架在適當的時候使用程序的回調函數去釋放和重建設備對象。下列是所有需要應用程序實現的回調函數:圖表略。

回調註冊函數

應用程序回調函數

框架調用的時間

DXUTSetCallbackDeviceChanging

LPDXUTCALLBACKMODIFYDEVICESETTINGS

Direct3D設備創建以後調用。它給了程序一個阻止設備更改的機會。

DXUTSetCallbackDeviceCreated

LPDXUTCALLBACKDEVICECREATED

Direct3D設備創建後被調用,通常發生在應用程序初始化和設備重建期間。

DXUTSetCallbackDeviceReset

LPDXUTCALLBACKDEVICERESET

Direct3D設備重置以後調用,通常發生在設備丟棄之後。

DXUTSetCallbackDeviceLost

LPDXUTCALLBACKDEVICELOST

Direct3D 設備進入丟棄狀態和設備重置期間。

DXUTSetCallbackDeviceDestroyed

LPDXUTCALLBACKDEVICEDESTROYED

Direct3D 毀壞後調用,通常發生應用程序終止或設備重建時。

當在窗口與全屏模式之間切換設備時, 它通常會執行設備重置(reset),但有時它必須重建Direct3D

這些回調註冊函數是可選的。然而,如果程序釋放了沒有註冊設備,並且設備使用:DXUTSetCallbackDeviceDestroyedDXUTSetCallbackDeviceCreated創建了的回調函數,那麼框架不能夠重建設備,因爲它將沒有辦法通知應用程序,設備被釋放或重建了。在這種情況下,更改設備或在halreference devices之間轉換將無法工作。

同樣,如果程序沒有註冊丟棄的設備並且設備調用:DXUTSetCallbackDeviceLostDXUTSetCallbackDeviceReset重置回調函數。那麼當設備丟棄和重置時,框架將沒有辦法通知程序。在這種情況下,如果所有的設備對象不在D3DPOOL_MANAGED類型的內存裏,重置設備將導致Direct3D失敗。

同樣注意,如果應用程序使用DXUTCreateDevice函數,它不需要調用DXUTSetCallbackDeviceChanging,因爲框架將會記得LPDXUTCALLBACKMODIFYDEVICESETTINGS函數。

框架事件

DXUT框架同樣提供框架事件,它在渲染過程期間的每幀中調用。應用程序將註冊並實現下列的回調函數:

 

 

 

 

 

 

應用程序回調函數

回調註冊函數

框架調用的時間

場景渲染

LPDXUTCALLBACKFRAMEMOVE

DXUTSetCallbackFrameMove

每幀開始的時候調用一次

這個回調函數是程序更新場景最好的地方, 但它不包括實際的渲染調用, 它在框架的渲染回調函數 (LPDXUTCALLBACKFRAMERENDER) 裏。

LPDXUTCALLBACKFRAMERENDER

DXUTSetCallbackFrameRender

如果窗口需要重畫時,在每幀結束的時候調用。

將在這個回調函數裏執行所有場景的渲染調用。 這個回調函數返回後,框架將調用Present 來顯示在交換鏈中的下個緩衝區的內容。

消息事件

框架通過回調函數和相應的註冊函數傳遞窗口消息,鍵盤事件和鼠標事件。編寫程序以提供響應事件。

應用程序回調函數

回調註冊函數

描述

LPDXUTCALLBACKMSGPROC

DXUTSetCallbackMsgProc

DXUT消息隊列中處理窗口消息。

LPDXUTCALLBACKKEYBOARD

DXUTSetCallbackKeyboard

DXUT消息隊列中處理鍵盤消息。

LPDXUTCALLBACKMOUSE

DXUTSetCallbackMouse

DXUT消息隊列中處理鼠標消息。

 

 

處理DXUT的錯誤

本主題包括被推薦的過程,該過程處理從DXUT程序中返回的錯誤。

·         錯誤處理效率

·         錯誤消息

錯誤處理效率

Direct3D API的設計使處理失敗更容易。即使大部分基本的Direct3D API函數返回HRESULTs值,API被設計成只有少數的方法和函數返回設備錯誤,如:D3DERR_DEVICELOSTD3DERR_DRIVERINTERNALERROR。然而,一個典型的Direct3D應用程序將使用許多不同的API方法和函數,當傳遞了錯誤的參數會返回D3DERR_INVALIDCALL

當一個Direct3D應用程序開發時,應該檢測所有的API調用是否失敗,如果失敗發生那麼函數將是無法預期的,程序應該設計成立即通知開發者或記錄錯誤。這樣當API函數調用出錯時,開發者可以很快捕捉到出錯位置。然而對於一個穩定的程序,大多數Direct3D API函數能夠正確的調用並安全的忽略錯誤代碼,在一些關鍵API函數中返回錯誤並處理異常,例如:Present TestCooperativeLevel

因爲只有少數代碼需要進行錯誤處理,因此在處理大部分重要的Direct3D函數時,你能夠改善執行速度並使程序代碼更有預見性、更強壯。在其他少數的API函數中必須對失敗進行正確的處理,例如:Present,它是在框架內部處理的。

錯誤消息

框架中的錯誤處理,在Direct3D API的設計中是如何匹配錯誤處理的(Error handling in the framework matches how error handling in the Direct3D API was designed.)。對於嚴重的錯誤,例如:缺少媒體資源,程序會通知用戶並終止。對於在每一幀中調用的大多數API函數,錯誤處理僅僅是在debug編譯版本中給開發者顯示一個錯誤對話框。對於更詳細的builds,這些錯誤是被忽視的。框架用在Dxstdafx.h中定義的幾個宏來完成:

#if defined(DEBUG) | defined(_DEBUG)

    #define V(x)

    {

        hr = x;

        if( FAILED(hr) )

        {

            DXUTTrace( __FILE__, (DWORD)__LINE__, hr, L#x, TRUE );

        }

    }

    #define V_RETURN(x)

    {

        hr = x;

        if( FAILED(hr) )

        {

            return DXUTTrace( __FILE__, (DWORD)__LINE__, hr, L#x, TRUE );

        }

    }

#else

    #define V(x)

    {

        hr = x;

    {

    #define V_RETURN(x)

    {

        hr = x;

        if( FAILED(hr) )

        {

            return hr;

        }

    }

#endif

 

一個典型的程序可以像下面這樣使用V()宏:

V( g_pEffect->BeginPass( iPass ) );

V( g_pEffect->CommitChanges() );

V( g_pMesh->DrawSubset( 0 ) );

 

每個調用都使用V()宏,release編譯版本將忽視API返回的代碼。對於debug編譯版本,宏將顯示一個錯誤消息,類似下面這樣:

 1.  V()宏返回錯誤消息給debug編譯版本

 

編譯器的debug輸出窗口將顯示類似下面這樣的消息框:

 

c:/basichlsl/basichlsl.cpp(242):

D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,

    OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial",

    NULL ) hr=D3DERR_INVALIDCALL (0x8876086c)

   

當使用Visual Studio .NET時,只要在debug輸出窗口上簡單的雙擊這一行,就會跳過發生錯誤的那行代碼。

 

應用程序可以像下面這樣使用V_RETURN()宏:

V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str,

                                    NULL, NULL, dwShaderFlags,

                                    NULL, &g_pEffect, NULL ) );

 

這個宏將在debug編譯版本中顯示一個類似的錯誤消息,但對於release編譯版本將同樣返回任何失敗的HRESULT類型給調用函數。這些錯誤消息的顯示,能夠避開一個對DXUTInit的調用或下面的命令行參數:

-noerrormsgboxes

要了解更多宏的用法,請查看 Tutorials and Samples部分。

 

 

DXUT高級設備選擇

本主題包括控制使用DXUT創建Direct3D設備的高級細節。

·           選擇最佳的設備

·           控制設備選擇對話框

選擇最佳設備(Best Available Device)

DXUT使用高度靈活的方法從列表中選擇最佳的設備,這個設備列表和隊列系統可以獨立的使用,在每幀的空閒期間(rest of the framework)調用DXUTFindValidDeviceSettings函數:

HRESULT DXUTFindValidDeviceSettings(

    DXUTDeviceSettings* pOut,

    DXUTDeviceSettings* pIn,

    DXUTMatchOptions*   pMatchOptions )

PIn參數是一個已有的DXUTDeviceSettings結構的指針。PMatchOptions參數描述保存的是哪個輸入設備的設定,哪個最接近的有效設定將被匹配,當選擇當前最佳的設備時哪個設定將被忽視。

舉個例子,假如調用函數想有一個D3DFMT_A2B10G10R10格式的hal設備的後備緩衝區。如果系統中的hal設備不支持這個後備緩衝區格式,但reference設備已經安裝,函數在reference設備和更改爲與reference設備兼容的後備緩衝格式中做出選擇。匹配的選擇在DXUT_MATCH_TYPE列舉中,讓調用者控制如何選擇這些模式。

每個匹配的選項(查看DXUTMatchOptions) 必須是下列類型之一:

DXUT_MATCH_TYPE

描述

DXUTMT_IGNORE_INPUT

爲默認的設備設定使用最接近有效值的值。

DXUTMT_PRESERVE_INPUT

使用沒改變的輸入參數,沒有找到有效的設備是可能的。

DXUTMT_CLOSEST_TO_INPUT

爲輸入使用最接近有效值的值。

如果pMatchOptionsNULL,那麼所有匹配選項是DXUTMT_IGNORE_INPUT。如果沒能找到有效的設備設定,DXUTFindValidDeviceSettings返回一個失敗的代碼;否則,函數返回成功的代碼,有效的設備設定被寫到pOut參數裏。

控制設備選擇對話框

你可能想完全控制DXUT設備選擇對話框中列出的,選項列表中選擇的項目。例如,可能是通知設備選擇對話框,程序需要一個模版緩衝。

在框架的設備選擇對話框中控制選項的列表,可以使用LPDXUTCALLBACKISDEVICEACCEPTABLE回調函數。將允許你去控制設備設定的哪個組合(adapter ordinal, device type, adapter format, back buffer format, and windowed)。在設備選擇對話框中控制其他設定,你可以使用CD3Denumeration類的成員函數,它定義在DXUTenum.cpp文件中,公佈在下面的頭文件中:

(SDK root)/Samples/C++/Common/DXUTenum.h

舉個例子,在對話框中控制深度緩衝區格式,你可以使用下列代碼:

CGrowableArray<D3DFORMAT>* pDSList;

pDSList = DXUTGetEnumeration()->GetPossibleDepthStencilFormatList();

 

nIndex = pDSList->IndexOf( D3DFMT_D16 );

if( nIndex >= 0 ) pDSList->Remove( nIndex );

 

nIndex = pDSList->IndexOf( D3DFMT_D24X8 );

if( nIndex >= 0 ) pDSList->Remove( nIndex );

 

nIndex = pDSList->IndexOf( D3DFMT_D24S8 );

if( nIndex >= 0 ) pDSList->Remove( nIndex );

調用CD3Denumeratio類的函數,像這個例子代碼,必須在設備創建以前使用。

DXUT高級功能

下面可選擇的函數允許你更改CXUT的行爲、取得內部變量。

Function

Description

Window Management

 

DXUTGetHINSTANCE

取得應用程序實例的句柄。

DXUTGetHWND

取得當前設備窗口的句柄。

DXUTGetHWNDFocus

取得焦點窗口的句柄。

DXUTGetHWNDDeviceFullScreen

取得全屏模式設備窗口的句柄。

DXUTGetHWNDDeviceWindowed

取得窗口模式設備窗口的句柄。.

DXUTGetWindowClientRect

取得應用程序設備窗口的矩形客戶區。

DXUTGetWindowTitle

取得應用程序窗口標題的指針。

DXUTIsWindowed

應用程序是否在窗口模式。

Device Management

 

DXUTSetCursorSettings

在全屏模式下爲鼠標的用法設置可選項。

DXUTSetMultimonSettings

在多顯示器下設置框架函數的行爲選項。

DXUTToggleFullscreen

應用程序的窗口和全屏模式間的轉換。

DXUTToggleREF

應用程序在 hal reference devices間的轉換。

DXUT Framework Management

 

DXUTResetFrameworkState

丟失所有先前的框架狀態,重置框架狀態(初始化默認狀態)。

DXUTShutdown

引發程序終止和框架的清除。

DXUTGetExitCode

取得框架出口代碼。

Direct3D Variable Retrieval

 

DXUTGetD3DObject

取得 IDirect3D9對象的指針。

DXUTGetD3DDevice

取得IDirect3DDevice9接口指針,描述當前設備。

DXUTGetDeviceSettings

取得DXUTDeviceSettings結構用來創建當前設備。

DXUTGetPresentParameters

取得當前設備的表示參數。

DXUTGetBackBufferSurfaceDesc

取得D3DSURFACE_DESC 接口的指針,描述當前適配器的後備緩衝區。

DXUTGetDeviceCaps

取得當前設備能力的D3DCAPS9 指針。

Statistics

 

DXUTGetFPS

取得當前每秒的幀數。

DXUTGetFrameStats

取得一個字符串指針,包含當前每秒幀數,resolution,後備緩衝區格式,深度/模版緩衝區格式。

DXUTGetDeviceStats

取得一個字符串指針,包含當前設備類型,頂點處理行爲,設備名稱。

Time

 

DXUTGetTime

取得當前時間()

DXUTGetElapsedTime

取得上一幀到現在所消耗的幀數。

DXUTSetConstantFrameTime

使用或禁用一個幀與幀間的常量時間。

Timer

 

DXUTSetTimer

初始化一個新的時間器。

DXUTKillTimer

卸載一個已有的時間器。

Pause

 

DXUTPause

設置幀間時間並且/或者渲染過程的暫停狀態。

DXUTIsRenderingPaused

在當前的設備上是否渲染已經暫停。

DXUTIsTimePaused

在當前的設備上是否時間已經暫停。

User Input

 

DXUTIsKeyDown

當函數被調用時,指定的一個鍵盤鍵是否處在彈起或按下狀態。

DXUTIsMouseButtonDown

當函數被調用時,指定的一個鼠標鍵是否處在彈起或按下狀態。

 

 

DXUT參考

這節包含了在DXUTdxut.h頭文件中提供的基本的參考信息。DXUT創建Direct3D例子、原型、工具,並更容易的建立堅固、專業的遊戲。它簡化了窗口和Direct3D API的使用。

參考內容分爲下列部分:

·         函數

·         回調函數

·         結構

·         列舉

·         常量

See Also

DXUT概觀

 

 

函數(functions)

DXUT提供下列函數給應用程序使用:

·         DXUTCreateDevice

·         DXUTCreateDeviceFromSettings

·         DXUTCreateWindow

·         DXUTFindValidDeviceSettings

·         DXUTGetBackBufferSurfaceDesc

·         DXUTGetD3DDevice

·         DXUTGetD3DObject

·         DXUTGetDeviceCaps

·         DXUTGetDeviceSettings

·         DXUTGetDeviceStats

·         DXUTGetElapsedTime

·         DXUTGetExitCode

·         DXUTGetFPS

·         DXUTGetFrameStats

·         DXUTGetHINSTANCE

·         DXUTGetHWND

·         DXUTGetHWNDDeviceFullScreen

·         DXUTGetHWNDDeviceWindowed

·         DXUTGetHWNDFocus

·         DXUTGetPresentParameters

·         DXUTGetShowMsgBoxOnError

·         DXUTGetTime

·         DXUTGetWindowClientRect

·         DXUTGetWindowTitle

·         DXUTInit

·         DXUTIsKeyDown

·         DXUTIsMouseButtonDown

·         DXUTIsRenderingPaused

·         DXUTIsTimePaused

·         DXUTIsWindowed

·         DXUTKillTimer

·         DXUTMainLoop

·         DXUTPause

·         DXUTRender3DEnvironment

·         DXUTResetFrameworkState

·         DXUTSetCallbackDeviceChanging

·         DXUTSetCallbackDeviceCreated

·         DXUTSetCallbackDeviceDestroyed

·         DXUTSetCallbackDeviceLost

·         DXUTSetCallbackDeviceReset

·         DXUTSetCallbackFrameMove

·         DXUTSetCallbackFrameRender

·         DXUTSetCallbackKeyboard

·         DXUTSetCallbackMouse

·         DXUTSetCallbackMsgProc

·         DXUTSetConstantFrameTime

·         DXUTSetCursorSettings

·         DXUTSetDevice

·         DXUTSetMultimonSettings

·         DXUTSetTimer

·         DXUTSetWindow

·         DXUTShutdown

·         DXUTStaticWndProc

·         DXUTToggleFullscreen

·         DXUTToggleREF

 

回調函數(structures)

DXUT 提供下列回調函數,它們可以在應用程序中實現:

·         LPDXUTCALLBACKDEVICECREATED

·         LPDXUTCALLBACKDEVICEDESTROYED

·         LPDXUTCALLBACKDEVICELOST

·         LPDXUTCALLBACKDEVICERESET

·         LPDXUTCALLBACKFRAMEMOVE

·         LPDXUTCALLBACKFRAMERENDER

·         LPDXUTCALLBACKISDEVICEACCEPTABLE

·         LPDXUTCALLBACKKEYBOARD

·         LPDXUTCALLBACKMODIFYDEVICESETTINGS

·         LPDXUTCALLBACKMOUSE

·         LPDXUTCALLBACKMSGPROC

·         LPDXUTCALLBACKTIMER

 

結構(structures)

DXUT提供下列結構:

·         DXUTDeviceSettings

·         DXUTMatchOptions

 

列舉(Enumerations)

DXUT提供下列列舉類型:

·         DXUT_MATCH_TYPE

 

常量(Constants)

DXUT 提供下列常量:

·         DXUTERR

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章