這里要討論的是,DXUT中的一般框架。以前看了很多資料了,講得十分詳細。不過我在這里就把一些簡單的東西總結一下,比如DXUT的工作機制以及模式。對只想了解一下并且快速上手使用的人應該很有幫助。
下面要說的只是我自己自學以及領悟到的內容而已,難免有疏漏和錯誤,希望讀者可以幫我指出。
DXUT,就是DirectX SDK中附帶的一個功能齊全的Direct3D底層框架,有各種語言版本,但其實構架都差不多。這里以C++的為標準,SDK版本為June 2008。
先把DirectX SDK里的EmptyProject安裝了,打開工程。
簡單了解的話,只用來看一下這個DXUT.h,我再稍微說一下就應該大概明白了。
不要被代碼嚇住!!!往后看吧。這個代碼是拿來對照講的。
1
//--------------------------------------------------------------------------------------
2
// File: DXUT.h
3
//
4
// Copyright (c) Microsoft Corporation. All rights reserved.
5
//--------------------------------------------------------------------------------------
6
#pragma once
7
#ifndef DXUT_H
8
#define DXUT_H
9
10
#ifndef UNICODE
11
#error "DXUT requires a Unicode build. See the nearby comments for details"
12
//
13
// If you are using Microsoft Visual C++ .NET, under the General tab of the project
14
// properties change the Character Set to 'Use Unicode Character Set'.
15
//
16
// Windows XP and later are native Unicode so Unicode applications will perform better.
17
// For Windows 98 and Windows Me support, consider using the Microsoft Layer for Unicode (MSLU).
18
//
19
// To use MSLU, link against a set of libraries similar to this
20
// /nod:kernel32.lib /nod:advapi32.lib /nod:user32.lib /nod:gdi32.lib /nod:shell32.lib /nod:comdlg32.lib /nod:version.lib /nod:mpr.lib /nod:rasapi32.lib /nod:winmm.lib /nod:winspool.lib /nod:vfw32.lib /nod:secur32.lib /nod:oleacc.lib /nod:oledlg.lib /nod:sensapi.lib UnicoWS.lib kernel32.lib advapi32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib version.lib mpr.lib rasapi32.lib winmm.lib winspool.lib vfw32.lib secur32.lib oleacc.lib oledlg.lib sensapi.lib dxerr.lib dxguid.lib d3dx9d.lib d3d9.lib comctl32.lib dsound.lib
21
// and put the unicows.dll (available for download from msdn.microsoft.com) in the exe's folder.
22
//
23
// For more details see the MSDN article titled:
24
// "MSLU: Develop Unicode Applications for Windows 9x Platforms with the Microsoft Layer for Unicode"
25
// at http://msdn.microsoft.com/msdnmag/issues/01/10/MSLU/default.aspx
26
//
27
#endif
28
29
//--------------------------------------------------------------------------------------
30
// Structs
31
//--------------------------------------------------------------------------------------
32
class CD3DEnumeration;
33
34
struct DXUTDeviceSettings
35

