在窗口和設(shè)備創(chuàng)建好之后,應(yīng)用程序需要使用消息循環(huán)處理窗口消息、更新和渲染場景、處理設(shè)備事件。應(yīng)用程序可以實現(xiàn)自己的消息循環(huán),也可以使用DXUT消息循環(huán),注冊相應(yīng)的回調(diào)函數(shù),可以讓DXUT處理設(shè)備、幀消息事件。
進(jìn)入消息循環(huán)
為使用DXUT框架的消息循環(huán),可以調(diào)用DXUTMainLoop()函數(shù):
Starts the main execution loop of DXUT.
HRESULT DXUTMainLoop(
HACCEL hAccel
) ;
Parameters
- hAccel
- [in] Handle to an accelerator table to use in
translating keyboard messages from the Windows message queue, or NULL if not
using an accelerator table. The default value is NULL.
Return Values
If the function succeeds, the return value is S_OK. If
the function fails, the return value can be one of the error codes in DXUTERR.
Remarks
This function starts the message loop that will run for
the lifetime of the application. During execution, DXUTMainLoop
calls the registered callback functions to ask the application to update and
render the frame, as well as handle any device or input events.
Custom Main Loop
For some advanced applications a custom main loop may be a better design. It
is possible to use DXUT with a custom main loop. An example of how to do this is
shown below.
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )
{
DXUTSetCallbackD3D9DeviceAcceptable( IsDeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnCreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnResetDevice );
DXUTSetCallbackD3D9FrameRender( OnFrameRender );
DXUTSetCallbackD3D9DeviceLost( OnLostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTInit( true, true );
DXUTCreateWindow( L"Example" );
DXUTCreateDevice( true, 640, 480 );
// Custom main loop
HWND hWnd = DXUTGetHWND();
BOOL bGotMsg;
MSG msg;
msg.message = WM_NULL;
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
while( WM_QUIT != msg.message )
{
// Use PeekMessage() so we can use idle time to render the scene
bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
if( bGotMsg )
{
// Translate and dispatch the message
if( 0 == TranslateAccelerator( hWnd, NULL, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
// Render a frame during idle time (no messages are waiting)
DXUTRender3DEnvironment();
}
}
return DXUTGetExitCode();
}
This example calls DXUTRender3DEnvironment to have DXUT update and render the
scene and handle device events. While it is possible for the application to
completely replicate this functionality, it is not recommended.
DXUTRender3DEnvironment
Renders the 3D environment.
VOID DXUTRender3DEnvironment() ;
Parameters
None.
Return Values
No return value.
Remarks
This method does not normally need to be called. It is
useful only when the application does not use DXUTMainLoop but still wants DXUT
to assist with rendering.
This method checks whether the device is lost. If so,
the method attempts to reset the device and then calls the
LPDXUTCALLBACKFRAMEMOVE and LPDXUTCALLBACKD3D10FRAMERENDER callback functions.
If the application window is minimized or the
application is paused, CPU time is yielded to other processes.
處理事件
框架使用回調(diào)函數(shù)機(jī)制來使應(yīng)用程序?qū)κ录龀龇磻?yīng)。應(yīng)用程序只需對框架注冊和設(shè)置相應(yīng)的函數(shù)指針,則當(dāng)事件發(fā)生時,框架就會調(diào)用相應(yīng)的函數(shù)。框架不需要注冊所有的回調(diào)函數(shù),所以應(yīng)用程序只須對所需要的回調(diào)函數(shù)進(jìn)行注冊即可。通過為回調(diào)函數(shù)設(shè)置參數(shù)pUserContext,回調(diào)函數(shù)可以從應(yīng)用程序接受內(nèi)容,比如將該參數(shù)設(shè)置為一個指向類對象的指針。
DXUT框架可以處理以下事件類型:
(1)設(shè)備事件
當(dāng)應(yīng)用程序使用Direct3D設(shè)備渲染圖形時,該設(shè)備有可能處于丟失狀態(tài)。這種情況的發(fā)生有多種原因,例如按下Alt +
Tab鍵離開一個全屏模式的應(yīng)用程序,或者按下Ctrl + Alt +
Del鍵,或者啟動了另一個全屏3D應(yīng)用程序。發(fā)生這種情況時,當(dāng)調(diào)用一些函數(shù)(如Present)時,Direct3D
API通過返回D3DERR_DEVICELOST通知應(yīng)用程序設(shè)備丟失。
當(dāng)設(shè)備丟失時,應(yīng)用程序負(fù)責(zé)釋放所有不能在設(shè)備丟失時存在的Direct3D資源對象,如在D3DPOOL_DEFAULT內(nèi)存池中創(chuàng)建的對象。如果沒有釋放這些對象,那么該設(shè)備從丟失狀態(tài)返回時就不能被重新設(shè)置。當(dāng)設(shè)備丟失時,應(yīng)用程序必須等待。當(dāng)設(shè)備返回時,應(yīng)用程序必須調(diào)用函數(shù)
IDirect3DDevice9::Reset(),并重新創(chuàng)建所有不能在Reset()函數(shù)中存在的對象。
通過DXUT框架,這個過程可以通過在應(yīng)用程序中使用回調(diào)函數(shù)來簡化,這些回調(diào)函數(shù)處理各種設(shè)備事件:設(shè)備改變、創(chuàng)建、重新設(shè)置、丟失或銷毀。當(dāng)設(shè)備丟失時,框架會有提示;當(dāng)它從丟失狀態(tài)返回時,框架會適當(dāng)調(diào)用相應(yīng)的回調(diào)函數(shù),重新設(shè)置該設(shè)備,即框架使用應(yīng)用程序的回調(diào)函數(shù)在適當(dāng)?shù)臅r間釋放和重新創(chuàng)建設(shè)備對象。應(yīng)用程序需要做的是注冊并實現(xiàn)相關(guān)回調(diào)函數(shù),各回調(diào)函數(shù)的類型、注冊、調(diào)用時機(jī)等細(xì)節(jié)見下表:
注冊函數(shù) |
應(yīng)用程序回調(diào)函數(shù) |
框架調(diào)用時機(jī) |
創(chuàng)建資源 |
釋放資源 |
DXUTSetCallback-
DeviceChanging |
LPDXUTCALLBACK-
MODIFYDEVICESETTINGS |
在創(chuàng)建Direct3D設(shè)備之前調(diào)用,應(yīng)用程序可以返回FALSE,拒絕改變該設(shè)備。 |
x |
x |
DXUTSetCallback-
D3D9DeviceCreated |
LPDXUTCALLBACK-
D3D9DEVICECREATED |
當(dāng)應(yīng)用程序初始化和重新創(chuàng)建設(shè)備時,在Direct3D設(shè)備創(chuàng)建之后立即調(diào)用。 |
創(chuàng)建D3DPOOL_MANAGED資源,因為這些資源無論什么時候被銷毀都需要重新加載,但這些資源被重新設(shè)置時不需要重新加載。在這里創(chuàng)建的資源需要在LPDXUTCALLBACK-DEVICEDESTROYED中釋放。 |
x |
DXUTSetCallback-
D3D9DeviceReset |
LPDXUTCALLBACK-
D3D9DEVICERESET |
當(dāng)Direct3D設(shè)備丟失又被重新設(shè)置后立即調(diào)用。 |
創(chuàng)建D3DPOOL_DEFAULT資源,因為這些資源無論什么時候丟失或重新設(shè)置時都需要重新加載,在這里創(chuàng)建的資源需要在LPDXUTCALLBACK-DEVICELOST中釋放。 |
x |
DXUTSetCallback-
D3D9DeviceLost |
LPDXUTCALLBACK-
D3D9DEVICELOST |
當(dāng)Direct3D設(shè)備變?yōu)閬G失狀態(tài)且在Reset調(diào)用之前,立即調(diào)用。 |
x |
釋放在回調(diào)函數(shù)LPDXUTCALLBACK-D3D9DEVICERESET中創(chuàng)建的資源,這些資源通常包括所有的D3DPOOL_DEFAULT資源。 |
DXUTSetCallback-
D3D9DeviceDestroyed |
LPDXUTCALLBACK-
D3D9DEVICEDESTROYED |
當(dāng)應(yīng)用程序終止或重新創(chuàng)建設(shè)備時,Direct3D設(shè)備被銷毀后,立即調(diào)用。 |
x |
釋放在回調(diào)函數(shù)LPDXUTCALLBACK-
D3D9DEVICECREATED中創(chuàng)建的資源,這些資源通常包括所有的D3DPOOL_MANAGED資源。 |
當(dāng)設(shè)備在窗口和全屏模式間切換時常常需要重新設(shè)置,但有時它必須通過Direct3D重新創(chuàng)建。
調(diào)用這些回調(diào)函數(shù)是可選的,但如果應(yīng)用程序沒有使用函數(shù)DXUTSetCallbackD3D9DeviceDestroyed()和
DXUTSetCallbackD3D9DeviceCreated()注冊銷毀回調(diào)函數(shù)和創(chuàng)建回調(diào)函數(shù),則改變設(shè)備或在硬件抽象層設(shè)備和參考設(shè)備間切換都不能進(jìn)行。
類似地,如果沒有用函數(shù)DXUTSetCallbackD3D9DeviceLost()和
DXUTSetCallbackD3D9DeviceReset()注冊丟失回調(diào)函數(shù)和重置回調(diào)函數(shù),則當(dāng)設(shè)備丟失或重置設(shè)備時,框架無法通知應(yīng)用程序。這樣一來,所有不在D3DPOOL_MANAGED內(nèi)存中的設(shè)備對象都不能重新設(shè)置。