这里要讨论的是,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//--------------------------------------------------------------------------------------
32class CD3DEnumeration;
33
34struct 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//--------------------------------------------------------------------------------------
61typedef bool (CALLBACK *LPDXUTCALLBACKISDEVICEACCEPTABLE)( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext );
62typedef bool (CALLBACK *LPDXUTCALLBACKMODIFYDEVICESETTINGS)( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext );
63typedef HRESULT (CALLBACK *LPDXUTCALLBACKDEVICECREATED)( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
64typedef HRESULT (CALLBACK *LPDXUTCALLBACKDEVICERESET)( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
65typedef void (CALLBACK *LPDXUTCALLBACKDEVICEDESTROYED)( void* pUserContext );
66typedef void (CALLBACK *LPDXUTCALLBACKDEVICELOST)( void* pUserContext );
67typedef void (CALLBACK *LPDXUTCALLBACKFRAMEMOVE)( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
68typedef void (CALLBACK *LPDXUTCALLBACKFRAMERENDER)( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
69typedef void (CALLBACK *LPDXUTCALLBACKKEYBOARD)( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
70typedef void (CALLBACK *LPDXUTCALLBACKMOUSE)( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos, void* pUserContext );
71typedef LRESULT (CALLBACK *LPDXUTCALLBACKMSGPROC)( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext );
72typedef void (CALLBACK *LPDXUTCALLBACKTIMER)( UINT idEvent, void* pUserContext );
73
74// Device callbacks
75void DXUTSetCallbackDeviceCreated( LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated, void* pUserContext = NULL );
76void DXUTSetCallbackDeviceReset( LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset, void* pUserContext = NULL );
77void DXUTSetCallbackDeviceLost( LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost, void* pUserContext = NULL );
78void DXUTSetCallbackDeviceDestroyed( LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed, void* pUserContext = NULL );
79void DXUTSetCallbackDeviceChanging( LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings, void* pUserContext = NULL );
80
81// Frame callbacks
82void DXUTSetCallbackFrameMove( LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove, void* pUserContext = NULL );
83void DXUTSetCallbackFrameRender( LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender, void* pUserContext = NULL );
84
85// Message callbacks
86void DXUTSetCallbackKeyboard( LPDXUTCALLBACKKEYBOARD pCallbackKeyboard, void* pUserContext = NULL );
87void DXUTSetCallbackMouse( LPDXUTCALLBACKMOUSE pCallbackMouse, bool bIncludeMouseMove = false, void* pUserContext = NULL );
88void DXUTSetCallbackMsgProc( LPDXUTCALLBACKMSGPROC pCallbackMsgProc, void* pUserContext = NULL );
89
90
91//--------------------------------------------------------------------------------------
92// Initialization
93//--------------------------------------------------------------------------------------
94HRESULT 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
97HRESULT 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 );
100HRESULT DXUTSetWindow( HWND hWndFocus, HWND hWndDeviceFullScreen, HWND hWndDeviceWindowed, bool bHandleMessages = true );
101LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
102
103// Choose either DXUTCreateDevice or DXUTSetDevice or DXUTCreateDeviceFromSettings
104HRESULT 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 );
109HRESULT DXUTCreateDeviceFromSettings( DXUTDeviceSettings* pDeviceSettings, bool bPreserveInput = false, bool bClipWindowToSingleAdapter = true );
110HRESULT DXUTSetDevice( IDirect3DDevice9* pd3dDevice );
111
112// Choose either DXUTMainLoop or implement your own main loop
113HRESULT DXUTMainLoop( HACCEL hAccel = NULL );
114
115// If not using DXUTMainLoop consider using DXUTRender3DEnvironment
116void DXUTRender3DEnvironment();
117
118
119//--------------------------------------------------------------------------------------
120// Finding valid device settings
121//--------------------------------------------------------------------------------------
122enum 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
129struct 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
148HRESULT DXUTFindValidDeviceSettings( DXUTDeviceSettings* pOut, DXUTDeviceSettings* pIn = NULL, DXUTMatchOptions* pMatchOptions = NULL );
149
150
151//--------------------------------------------------------------------------------------
152// Common Tasks
153//--------------------------------------------------------------------------------------
154void DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen );
155void DXUTSetMultimonSettings( bool bAutoChangeAdapter );
156void DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen = false, bool bAllowWhenWindowed = true ); // Controls the Windows key, and accessibility shortcut keys
157void DXUTSetWindowSettings( bool bCallDefWindowProc = true );
158void DXUTSetConstantFrameTime( bool bConstantFrameTime, float fTimePerFrame = 0.0163f );
159HRESULT DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs = 1.0f, UINT* pnIDEvent = NULL, void* pCallbackUserContext = NULL );
160HRESULT DXUTKillTimer( UINT nIDEvent );
161HRESULT DXUTToggleFullScreen();
162HRESULT DXUTToggleREF();
163void DXUTPause( bool bPauseTime, bool bPauseRendering );
164void DXUTResetFrameworkState();
165void DXUTShutdown( int nExitCode = 0 );
166
167
168//--------------------------------------------------------------------------------------
169// State Retrieval
170//--------------------------------------------------------------------------------------
171IDirect3D9* DXUTGetD3DObject(); // Does not addref unlike typical Get* APIs
172IDirect3DDevice9* DXUTGetD3DDevice(); // Does not addref unlike typical Get* APIs
173DXUTDeviceSettings DXUTGetDeviceSettings();
174D3DPRESENT_PARAMETERS DXUTGetPresentParameters();
175const D3DSURFACE_DESC* DXUTGetBackBufferSurfaceDesc();
176const D3DCAPS9* DXUTGetDeviceCaps();
177HINSTANCE DXUTGetHINSTANCE();
178HWND DXUTGetHWND();
179HWND DXUTGetHWNDFocus();
180HWND DXUTGetHWNDDeviceFullScreen();
181HWND DXUTGetHWNDDeviceWindowed();
182RECT DXUTGetWindowClientRect();
183RECT DXUTGetWindowClientRectAtModeChange(); // Useful for returning to windowed mode with the same resolution as before toggle to full screen mode
184RECT DXUTGetFullsceenClientRectAtModeChange(); // Useful for returning to full screen mode with the same resolution as before toggle to windowed mode
185double DXUTGetTime();
186float DXUTGetElapsedTime();
187bool DXUTIsWindowed();
188float DXUTGetFPS();
189LPCWSTR DXUTGetWindowTitle();
190LPCWSTR DXUTGetFrameStats( bool bIncludeFPS = false );
191LPCWSTR DXUTGetDeviceStats();
192bool DXUTIsRenderingPaused();
193bool DXUTIsTimePaused();
194bool DXUTIsActive();
195int DXUTGetExitCode();
196bool DXUTGetShowMsgBoxOnError();
197bool DXUTGetHandleDefaultHotkeys();
198bool DXUTIsKeyDown( BYTE vKey ); // Pass a virtual-key code, ex. VK_F1, 'A', VK_RETURN, VK_LSHIFT, etc
199bool DXUTIsMouseButtonDown( BYTE vButton ); // Pass a virtual-key code: VK_LBUTTON, VK_RBUTTON, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2
200bool 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//--------------------------------------------------------------------------------------
4INT 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运用。有空再写了,先预告了吧。