{
36
UINT AdapterOrdinal;
37
D3DDEVTYPE DeviceType;
38
D3DFORMAT AdapterFormat;
39
DWORD BehaviorFlags;
40
D3DPRESENT_PARAMETERS pp;
41
};
42
43
44
//--------------------------------------------------------------------------------------
45
// Error codes
46
//--------------------------------------------------------------------------------------
47
#define DXUTERR_NODIRECT3D MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0901)
48
#define DXUTERR_NOCOMPATIBLEDEVICES MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0902)
49
#define DXUTERR_MEDIANOTFOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0903)
50
#define DXUTERR_NONZEROREFCOUNT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0904)
51
#define DXUTERR_CREATINGDEVICE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0905)
52
#define DXUTERR_RESETTINGDEVICE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0906)
53
#define DXUTERR_CREATINGDEVICEOBJECTS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0907)
54
#define DXUTERR_RESETTINGDEVICEOBJECTS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0908)
55
#define DXUTERR_INCORRECTVERSION MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0909)
56
57
58
//--------------------------------------------------------------------------------------
59
// Callback registration
60
//--------------------------------------------------------------------------------------
61
typedef bool (CALLBACK *LPDXUTCALLBACKISDEVICEACCEPTABLE)( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext );
62
typedef bool (CALLBACK *LPDXUTCALLBACKMODIFYDEVICESETTINGS)( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext );
63
typedef HRESULT (CALLBACK *LPDXUTCALLBACKDEVICECREATED)( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
64
typedef HRESULT (CALLBACK *LPDXUTCALLBACKDEVICERESET)( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
65
typedef void (CALLBACK *LPDXUTCALLBACKDEVICEDESTROYED)( void* pUserContext );
66
typedef void (CALLBACK *LPDXUTCALLBACKDEVICELOST)( void* pUserContext );
67
typedef void (CALLBACK *LPDXUTCALLBACKFRAMEMOVE)( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
68
typedef void (CALLBACK *LPDXUTCALLBACKFRAMERENDER)( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
69
typedef void (CALLBACK *LPDXUTCALLBACKKEYBOARD)( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
70
typedef void (CALLBACK *LPDXUTCALLBACKMOUSE)( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos, void* pUserContext );
71
typedef LRESULT (CALLBACK *LPDXUTCALLBACKMSGPROC)( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext );
72
typedef void (CALLBACK *LPDXUTCALLBACKTIMER)( UINT idEvent, void* pUserContext );
73
74
// Device callbacks
75
void DXUTSetCallbackDeviceCreated( LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated, void* pUserContext = NULL );
76
void DXUTSetCallbackDeviceReset( LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset, void* pUserContext = NULL );
77
void DXUTSetCallbackDeviceLost( LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost, void* pUserContext = NULL );
78
void DXUTSetCallbackDeviceDestroyed( LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed, void* pUserContext = NULL );
79
void DXUTSetCallbackDeviceChanging( LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings, void* pUserContext = NULL );
80
81
// Frame callbacks
82
void DXUTSetCallbackFrameMove( LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove, void* pUserContext = NULL );
83
void DXUTSetCallbackFrameRender( LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender, void* pUserContext = NULL );
84
85
// Message callbacks
86
void DXUTSetCallbackKeyboard( LPDXUTCALLBACKKEYBOARD pCallbackKeyboard, void* pUserContext = NULL );
87
void DXUTSetCallbackMouse( LPDXUTCALLBACKMOUSE pCallbackMouse, bool bIncludeMouseMove = false, void* pUserContext = NULL );
88
void DXUTSetCallbackMsgProc( LPDXUTCALLBACKMSGPROC pCallbackMsgProc, void* pUserContext = NULL );
89
90
91
//--------------------------------------------------------------------------------------
92
// Initialization
93
//--------------------------------------------------------------------------------------
94
HRESULT DXUTInit( bool bParseCommandLine = true, bool bHandleDefaultHotkeys = true, bool bShowMsgBoxOnError = true, bool bHandleAltEnter = true );
95
96
// Choose either DXUTCreateWindow or DXUTSetWindow. If using DXUTSetWindow, consider using DXUTStaticWndProc
97
HRESULT DXUTCreateWindow( const WCHAR* strWindowTitle = L"Direct3D Window",
98
HINSTANCE hInstance = NULL, HICON hIcon = NULL, HMENU hMenu = NULL,
99
int x = CW_USEDEFAULT, int y = CW_USEDEFAULT );
100
HRESULT DXUTSetWindow( HWND hWndFocus, HWND hWndDeviceFullScreen, HWND hWndDeviceWindowed, bool bHandleMessages = true );
101
LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
102
103
// Choose either DXUTCreateDevice or DXUTSetDevice or DXUTCreateDeviceFromSettings
104
HRESULT DXUTCreateDevice( UINT AdapterOrdinal = D3DADAPTER_DEFAULT, bool bWindowed = true,
105
int nSuggestedWidth = 0, int nSuggestedHeight = 0,
106
LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable = NULL,
107
LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = NULL,
108
void* pUserContext = NULL );
109
HRESULT DXUTCreateDeviceFromSettings( DXUTDeviceSettings* pDeviceSettings, bool bPreserveInput = false, bool bClipWindowToSingleAdapter = true );
110
HRESULT DXUTSetDevice( IDirect3DDevice9* pd3dDevice );
111
112
// Choose either DXUTMainLoop or implement your own main loop
113
HRESULT DXUTMainLoop( HACCEL hAccel = NULL );
114
115
// If not using DXUTMainLoop consider using DXUTRender3DEnvironment
116
void DXUTRender3DEnvironment();
117
118
119
//--------------------------------------------------------------------------------------
120
// Finding valid device settings
121
//--------------------------------------------------------------------------------------
122
enum DXUT_MATCH_TYPE
123

{
124
DXUTMT_IGNORE_INPUT = 0, // Use the closest valid value to a default
125
DXUTMT_PRESERVE_INPUT, // Use input without change, but may cause no valid device to be found
126
DXUTMT_CLOSEST_TO_INPUT // Use the closest valid value to the input
127
};
128
129
struct DXUTMatchOptions
130

{
131
DXUT_MATCH_TYPE eAdapterOrdinal;
132
DXUT_MATCH_TYPE eDeviceType;
133
DXUT_MATCH_TYPE eWindowed;
134
DXUT_MATCH_TYPE eAdapterFormat;
135
DXUT_MATCH_TYPE eVertexProcessing;
136
DXUT_MATCH_TYPE eResolution;
137
DXUT_MATCH_TYPE eBackBufferFormat;
138
DXUT_MATCH_TYPE eBackBufferCount;
139
DXUT_MATCH_TYPE eMultiSample;
140
DXUT_MATCH_TYPE eSwapEffect;
141
DXUT_MATCH_TYPE eDepthFormat;
142
DXUT_MATCH_TYPE eStencilFormat;
143
DXUT_MATCH_TYPE ePresentFlags;
144
DXUT_MATCH_TYPE eRefreshRate;
145
DXUT_MATCH_TYPE ePresentInterval;
146
};
147
148
HRESULT DXUTFindValidDeviceSettings( DXUTDeviceSettings* pOut, DXUTDeviceSettings* pIn = NULL, DXUTMatchOptions* pMatchOptions = NULL );
149
150
151
//--------------------------------------------------------------------------------------
152
// Common Tasks
153
//--------------------------------------------------------------------------------------
154
void DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen );
155
void DXUTSetMultimonSettings( bool bAutoChangeAdapter );
156
void DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen = false, bool bAllowWhenWindowed = true ); // Controls the Windows key, and accessibility shortcut keys
157
void DXUTSetWindowSettings( bool bCallDefWindowProc = true );
158
void DXUTSetConstantFrameTime( bool bConstantFrameTime, float fTimePerFrame = 0.0163f );
159
HRESULT DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs = 1.0f, UINT* pnIDEvent = NULL, void* pCallbackUserContext = NULL );
160
HRESULT DXUTKillTimer( UINT nIDEvent );
161
HRESULT DXUTToggleFullScreen();
162
HRESULT DXUTToggleREF();
163
void DXUTPause( bool bPauseTime, bool bPauseRendering );
164
void DXUTResetFrameworkState();
165
void DXUTShutdown( int nExitCode = 0 );
166
167
168
//--------------------------------------------------------------------------------------
169
// State Retrieval
170
//--------------------------------------------------------------------------------------
171
IDirect3D9* DXUTGetD3DObject(); // Does not addref unlike typical Get* APIs
172
IDirect3DDevice9* DXUTGetD3DDevice(); // Does not addref unlike typical Get* APIs
173
DXUTDeviceSettings DXUTGetDeviceSettings();
174
D3DPRESENT_PARAMETERS DXUTGetPresentParameters();
175
const D3DSURFACE_DESC* DXUTGetBackBufferSurfaceDesc();
176
const D3DCAPS9* DXUTGetDeviceCaps();
177
HINSTANCE DXUTGetHINSTANCE();
178
HWND DXUTGetHWND();
179
HWND DXUTGetHWNDFocus();
180
HWND DXUTGetHWNDDeviceFullScreen();
181
HWND DXUTGetHWNDDeviceWindowed();
182
RECT DXUTGetWindowClientRect();
183
RECT DXUTGetWindowClientRectAtModeChange(); // Useful for returning to windowed mode with the same resolution as before toggle to full screen mode
184
RECT DXUTGetFullsceenClientRectAtModeChange(); // Useful for returning to full screen mode with the same resolution as before toggle to windowed mode
185
double DXUTGetTime();
186
float DXUTGetElapsedTime();
187
bool DXUTIsWindowed();
188
float DXUTGetFPS();
189
LPCWSTR DXUTGetWindowTitle();
190
LPCWSTR DXUTGetFrameStats( bool bIncludeFPS = false );
191
LPCWSTR DXUTGetDeviceStats();
192
bool DXUTIsRenderingPaused();
193
bool DXUTIsTimePaused();
194
bool DXUTIsActive();
195
int DXUTGetExitCode();
196
bool DXUTGetShowMsgBoxOnError();
197
bool DXUTGetHandleDefaultHotkeys();
198
bool DXUTIsKeyDown( BYTE vKey ); // Pass a virtual-key code, ex. VK_F1, 'A', VK_RETURN, VK_LSHIFT, etc
199
bool DXUTIsMouseButtonDown( BYTE vButton ); // Pass a virtual-key code: VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2
200
bool DXUTGetAutomation(); // Returns true if -automation parameter is used to launch the app
201
202
#endif
203
204
205
206
207
千萬別被代碼嚇住。對于不需要深入理解的我們來說,大多數都是不需要關心的。如果您需要深入理解的話,我非常抱歉我幫不上忙。在CPPBLOG里面有個標題為“天行健 君子當自強不息”的一個BLOG里面有專門詳細解析DXUT的文章。鏈接請自己百度一下吧。
于是我們來關注一下這個優美的框架。它定義了很多回調函數,以及留了許多接口。
我們需要關心的是這幾個:
DXUTSetCallbackDeviceCreated
為框架掛接上Direct3D設備創建后的回調函數
DXUTSetCallbackDeviceReset
掛接Direct3D設備重置后的回調函數
DXUTSetCallbackDeviceLost
掛接Direct3D設備丟失后的回調函數
DXUTSetCallbackDeviceDestroyed
掛接Direct3D設備銷毀后的回調函數
DXUTSetCallbackFrameRender
掛接每幀渲染場景時的回調函數
DXUTSetCallbackFrameMove
掛接每幀渲染前需要更新場景時的回調函數
DXUTSetCallbackMouse
掛接鼠標事件的回調函數
DXUTSetCallbackKeyboard
掛接鍵盤事件的回調函數
于是我們打開EmptyProject.cpp
看著WinMain函數
1
//--------------------------------------------------------------------------------------
2
// Initialize everything and go into a render loop
3
//--------------------------------------------------------------------------------------
4
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
5

{
6
7
//設置回調函數
8
DXUTSetCallbackDeviceCreated( OnCreateDevice );
9
DXUTSetCallbackDeviceReset( OnResetDevice );
10
DXUTSetCallbackDeviceLost( OnLostDevice );
11
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
12
DXUTSetCallbackMsgProc( MsgProc );
13
DXUTSetCallbackFrameRender( OnFrameRender );
14
DXUTSetCallbackFrameMove( OnFrameMove );
15
DXUTSetCallbackMouse( OnMouseEvent ,true);//第二個參數是指是否包含鼠標移動事件
16
DXUTSetCallbackKeyboard( OnKeyEvent );
17
18
// 這里寫在程序底層初始化前需要的代碼
19
20
21
// 初始化DXUT、程序窗口、Direct3D設備
22
DXUTInit( true, false, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
23
DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
24
DXUTCreateWindow( “EmptyProject”);//窗口標題
25
DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );//創建設備
26
// 開始DXUT主循環
27
DXUTMainLoop();
28
29
// 這里寫清理底層的代碼
30
return DXUTGetExitCode();
31
}
看見了么,在這里掛接了需要的回調函數,不如我們將他們叫做“事件”,這樣更好理解。
自己看一下就能明白那些代碼的意思了
OnCreateDevice OnResetDevice OnLostDevice OnDestroyDevice MSgProc OnFrameRender OnFrameMove OnMouseEvent OnKetEvent
這些都是已經定義好的CALLBACK,我們的框架將從DXUTMainLoop()這里開始
簡單來說,我們需要了解的就只有這些事件的觸發順序了。
HRESULT CALLBACK OnCreateDevice( Device* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
這個事件在設備創建完畢時就會觸發,最先觸發的東西。第一個參數是創建后的設備,第二個是設備的表面參數。pUserContext不需要關心,因此不討論。下同。
HRESULT CALLBACK OnResetDevice( Device* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
這個事件在設備重置的時候會觸發。那么什么叫做設備重置呢?等下會和設備丟失一起說。第一個參數是重置后的設備,第二個是重置后設備的表面參數。
void CALLBACK OnLostDevice( void* pUserContext )
這個事件在設備丟失的時候會觸發。舉個簡單的例子,把窗口最小化的時候設備會丟失,而恢復的時候設備會重置。從全屏換為窗口的時候也會丟失并且重置。大概就是改變窗口的大小、位置、是否全屏的時候,會導致設備丟失,隨后恢復的時候會重置。這兩個事件的觸發就是為了在窗口改變的時候重新設置一些參數,讓畫面適應當前窗口設置。
void CALLBACK OnFrameMove( Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
這個事件在每幀繪制前會觸發,為的是更新場景信息。第一個參數是傳入的Direct3D設備,第二個參數是從第一次觸發這個事件到現在為止的時間,第三個參數是這次觸發此事件距上次的時間。
void CALLBACK OnFrameRender( Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
這個事件在每幀渲染屏幕的時候觸發。參數意義和OnFrameMove一樣。
void CALLBACK OnMouseEvent(bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down,
bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos, void* pUserContext)
這個事件在鼠標有動作的時候觸發。bLeftButtonDown:左鍵是否按下,bRighButtonDown:右鍵是否按下,bMiddleButtonDown:中間鍵是否按下,bSidebutton1Down:邊鍵1是否按下,bSideButton2Down:邊鍵2是否按下,nMouseWheelDelta:滾輪的滾動值,向手指指的方向滾動一格是-120,反之則為120,xPos:在窗口中的X坐標,yPos:在窗口中的Y坐標。
void CALLBACK OnKeyEvent( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
這個事件在鍵盤有動作的時候觸發。nChar:發生動作的鍵,bKeyDown:發生動作的鍵是被按下還是被抬起,bAltDown:Alt鍵是否同時被按下。
這些了解了后,你就可以開始干事兒了。你可以把上面的回調函數都當做事件來看,而且是多線程的,這樣更方便。
總結一下事件順序:

如上圖所示,DXUT的工作順序大概就是這樣。對于不需要深入了解DXUT工作細節來說,已經差不多了。
現在應該對框架的工作機制有一定得認識了,這篇簡單的文章也就這樣結束了。下一篇還是預告了吧,是在DXUT框架下,關于2D方面的東西。
順便說一些DXUT.h中比較實用的接口
163行:void DXUTPause( bool bPauseTime, bool bPauseRendering ); 讓OnFrameMove和OnFrameRender事件暫停或恢復觸發,第一個參數為是否停止計時,第二個為是否停止繪制。
178行:HWND DXUTGetHWND();獲取目前窗口句柄
182行:RECT DXUTGetWindowClientRect();
188行:float DXUTGetFPS();獲取當前的FPS(Frame Per second 每秒幀數)
差不多就這些。
以上的代碼在EmptyProject里面全部都有,這篇文章只是幫還沒有接觸過的新手入門而已。請勿鄙視,有任何意見和建議請提出,謝謝了。
現在已經傻瓜式地把框架搭建好了,并且可以簡單使用了。那么下一步該干嘛?干事兒唄。
下一篇:Direct3D中的簡單2D運用。有空再寫了,先預告了吧。