1 //--------------------------------------------------------------------------------------
2 // File: DXUT.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //--------------------------------------------------------------------------------------
6 #include "dxstdafx.h"
7 #define DXUT_MIN_WINDOW_SIZE_X 200
8 #define DXUT_MIN_WINDOW_SIZE_Y 200
9 #undef min // use __min instead inside this source file
10 #undef max // use __max instead inside this source file
11
12 //--------------------------------------------------------------------------------------
13 // Thread safety
14 //--------------------------------------------------------------------------------------
15 CRITICAL_SECTION g_cs;
16 bool g_bThreadSafe = true;
17
18
19 //--------------------------------------------------------------------------------------
20 // Automatically enters & leaves the CS upon object creation/deletion
21 //--------------------------------------------------------------------------------------
22 class DXUTLock
23 {
24 public:
DXUTLock()25 inline DXUTLock() { if( g_bThreadSafe ) EnterCriticalSection( &g_cs ); }
~DXUTLock()26 inline ~DXUTLock() { if( g_bThreadSafe ) LeaveCriticalSection( &g_cs ); }
27 };
28
29
30
31 //--------------------------------------------------------------------------------------
32 // Helper macros to build member functions that access member variables with thread safety
33 //--------------------------------------------------------------------------------------
34 #define SET_ACCESSOR( x, y ) inline void Set##y( x t ) { DXUTLock l; m_state.m_##y = t; };
35 #define GET_ACCESSOR( x, y ) inline x Get##y() { DXUTLock l; return m_state.m_##y; };
36 #define GET_SET_ACCESSOR( x, y ) SET_ACCESSOR( x, y ) GET_ACCESSOR( x, y )
37
38 #define SETP_ACCESSOR( x, y ) inline void Set##y( x* t ) { DXUTLock l; m_state.m_##y = *t; };
39 #define GETP_ACCESSOR( x, y ) inline x* Get##y() { DXUTLock l; return &m_state.m_##y; };
40 #define GETP_SETP_ACCESSOR( x, y ) SETP_ACCESSOR( x, y ) GETP_ACCESSOR( x, y )
41
42
43 //--------------------------------------------------------------------------------------
44 // Stores timer callback info
45 //--------------------------------------------------------------------------------------
46 struct DXUT_TIMER
47 {
48 LPDXUTCALLBACKTIMER pCallbackTimer;
49 void* pCallbackUserContext;
50 float fTimeoutInSecs;
51 float fCountdown;
52 bool bEnabled;
53 UINT nID;
54 };
55
56
57 //--------------------------------------------------------------------------------------
58 // Stores DXUT state and data access is done with thread safety (if g_bThreadSafe==true)
59 //--------------------------------------------------------------------------------------
60 class DXUTState
61 {
62 protected:
63 struct STATE
64 {
65 IDirect3D9* m_D3D; // the main D3D object
66
67 IDirect3DDevice9* m_D3DDevice; // the D3D rendering device
68 CD3DEnumeration* m_D3DEnumeration; // CD3DEnumeration object
69
70 DXUTDeviceSettings* m_CurrentDeviceSettings; // current device settings
71 D3DSURFACE_DESC m_BackBufferSurfaceDesc; // back buffer surface description
72 D3DCAPS9 m_Caps; // D3D caps for current device
73
74 HWND m_HWNDFocus; // the main app focus window
75 HWND m_HWNDDeviceFullScreen; // the main app device window in fullscreen mode
76 HWND m_HWNDDeviceWindowed; // the main app device window in windowed mode
77 HMONITOR m_AdapterMonitor; // the monitor of the adapter
78 HMENU m_Menu; // handle to menu
79
80 UINT m_FullScreenBackBufferWidthAtModeChange; // back buffer size of fullscreen mode right before switching to windowed mode. Used to restore to same resolution when toggling back to fullscreen
81 UINT m_FullScreenBackBufferHeightAtModeChange; // back buffer size of fullscreen mode right before switching to windowed mode. Used to restore to same resolution when toggling back to fullscreen
82 UINT m_WindowBackBufferWidthAtModeChange; // back buffer size of windowed mode right before switching to fullscreen mode. Used to restore to same resolution when toggling back to windowed mode
83 UINT m_WindowBackBufferHeightAtModeChange; // back buffer size of windowed mode right before switching to fullscreen mode. Used to restore to same resolution when toggling back to windowed mode
84 DWORD m_WindowedStyleAtModeChange; // window style
85 WINDOWPLACEMENT m_WindowedPlacement; // record of windowed HWND position/show state/etc
86 bool m_TopmostWhileWindowed; // if true, the windowed HWND is topmost
87 bool m_Minimized; // if true, the HWND is minimized
88 bool m_Maximized; // if true, the HWND is maximized
89 bool m_MinimizedWhileFullscreen; // if true, the HWND is minimized due to a focus switch away when fullscreen mode
90 bool m_IgnoreSizeChange; // if true, DXUT won't reset the device upon HWND size change
91
92 double m_Time; // current time in seconds
93 double m_AbsoluteTime; // absolute time in seconds
94 float m_ElapsedTime; // time elapsed since last frame
95
96 HINSTANCE m_HInstance; // handle to the app instance
97 double m_LastStatsUpdateTime; // last time the stats were updated
98 DWORD m_LastStatsUpdateFrames; // frames count since last time the stats were updated
99 float m_FPS; // frames per second
100 int m_CurrentFrameNumber; // the current frame number
101 HHOOK m_KeyboardHook; // handle to keyboard hook
102 bool m_AllowShortcutKeysWhenFullscreen; // if true, when fullscreen enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut)
103 bool m_AllowShortcutKeysWhenWindowed; // if true, when windowed enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut)
104 bool m_AllowShortcutKeys; // if true, then shortcut keys are currently disabled (Windows key, etc)
105 bool m_CallDefWindowProc; // if true, DXUTStaticWndProc will call DefWindowProc for unhandled messages. Applications rendering to a dialog may need to set this to false.
106 STICKYKEYS m_StartupStickyKeys; // StickyKey settings upon startup so they can be restored later
107 TOGGLEKEYS m_StartupToggleKeys; // ToggleKey settings upon startup so they can be restored later
108 FILTERKEYS m_StartupFilterKeys; // FilterKey settings upon startup so they can be restored later
109
110 bool m_HandleDefaultHotkeys; // if true, then DXUT will handle some default hotkeys
111 bool m_HandleAltEnter; // if true, then DXUT will handle Alt-Enter
112 bool m_ShowMsgBoxOnError; // if true, then msgboxes are displayed upon errors
113 bool m_NoStats; // if true, then DXUTGetFrameStats() and DXUTGetDeviceStats() will return blank strings
114 bool m_ClipCursorWhenFullScreen; // if true, then DXUT will keep the cursor from going outside the window when full screen
115 bool m_ShowCursorWhenFullScreen; // if true, then DXUT will show a cursor when full screen
116 bool m_ConstantFrameTime; // if true, then elapsed frame time will always be 0.05f seconds which is good for debugging or automated capture
117 float m_TimePerFrame; // the constant time per frame in seconds, only valid if m_ConstantFrameTime==true
118 bool m_WireframeMode; // if true, then D3DRS_FILLMODE==D3DFILL_WIREFRAME else D3DRS_FILLMODE==D3DFILL_SOLID
119 bool m_AutoChangeAdapter; // if true, then the adapter will automatically change if the window is different monitor
120 bool m_WindowCreatedWithDefaultPositions; // if true, then CW_USEDEFAULT was used and the window should be moved to the right adapter
121 int m_ExitCode; // the exit code to be returned to the command line
122
123 bool m_DXUTInited; // if true, then DXUTInit() has succeeded
124 bool m_WindowCreated; // if true, then DXUTCreateWindow() or DXUTSetWindow() has succeeded
125 bool m_DeviceCreated; // if true, then DXUTCreateDevice*() or DXUTSetDevice() has succeeded
126
127 bool m_DXUTInitCalled; // if true, then DXUTInit() was called
128 bool m_WindowCreateCalled; // if true, then DXUTCreateWindow() or DXUTSetWindow() was called
129 bool m_DeviceCreateCalled; // if true, then DXUTCreateDevice*() or DXUTSetDevice() was called
130
131 bool m_DeviceObjectsCreated; // if true, then DeviceCreated callback has been called (if non-NULL)
132 bool m_DeviceObjectsReset; // if true, then DeviceReset callback has been called (if non-NULL)
133 bool m_InsideDeviceCallback; // if true, then the framework is inside an app device callback
134 bool m_InsideMainloop; // if true, then the framework is inside the main loop
135 bool m_Active; // if true, then the app is the active top level window
136 bool m_TimePaused; // if true, then time is paused
137 bool m_RenderingPaused; // if true, then rendering is paused
138 int m_PauseRenderingCount; // pause rendering ref count
139 int m_PauseTimeCount; // pause time ref count
140 bool m_DeviceLost; // if true, then the device is lost and needs to be reset
141 bool m_NotifyOnMouseMove; // if true, include WM_MOUSEMOVE in mousecallback
142 bool m_Automation; // if true, automation is enabled
143 bool m_InSizeMove; // if true, app is inside a WM_ENTERSIZEMOVE
144 UINT m_TimerLastID; // last ID of the DXUT timer
145
146 int m_OverrideAdapterOrdinal; // if != -1, then override to use this adapter ordinal
147 bool m_OverrideWindowed; // if true, then force to start windowed
148 bool m_OverrideFullScreen; // if true, then force to start full screen
149 int m_OverrideStartX; // if != -1, then override to this X position of the window
150 int m_OverrideStartY; // if != -1, then override to this Y position of the window
151 int m_OverrideWidth; // if != 0, then override to this width
152 int m_OverrideHeight; // if != 0, then override to this height
153 bool m_OverrideForceHAL; // if true, then force to HAL device (failing if one doesn't exist)
154 bool m_OverrideForceREF; // if true, then force to REF device (failing if one doesn't exist)
155 bool m_OverrideForcePureHWVP; // if true, then force to use pure HWVP (failing if device doesn't support it)
156 bool m_OverrideForceHWVP; // if true, then force to use HWVP (failing if device doesn't support it)
157 bool m_OverrideForceSWVP; // if true, then force to use SWVP
158 bool m_OverrideConstantFrameTime; // if true, then force to constant frame time
159 float m_OverrideConstantTimePerFrame; // the constant time per frame in seconds if m_OverrideConstantFrameTime==true
160 int m_OverrideQuitAfterFrame; // if != 0, then it will force the app to quit after that frame
161 int m_OverrideForceVsync; // if == 0, then it will force the app to use D3DPRESENT_INTERVAL_IMMEDIATE, if == 1 force use of D3DPRESENT_INTERVAL_DEFAULT
162 bool m_OverrideRelaunchMCE; // if true, then force relaunch of MCE at exit
163
164 LPDXUTCALLBACKISDEVICEACCEPTABLE m_IsDeviceAcceptableFunc; // is device acceptable callback
165 LPDXUTCALLBACKMODIFYDEVICESETTINGS m_ModifyDeviceSettingsFunc; // modify device settings callback
166 LPDXUTCALLBACKDEVICECREATED m_DeviceCreatedFunc; // device created callback
167 LPDXUTCALLBACKDEVICERESET m_DeviceResetFunc; // device reset callback
168 LPDXUTCALLBACKDEVICELOST m_DeviceLostFunc; // device lost callback
169 LPDXUTCALLBACKDEVICEDESTROYED m_DeviceDestroyedFunc; // device destroyed callback
170 LPDXUTCALLBACKFRAMEMOVE m_FrameMoveFunc; // frame move callback
171 LPDXUTCALLBACKFRAMERENDER m_FrameRenderFunc; // frame render callback
172 LPDXUTCALLBACKKEYBOARD m_KeyboardFunc; // keyboard callback
173 LPDXUTCALLBACKMOUSE m_MouseFunc; // mouse callback
174 LPDXUTCALLBACKMSGPROC m_WindowMsgFunc; // window messages callback
175
176 void* m_IsDeviceAcceptableFuncUserContext; // user context for is device acceptable callback
177 void* m_ModifyDeviceSettingsFuncUserContext; // user context for modify device settings callback
178 void* m_DeviceCreatedUserContext; // user context for device created callback
179 void* m_DeviceCreatedFuncUserContext; // user context for device created callback
180 void* m_DeviceResetFuncUserContext; // user context for device reset callback
181 void* m_DeviceLostFuncUserContext; // user context for device lost callback
182 void* m_DeviceDestroyedFuncUserContext; // user context for device destroyed callback
183 void* m_FrameMoveFuncUserContext; // user context for frame move callback
184 void* m_FrameRenderFuncUserContext; // user context for frame render callback
185 void* m_KeyboardFuncUserContext; // user context for keyboard callback
186 void* m_MouseFuncUserContext; // user context for mouse callback
187 void* m_WindowMsgFuncUserContext; // user context for window messages callback
188
189 bool m_Keys[256]; // array of key state
190 bool m_MouseButtons[5]; // array of mouse states
191
192 CGrowableArray<DXUT_TIMER>* m_TimerList; // list of DXUT_TIMER structs
193 WCHAR m_StaticFrameStats[256]; // static part of frames stats
194 WCHAR m_FPSStats[64]; // fps stats
195 WCHAR m_FrameStats[256]; // frame stats (fps, width, etc)
196 WCHAR m_DeviceStats[256]; // device stats (description, device type, etc)
197 WCHAR m_WindowTitle[256]; // window title
198 };
199
200 STATE m_state;
201
202 public:
DXUTState()203 DXUTState() { Create(); }
~DXUTState()204 ~DXUTState() { Destroy(); }
205
Create()206 void Create()
207 {
208 // Make sure these are created before DXUTState so they
209 // destroyed last because DXUTState cleanup needs them
210 DXUTGetGlobalResourceCache();
211
212 ZeroMemory( &m_state, sizeof(STATE) );
213 g_bThreadSafe = true;
214 InitializeCriticalSection( &g_cs );
215 m_state.m_OverrideStartX = -1;
216 m_state.m_OverrideStartY = -1;
217 m_state.m_OverrideAdapterOrdinal = -1;
218 m_state.m_OverrideForceVsync = -1;
219 m_state.m_AutoChangeAdapter = true;
220 m_state.m_ShowMsgBoxOnError = true;
221 m_state.m_AllowShortcutKeysWhenWindowed = true;
222 m_state.m_Active = true;
223 m_state.m_CallDefWindowProc = true;
224 }
225
Destroy()226 void Destroy()
227 {
228 DXUTShutdown();
229 DeleteCriticalSection( &g_cs );
230 }
231
232 // Macros to define access functions for thread safe access into m_state
233 GET_SET_ACCESSOR( IDirect3D9*, D3D );
234
235 GET_SET_ACCESSOR( IDirect3DDevice9*, D3DDevice );
236 GET_SET_ACCESSOR( CD3DEnumeration*, D3DEnumeration );
237 GET_SET_ACCESSOR( DXUTDeviceSettings*, CurrentDeviceSettings );
238 GETP_SETP_ACCESSOR( D3DSURFACE_DESC, BackBufferSurfaceDesc );
239 GETP_SETP_ACCESSOR( D3DCAPS9, Caps );
240
241 GET_SET_ACCESSOR( HWND, HWNDFocus );
242 GET_SET_ACCESSOR( HWND, HWNDDeviceFullScreen );
243 GET_SET_ACCESSOR( HWND, HWNDDeviceWindowed );
244 GET_SET_ACCESSOR( HMONITOR, AdapterMonitor );
245 GET_SET_ACCESSOR( HMENU, Menu );
246
247 GET_SET_ACCESSOR( UINT, FullScreenBackBufferWidthAtModeChange );
248 GET_SET_ACCESSOR( UINT, FullScreenBackBufferHeightAtModeChange );
249 GET_SET_ACCESSOR( UINT, WindowBackBufferWidthAtModeChange );
250 GET_SET_ACCESSOR( UINT, WindowBackBufferHeightAtModeChange );
251 GETP_SETP_ACCESSOR( WINDOWPLACEMENT, WindowedPlacement );
252 GET_SET_ACCESSOR( DWORD, WindowedStyleAtModeChange );
253 GET_SET_ACCESSOR( bool, TopmostWhileWindowed );
254 GET_SET_ACCESSOR( bool, Minimized );
255 GET_SET_ACCESSOR( bool, Maximized );
256 GET_SET_ACCESSOR( bool, MinimizedWhileFullscreen );
257 GET_SET_ACCESSOR( bool, IgnoreSizeChange );
258
259 GET_SET_ACCESSOR( double, Time );
260 GET_SET_ACCESSOR( double, AbsoluteTime );
261 GET_SET_ACCESSOR( float, ElapsedTime );
262
263 GET_SET_ACCESSOR( HINSTANCE, HInstance );
264 GET_SET_ACCESSOR( double, LastStatsUpdateTime );
265 GET_SET_ACCESSOR( DWORD, LastStatsUpdateFrames );
266 GET_SET_ACCESSOR( float, FPS );
267 GET_SET_ACCESSOR( int, CurrentFrameNumber );
268 GET_SET_ACCESSOR( HHOOK, KeyboardHook );
269 GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenFullscreen );
270 GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenWindowed );
271 GET_SET_ACCESSOR( bool, AllowShortcutKeys );
272 GET_SET_ACCESSOR( bool, CallDefWindowProc );
273 GET_SET_ACCESSOR( STICKYKEYS, StartupStickyKeys );
274 GET_SET_ACCESSOR( TOGGLEKEYS, StartupToggleKeys );
275 GET_SET_ACCESSOR( FILTERKEYS, StartupFilterKeys );
276
277 GET_SET_ACCESSOR( bool, HandleDefaultHotkeys );
278 GET_SET_ACCESSOR( bool, HandleAltEnter );
279 GET_SET_ACCESSOR( bool, ShowMsgBoxOnError );
280 GET_SET_ACCESSOR( bool, NoStats );
281 GET_SET_ACCESSOR( bool, ClipCursorWhenFullScreen );
282 GET_SET_ACCESSOR( bool, ShowCursorWhenFullScreen );
283 GET_SET_ACCESSOR( bool, ConstantFrameTime );
284 GET_SET_ACCESSOR( float, TimePerFrame );
285 GET_SET_ACCESSOR( bool, WireframeMode );
286 GET_SET_ACCESSOR( bool, AutoChangeAdapter );
287 GET_SET_ACCESSOR( bool, WindowCreatedWithDefaultPositions );
288 GET_SET_ACCESSOR( int, ExitCode );
289
290 GET_SET_ACCESSOR( bool, DXUTInited );
291 GET_SET_ACCESSOR( bool, WindowCreated );
292 GET_SET_ACCESSOR( bool, DeviceCreated );
293 GET_SET_ACCESSOR( bool, DXUTInitCalled );
294 GET_SET_ACCESSOR( bool, WindowCreateCalled );
295 GET_SET_ACCESSOR( bool, DeviceCreateCalled );
296 GET_SET_ACCESSOR( bool, InsideDeviceCallback );
297 GET_SET_ACCESSOR( bool, InsideMainloop );
298 GET_SET_ACCESSOR( bool, DeviceObjectsCreated );
299 GET_SET_ACCESSOR( bool, DeviceObjectsReset );
300 GET_SET_ACCESSOR( bool, Active );
301 GET_SET_ACCESSOR( bool, RenderingPaused );
302 GET_SET_ACCESSOR( bool, TimePaused );
303 GET_SET_ACCESSOR( int, PauseRenderingCount );
304 GET_SET_ACCESSOR( int, PauseTimeCount );
305 GET_SET_ACCESSOR( bool, DeviceLost );
306 GET_SET_ACCESSOR( bool, NotifyOnMouseMove );
307 GET_SET_ACCESSOR( bool, Automation );
308 GET_SET_ACCESSOR( bool, InSizeMove );
309 GET_SET_ACCESSOR( UINT, TimerLastID );
310
311 GET_SET_ACCESSOR( int, OverrideAdapterOrdinal );
312 GET_SET_ACCESSOR( bool, OverrideWindowed );
313 GET_SET_ACCESSOR( bool, OverrideFullScreen );
314 GET_SET_ACCESSOR( int, OverrideStartX );
315 GET_SET_ACCESSOR( int, OverrideStartY );
316 GET_SET_ACCESSOR( int, OverrideWidth );
317 GET_SET_ACCESSOR( int, OverrideHeight );
318 GET_SET_ACCESSOR( bool, OverrideForceHAL );
319 GET_SET_ACCESSOR( bool, OverrideForceREF );
320 GET_SET_ACCESSOR( bool, OverrideForcePureHWVP );
321 GET_SET_ACCESSOR( bool, OverrideForceHWVP );
322 GET_SET_ACCESSOR( bool, OverrideForceSWVP );
323 GET_SET_ACCESSOR( bool, OverrideConstantFrameTime );
324 GET_SET_ACCESSOR( float, OverrideConstantTimePerFrame );
325 GET_SET_ACCESSOR( int, OverrideQuitAfterFrame );
326 GET_SET_ACCESSOR( int, OverrideForceVsync );
327 GET_SET_ACCESSOR( bool, OverrideRelaunchMCE );
328
329 GET_SET_ACCESSOR( LPDXUTCALLBACKISDEVICEACCEPTABLE, IsDeviceAcceptableFunc );
330 GET_SET_ACCESSOR( LPDXUTCALLBACKMODIFYDEVICESETTINGS, ModifyDeviceSettingsFunc );
331 GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICECREATED, DeviceCreatedFunc );
332 GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICERESET, DeviceResetFunc );
333 GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICELOST, DeviceLostFunc );
334 GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICEDESTROYED, DeviceDestroyedFunc );
335 GET_SET_ACCESSOR( LPDXUTCALLBACKFRAMEMOVE, FrameMoveFunc );
336 GET_SET_ACCESSOR( LPDXUTCALLBACKFRAMERENDER, FrameRenderFunc );
337 GET_SET_ACCESSOR( LPDXUTCALLBACKKEYBOARD, KeyboardFunc );
338 GET_SET_ACCESSOR( LPDXUTCALLBACKMOUSE, MouseFunc );
339 GET_SET_ACCESSOR( LPDXUTCALLBACKMSGPROC, WindowMsgFunc );
340
341 GET_SET_ACCESSOR( void*, IsDeviceAcceptableFuncUserContext );
342 GET_SET_ACCESSOR( void*, ModifyDeviceSettingsFuncUserContext );
343 GET_SET_ACCESSOR( void*, DeviceCreatedFuncUserContext );
344 GET_SET_ACCESSOR( void*, DeviceResetFuncUserContext );
345 GET_SET_ACCESSOR( void*, DeviceLostFuncUserContext );
346 GET_SET_ACCESSOR( void*, DeviceDestroyedFuncUserContext );
347 GET_SET_ACCESSOR( void*, FrameMoveFuncUserContext );
348 GET_SET_ACCESSOR( void*, FrameRenderFuncUserContext );
349 GET_SET_ACCESSOR( void*, KeyboardFuncUserContext );
350 GET_SET_ACCESSOR( void*, MouseFuncUserContext );
351 GET_SET_ACCESSOR( void*, WindowMsgFuncUserContext );
352
353 GET_SET_ACCESSOR( CGrowableArray<DXUT_TIMER>*, TimerList );
354 GET_ACCESSOR( bool*, Keys );
355 GET_ACCESSOR( bool*, MouseButtons );
356 GET_ACCESSOR( WCHAR*, StaticFrameStats );
357 GET_ACCESSOR( WCHAR*, FPSStats );
358 GET_ACCESSOR( WCHAR*, FrameStats );
359 GET_ACCESSOR( WCHAR*, DeviceStats );
360 GET_ACCESSOR( WCHAR*, WindowTitle );
361 };
362
363
364 //--------------------------------------------------------------------------------------
365 // Global state class
366 //--------------------------------------------------------------------------------------
GetDXUTState()367 DXUTState& GetDXUTState()
368 {
369 // Using an accessor function gives control of the construction order
370 static DXUTState state;
371 return state;
372 }
373
374
375 //--------------------------------------------------------------------------------------
376 // Internal functions forward declarations
377 //--------------------------------------------------------------------------------------
378 typedef IDirect3D9* (WINAPI* LPDIRECT3DCREATE9)(UINT SDKVersion);
379 typedef DECLSPEC_IMPORT UINT (WINAPI* LPTIMEBEGINPERIOD)( UINT uPeriod );
380 int DXUTMapButtonToArrayIndex( BYTE vButton );
381 void DXUTSetProcessorAffinity();
382 void DXUTParseCommandLine();
383 CD3DEnumeration* DXUTPrepareEnumerationObject( bool bEnumerate = false );
384 void DXUTBuildOptimalDeviceSettings( DXUTDeviceSettings* pOptimalDeviceSettings, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
385 bool DXUTDoesDeviceComboMatchPreserveOptions( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
386 float DXUTRankDeviceCombo( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, D3DDISPLAYMODE* pAdapterDesktopDisplayMode );
387 void DXUTBuildValidDeviceSettings( DXUTDeviceSettings* pDeviceSettings, CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, DXUTDeviceSettings* pDeviceSettingsIn, DXUTMatchOptions* pMatchOptions );
388 HRESULT DXUTFindValidResolution( CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo, D3DDISPLAYMODE displayModeIn, D3DDISPLAYMODE* pBestDisplayMode );
389 HRESULT DXUTFindAdapterFormat( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT BackBufferFormat, BOOL Windowed, D3DFORMAT* pAdapterFormat );
390 HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, IDirect3DDevice9* pd3dDeviceFromApp, bool bForceRecreate, bool bClipWindowToSingleAdapter );
391 void DXUTUpdateDeviceSettingsWithOverrides( DXUTDeviceSettings* pNewDeviceSettings );
392 HRESULT DXUTCreate3DEnvironment( IDirect3DDevice9* pd3dDeviceFromApp );
393 HRESULT DXUTReset3DEnvironment();
394 void DXUTRender3DEnvironment();
395 void DXUTCleanup3DEnvironment( bool bReleaseSettings = true );
396 void DXUTUpdateFrameStats();
397 void DXUTUpdateDeviceStats( D3DDEVTYPE DeviceType, DWORD BehaviorFlags, D3DADAPTER_IDENTIFIER9* pAdapterIdentifier );
398 void DXUTUpdateStaticFrameStats();
399 void DXUTHandleTimers();
400 bool DXUTIsNextArg( WCHAR*& strCmdLine, WCHAR* strArg );
401 bool DXUTGetCmdParam( WCHAR*& strCmdLine, WCHAR* strFlag );
402 void DXUTDisplayErrorMessage( HRESULT hr );
403 LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
404 void DXUTCheckForWindowSizeChange();
405 void DXUTCheckForWindowChangingMonitors();
406 UINT DXUTColorChannelBits( D3DFORMAT fmt );
407 UINT DXUTStencilBits( D3DFORMAT fmt );
408 UINT DXUTDepthBits( D3DFORMAT fmt );
409 HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal );
410 void DXUTAllowShortcutKeys( bool bAllowKeys );
411 void DXUTUpdateBackBufferDesc();
412 void DXUTSetupCursor();
413 HRESULT DXUTSetDeviceCursor( IDirect3DDevice9* pd3dDevice, HCURSOR hCursor, bool bAddWatermark );
414
415
416 //--------------------------------------------------------------------------------------
417 // External callback setup functions
418 //--------------------------------------------------------------------------------------
DXUTSetCallbackDeviceCreated(LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated,void * pUserContext)419 void DXUTSetCallbackDeviceCreated( LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated, void* pUserContext ) { GetDXUTState().SetDeviceCreatedFunc( pCallbackDeviceCreated ); GetDXUTState().SetDeviceCreatedFuncUserContext( pUserContext ); }
DXUTSetCallbackDeviceReset(LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset,void * pUserContext)420 void DXUTSetCallbackDeviceReset( LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset, void* pUserContext ) { GetDXUTState().SetDeviceResetFunc( pCallbackDeviceReset ); GetDXUTState().SetDeviceResetFuncUserContext( pUserContext ); }
DXUTSetCallbackDeviceLost(LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost,void * pUserContext)421 void DXUTSetCallbackDeviceLost( LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost, void* pUserContext ) { GetDXUTState().SetDeviceLostFunc( pCallbackDeviceLost ); GetDXUTState().SetDeviceLostFuncUserContext( pUserContext ); }
DXUTSetCallbackDeviceDestroyed(LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed,void * pUserContext)422 void DXUTSetCallbackDeviceDestroyed( LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed, void* pUserContext ) { GetDXUTState().SetDeviceDestroyedFunc( pCallbackDeviceDestroyed ); GetDXUTState().SetDeviceDestroyedFuncUserContext( pUserContext ); }
DXUTSetCallbackDeviceChanging(LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings,void * pUserContext)423 void DXUTSetCallbackDeviceChanging( LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings, void* pUserContext ) { GetDXUTState().SetModifyDeviceSettingsFunc( pCallbackModifyDeviceSettings ); GetDXUTState().SetModifyDeviceSettingsFuncUserContext( pUserContext ); }
DXUTSetCallbackFrameMove(LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove,void * pUserContext)424 void DXUTSetCallbackFrameMove( LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove, void* pUserContext ) { GetDXUTState().SetFrameMoveFunc( pCallbackFrameMove ); GetDXUTState().SetFrameMoveFuncUserContext( pUserContext ); }
DXUTSetCallbackFrameRender(LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender,void * pUserContext)425 void DXUTSetCallbackFrameRender( LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender, void* pUserContext ) { GetDXUTState().SetFrameRenderFunc( pCallbackFrameRender ); GetDXUTState().SetFrameRenderFuncUserContext( pUserContext ); }
DXUTSetCallbackKeyboard(LPDXUTCALLBACKKEYBOARD pCallbackKeyboard,void * pUserContext)426 void DXUTSetCallbackKeyboard( LPDXUTCALLBACKKEYBOARD pCallbackKeyboard, void* pUserContext ) { GetDXUTState().SetKeyboardFunc( pCallbackKeyboard ); GetDXUTState().SetKeyboardFuncUserContext( pUserContext ); }
DXUTSetCallbackMouse(LPDXUTCALLBACKMOUSE pCallbackMouse,bool bIncludeMouseMove,void * pUserContext)427 void DXUTSetCallbackMouse( LPDXUTCALLBACKMOUSE pCallbackMouse, bool bIncludeMouseMove, void* pUserContext ) { GetDXUTState().SetMouseFunc( pCallbackMouse ); GetDXUTState().SetNotifyOnMouseMove( bIncludeMouseMove ); GetDXUTState().SetMouseFuncUserContext( pUserContext ); }
DXUTSetCallbackMsgProc(LPDXUTCALLBACKMSGPROC pCallbackMsgProc,void * pUserContext)428 void DXUTSetCallbackMsgProc( LPDXUTCALLBACKMSGPROC pCallbackMsgProc, void* pUserContext ) { GetDXUTState().SetWindowMsgFunc( pCallbackMsgProc ); GetDXUTState().SetWindowMsgFuncUserContext( pUserContext ); }
429
430 //--------------------------------------------------------------------------------------
431 // Optionally parses the command line and sets if default hotkeys are handled
432 //
433 // Possible command line parameters are:
434 // -adapter:# forces app to use this adapter # (fails if the adapter doesn't exist)
435 // -windowed forces app to start windowed
436 // -fullscreen forces app to start full screen
437 // -forcehal forces app to use HAL (fails if HAL doesn't exist)
438 // -forceref forces app to use REF (fails if REF doesn't exist)
439 // -forcepurehwvp forces app to use pure HWVP (fails if device doesn't support it)
440 // -forcehwvp forces app to use HWVP (fails if device doesn't support it)
441 // -forceswvp forces app to use SWVP
442 // -forcevsync:# if # is 0, forces app to use D3DPRESENT_INTERVAL_IMMEDIATE otherwise force use of D3DPRESENT_INTERVAL_DEFAULT
443 // -width:# forces app to use # for width. for full screen, it will pick the closest possible supported mode
444 // -height:# forces app to use # for height. for full screen, it will pick the closest possible supported mode
445 // -startx:# forces app to use # for the x coord of the window position for windowed mode
446 // -starty:# forces app to use # for the y coord of the window position for windowed mode
447 // -constantframetime:# forces app to use constant frame time, where # is the time/frame in seconds
448 // -quitafterframe:x forces app to quit after # frames
449 // -noerrormsgboxes prevents the display of message boxes generated by the framework so the application can be run without user interaction
450 // -nostats prevents the display of the stats
451 // -relaunchmce re-launches the MCE UI after the app exits
452 // -automation every CDXUTDialog created will have EnableKeyboardInput(true) called, enabling UI navigation with keyboard
453 // This is useful when automating application testing.
454 //
455 // Hotkeys handled by default are:
456 // Alt-Enter toggle between full screen & windowed (hotkey always enabled)
457 // ESC exit app
458 // F3 toggle HAL/REF
459 // F8 toggle wire-frame mode
460 // Pause pause time
461 //--------------------------------------------------------------------------------------
DXUTInit(bool bParseCommandLine,bool bHandleDefaultHotkeys,bool bShowMsgBoxOnError,bool bHandleAltEnter)462 HRESULT DXUTInit( bool bParseCommandLine, bool bHandleDefaultHotkeys, bool bShowMsgBoxOnError, bool bHandleAltEnter )
463 {
464 GetDXUTState().SetDXUTInitCalled( true );
465
466 // Not always needed, but lets the app create GDI dialogs
467 InitCommonControls();
468
469 // Save the current sticky/toggle/filter key settings so DXUT can restore them later
470 STICKYKEYS sk = {sizeof(STICKYKEYS), 0};
471 SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0);
472 GetDXUTState().SetStartupStickyKeys( sk );
473
474 TOGGLEKEYS tk = {sizeof(TOGGLEKEYS), 0};
475 SystemParametersInfo(SPI_GETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0);
476 GetDXUTState().SetStartupToggleKeys( tk );
477
478 FILTERKEYS fk = {sizeof(FILTERKEYS), 0};
479 SystemParametersInfo(SPI_GETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0);
480 GetDXUTState().SetStartupFilterKeys( fk );
481
482 // Increase the accuracy of Sleep() without needing to link to winmm.lib
483 WCHAR wszPath[MAX_PATH+1];
484 if( GetSystemDirectory( wszPath, MAX_PATH+1 ) )
485 {
486 StringCchCat( wszPath, MAX_PATH, L"\\winmm.dll" );
487 HINSTANCE hInstWinMM = LoadLibrary( wszPath );
488 if( hInstWinMM )
489 {
490 LPTIMEBEGINPERIOD pTimeBeginPeriod = (LPTIMEBEGINPERIOD)GetProcAddress( hInstWinMM, "timeBeginPeriod" );
491 if( NULL != pTimeBeginPeriod )
492 pTimeBeginPeriod(1);
493
494 FreeLibrary(hInstWinMM);
495 }
496 }
497
498 GetDXUTState().SetShowMsgBoxOnError( bShowMsgBoxOnError );
499 GetDXUTState().SetHandleDefaultHotkeys( bHandleDefaultHotkeys );
500 GetDXUTState().SetHandleAltEnter( bHandleAltEnter );
501
502 if( bParseCommandLine )
503 DXUTParseCommandLine();
504
505 // Verify D3DX version
506 if( !D3DXCheckVersion( D3D_SDK_VERSION, D3DX_SDK_VERSION ) )
507 {
508 DXUTDisplayErrorMessage( DXUTERR_INCORRECTVERSION );
509 return DXUT_ERR( L"D3DXCheckVersion", DXUTERR_INCORRECTVERSION );
510 }
511
512 // Create a Direct3D object if one has not already been created
513 IDirect3D9* pD3D = DXUTGetD3DObject();
514 if( pD3D == NULL )
515 {
516 // This may fail if DirectX 9 isn't installed
517 // This may fail if the DirectX headers are out of sync with the installed DirectX DLLs
518 pD3D = DXUT_Dynamic_Direct3DCreate9( D3D_SDK_VERSION );
519 GetDXUTState().SetD3D( pD3D );
520 }
521
522 if( pD3D == NULL )
523 {
524 // If still NULL, then something went wrong
525 DXUTDisplayErrorMessage( DXUTERR_NODIRECT3D );
526 return DXUT_ERR( L"Direct3DCreate9", DXUTERR_NODIRECT3D );
527 }
528
529 // Reset the timer
530 DXUTGetGlobalTimer()->Reset();
531
532 GetDXUTState().SetDXUTInited( true );
533
534 return S_OK;
535 }
536
537
538 //--------------------------------------------------------------------------------------
539 // Parses the command line for parameters. See DXUTInit() for list
540 //--------------------------------------------------------------------------------------
DXUTParseCommandLine()541 void DXUTParseCommandLine()
542 {
543 WCHAR* strCmdLine;
544 WCHAR strFlag[MAX_PATH];
545
546 int nNumArgs;
547 WCHAR** pstrArgList = CommandLineToArgvW( GetCommandLine(), &nNumArgs );
548 for( int iArg=1; iArg<nNumArgs; iArg++ )
549 {
550 strCmdLine = pstrArgList[iArg];
551
552 // Handle flag args
553 if( *strCmdLine == L'/' || *strCmdLine == L'-' )
554 {
555 strCmdLine++;
556
557 if( DXUTIsNextArg( strCmdLine, L"adapter" ) )
558 {
559 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
560 {
561 int nAdapter = _wtoi(strFlag);
562 GetDXUTState().SetOverrideAdapterOrdinal( nAdapter );
563 continue;
564 }
565 }
566
567 if( DXUTIsNextArg( strCmdLine, L"windowed" ) )
568 {
569 GetDXUTState().SetOverrideWindowed( true );
570 continue;
571 }
572
573 if( DXUTIsNextArg( strCmdLine, L"fullscreen" ) )
574 {
575 GetDXUTState().SetOverrideFullScreen( true );
576 continue;
577 }
578
579 if( DXUTIsNextArg( strCmdLine, L"forcehal" ) )
580 {
581 GetDXUTState().SetOverrideForceHAL( true );
582 continue;
583 }
584
585 if( DXUTIsNextArg( strCmdLine, L"forceref" ) )
586 {
587 GetDXUTState().SetOverrideForceREF( true );
588 continue;
589 }
590
591 if( DXUTIsNextArg( strCmdLine, L"forcepurehwvp" ) )
592 {
593 GetDXUTState().SetOverrideForcePureHWVP( true );
594 continue;
595 }
596
597 if( DXUTIsNextArg( strCmdLine, L"forcehwvp" ) )
598 {
599 GetDXUTState().SetOverrideForceHWVP( true );
600 continue;
601 }
602
603 if( DXUTIsNextArg( strCmdLine, L"forceswvp" ) )
604 {
605 GetDXUTState().SetOverrideForceSWVP( true );
606 continue;
607 }
608
609 if( DXUTIsNextArg( strCmdLine, L"forcevsync" ) )
610 {
611 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
612 {
613 int nOn = _wtoi(strFlag);
614 GetDXUTState().SetOverrideForceVsync( nOn );
615 continue;
616 }
617 }
618
619 if( DXUTIsNextArg( strCmdLine, L"width" ) )
620 {
621 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
622 {
623 int nWidth = _wtoi(strFlag);
624 GetDXUTState().SetOverrideWidth( nWidth );
625 continue;
626 }
627 }
628
629 if( DXUTIsNextArg( strCmdLine, L"height" ) )
630 {
631 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
632 {
633 int nHeight = _wtoi(strFlag);
634 GetDXUTState().SetOverrideHeight( nHeight );
635 continue;
636 }
637 }
638
639 if( DXUTIsNextArg( strCmdLine, L"startx" ) )
640 {
641 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
642 {
643 int nX = _wtoi(strFlag);
644 GetDXUTState().SetOverrideStartX( nX );
645 continue;
646 }
647 }
648
649 if( DXUTIsNextArg( strCmdLine, L"starty" ) )
650 {
651 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
652 {
653 int nY = _wtoi(strFlag);
654 GetDXUTState().SetOverrideStartY( nY );
655 continue;
656 }
657 }
658
659 if( DXUTIsNextArg( strCmdLine, L"constantframetime" ) )
660 {
661 float fTimePerFrame;
662 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
663 fTimePerFrame = (float)wcstod( strFlag, NULL );
664 else
665 fTimePerFrame = 0.0333f;
666 GetDXUTState().SetOverrideConstantFrameTime( true );
667 GetDXUTState().SetOverrideConstantTimePerFrame( fTimePerFrame );
668 DXUTSetConstantFrameTime( true, fTimePerFrame );
669 continue;
670 }
671
672 if( DXUTIsNextArg( strCmdLine, L"quitafterframe" ) )
673 {
674 if( DXUTGetCmdParam( strCmdLine, strFlag ) )
675 {
676 int nFrame = _wtoi(strFlag);
677 GetDXUTState().SetOverrideQuitAfterFrame( nFrame );
678 continue;
679 }
680 }
681
682 if( DXUTIsNextArg( strCmdLine, L"noerrormsgboxes" ) )
683 {
684 GetDXUTState().SetShowMsgBoxOnError( false );
685 continue;
686 }
687
688 if( DXUTIsNextArg( strCmdLine, L"nostats" ) )
689 {
690 GetDXUTState().SetNoStats( true );
691 continue;
692 }
693
694 if( DXUTIsNextArg( strCmdLine, L"relaunchmce" ) )
695 {
696 GetDXUTState().SetOverrideRelaunchMCE( true );
697 continue;
698 }
699
700 if( DXUTIsNextArg( strCmdLine, L"automation" ) )
701 {
702 GetDXUTState().SetAutomation( true );
703 continue;
704 }
705 }
706
707 // Unrecognized flag
708 StringCchCopy( strFlag, 256, strCmdLine );
709 WCHAR* strSpace = strFlag;
710 while (*strSpace && (*strSpace > L' '))
711 strSpace++;
712 *strSpace = 0;
713
714 DXUTOutputDebugString( L"Unrecognized flag: %s", strFlag );
715 strCmdLine += wcslen(strFlag);
716 }
717 }
718
719
720 //--------------------------------------------------------------------------------------
721 // Helper function for DXUTParseCommandLine
722 //--------------------------------------------------------------------------------------
DXUTIsNextArg(WCHAR * & strCmdLine,WCHAR * strArg)723 bool DXUTIsNextArg( WCHAR*& strCmdLine, WCHAR* strArg )
724 {
725 int nArgLen = (int) wcslen(strArg);
726 int nCmdLen = (int) wcslen(strCmdLine);
727
728 if( nCmdLen >= nArgLen &&
729 _wcsnicmp( strCmdLine, strArg, nArgLen ) == 0 &&
730 (strCmdLine[nArgLen] == 0 || strCmdLine[nArgLen] == L':') )
731 {
732 strCmdLine += nArgLen;
733 return true;
734 }
735
736 return false;
737 }
738
739
740 //--------------------------------------------------------------------------------------
741 // Helper function for DXUTParseCommandLine. Updates strCmdLine and strFlag
742 // Example: if strCmdLine=="-width:1024 -forceref"
743 // then after: strCmdLine==" -forceref" and strFlag=="1024"
744 //--------------------------------------------------------------------------------------
DXUTGetCmdParam(WCHAR * & strCmdLine,WCHAR * strFlag)745 bool DXUTGetCmdParam( WCHAR*& strCmdLine, WCHAR* strFlag )
746 {
747 if( *strCmdLine == L':' )
748 {
749 strCmdLine++; // Skip ':'
750
751 // Place NULL terminator in strFlag after current token
752 StringCchCopy( strFlag, 256, strCmdLine );
753 WCHAR* strSpace = strFlag;
754 while (*strSpace && (*strSpace > L' '))
755 strSpace++;
756 *strSpace = 0;
757
758 // Update strCmdLine
759 strCmdLine += wcslen(strFlag);
760 return true;
761 }
762 else
763 {
764 strFlag[0] = 0;
765 return false;
766 }
767 }
768
769
770 //--------------------------------------------------------------------------------------
771 // Creates a window with the specified window title, icon, menu, and
772 // starting position. If DXUTInit() has not already been called, it will
773 // call it with the default parameters. Instead of calling this, you can
774 // call DXUTSetWindow() to use an existing window.
775 //--------------------------------------------------------------------------------------
DXUTCreateWindow(const WCHAR * strWindowTitle,HINSTANCE hInstance,HICON hIcon,HMENU hMenu,int x,int y)776 HRESULT DXUTCreateWindow( const WCHAR* strWindowTitle, HINSTANCE hInstance,
777 HICON hIcon, HMENU hMenu, int x, int y )
778 {
779 HRESULT hr;
780
781 // Not allowed to call this from inside the device callbacks
782 if( GetDXUTState().GetInsideDeviceCallback() )
783 return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
784
785 GetDXUTState().SetWindowCreateCalled( true );
786
787 if( !GetDXUTState().GetDXUTInited() )
788 {
789 // If DXUTInit() was already called and failed, then fail.
790 // DXUTInit() must first succeed for this function to succeed
791 if( GetDXUTState().GetDXUTInitCalled() )
792 return E_FAIL;
793
794 // If DXUTInit() hasn't been called, then automatically call it
795 // with default params
796 hr = DXUTInit();
797 if( FAILED(hr) )
798 return hr;
799 }
800
801 if( DXUTGetHWNDFocus() == NULL )
802 {
803 if( hInstance == NULL )
804 hInstance = (HINSTANCE)GetModuleHandle(NULL);
805 GetDXUTState().SetHInstance( hInstance );
806
807 WCHAR szExePath[MAX_PATH];
808 GetModuleFileName( NULL, szExePath, MAX_PATH );
809 if( hIcon == NULL ) // If the icon is NULL, then use the first one found in the exe
810 hIcon = ExtractIcon( hInstance, szExePath, 0 );
811
812 // Register the windows class
813 WNDCLASS wndClass;
814 wndClass.style = CS_DBLCLKS;
815 wndClass.lpfnWndProc = DXUTStaticWndProc;
816 wndClass.cbClsExtra = 0;
817 wndClass.cbWndExtra = 0;
818 wndClass.hInstance = hInstance;
819 wndClass.hIcon = hIcon;
820 wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
821 wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
822 wndClass.lpszMenuName = NULL;
823 wndClass.lpszClassName = L"Direct3DWindowClass";
824
825 if( !RegisterClass( &wndClass ) )
826 {
827 DWORD dwError = GetLastError();
828 if( dwError != ERROR_CLASS_ALREADY_EXISTS )
829 return DXUT_ERR_MSGBOX( L"RegisterClass", HRESULT_FROM_WIN32(dwError) );
830 }
831
832 RECT rc;
833 // Override the window's initial & size position if there were cmd line args
834 if( GetDXUTState().GetOverrideStartX() != -1 )
835 x = GetDXUTState().GetOverrideStartX();
836 if( GetDXUTState().GetOverrideStartY() != -1 )
837 y = GetDXUTState().GetOverrideStartY();
838
839 GetDXUTState().SetWindowCreatedWithDefaultPositions( false );
840 if( x == CW_USEDEFAULT && y == CW_USEDEFAULT )
841 GetDXUTState().SetWindowCreatedWithDefaultPositions( true );
842
843 // Find the window's initial size, but it might be changed later
844 int nDefaultWidth = 640;
845 int nDefaultHeight = 480;
846 if( GetDXUTState().GetOverrideWidth() != 0 )
847 nDefaultWidth = GetDXUTState().GetOverrideWidth();
848 if( GetDXUTState().GetOverrideHeight() != 0 )
849 nDefaultHeight = GetDXUTState().GetOverrideHeight();
850 SetRect( &rc, 0, 0, nDefaultWidth, nDefaultHeight );
851 AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, ( hMenu != NULL ) ? true : false );
852
853 WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle();
854 StringCchCopy( strCachedWindowTitle, 256, strWindowTitle );
855
856 // Create the render window
857 HWND hWnd = CreateWindow( L"Direct3DWindowClass", strWindowTitle, WS_OVERLAPPEDWINDOW,
858 x, y, (rc.right-rc.left), (rc.bottom-rc.top), 0,
859 hMenu, hInstance, 0 );
860 if( hWnd == NULL )
861 {
862 DWORD dwError = GetLastError();
863 return DXUT_ERR_MSGBOX( L"CreateWindow", HRESULT_FROM_WIN32(dwError) );
864 }
865
866 GetDXUTState().SetWindowCreated( true );
867 GetDXUTState().SetHWNDFocus( hWnd );
868 GetDXUTState().SetHWNDDeviceFullScreen( hWnd );
869 GetDXUTState().SetHWNDDeviceWindowed( hWnd );
870 }
871
872 return S_OK;
873 }
874
875
876 //--------------------------------------------------------------------------------------
877 // Sets a previously created window for the framework to use. If DXUTInit()
878 // has not already been called, it will call it with the default parameters.
879 // Instead of calling this, you can call DXUTCreateWindow() to create a new window.
880 //--------------------------------------------------------------------------------------
DXUTSetWindow(HWND hWndFocus,HWND hWndDeviceFullScreen,HWND hWndDeviceWindowed,bool bHandleMessages)881 HRESULT DXUTSetWindow( HWND hWndFocus, HWND hWndDeviceFullScreen, HWND hWndDeviceWindowed, bool bHandleMessages )
882 {
883 HRESULT hr;
884
885 // Not allowed to call this from inside the device callbacks
886 if( GetDXUTState().GetInsideDeviceCallback() )
887 return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
888
889 GetDXUTState().SetWindowCreateCalled( true );
890
891 // To avoid confusion, we do not allow any HWND to be NULL here. The
892 // caller must pass in valid HWND for all three parameters. The same
893 // HWND may be used for more than one parameter.
894 if( hWndFocus == NULL || hWndDeviceFullScreen == NULL || hWndDeviceWindowed == NULL )
895 return DXUT_ERR_MSGBOX( L"DXUTSetWindow", E_INVALIDARG );
896
897 // If subclassing the window, set the pointer to the local window procedure
898 if( bHandleMessages )
899 {
900 // Switch window procedures
901 #ifdef _WIN64
902 LONG_PTR nResult = SetWindowLongPtr( hWndFocus, GWLP_WNDPROC, (LONG_PTR)DXUTStaticWndProc );
903 #else
904 LONG_PTR nResult = SetWindowLongPtr( hWndFocus, GWLP_WNDPROC, (LONG)(LONG_PTR)DXUTStaticWndProc );
905 #endif
906
907 DWORD dwError = GetLastError();
908 if( nResult == 0 )
909 return DXUT_ERR_MSGBOX( L"SetWindowLongPtr", HRESULT_FROM_WIN32(dwError) );
910 }
911
912 if( !GetDXUTState().GetDXUTInited() )
913 {
914 // If DXUTInit() was already called and failed, then fail.
915 // DXUTInit() must first succeed for this function to succeed
916 if( GetDXUTState().GetDXUTInitCalled() )
917 return E_FAIL;
918
919 // If DXUTInit() hasn't been called, then automatically call it
920 // with default params
921 hr = DXUTInit();
922 if( FAILED(hr) )
923 return hr;
924 }
925
926 WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle();
927 GetWindowText( hWndFocus, strCachedWindowTitle, 255 );
928 strCachedWindowTitle[255] = 0;
929
930 HINSTANCE hInstance = (HINSTANCE) (LONG_PTR) GetWindowLongPtr( hWndFocus, GWLP_HINSTANCE );
931 GetDXUTState().SetHInstance( hInstance );
932 GetDXUTState().SetWindowCreatedWithDefaultPositions( false );
933 GetDXUTState().SetWindowCreated( true );
934 GetDXUTState().SetHWNDFocus( hWndFocus );
935 GetDXUTState().SetHWNDDeviceFullScreen( hWndDeviceFullScreen );
936 GetDXUTState().SetHWNDDeviceWindowed( hWndDeviceWindowed );
937
938 return S_OK;
939 }
940
941
942 //--------------------------------------------------------------------------------------
943 // Creates a Direct3D device. If DXUTCreateWindow() or DXUTSetWindow() has not already
944 // been called, it will call DXUTCreateWindow() with the default parameters.
945 // Instead of calling this, you can call DXUTSetDevice() or DXUTCreateDeviceFromSettings()
946 //--------------------------------------------------------------------------------------
DXUTCreateDevice(UINT AdapterOrdinal,bool bWindowed,int nSuggestedWidth,int nSuggestedHeight,LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable,LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings,void * pUserContext)947 HRESULT DXUTCreateDevice( UINT AdapterOrdinal, bool bWindowed,
948 int nSuggestedWidth, int nSuggestedHeight,
949 LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable,
950 LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings,
951 void* pUserContext )
952 {
953 HRESULT hr;
954
955 // Not allowed to call this from inside the device callbacks
956 if( GetDXUTState().GetInsideDeviceCallback() )
957 return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
958
959 // Record the function arguments in the global state
960 GetDXUTState().SetIsDeviceAcceptableFunc( pCallbackIsDeviceAcceptable );
961 GetDXUTState().SetModifyDeviceSettingsFunc( pCallbackModifyDeviceSettings );
962 GetDXUTState().SetIsDeviceAcceptableFuncUserContext( pUserContext );
963 GetDXUTState().SetModifyDeviceSettingsFuncUserContext( pUserContext );
964
965 GetDXUTState().SetDeviceCreateCalled( true );
966
967 // If DXUTCreateWindow() or DXUTSetWindow() has not already been called,
968 // then call DXUTCreateWindow() with the default parameters.
969 if( !GetDXUTState().GetWindowCreated() )
970 {
971 // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
972 // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
973 if( GetDXUTState().GetWindowCreateCalled() )
974 return E_FAIL;
975
976 // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then
977 // automatically call DXUTCreateWindow() with default params
978 hr = DXUTCreateWindow();
979 if( FAILED(hr) )
980 return hr;
981 }
982
983 // Force an enumeration with the new IsDeviceAcceptable callback
984 DXUTPrepareEnumerationObject( true );
985
986 DXUTMatchOptions matchOptions;
987 matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
988 matchOptions.eDeviceType = DXUTMT_IGNORE_INPUT;
989 matchOptions.eWindowed = DXUTMT_PRESERVE_INPUT;
990 matchOptions.eAdapterFormat = DXUTMT_IGNORE_INPUT;
991 matchOptions.eVertexProcessing = DXUTMT_IGNORE_INPUT;
992 if( bWindowed || (nSuggestedWidth != 0 && nSuggestedHeight != 0) )
993 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
994 else
995 matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
996 matchOptions.eBackBufferFormat = DXUTMT_IGNORE_INPUT;
997 matchOptions.eBackBufferCount = DXUTMT_IGNORE_INPUT;
998 matchOptions.eMultiSample = DXUTMT_IGNORE_INPUT;
999 matchOptions.eSwapEffect = DXUTMT_IGNORE_INPUT;
1000 matchOptions.eDepthFormat = DXUTMT_IGNORE_INPUT;
1001 matchOptions.eStencilFormat = DXUTMT_IGNORE_INPUT;
1002 matchOptions.ePresentFlags = DXUTMT_IGNORE_INPUT;
1003 matchOptions.eRefreshRate = DXUTMT_IGNORE_INPUT;
1004 matchOptions.ePresentInterval = DXUTMT_IGNORE_INPUT;
1005
1006 DXUTDeviceSettings deviceSettings;
1007 ZeroMemory( &deviceSettings, sizeof(DXUTDeviceSettings) );
1008 deviceSettings.AdapterOrdinal = AdapterOrdinal;
1009 deviceSettings.pp.Windowed = bWindowed;
1010 deviceSettings.pp.BackBufferWidth = nSuggestedWidth;
1011 deviceSettings.pp.BackBufferHeight = nSuggestedHeight;
1012
1013 // Override with settings from the command line
1014 if( GetDXUTState().GetOverrideWidth() != 0 )
1015 deviceSettings.pp.BackBufferWidth = GetDXUTState().GetOverrideWidth();
1016 if( GetDXUTState().GetOverrideHeight() != 0 )
1017 deviceSettings.pp.BackBufferHeight = GetDXUTState().GetOverrideHeight();
1018
1019 if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 )
1020 deviceSettings.AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal();
1021
1022 if( GetDXUTState().GetOverrideFullScreen() )
1023 {
1024 deviceSettings.pp.Windowed = FALSE;
1025 if( GetDXUTState().GetOverrideWidth() == 0 && GetDXUTState().GetOverrideHeight() == 0 )
1026 matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
1027 }
1028 if( GetDXUTState().GetOverrideWindowed() )
1029 deviceSettings.pp.Windowed = TRUE;
1030
1031 if( GetDXUTState().GetOverrideForceHAL() )
1032 {
1033 deviceSettings.DeviceType = D3DDEVTYPE_HAL;
1034 matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
1035 }
1036 if( GetDXUTState().GetOverrideForceREF() )
1037 {
1038 deviceSettings.DeviceType = D3DDEVTYPE_REF;
1039 matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
1040 }
1041
1042 if( GetDXUTState().GetOverrideForcePureHWVP() )
1043 {
1044 deviceSettings.BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
1045 matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
1046 }
1047 else if( GetDXUTState().GetOverrideForceHWVP() )
1048 {
1049 deviceSettings.BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
1050 matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
1051 }
1052 else if( GetDXUTState().GetOverrideForceSWVP() )
1053 {
1054 deviceSettings.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
1055 matchOptions.eVertexProcessing = DXUTMT_PRESERVE_INPUT;
1056 }
1057
1058 if( GetDXUTState().GetOverrideForceVsync() == 0 )
1059 {
1060 deviceSettings.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1061 matchOptions.ePresentInterval = DXUTMT_PRESERVE_INPUT;
1062 }
1063 else if( GetDXUTState().GetOverrideForceVsync() == 1 )
1064 {
1065 deviceSettings.pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
1066 matchOptions.ePresentInterval = DXUTMT_PRESERVE_INPUT;
1067 }
1068
1069 hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
1070 if( FAILED(hr) ) // the call will fail if no valid devices were found
1071 {
1072 DXUTDisplayErrorMessage( hr );
1073 return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr );
1074 }
1075
1076 // Change to a Direct3D device created from the new device settings.
1077 // If there is an existing device, then either reset or recreated the scene
1078 hr = DXUTChangeDevice( &deviceSettings, NULL, false, true );
1079 if( FAILED(hr) )
1080 return hr;
1081
1082 return S_OK;
1083 }
1084
1085
1086 //--------------------------------------------------------------------------------------
1087 // Passes a previously created Direct3D device for use by the framework.
1088 // If DXUTCreateWindow() has not already been called, it will call it with the
1089 // default parameters. Instead of calling this, you can call DXUTCreateDevice() or
1090 // DXUTCreateDeviceFromSettings()
1091 //--------------------------------------------------------------------------------------
DXUTSetDevice(IDirect3DDevice9 * pd3dDevice)1092 HRESULT DXUTSetDevice( IDirect3DDevice9* pd3dDevice )
1093 {
1094 HRESULT hr;
1095
1096 if( pd3dDevice == NULL )
1097 return DXUT_ERR_MSGBOX( L"DXUTSetDevice", E_INVALIDARG );
1098
1099 // Not allowed to call this from inside the device callbacks
1100 if( GetDXUTState().GetInsideDeviceCallback() )
1101 return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL );
1102
1103 GetDXUTState().SetDeviceCreateCalled( true );
1104
1105 // If DXUTCreateWindow() or DXUTSetWindow() has not already been called,
1106 // then call DXUTCreateWindow() with the default parameters.
1107 if( !GetDXUTState().GetWindowCreated() )
1108 {
1109 // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
1110 // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
1111 if( GetDXUTState().GetWindowCreateCalled() )
1112 return E_FAIL;
1113
1114 // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then
1115 // automatically call DXUTCreateWindow() with default params
1116 hr = DXUTCreateWindow();
1117 if( FAILED(hr) )
1118 return hr;
1119 }
1120
1121 DXUTDeviceSettings* pDeviceSettings = new DXUTDeviceSettings;
1122 if( pDeviceSettings == NULL )
1123 return E_OUTOFMEMORY;
1124 ZeroMemory( pDeviceSettings, sizeof(DXUTDeviceSettings) );
1125
1126 // Get the present params from the swap chain
1127 IDirect3DSurface9* pBackBuffer = NULL;
1128 hr = pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
1129 if( SUCCEEDED(hr) )
1130 {
1131 IDirect3DSwapChain9* pSwapChain = NULL;
1132 hr = pBackBuffer->GetContainer( IID_IDirect3DSwapChain9, (void**) &pSwapChain );
1133 if( SUCCEEDED(hr) )
1134 {
1135 pSwapChain->GetPresentParameters( &pDeviceSettings->pp );
1136 SAFE_RELEASE( pSwapChain );
1137 }
1138
1139 SAFE_RELEASE( pBackBuffer );
1140 }
1141
1142 D3DDEVICE_CREATION_PARAMETERS d3dCreationParams;
1143 pd3dDevice->GetCreationParameters( &d3dCreationParams );
1144
1145 // Fill out the rest of the device settings struct
1146 pDeviceSettings->AdapterOrdinal = d3dCreationParams.AdapterOrdinal;
1147 pDeviceSettings->DeviceType = d3dCreationParams.DeviceType;
1148 DXUTFindAdapterFormat( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType,
1149 pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed,
1150 &pDeviceSettings->AdapterFormat );
1151 pDeviceSettings->BehaviorFlags = d3dCreationParams.BehaviorFlags;
1152
1153 // Change to the Direct3D device passed in
1154 hr = DXUTChangeDevice( pDeviceSettings, pd3dDevice, false, false );
1155
1156 delete pDeviceSettings;
1157
1158 if( FAILED(hr) )
1159 return hr;
1160
1161 return S_OK;
1162 }
1163
1164
1165 //--------------------------------------------------------------------------------------
1166 // Tells the framework to change to a device created from the passed in device settings
1167 // If DXUTCreateWindow() has not already been called, it will call it with the
1168 // default parameters. Instead of calling this, you can call DXUTCreateDevice()
1169 // or DXUTSetDevice()
1170 //--------------------------------------------------------------------------------------
DXUTCreateDeviceFromSettings(DXUTDeviceSettings * pDeviceSettings,bool bPreserveInput,bool bClipWindowToSingleAdapter)1171 HRESULT DXUTCreateDeviceFromSettings( DXUTDeviceSettings* pDeviceSettings, bool bPreserveInput, bool bClipWindowToSingleAdapter )
1172 {
1173 HRESULT hr;
1174
1175 GetDXUTState().SetDeviceCreateCalled( true );
1176
1177 // If DXUTCreateWindow() or DXUTSetWindow() has not already been called,
1178 // then call DXUTCreateWindow() with the default parameters.
1179 if( !GetDXUTState().GetWindowCreated() )
1180 {
1181 // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail.
1182 // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed
1183 if( GetDXUTState().GetWindowCreateCalled() )
1184 return E_FAIL;
1185
1186 // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then
1187 // automatically call DXUTCreateWindow() with default params
1188 hr = DXUTCreateWindow();
1189 if( FAILED(hr) )
1190 return hr;
1191 }
1192
1193 if( !bPreserveInput )
1194 {
1195 // If not preserving the input, then find the closest valid to it
1196 DXUTMatchOptions matchOptions;
1197 matchOptions.eAdapterOrdinal = DXUTMT_CLOSEST_TO_INPUT;
1198 matchOptions.eDeviceType = DXUTMT_CLOSEST_TO_INPUT;
1199 matchOptions.eWindowed = DXUTMT_CLOSEST_TO_INPUT;
1200 matchOptions.eAdapterFormat = DXUTMT_CLOSEST_TO_INPUT;
1201 matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
1202 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
1203 matchOptions.eBackBufferFormat = DXUTMT_CLOSEST_TO_INPUT;
1204 matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
1205 matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
1206 matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
1207 matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
1208 matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
1209 matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
1210 matchOptions.eRefreshRate = DXUTMT_CLOSEST_TO_INPUT;
1211 matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;
1212
1213 hr = DXUTFindValidDeviceSettings( pDeviceSettings, pDeviceSettings, &matchOptions );
1214 if( FAILED(hr) ) // the call will fail if no valid devices were found
1215 {
1216 DXUTDisplayErrorMessage( hr );
1217 return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr );
1218 }
1219 }
1220
1221 // Change to a Direct3D device created from the new device settings.
1222 // If there is an existing device, then either reset or recreate the scene
1223 hr = DXUTChangeDevice( pDeviceSettings, NULL, false, bClipWindowToSingleAdapter );
1224 if( FAILED(hr) )
1225 return hr;
1226
1227 return S_OK;
1228 }
1229
1230
1231 //--------------------------------------------------------------------------------------
1232 // Toggle between full screen and windowed
1233 //--------------------------------------------------------------------------------------
DXUTToggleFullScreen()1234 HRESULT DXUTToggleFullScreen()
1235 {
1236 HRESULT hr;
1237
1238 // Get the current device settings and flip the windowed state then
1239 // find the closest valid device settings with this change
1240 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
1241 deviceSettings.pp.Windowed = !deviceSettings.pp.Windowed;
1242
1243 DXUTMatchOptions matchOptions;
1244 matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
1245 matchOptions.eDeviceType = DXUTMT_CLOSEST_TO_INPUT;
1246 matchOptions.eWindowed = DXUTMT_PRESERVE_INPUT;
1247 matchOptions.eAdapterFormat = DXUTMT_IGNORE_INPUT;
1248 matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
1249 matchOptions.eBackBufferFormat = DXUTMT_IGNORE_INPUT;
1250 matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
1251 matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
1252 matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
1253 matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
1254 matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
1255 matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
1256 matchOptions.eRefreshRate = DXUTMT_IGNORE_INPUT;
1257 matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;
1258
1259 // Go back to previous state
1260
1261 UINT nWidth = ( deviceSettings.pp.Windowed ) ? GetDXUTState().GetWindowBackBufferWidthAtModeChange() : GetDXUTState().GetFullScreenBackBufferWidthAtModeChange();
1262 UINT nHeight = ( deviceSettings.pp.Windowed ) ? GetDXUTState().GetWindowBackBufferHeightAtModeChange() : GetDXUTState().GetFullScreenBackBufferHeightAtModeChange();
1263 if( nWidth > 0 && nHeight > 0 )
1264 {
1265 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
1266 deviceSettings.pp.BackBufferWidth = nWidth;
1267 deviceSettings.pp.BackBufferHeight = nHeight;
1268 }
1269 else
1270 {
1271 // No previous data, so just switch to defaults
1272 matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
1273 }
1274
1275 hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
1276 if( SUCCEEDED(hr) )
1277 {
1278 // Create a Direct3D device using the new device settings.
1279 // If there is an existing device, then it will either reset or recreate the scene.
1280 hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
1281
1282 // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed
1283 if( FAILED(hr) && (hr != E_ABORT) )
1284 {
1285 // Failed creating device, try to switch back.
1286 deviceSettings.pp.Windowed = !deviceSettings.pp.Windowed;
1287 UINT nWidth = ( deviceSettings.pp.Windowed ) ? GetDXUTState().GetWindowBackBufferWidthAtModeChange() : GetDXUTState().GetFullScreenBackBufferWidthAtModeChange();
1288 UINT nHeight = ( deviceSettings.pp.Windowed ) ? GetDXUTState().GetWindowBackBufferHeightAtModeChange() : GetDXUTState().GetFullScreenBackBufferHeightAtModeChange();
1289 if( nWidth > 0 && nHeight > 0 )
1290 {
1291 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
1292 deviceSettings.pp.BackBufferWidth = nWidth;
1293 deviceSettings.pp.BackBufferHeight = nHeight;
1294 }
1295 else
1296 {
1297 matchOptions.eResolution = DXUTMT_IGNORE_INPUT;
1298 }
1299
1300 DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
1301
1302 HRESULT hr2 = DXUTChangeDevice( &deviceSettings, NULL, false, false );
1303 if( FAILED(hr2) )
1304 {
1305 // If this failed, then shutdown
1306 DXUTShutdown();
1307 }
1308 }
1309 }
1310
1311 return hr;
1312 }
1313
1314
1315 //--------------------------------------------------------------------------------------
1316 // Toggle between HAL and REF
1317 //--------------------------------------------------------------------------------------
DXUTToggleREF()1318 HRESULT DXUTToggleREF()
1319 {
1320 HRESULT hr;
1321
1322 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
1323 if( deviceSettings.DeviceType == D3DDEVTYPE_HAL )
1324 deviceSettings.DeviceType = D3DDEVTYPE_REF;
1325 else if( deviceSettings.DeviceType == D3DDEVTYPE_REF )
1326 deviceSettings.DeviceType = D3DDEVTYPE_HAL;
1327
1328 DXUTMatchOptions matchOptions;
1329 matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
1330 matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
1331 matchOptions.eWindowed = DXUTMT_CLOSEST_TO_INPUT;
1332 matchOptions.eAdapterFormat = DXUTMT_CLOSEST_TO_INPUT;
1333 matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
1334 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
1335 matchOptions.eBackBufferFormat = DXUTMT_CLOSEST_TO_INPUT;
1336 matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
1337 matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
1338 matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
1339 matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
1340 matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
1341 matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
1342 matchOptions.eRefreshRate = DXUTMT_CLOSEST_TO_INPUT;
1343 matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;
1344
1345 hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
1346 if( SUCCEEDED(hr) )
1347 {
1348 // Create a Direct3D device using the new device settings.
1349 // If there is an existing device, then it will either reset or recreate the scene.
1350 hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
1351
1352 // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed
1353 if( FAILED( hr ) && (hr != E_ABORT) )
1354 {
1355 // Failed creating device, try to switch back.
1356 if( deviceSettings.DeviceType == D3DDEVTYPE_HAL )
1357 deviceSettings.DeviceType = D3DDEVTYPE_REF;
1358 else if( deviceSettings.DeviceType == D3DDEVTYPE_REF )
1359 deviceSettings.DeviceType = D3DDEVTYPE_HAL;
1360
1361 DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
1362
1363 HRESULT hr2 = DXUTChangeDevice( &deviceSettings, NULL, false, false );
1364 if( FAILED(hr2) )
1365 {
1366 // If this failed, then shutdown
1367 DXUTShutdown();
1368 }
1369 }
1370 }
1371
1372 return hr;
1373 }
1374
1375
1376 //--------------------------------------------------------------------------------------
1377 // Internal helper function to prepare the enumeration object by creating it if it
1378 // didn't already exist and enumerating if desired.
1379 //--------------------------------------------------------------------------------------
DXUTPrepareEnumerationObject(bool bEnumerate)1380 CD3DEnumeration* DXUTPrepareEnumerationObject( bool bEnumerate )
1381 {
1382 // Create a new CD3DEnumeration object and enumerate all devices unless its already been done
1383 CD3DEnumeration* pd3dEnum = GetDXUTState().GetD3DEnumeration();
1384 if( pd3dEnum == NULL )
1385 {
1386 pd3dEnum = DXUTGetEnumeration();
1387 GetDXUTState().SetD3DEnumeration( pd3dEnum );
1388
1389 bEnumerate = true;
1390 }
1391
1392 if( bEnumerate )
1393 {
1394 // Enumerate for each adapter all of the supported display modes,
1395 // device types, adapter formats, back buffer formats, window/full screen support,
1396 // depth stencil formats, multisampling types/qualities, and presentations intervals.
1397 //
1398 // For each combination of device type (HAL/REF), adapter format, back buffer format, and
1399 // IsWindowed it will call the app's ConfirmDevice callback. This allows the app
1400 // to reject or allow that combination based on its caps/etc. It also allows the
1401 // app to change the BehaviorFlags. The BehaviorFlags defaults non-pure HWVP
1402 // if supported otherwise it will default to SWVP, however the app can change this
1403 // through the ConfirmDevice callback.
1404 IDirect3D9* pD3D = DXUTGetD3DObject();
1405 pd3dEnum->Enumerate( pD3D, GetDXUTState().GetIsDeviceAcceptableFunc(), GetDXUTState().GetIsDeviceAcceptableFuncUserContext() );
1406 }
1407
1408 return pd3dEnum;
1409 }
1410
1411
1412 //--------------------------------------------------------------------------------------
1413 // This function tries to find valid device settings based upon the input device settings
1414 // struct and the match options. For each device setting a match option in the
1415 // DXUTMatchOptions struct specifies how the function makes decisions. For example, if
1416 // the caller wants a HAL device with a back buffer format of D3DFMT_A2B10G10R10 but the
1417 // HAL device on the system does not support D3DFMT_A2B10G10R10 however a REF device is
1418 // installed that does, then the function has a choice to either use REF or to change to
1419 // a back buffer format to compatible with the HAL device. The match options lets the
1420 // caller control how these choices are made.
1421 //
1422 // Each match option must be one of the following types:
1423 // DXUTMT_IGNORE_INPUT: Uses the closest valid value to a default
1424 // DXUTMT_PRESERVE_INPUT: Uses the input without change, but may cause no valid device to be found
1425 // DXUTMT_CLOSEST_TO_INPUT: Uses the closest valid value to the input
1426 //
1427 // If pMatchOptions is NULL then, all of the match options are assumed to be DXUTMT_IGNORE_INPUT.
1428 // The function returns failure if no valid device settings can be found otherwise
1429 // the function returns success and the valid device settings are written to pOut.
1430 //--------------------------------------------------------------------------------------
DXUTFindValidDeviceSettings(DXUTDeviceSettings * pOut,DXUTDeviceSettings * pIn,DXUTMatchOptions * pMatchOptions)1431 HRESULT DXUTFindValidDeviceSettings( DXUTDeviceSettings* pOut, DXUTDeviceSettings* pIn,
1432 DXUTMatchOptions* pMatchOptions )
1433 {
1434 if( pOut == NULL )
1435 return DXUT_ERR_MSGBOX( L"DXUTFindValidDeviceSettings", E_INVALIDARG );
1436
1437 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject( false );
1438 IDirect3D9* pD3D = DXUTGetD3DObject();
1439
1440 // Default to DXUTMT_IGNORE_INPUT for everything unless pMatchOptions isn't NULL
1441 DXUTMatchOptions defaultMatchOptions;
1442 if( NULL == pMatchOptions )
1443 {
1444 ZeroMemory( &defaultMatchOptions, sizeof(DXUTMatchOptions) );
1445 pMatchOptions = &defaultMatchOptions;
1446 }
1447
1448 // Build an optimal device settings structure based upon the match
1449 // options. If the match option is set to ignore, then a optimal default value is used.
1450 // The default value may not exist on the system, but later this will be taken
1451 // into account.
1452 DXUTDeviceSettings optimalDeviceSettings;
1453 DXUTBuildOptimalDeviceSettings( &optimalDeviceSettings, pIn, pMatchOptions );
1454
1455 // Find the best combination of:
1456 // Adapter Ordinal
1457 // Device Type
1458 // Adapter Format
1459 // Back Buffer Format
1460 // Windowed
1461 // given what's available on the system and the match options combined with the device settings input.
1462 // This combination of settings is encapsulated by the CD3DEnumDeviceSettingsCombo class.
1463 float fBestRanking = -1.0f;
1464 CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo = NULL;
1465 D3DDISPLAYMODE adapterDesktopDisplayMode;
1466
1467 CGrowableArray<CD3DEnumAdapterInfo*>* pAdapterList = pd3dEnum->GetAdapterInfoList();
1468 for( int iAdapter=0; iAdapter<pAdapterList->GetSize(); iAdapter++ )
1469 {
1470 CD3DEnumAdapterInfo* pAdapterInfo = pAdapterList->GetAt(iAdapter);
1471
1472 // Get the desktop display mode of adapter
1473 pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
1474
1475 // Enum all the device types supported by this adapter to find the best device settings
1476 for( int iDeviceInfo=0; iDeviceInfo<pAdapterInfo->deviceInfoList.GetSize(); iDeviceInfo++ )
1477 {
1478 CD3DEnumDeviceInfo* pDeviceInfo = pAdapterInfo->deviceInfoList.GetAt(iDeviceInfo);
1479
1480 // Enum all the device settings combinations. A device settings combination is
1481 // a unique set of an adapter format, back buffer format, and IsWindowed.
1482 for( int iDeviceCombo=0; iDeviceCombo<pDeviceInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
1483 {
1484 CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pDeviceInfo->deviceSettingsComboList.GetAt(iDeviceCombo);
1485
1486 // If windowed mode the adapter format has to be the same as the desktop
1487 // display mode format so skip any that don't match
1488 if (pDeviceSettingsCombo->Windowed && (pDeviceSettingsCombo->AdapterFormat != adapterDesktopDisplayMode.Format))
1489 continue;
1490
1491 // Skip any combo that doesn't meet the preserve match options
1492 if( false == DXUTDoesDeviceComboMatchPreserveOptions( pDeviceSettingsCombo, pIn, pMatchOptions ) )
1493 continue;
1494
1495 // Get a ranking number that describes how closely this device combo matches the optimal combo
1496 float fCurRanking = DXUTRankDeviceCombo( pDeviceSettingsCombo, &optimalDeviceSettings, &adapterDesktopDisplayMode );
1497
1498 // If this combo better matches the input device settings then save it
1499 if( fCurRanking > fBestRanking )
1500 {
1501 pBestDeviceSettingsCombo = pDeviceSettingsCombo;
1502 fBestRanking = fCurRanking;
1503 }
1504 }
1505 }
1506 }
1507
1508 // If no best device combination was found then fail
1509 if( pBestDeviceSettingsCombo == NULL )
1510 return DXUTERR_NOCOMPATIBLEDEVICES;
1511
1512 // Using the best device settings combo found, build valid device settings taking heed of
1513 // the match options and the input device settings
1514 DXUTDeviceSettings validDeviceSettings;
1515 DXUTBuildValidDeviceSettings( &validDeviceSettings, pBestDeviceSettingsCombo, pIn, pMatchOptions );
1516 *pOut = validDeviceSettings;
1517
1518 return S_OK;
1519 }
1520
1521
1522 //--------------------------------------------------------------------------------------
1523 // Internal helper function to build a device settings structure based upon the match
1524 // options. If the match option is set to ignore, then a optimal default value is used.
1525 // The default value may not exist on the system, but later this will be taken
1526 // into account.
1527 //--------------------------------------------------------------------------------------
DXUTBuildOptimalDeviceSettings(DXUTDeviceSettings * pOptimalDeviceSettings,DXUTDeviceSettings * pDeviceSettingsIn,DXUTMatchOptions * pMatchOptions)1528 void DXUTBuildOptimalDeviceSettings( DXUTDeviceSettings* pOptimalDeviceSettings,
1529 DXUTDeviceSettings* pDeviceSettingsIn,
1530 DXUTMatchOptions* pMatchOptions )
1531 {
1532 IDirect3D9* pD3D = DXUTGetD3DObject();
1533 D3DDISPLAYMODE adapterDesktopDisplayMode;
1534
1535 ZeroMemory( pOptimalDeviceSettings, sizeof(DXUTDeviceSettings) );
1536
1537 //---------------------
1538 // Adapter ordinal
1539 //---------------------
1540 if( pMatchOptions->eAdapterOrdinal == DXUTMT_IGNORE_INPUT )
1541 pOptimalDeviceSettings->AdapterOrdinal = D3DADAPTER_DEFAULT;
1542 else
1543 pOptimalDeviceSettings->AdapterOrdinal = pDeviceSettingsIn->AdapterOrdinal;
1544
1545 //---------------------
1546 // Device type
1547 //---------------------
1548 if( pMatchOptions->eDeviceType == DXUTMT_IGNORE_INPUT )
1549 pOptimalDeviceSettings->DeviceType = D3DDEVTYPE_HAL;
1550 else
1551 pOptimalDeviceSettings->DeviceType = pDeviceSettingsIn->DeviceType;
1552
1553 //---------------------
1554 // Windowed
1555 //---------------------
1556 if( pMatchOptions->eWindowed == DXUTMT_IGNORE_INPUT )
1557 pOptimalDeviceSettings->pp.Windowed = TRUE;
1558 else
1559 pOptimalDeviceSettings->pp.Windowed = pDeviceSettingsIn->pp.Windowed;
1560
1561 //---------------------
1562 // Adapter format
1563 //---------------------
1564 if( pMatchOptions->eAdapterFormat == DXUTMT_IGNORE_INPUT )
1565 {
1566 // If windowed, default to the desktop display mode
1567 // If fullscreen, default to the desktop display mode for quick mode change or
1568 // default to D3DFMT_X8R8G8B8 if the desktop display mode is < 32bit
1569 pD3D->GetAdapterDisplayMode( pOptimalDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
1570 if( pOptimalDeviceSettings->pp.Windowed || DXUTColorChannelBits(adapterDesktopDisplayMode.Format) >= 8 )
1571 pOptimalDeviceSettings->AdapterFormat = adapterDesktopDisplayMode.Format;
1572 else
1573 pOptimalDeviceSettings->AdapterFormat = D3DFMT_X8R8G8B8;
1574 }
1575 else
1576 {
1577 pOptimalDeviceSettings->AdapterFormat = pDeviceSettingsIn->AdapterFormat;
1578 }
1579
1580 //---------------------
1581 // Vertex processing
1582 //---------------------
1583 if( pMatchOptions->eVertexProcessing == DXUTMT_IGNORE_INPUT )
1584 pOptimalDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
1585 else
1586 pOptimalDeviceSettings->BehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
1587
1588 //---------------------
1589 // Resolution
1590 //---------------------
1591 if( pMatchOptions->eResolution == DXUTMT_IGNORE_INPUT )
1592 {
1593 // If windowed, default to 640x480
1594 // If fullscreen, default to the desktop res for quick mode change
1595 if( pOptimalDeviceSettings->pp.Windowed )
1596 {
1597 pOptimalDeviceSettings->pp.BackBufferWidth = 640;
1598 pOptimalDeviceSettings->pp.BackBufferHeight = 480;
1599 }
1600 else
1601 {
1602 pD3D->GetAdapterDisplayMode( pOptimalDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
1603 pOptimalDeviceSettings->pp.BackBufferWidth = adapterDesktopDisplayMode.Width;
1604 pOptimalDeviceSettings->pp.BackBufferHeight = adapterDesktopDisplayMode.Height;
1605 }
1606 }
1607 else
1608 {
1609 pOptimalDeviceSettings->pp.BackBufferWidth = pDeviceSettingsIn->pp.BackBufferWidth;
1610 pOptimalDeviceSettings->pp.BackBufferHeight = pDeviceSettingsIn->pp.BackBufferHeight;
1611 }
1612
1613 //---------------------
1614 // Back buffer format
1615 //---------------------
1616 if( pMatchOptions->eBackBufferFormat == DXUTMT_IGNORE_INPUT )
1617 pOptimalDeviceSettings->pp.BackBufferFormat = pOptimalDeviceSettings->AdapterFormat; // Default to match the adapter format
1618 else
1619 pOptimalDeviceSettings->pp.BackBufferFormat = pDeviceSettingsIn->pp.BackBufferFormat;
1620
1621 //---------------------
1622 // Back buffer count
1623 //---------------------
1624 if( pMatchOptions->eBackBufferCount == DXUTMT_IGNORE_INPUT )
1625 pOptimalDeviceSettings->pp.BackBufferCount = 2; // Default to triple buffering for perf gain
1626 else
1627 pOptimalDeviceSettings->pp.BackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
1628
1629 //---------------------
1630 // Multisample
1631 //---------------------
1632 if( pMatchOptions->eMultiSample == DXUTMT_IGNORE_INPUT )
1633 {
1634 // Default to no multisampling
1635 pOptimalDeviceSettings->pp.MultiSampleType = D3DMULTISAMPLE_NONE;
1636 pOptimalDeviceSettings->pp.MultiSampleQuality = 0;
1637 }
1638 else
1639 {
1640 pOptimalDeviceSettings->pp.MultiSampleType = pDeviceSettingsIn->pp.MultiSampleType;
1641 pOptimalDeviceSettings->pp.MultiSampleQuality = pDeviceSettingsIn->pp.MultiSampleQuality;
1642 }
1643
1644 //---------------------
1645 // Swap effect
1646 //---------------------
1647 if( pMatchOptions->eSwapEffect == DXUTMT_IGNORE_INPUT )
1648 pOptimalDeviceSettings->pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1649 else
1650 pOptimalDeviceSettings->pp.SwapEffect = pDeviceSettingsIn->pp.SwapEffect;
1651
1652 //---------------------
1653 // Depth stencil
1654 //---------------------
1655 if( pMatchOptions->eDepthFormat == DXUTMT_IGNORE_INPUT &&
1656 pMatchOptions->eStencilFormat == DXUTMT_IGNORE_INPUT )
1657 {
1658 UINT nBackBufferBits = DXUTColorChannelBits( pOptimalDeviceSettings->pp.BackBufferFormat );
1659 if( nBackBufferBits >= 8 )
1660 pOptimalDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D32;
1661 else
1662 pOptimalDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D16;
1663 }
1664 else
1665 {
1666 pOptimalDeviceSettings->pp.AutoDepthStencilFormat = pDeviceSettingsIn->pp.AutoDepthStencilFormat;
1667 }
1668
1669 //---------------------
1670 // Present flags
1671 //---------------------
1672 if( pMatchOptions->ePresentFlags == DXUTMT_IGNORE_INPUT )
1673 pOptimalDeviceSettings->pp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
1674 else
1675 pOptimalDeviceSettings->pp.Flags = pDeviceSettingsIn->pp.Flags;
1676
1677 //---------------------
1678 // Refresh rate
1679 //---------------------
1680 if( pMatchOptions->eRefreshRate == DXUTMT_IGNORE_INPUT )
1681 pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz = 0;
1682 else
1683 pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
1684
1685 //---------------------
1686 // Present interval
1687 //---------------------
1688 if( pMatchOptions->ePresentInterval == DXUTMT_IGNORE_INPUT )
1689 {
1690 // For windowed and fullscreen, default to D3DPRESENT_INTERVAL_DEFAULT
1691 // which will wait for the vertical retrace period to prevent tearing.
1692 // For benchmarking, use D3DPRESENT_INTERVAL_DEFAULT which will
1693 // will wait not for the vertical retrace period but may introduce tearing.
1694 pOptimalDeviceSettings->pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
1695 }
1696 else
1697 {
1698 pOptimalDeviceSettings->pp.PresentationInterval = pDeviceSettingsIn->pp.PresentationInterval;
1699 }
1700 }
1701
1702
1703 //--------------------------------------------------------------------------------------
1704 // Returns false for any CD3DEnumDeviceSettingsCombo that doesn't meet the preserve
1705 // match options against the input pDeviceSettingsIn.
1706 //--------------------------------------------------------------------------------------
DXUTDoesDeviceComboMatchPreserveOptions(CD3DEnumDeviceSettingsCombo * pDeviceSettingsCombo,DXUTDeviceSettings * pDeviceSettingsIn,DXUTMatchOptions * pMatchOptions)1707 bool DXUTDoesDeviceComboMatchPreserveOptions( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo,
1708 DXUTDeviceSettings* pDeviceSettingsIn,
1709 DXUTMatchOptions* pMatchOptions )
1710 {
1711 //---------------------
1712 // Adapter ordinal
1713 //---------------------
1714 if( pMatchOptions->eAdapterOrdinal == DXUTMT_PRESERVE_INPUT &&
1715 (pDeviceSettingsCombo->AdapterOrdinal != pDeviceSettingsIn->AdapterOrdinal) )
1716 return false;
1717
1718 //---------------------
1719 // Device type
1720 //---------------------
1721 if( pMatchOptions->eDeviceType == DXUTMT_PRESERVE_INPUT &&
1722 (pDeviceSettingsCombo->DeviceType != pDeviceSettingsIn->DeviceType) )
1723 return false;
1724
1725 //---------------------
1726 // Windowed
1727 //---------------------
1728 if( pMatchOptions->eWindowed == DXUTMT_PRESERVE_INPUT &&
1729 (pDeviceSettingsCombo->Windowed != pDeviceSettingsIn->pp.Windowed) )
1730 return false;
1731
1732 //---------------------
1733 // Adapter format
1734 //---------------------
1735 if( pMatchOptions->eAdapterFormat == DXUTMT_PRESERVE_INPUT &&
1736 (pDeviceSettingsCombo->AdapterFormat != pDeviceSettingsIn->AdapterFormat) )
1737 return false;
1738
1739 //---------------------
1740 // Vertex processing
1741 //---------------------
1742 // If keep VP and input has HWVP, then skip if this combo doesn't have HWTL
1743 if( pMatchOptions->eVertexProcessing == DXUTMT_PRESERVE_INPUT &&
1744 ((pDeviceSettingsIn->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0) &&
1745 ((pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0) )
1746 return false;
1747
1748 //---------------------
1749 // Resolution
1750 //---------------------
1751 // If keep resolution then check that width and height supported by this combo
1752 if( pMatchOptions->eResolution == DXUTMT_PRESERVE_INPUT )
1753 {
1754 bool bFound = false;
1755 for( int i=0; i< pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); i++ )
1756 {
1757 D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( i );
1758 if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
1759 continue; // Skip this display mode if it doesn't match the combo's adapter format
1760
1761 if( displayMode.Width == pDeviceSettingsIn->pp.BackBufferWidth &&
1762 displayMode.Height == pDeviceSettingsIn->pp.BackBufferHeight )
1763 {
1764 bFound = true;
1765 break;
1766 }
1767 }
1768
1769 // If the width and height are not supported by this combo, return false
1770 if( !bFound )
1771 return false;
1772 }
1773
1774 //---------------------
1775 // Back buffer format
1776 //---------------------
1777 if( pMatchOptions->eBackBufferFormat == DXUTMT_PRESERVE_INPUT &&
1778 pDeviceSettingsCombo->BackBufferFormat != pDeviceSettingsIn->pp.BackBufferFormat )
1779 return false;
1780
1781 //---------------------
1782 // Back buffer count
1783 //---------------------
1784 // No caps for the back buffer count
1785
1786 //---------------------
1787 // Multisample
1788 //---------------------
1789 if( pMatchOptions->eMultiSample == DXUTMT_PRESERVE_INPUT )
1790 {
1791 bool bFound = false;
1792 for( int i=0; i<pDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
1793 {
1794 D3DMULTISAMPLE_TYPE msType = pDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
1795 DWORD msQuality = pDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
1796
1797 if( msType == pDeviceSettingsIn->pp.MultiSampleType &&
1798 msQuality >= pDeviceSettingsIn->pp.MultiSampleQuality )
1799 {
1800 bFound = true;
1801 break;
1802 }
1803 }
1804
1805 // If multisample type/quality not supported by this combo, then return false
1806 if( !bFound )
1807 return false;
1808 }
1809
1810 //---------------------
1811 // Swap effect
1812 //---------------------
1813 // No caps for swap effects
1814
1815 //---------------------
1816 // Depth stencil
1817 //---------------------
1818 // If keep depth stencil format then check that the depth stencil format is supported by this combo
1819 if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT &&
1820 pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT )
1821 {
1822 if( pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN &&
1823 !pDeviceSettingsCombo->depthStencilFormatList.Contains( pDeviceSettingsIn->pp.AutoDepthStencilFormat ) )
1824 return false;
1825 }
1826
1827 // If keep depth format then check that the depth format is supported by this combo
1828 if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT &&
1829 pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN )
1830 {
1831 bool bFound = false;
1832 UINT dwDepthBits = DXUTDepthBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
1833 for( int i=0; i<pDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
1834 {
1835 D3DFORMAT depthStencilFmt = pDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
1836 UINT dwCurDepthBits = DXUTDepthBits( depthStencilFmt );
1837 if( dwCurDepthBits - dwDepthBits == 0)
1838 bFound = true;
1839 }
1840
1841 if( !bFound )
1842 return false;
1843 }
1844
1845 // If keep depth format then check that the depth format is supported by this combo
1846 if( pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT &&
1847 pDeviceSettingsIn->pp.AutoDepthStencilFormat != D3DFMT_UNKNOWN )
1848 {
1849 bool bFound = false;
1850 UINT dwStencilBits = DXUTStencilBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
1851 for( int i=0; i<pDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
1852 {
1853 D3DFORMAT depthStencilFmt = pDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
1854 UINT dwCurStencilBits = DXUTStencilBits( depthStencilFmt );
1855 if( dwCurStencilBits - dwStencilBits == 0)
1856 bFound = true;
1857 }
1858
1859 if( !bFound )
1860 return false;
1861 }
1862
1863 //---------------------
1864 // Present flags
1865 //---------------------
1866 // No caps for the present flags
1867
1868 //---------------------
1869 // Refresh rate
1870 //---------------------
1871 // If keep refresh rate then check that the resolution is supported by this combo
1872 if( pMatchOptions->eRefreshRate == DXUTMT_PRESERVE_INPUT )
1873 {
1874 bool bFound = false;
1875 for( int i=0; i<pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); i++ )
1876 {
1877 D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( i );
1878 if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
1879 continue;
1880 if( displayMode.RefreshRate == pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz )
1881 {
1882 bFound = true;
1883 break;
1884 }
1885 }
1886
1887 // If refresh rate not supported by this combo, then return false
1888 if( !bFound )
1889 return false;
1890 }
1891
1892 //---------------------
1893 // Present interval
1894 //---------------------
1895 // If keep present interval then check that the present interval is supported by this combo
1896 if( pMatchOptions->ePresentInterval == DXUTMT_PRESERVE_INPUT &&
1897 !pDeviceSettingsCombo->presentIntervalList.Contains( pDeviceSettingsIn->pp.PresentationInterval ) )
1898 return false;
1899
1900 return true;
1901 }
1902
1903
1904 //--------------------------------------------------------------------------------------
1905 // Returns a ranking number that describes how closely this device
1906 // combo matches the optimal combo based on the match options and the optimal device settings
1907 //--------------------------------------------------------------------------------------
DXUTRankDeviceCombo(CD3DEnumDeviceSettingsCombo * pDeviceSettingsCombo,DXUTDeviceSettings * pOptimalDeviceSettings,D3DDISPLAYMODE * pAdapterDesktopDisplayMode)1908 float DXUTRankDeviceCombo( CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo,
1909 DXUTDeviceSettings* pOptimalDeviceSettings,
1910 D3DDISPLAYMODE* pAdapterDesktopDisplayMode )
1911 {
1912 float fCurRanking = 0.0f;
1913
1914 // Arbitrary weights. Gives preference to the ordinal, device type, and windowed
1915 const float fAdapterOrdinalWeight = 1000.0f;
1916 const float fDeviceTypeWeight = 100.0f;
1917 const float fWindowWeight = 10.0f;
1918 const float fAdapterFormatWeight = 1.0f;
1919 const float fVertexProcessingWeight = 1.0f;
1920 const float fResolutionWeight = 1.0f;
1921 const float fBackBufferFormatWeight = 1.0f;
1922 const float fMultiSampleWeight = 1.0f;
1923 const float fDepthStencilWeight = 1.0f;
1924 const float fRefreshRateWeight = 1.0f;
1925 const float fPresentIntervalWeight = 1.0f;
1926
1927 //---------------------
1928 // Adapter ordinal
1929 //---------------------
1930 if( pDeviceSettingsCombo->AdapterOrdinal == pOptimalDeviceSettings->AdapterOrdinal )
1931 fCurRanking += fAdapterOrdinalWeight;
1932
1933 //---------------------
1934 // Device type
1935 //---------------------
1936 if( pDeviceSettingsCombo->DeviceType == pOptimalDeviceSettings->DeviceType )
1937 fCurRanking += fDeviceTypeWeight;
1938 // Slightly prefer HAL
1939 if( pDeviceSettingsCombo->DeviceType == D3DDEVTYPE_HAL )
1940 fCurRanking += 0.1f;
1941
1942 //---------------------
1943 // Windowed
1944 //---------------------
1945 if( pDeviceSettingsCombo->Windowed == pOptimalDeviceSettings->pp.Windowed )
1946 fCurRanking += fWindowWeight;
1947
1948 //---------------------
1949 // Adapter format
1950 //---------------------
1951 if( pDeviceSettingsCombo->AdapterFormat == pOptimalDeviceSettings->AdapterFormat )
1952 {
1953 fCurRanking += fAdapterFormatWeight;
1954 }
1955 else
1956 {
1957 int nBitDepthDelta = abs( (long) DXUTColorChannelBits(pDeviceSettingsCombo->AdapterFormat) -
1958 (long) DXUTColorChannelBits(pOptimalDeviceSettings->AdapterFormat) );
1959 float fScale = __max(0.9f - (float)nBitDepthDelta*0.2f, 0.0f);
1960 fCurRanking += fScale * fAdapterFormatWeight;
1961 }
1962
1963 if( !pDeviceSettingsCombo->Windowed )
1964 {
1965 // Slightly prefer when it matches the desktop format or is D3DFMT_X8R8G8B8
1966 bool bAdapterOptimalMatch;
1967 if( DXUTColorChannelBits(pAdapterDesktopDisplayMode->Format) >= 8 )
1968 bAdapterOptimalMatch = (pDeviceSettingsCombo->AdapterFormat == pAdapterDesktopDisplayMode->Format);
1969 else
1970 bAdapterOptimalMatch = (pDeviceSettingsCombo->AdapterFormat == D3DFMT_X8R8G8B8);
1971
1972 if( bAdapterOptimalMatch )
1973 fCurRanking += 0.1f;
1974 }
1975
1976 //---------------------
1977 // Vertex processing
1978 //---------------------
1979 if( (pOptimalDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 ||
1980 (pOptimalDeviceSettings->BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 )
1981 {
1982 if( (pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0 )
1983 fCurRanking += fVertexProcessingWeight;
1984 }
1985 // Slightly prefer HW T&L
1986 if( (pDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0 )
1987 fCurRanking += 0.1f;
1988
1989 //---------------------
1990 // Resolution
1991 //---------------------
1992 bool bResolutionFound = false;
1993 for( int idm = 0; idm < pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); idm++ )
1994 {
1995 D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( idm );
1996 if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
1997 continue;
1998 if( displayMode.Width == pOptimalDeviceSettings->pp.BackBufferWidth &&
1999 displayMode.Height == pOptimalDeviceSettings->pp.BackBufferHeight )
2000 bResolutionFound = true;
2001 }
2002 if( bResolutionFound )
2003 fCurRanking += fResolutionWeight;
2004
2005 //---------------------
2006 // Back buffer format
2007 //---------------------
2008 if( pDeviceSettingsCombo->BackBufferFormat == pOptimalDeviceSettings->pp.BackBufferFormat )
2009 {
2010 fCurRanking += fBackBufferFormatWeight;
2011 }
2012 else
2013 {
2014 int nBitDepthDelta = abs( (long) DXUTColorChannelBits(pDeviceSettingsCombo->BackBufferFormat) -
2015 (long) DXUTColorChannelBits(pOptimalDeviceSettings->pp.BackBufferFormat) );
2016 float fScale = __max(0.9f - (float)nBitDepthDelta*0.2f, 0.0f);
2017 fCurRanking += fScale * fBackBufferFormatWeight;
2018 }
2019
2020 // Check if this back buffer format is the same as
2021 // the adapter format since this is preferred.
2022 bool bAdapterMatchesBB = (pDeviceSettingsCombo->BackBufferFormat == pDeviceSettingsCombo->AdapterFormat);
2023 if( bAdapterMatchesBB )
2024 fCurRanking += 0.1f;
2025
2026 //---------------------
2027 // Back buffer count
2028 //---------------------
2029 // No caps for the back buffer count
2030
2031 //---------------------
2032 // Multisample
2033 //---------------------
2034 bool bMultiSampleFound = false;
2035 for( int i=0; i<pDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
2036 {
2037 D3DMULTISAMPLE_TYPE msType = pDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
2038 DWORD msQuality = pDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
2039
2040 if( msType == pOptimalDeviceSettings->pp.MultiSampleType &&
2041 msQuality >= pOptimalDeviceSettings->pp.MultiSampleQuality )
2042 {
2043 bMultiSampleFound = true;
2044 break;
2045 }
2046 }
2047 if( bMultiSampleFound )
2048 fCurRanking += fMultiSampleWeight;
2049
2050 //---------------------
2051 // Swap effect
2052 //---------------------
2053 // No caps for swap effects
2054
2055 //---------------------
2056 // Depth stencil
2057 //---------------------
2058 if( pDeviceSettingsCombo->depthStencilFormatList.Contains( pOptimalDeviceSettings->pp.AutoDepthStencilFormat ) )
2059 fCurRanking += fDepthStencilWeight;
2060
2061 //---------------------
2062 // Present flags
2063 //---------------------
2064 // No caps for the present flags
2065
2066 //---------------------
2067 // Refresh rate
2068 //---------------------
2069 bool bRefreshFound = false;
2070 for( int idm = 0; idm < pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetSize(); idm++ )
2071 {
2072 D3DDISPLAYMODE displayMode = pDeviceSettingsCombo->pAdapterInfo->displayModeList.GetAt( idm );
2073 if( displayMode.Format != pDeviceSettingsCombo->AdapterFormat )
2074 continue;
2075 if( displayMode.RefreshRate == pOptimalDeviceSettings->pp.FullScreen_RefreshRateInHz )
2076 bRefreshFound = true;
2077 }
2078 if( bRefreshFound )
2079 fCurRanking += fRefreshRateWeight;
2080
2081 //---------------------
2082 // Present interval
2083 //---------------------
2084 // If keep present interval then check that the present interval is supported by this combo
2085 if( pDeviceSettingsCombo->presentIntervalList.Contains( pOptimalDeviceSettings->pp.PresentationInterval ) )
2086 fCurRanking += fPresentIntervalWeight;
2087
2088 return fCurRanking;
2089 }
2090
2091
2092 //--------------------------------------------------------------------------------------
2093 // Builds valid device settings using the match options, the input device settings, and the
2094 // best device settings combo found.
2095 //--------------------------------------------------------------------------------------
DXUTBuildValidDeviceSettings(DXUTDeviceSettings * pValidDeviceSettings,CD3DEnumDeviceSettingsCombo * pBestDeviceSettingsCombo,DXUTDeviceSettings * pDeviceSettingsIn,DXUTMatchOptions * pMatchOptions)2096 void DXUTBuildValidDeviceSettings( DXUTDeviceSettings* pValidDeviceSettings,
2097 CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo,
2098 DXUTDeviceSettings* pDeviceSettingsIn,
2099 DXUTMatchOptions* pMatchOptions )
2100 {
2101 IDirect3D9* pD3D = DXUTGetD3DObject();
2102 D3DDISPLAYMODE adapterDesktopDisplayMode;
2103 pD3D->GetAdapterDisplayMode( pBestDeviceSettingsCombo->AdapterOrdinal, &adapterDesktopDisplayMode );
2104
2105 // For each setting pick the best, taking into account the match options and
2106 // what's supported by the device
2107
2108 //---------------------
2109 // Adapter Ordinal
2110 //---------------------
2111 // Just using pBestDeviceSettingsCombo->AdapterOrdinal
2112
2113 //---------------------
2114 // Device Type
2115 //---------------------
2116 // Just using pBestDeviceSettingsCombo->DeviceType
2117
2118 //---------------------
2119 // Windowed
2120 //---------------------
2121 // Just using pBestDeviceSettingsCombo->Windowed
2122
2123 //---------------------
2124 // Adapter Format
2125 //---------------------
2126 // Just using pBestDeviceSettingsCombo->AdapterFormat
2127
2128 //---------------------
2129 // Vertex processing
2130 //---------------------
2131 DWORD dwBestBehaviorFlags = 0;
2132 if( pMatchOptions->eVertexProcessing == DXUTMT_PRESERVE_INPUT )
2133 {
2134 dwBestBehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
2135 }
2136 else if( pMatchOptions->eVertexProcessing == DXUTMT_IGNORE_INPUT )
2137 {
2138 // The framework defaults to HWVP if available otherwise use SWVP
2139 if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
2140 dwBestBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
2141 else
2142 dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
2143 }
2144 else // if( pMatchOptions->eVertexProcessing == DXUTMT_CLOSEST_TO_INPUT )
2145 {
2146 // Default to input, and fallback to SWVP if HWVP not available
2147 dwBestBehaviorFlags = pDeviceSettingsIn->BehaviorFlags;
2148 if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 &&
2149 ( (dwBestBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 ||
2150 (dwBestBehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0) )
2151 {
2152 dwBestBehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
2153 dwBestBehaviorFlags &= ~D3DCREATE_MIXED_VERTEXPROCESSING;
2154 dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
2155 }
2156
2157 // One of these must be selected
2158 if( (dwBestBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) == 0 &&
2159 (dwBestBehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING) == 0 &&
2160 (dwBestBehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) == 0 )
2161 {
2162 if ((pBestDeviceSettingsCombo->pDeviceInfo->Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
2163 dwBestBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
2164 else
2165 dwBestBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
2166 }
2167 }
2168
2169 //---------------------
2170 // Resolution
2171 //---------------------
2172 D3DDISPLAYMODE bestDisplayMode;
2173 if( pMatchOptions->eResolution == DXUTMT_PRESERVE_INPUT )
2174 {
2175 bestDisplayMode.Width = pDeviceSettingsIn->pp.BackBufferWidth;
2176 bestDisplayMode.Height = pDeviceSettingsIn->pp.BackBufferHeight;
2177 }
2178 else
2179 {
2180 D3DDISPLAYMODE displayModeIn;
2181 if( pMatchOptions->eResolution == DXUTMT_CLOSEST_TO_INPUT &&
2182 pDeviceSettingsIn )
2183 {
2184 displayModeIn.Width = pDeviceSettingsIn->pp.BackBufferWidth;
2185 displayModeIn.Height = pDeviceSettingsIn->pp.BackBufferHeight;
2186 }
2187 else // if( pMatchOptions->eResolution == DXUTMT_IGNORE_INPUT )
2188 {
2189 if( pBestDeviceSettingsCombo->Windowed )
2190 {
2191 // The framework defaults to 640x480 for windowed
2192 displayModeIn.Width = 640;
2193 displayModeIn.Height = 480;
2194 }
2195 else
2196 {
2197 // The framework defaults to desktop resolution for fullscreen to try to avoid slow mode change
2198 displayModeIn.Width = adapterDesktopDisplayMode.Width;
2199 displayModeIn.Height = adapterDesktopDisplayMode.Height;
2200 }
2201 }
2202
2203 // Call a helper function to find the closest valid display mode to the optimal
2204 DXUTFindValidResolution( pBestDeviceSettingsCombo, displayModeIn, &bestDisplayMode );
2205 }
2206
2207 //---------------------
2208 // Back Buffer Format
2209 //---------------------
2210 // Just using pBestDeviceSettingsCombo->BackBufferFormat
2211
2212 //---------------------
2213 // Back buffer count
2214 //---------------------
2215 UINT bestBackBufferCount;
2216 if( pMatchOptions->eBackBufferCount == DXUTMT_PRESERVE_INPUT )
2217 {
2218 bestBackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
2219 }
2220 else if( pMatchOptions->eBackBufferCount == DXUTMT_IGNORE_INPUT )
2221 {
2222 // The framework defaults to triple buffering
2223 bestBackBufferCount = 2;
2224 }
2225 else // if( pMatchOptions->eBackBufferCount == DXUTMT_CLOSEST_TO_INPUT )
2226 {
2227 bestBackBufferCount = pDeviceSettingsIn->pp.BackBufferCount;
2228 if( bestBackBufferCount > 3 )
2229 bestBackBufferCount = 3;
2230 if( bestBackBufferCount < 1 )
2231 bestBackBufferCount = 1;
2232 }
2233
2234 //---------------------
2235 // Multisample
2236 //---------------------
2237 D3DMULTISAMPLE_TYPE bestMultiSampleType;
2238 DWORD bestMultiSampleQuality;
2239 if( pDeviceSettingsIn && pDeviceSettingsIn->pp.SwapEffect != D3DSWAPEFFECT_DISCARD )
2240 {
2241 // Swap effect is not set to discard so multisampling has to off
2242 bestMultiSampleType = D3DMULTISAMPLE_NONE;
2243 bestMultiSampleQuality = 0;
2244 }
2245 else
2246 {
2247 if( pMatchOptions->eMultiSample == DXUTMT_PRESERVE_INPUT )
2248 {
2249 bestMultiSampleType = pDeviceSettingsIn->pp.MultiSampleType;
2250 bestMultiSampleQuality = pDeviceSettingsIn->pp.MultiSampleQuality;
2251 }
2252 else if( pMatchOptions->eMultiSample == DXUTMT_IGNORE_INPUT )
2253 {
2254 // Default to no multisampling (always supported)
2255 bestMultiSampleType = D3DMULTISAMPLE_NONE;
2256 bestMultiSampleQuality = 0;
2257 }
2258 else if( pMatchOptions->eMultiSample == DXUTMT_CLOSEST_TO_INPUT )
2259 {
2260 // Default to no multisampling (always supported)
2261 bestMultiSampleType = D3DMULTISAMPLE_NONE;
2262 bestMultiSampleQuality = 0;
2263
2264 for( int i=0; i < pBestDeviceSettingsCombo->multiSampleTypeList.GetSize(); i++ )
2265 {
2266 D3DMULTISAMPLE_TYPE type = pBestDeviceSettingsCombo->multiSampleTypeList.GetAt(i);
2267 DWORD qualityLevels = pBestDeviceSettingsCombo->multiSampleQualityList.GetAt(i);
2268
2269 // Check whether supported type is closer to the input than our current best
2270 if( abs(type - pDeviceSettingsIn->pp.MultiSampleType) < abs(bestMultiSampleType - pDeviceSettingsIn->pp.MultiSampleType) )
2271 {
2272 bestMultiSampleType = type;
2273 bestMultiSampleQuality = __min( qualityLevels-1, pDeviceSettingsIn->pp.MultiSampleQuality );
2274 }
2275 }
2276 }
2277 else
2278 {
2279 // Error case
2280 bestMultiSampleType = D3DMULTISAMPLE_NONE;
2281 bestMultiSampleQuality = 0;
2282 }
2283 }
2284
2285 //---------------------
2286 // Swap effect
2287 //---------------------
2288 D3DSWAPEFFECT bestSwapEffect;
2289 if( pMatchOptions->eSwapEffect == DXUTMT_PRESERVE_INPUT )
2290 {
2291 bestSwapEffect = pDeviceSettingsIn->pp.SwapEffect;
2292 }
2293 else if( pMatchOptions->eSwapEffect == DXUTMT_IGNORE_INPUT )
2294 {
2295 bestSwapEffect = D3DSWAPEFFECT_DISCARD;
2296 }
2297 else // if( pMatchOptions->eSwapEffect == DXUTMT_CLOSEST_TO_INPUT )
2298 {
2299 bestSwapEffect = pDeviceSettingsIn->pp.SwapEffect;
2300
2301 // Swap effect has to be one of these 3
2302 if( bestSwapEffect != D3DSWAPEFFECT_DISCARD &&
2303 bestSwapEffect != D3DSWAPEFFECT_FLIP &&
2304 bestSwapEffect != D3DSWAPEFFECT_COPY )
2305 {
2306 bestSwapEffect = D3DSWAPEFFECT_DISCARD;
2307 }
2308 }
2309
2310 //---------------------
2311 // Depth stencil
2312 //---------------------
2313 D3DFORMAT bestDepthStencilFormat;
2314 BOOL bestEnableAutoDepthStencil;
2315
2316 CGrowableArray< int > depthStencilRanking;
2317 depthStencilRanking.SetSize( pBestDeviceSettingsCombo->depthStencilFormatList.GetSize() );
2318
2319 UINT dwBackBufferBitDepth = DXUTColorChannelBits( pBestDeviceSettingsCombo->BackBufferFormat );
2320 UINT dwInputDepthBitDepth = 0;
2321 if( pDeviceSettingsIn )
2322 dwInputDepthBitDepth = DXUTDepthBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
2323
2324 for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
2325 {
2326 D3DFORMAT curDepthStencilFmt = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
2327 DWORD dwCurDepthBitDepth = DXUTDepthBits( curDepthStencilFmt );
2328 int nRanking;
2329
2330 if( pMatchOptions->eDepthFormat == DXUTMT_PRESERVE_INPUT )
2331 {
2332 // Need to match bit depth of input
2333 if(dwCurDepthBitDepth == dwInputDepthBitDepth)
2334 nRanking = 0;
2335 else
2336 nRanking = 10000;
2337 }
2338 else if( pMatchOptions->eDepthFormat == DXUTMT_IGNORE_INPUT )
2339 {
2340 // Prefer match of backbuffer bit depth
2341 nRanking = abs((int)dwCurDepthBitDepth - (int)dwBackBufferBitDepth*4);
2342 }
2343 else // if( pMatchOptions->eDepthFormat == DXUTMT_CLOSEST_TO_INPUT )
2344 {
2345 // Prefer match of input depth format bit depth
2346 nRanking = abs((int)dwCurDepthBitDepth - (int)dwInputDepthBitDepth);
2347 }
2348
2349 depthStencilRanking.Add( nRanking );
2350 }
2351
2352 UINT dwInputStencilBitDepth = 0;
2353 if( pDeviceSettingsIn )
2354 dwInputStencilBitDepth = DXUTStencilBits( pDeviceSettingsIn->pp.AutoDepthStencilFormat );
2355
2356 for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
2357 {
2358 D3DFORMAT curDepthStencilFmt = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(i);
2359 int nRanking = depthStencilRanking.GetAt(i);
2360 DWORD dwCurStencilBitDepth = DXUTStencilBits( curDepthStencilFmt );
2361
2362 if( pMatchOptions->eStencilFormat == DXUTMT_PRESERVE_INPUT )
2363 {
2364 // Need to match bit depth of input
2365 if(dwCurStencilBitDepth == dwInputStencilBitDepth)
2366 nRanking += 0;
2367 else
2368 nRanking += 10000;
2369 }
2370 else if( pMatchOptions->eStencilFormat == DXUTMT_IGNORE_INPUT )
2371 {
2372 // Prefer 0 stencil bit depth
2373 nRanking += dwCurStencilBitDepth;
2374 }
2375 else // if( pMatchOptions->eStencilFormat == DXUTMT_CLOSEST_TO_INPUT )
2376 {
2377 // Prefer match of input stencil format bit depth
2378 nRanking += abs((int)dwCurStencilBitDepth - (int)dwInputStencilBitDepth);
2379 }
2380
2381 depthStencilRanking.SetAt( i, nRanking );
2382 }
2383
2384 int nBestRanking = 100000;
2385 int nBestIndex = -1;
2386 for( int i=0; i<pBestDeviceSettingsCombo->depthStencilFormatList.GetSize(); i++ )
2387 {
2388 int nRanking = depthStencilRanking.GetAt(i);
2389 if( nRanking < nBestRanking )
2390 {
2391 nBestRanking = nRanking;
2392 nBestIndex = i;
2393 }
2394 }
2395
2396 if( nBestIndex >= 0 )
2397 {
2398 bestDepthStencilFormat = pBestDeviceSettingsCombo->depthStencilFormatList.GetAt(nBestIndex);
2399 bestEnableAutoDepthStencil = true;
2400 }
2401 else
2402 {
2403 bestDepthStencilFormat = D3DFMT_UNKNOWN;
2404 bestEnableAutoDepthStencil = false;
2405 }
2406
2407
2408 //---------------------
2409 // Present flags
2410 //---------------------
2411 DWORD dwBestFlags;
2412 if( pMatchOptions->ePresentFlags == DXUTMT_PRESERVE_INPUT )
2413 {
2414 dwBestFlags = pDeviceSettingsIn->pp.Flags;
2415 }
2416 else if( pMatchOptions->ePresentFlags == DXUTMT_IGNORE_INPUT )
2417 {
2418 dwBestFlags = 0;
2419 if( bestEnableAutoDepthStencil )
2420 dwBestFlags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
2421 }
2422 else // if( pMatchOptions->ePresentFlags == DXUTMT_CLOSEST_TO_INPUT )
2423 {
2424 dwBestFlags = pDeviceSettingsIn->pp.Flags;
2425 if( bestEnableAutoDepthStencil )
2426 dwBestFlags |= D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
2427 }
2428
2429 //---------------------
2430 // Refresh rate
2431 //---------------------
2432 if( pBestDeviceSettingsCombo->Windowed )
2433 {
2434 // Must be 0 for windowed
2435 bestDisplayMode.RefreshRate = 0;
2436 }
2437 else
2438 {
2439 if( pMatchOptions->eRefreshRate == DXUTMT_PRESERVE_INPUT )
2440 {
2441 bestDisplayMode.RefreshRate = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
2442 }
2443 else
2444 {
2445 UINT refreshRateMatch;
2446 if( pMatchOptions->eRefreshRate == DXUTMT_CLOSEST_TO_INPUT )
2447 {
2448 refreshRateMatch = pDeviceSettingsIn->pp.FullScreen_RefreshRateInHz;
2449 }
2450 else // if( pMatchOptions->eRefreshRate == DXUTMT_IGNORE_INPUT )
2451 {
2452 refreshRateMatch = adapterDesktopDisplayMode.RefreshRate;
2453 }
2454
2455 bestDisplayMode.RefreshRate = 0;
2456
2457 if( refreshRateMatch != 0 )
2458 {
2459 int nBestRefreshRanking = 100000;
2460 CGrowableArray<D3DDISPLAYMODE>* pDisplayModeList = &pBestDeviceSettingsCombo->pAdapterInfo->displayModeList;
2461 for( int iDisplayMode=0; iDisplayMode<pDisplayModeList->GetSize(); iDisplayMode++ )
2462 {
2463 D3DDISPLAYMODE displayMode = pDisplayModeList->GetAt(iDisplayMode);
2464 if( displayMode.Format != pBestDeviceSettingsCombo->AdapterFormat ||
2465 displayMode.Height != bestDisplayMode.Height ||
2466 displayMode.Width != bestDisplayMode.Width )
2467 continue; // Skip display modes that don't match
2468
2469 // Find the delta between the current refresh rate and the optimal refresh rate
2470 int nCurRanking = abs((int)displayMode.RefreshRate - (int)refreshRateMatch);
2471
2472 if( nCurRanking < nBestRefreshRanking )
2473 {
2474 bestDisplayMode.RefreshRate = displayMode.RefreshRate;
2475 nBestRefreshRanking = nCurRanking;
2476
2477 // Stop if perfect match found
2478 if( nBestRefreshRanking == 0 )
2479 break;
2480 }
2481 }
2482 }
2483 }
2484 }
2485
2486 //---------------------
2487 // Present interval
2488 //---------------------
2489 UINT bestPresentInterval;
2490 if( pMatchOptions->ePresentInterval == DXUTMT_PRESERVE_INPUT )
2491 {
2492 bestPresentInterval = pDeviceSettingsIn->pp.PresentationInterval;
2493 }
2494 else if( pMatchOptions->ePresentInterval == DXUTMT_IGNORE_INPUT )
2495 {
2496 // For windowed and fullscreen, default to D3DPRESENT_INTERVAL_DEFAULT
2497 // which will wait for the vertical retrace period to prevent tearing.
2498 // For benchmarking, use D3DPRESENT_INTERVAL_DEFAULT which will
2499 // will wait not for the vertical retrace period but may introduce tearing.
2500 bestPresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
2501 }
2502 else // if( pMatchOptions->ePresentInterval == DXUTMT_CLOSEST_TO_INPUT )
2503 {
2504 if( pBestDeviceSettingsCombo->presentIntervalList.Contains( pDeviceSettingsIn->pp.PresentationInterval ) )
2505 {
2506 bestPresentInterval = pDeviceSettingsIn->pp.PresentationInterval;
2507 }
2508 else
2509 {
2510 bestPresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
2511 }
2512 }
2513
2514 // Fill the device settings struct
2515 ZeroMemory( pValidDeviceSettings, sizeof(DXUTDeviceSettings) );
2516 pValidDeviceSettings->AdapterOrdinal = pBestDeviceSettingsCombo->AdapterOrdinal;
2517 pValidDeviceSettings->DeviceType = pBestDeviceSettingsCombo->DeviceType;
2518 pValidDeviceSettings->AdapterFormat = pBestDeviceSettingsCombo->AdapterFormat;
2519 pValidDeviceSettings->BehaviorFlags = dwBestBehaviorFlags;
2520 pValidDeviceSettings->pp.BackBufferWidth = bestDisplayMode.Width;
2521 pValidDeviceSettings->pp.BackBufferHeight = bestDisplayMode.Height;
2522 pValidDeviceSettings->pp.BackBufferFormat = pBestDeviceSettingsCombo->BackBufferFormat;
2523 pValidDeviceSettings->pp.BackBufferCount = bestBackBufferCount;
2524 pValidDeviceSettings->pp.MultiSampleType = bestMultiSampleType;
2525 pValidDeviceSettings->pp.MultiSampleQuality = bestMultiSampleQuality;
2526 pValidDeviceSettings->pp.SwapEffect = bestSwapEffect;
2527 pValidDeviceSettings->pp.hDeviceWindow = pBestDeviceSettingsCombo->Windowed ? DXUTGetHWNDDeviceWindowed() : DXUTGetHWNDDeviceFullScreen();
2528 pValidDeviceSettings->pp.Windowed = pBestDeviceSettingsCombo->Windowed;
2529 pValidDeviceSettings->pp.EnableAutoDepthStencil = bestEnableAutoDepthStencil;
2530 pValidDeviceSettings->pp.AutoDepthStencilFormat = bestDepthStencilFormat;
2531 pValidDeviceSettings->pp.Flags = dwBestFlags;
2532 pValidDeviceSettings->pp.FullScreen_RefreshRateInHz = bestDisplayMode.RefreshRate;
2533 pValidDeviceSettings->pp.PresentationInterval = bestPresentInterval;
2534 }
2535
2536
2537 //--------------------------------------------------------------------------------------
2538 // Internal helper function to find the closest allowed display mode to the optimal
2539 //--------------------------------------------------------------------------------------
DXUTFindValidResolution(CD3DEnumDeviceSettingsCombo * pBestDeviceSettingsCombo,D3DDISPLAYMODE displayModeIn,D3DDISPLAYMODE * pBestDisplayMode)2540 HRESULT DXUTFindValidResolution( CD3DEnumDeviceSettingsCombo* pBestDeviceSettingsCombo,
2541 D3DDISPLAYMODE displayModeIn, D3DDISPLAYMODE* pBestDisplayMode )
2542 {
2543 D3DDISPLAYMODE bestDisplayMode;
2544 ZeroMemory( &bestDisplayMode, sizeof(D3DDISPLAYMODE) );
2545
2546 if( pBestDeviceSettingsCombo->Windowed )
2547 {
2548 // In windowed mode, all resolutions are valid but restritions still apply
2549 // on the size of the window. See DXUTChangeDevice() for details
2550 *pBestDisplayMode = displayModeIn;
2551 }
2552 else
2553 {
2554 int nBestRanking = 100000;
2555 int nCurRanking;
2556 CGrowableArray<D3DDISPLAYMODE>* pDisplayModeList = &pBestDeviceSettingsCombo->pAdapterInfo->displayModeList;
2557 for( int iDisplayMode=0; iDisplayMode<pDisplayModeList->GetSize(); iDisplayMode++ )
2558 {
2559 D3DDISPLAYMODE displayMode = pDisplayModeList->GetAt(iDisplayMode);
2560
2561 // Skip display modes that don't match the combo's adapter format
2562 if( displayMode.Format != pBestDeviceSettingsCombo->AdapterFormat )
2563 continue;
2564
2565 // Find the delta between the current width/height and the optimal width/height
2566 nCurRanking = abs((int)displayMode.Width - (int)displayModeIn.Width) +
2567 abs((int)displayMode.Height- (int)displayModeIn.Height);
2568
2569 if( nCurRanking < nBestRanking )
2570 {
2571 bestDisplayMode = displayMode;
2572 nBestRanking = nCurRanking;
2573
2574 // Stop if perfect match found
2575 if( nBestRanking == 0 )
2576 break;
2577 }
2578 }
2579
2580 if( bestDisplayMode.Width == 0 )
2581 {
2582 *pBestDisplayMode = displayModeIn;
2583 return E_FAIL; // No valid display modes found
2584 }
2585
2586 *pBestDisplayMode = bestDisplayMode;
2587 }
2588
2589 return S_OK;
2590 }
2591
2592
2593 //--------------------------------------------------------------------------------------
2594 // Internal helper function to return the adapter format from the first device settings
2595 // combo that matches the passed adapter ordinal, device type, backbuffer format, and windowed.
2596 //--------------------------------------------------------------------------------------
DXUTFindAdapterFormat(UINT AdapterOrdinal,D3DDEVTYPE DeviceType,D3DFORMAT BackBufferFormat,BOOL Windowed,D3DFORMAT * pAdapterFormat)2597 HRESULT DXUTFindAdapterFormat( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT BackBufferFormat,
2598 BOOL Windowed, D3DFORMAT* pAdapterFormat )
2599 {
2600 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
2601 CD3DEnumDeviceInfo* pDeviceInfo = pd3dEnum->GetDeviceInfo( AdapterOrdinal, DeviceType );
2602 if( pDeviceInfo )
2603 {
2604 for( int iDeviceCombo=0; iDeviceCombo<pDeviceInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
2605 {
2606 CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pDeviceInfo->deviceSettingsComboList.GetAt(iDeviceCombo);
2607 if( pDeviceSettingsCombo->BackBufferFormat == BackBufferFormat &&
2608 pDeviceSettingsCombo->Windowed == Windowed )
2609 {
2610 // Return the adapter format from the first match
2611 *pAdapterFormat = pDeviceSettingsCombo->AdapterFormat;
2612 return S_OK;
2613 }
2614 }
2615 }
2616
2617 *pAdapterFormat = BackBufferFormat;
2618 return E_FAIL;
2619 }
2620
2621
2622 //--------------------------------------------------------------------------------------
2623 // Change to a Direct3D device created from the device settings or passed in.
2624 // The framework will only reset if the device is similar to the previous device
2625 // otherwise it will cleanup the previous device (if there is one) and recreate the
2626 // scene using the app's device callbacks.
2627 //--------------------------------------------------------------------------------------
DXUTChangeDevice(DXUTDeviceSettings * pNewDeviceSettings,IDirect3DDevice9 * pd3dDeviceFromApp,bool bForceRecreate,bool bClipWindowToSingleAdapter)2628 HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, IDirect3DDevice9* pd3dDeviceFromApp, bool bForceRecreate, bool bClipWindowToSingleAdapter )
2629 {
2630 HRESULT hr;
2631 DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
2632
2633 if( DXUTGetD3DObject() == NULL )
2634 return S_FALSE;
2635
2636 // Make a copy of the pNewDeviceSettings on the heap
2637 DXUTDeviceSettings* pNewDeviceSettingsOnHeap = new DXUTDeviceSettings;
2638 if( pNewDeviceSettingsOnHeap == NULL )
2639 return E_OUTOFMEMORY;
2640 memcpy( pNewDeviceSettingsOnHeap, pNewDeviceSettings, sizeof(DXUTDeviceSettings) );
2641 pNewDeviceSettings = pNewDeviceSettingsOnHeap;
2642
2643 // If the ModifyDeviceSettings callback is non-NULL, then call it to let the app
2644 // change the settings or reject the device change by returning false.
2645 LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = GetDXUTState().GetModifyDeviceSettingsFunc();
2646 if( pCallbackModifyDeviceSettings )
2647 {
2648 D3DCAPS9 caps;
2649 IDirect3D9* pD3D = DXUTGetD3DObject();
2650 pD3D->GetDeviceCaps( pNewDeviceSettings->AdapterOrdinal, pNewDeviceSettings->DeviceType, &caps );
2651
2652 bool bContinue = pCallbackModifyDeviceSettings( pNewDeviceSettings, &caps, GetDXUTState().GetModifyDeviceSettingsFuncUserContext() );
2653 if( !bContinue )
2654 {
2655 // The app rejected the device change by returning false, so just use the current device if there is one.
2656 if( pOldDeviceSettings == NULL )
2657 DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES );
2658 SAFE_DELETE( pNewDeviceSettings );
2659 return E_ABORT;
2660 }
2661 if( GetDXUTState().GetD3D() == NULL )
2662 {
2663 SAFE_DELETE( pNewDeviceSettings );
2664 return S_FALSE;
2665 }
2666 }
2667
2668 GetDXUTState().SetCurrentDeviceSettings( pNewDeviceSettings );
2669
2670 DXUTPause( true, true );
2671
2672 // When a WM_SIZE message is received, it calls DXUTCheckForWindowSizeChange().
2673 // A WM_SIZE message might be sent when adjusting the window, so tell
2674 // DXUTCheckForWindowSizeChange() to ignore size changes temporarily
2675 GetDXUTState().SetIgnoreSizeChange( true );
2676
2677 // Update thread safety on/off depending on Direct3D device's thread safety
2678 g_bThreadSafe = ((pNewDeviceSettings->BehaviorFlags & D3DCREATE_MULTITHREADED) != 0 );
2679
2680 // Only apply the cmd line overrides if this is the first device created
2681 // and DXUTSetDevice() isn't used
2682 if( NULL == pd3dDeviceFromApp && NULL == pOldDeviceSettings )
2683 {
2684 // Updates the device settings struct based on the cmd line args.
2685 // Warning: if the device doesn't support these new settings then CreateDevice() will fail.
2686 DXUTUpdateDeviceSettingsWithOverrides( pNewDeviceSettings );
2687 }
2688
2689 // Take note if the backbuffer width & height are 0 now as they will change after pd3dDevice->Reset()
2690 bool bKeepCurrentWindowSize = false;
2691 if( pNewDeviceSettings->pp.BackBufferWidth == 0 && pNewDeviceSettings->pp.BackBufferHeight == 0 )
2692 bKeepCurrentWindowSize = true;
2693
2694 //////////////////////////
2695 // Before reset
2696 /////////////////////////
2697 if( pNewDeviceSettings->pp.Windowed )
2698 {
2699 // Going to windowed mode
2700
2701 if( pOldDeviceSettings && !pOldDeviceSettings->pp.Windowed )
2702 {
2703 // Going from fullscreen -> windowed
2704 GetDXUTState().SetFullScreenBackBufferWidthAtModeChange( pOldDeviceSettings->pp.BackBufferWidth );
2705 GetDXUTState().SetFullScreenBackBufferHeightAtModeChange( pOldDeviceSettings->pp.BackBufferHeight );
2706
2707 // Restore windowed mode style
2708 SetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE, GetDXUTState().GetWindowedStyleAtModeChange() );
2709 }
2710
2711 // If different device windows are used for windowed mode and fullscreen mode,
2712 // hide the fullscreen window so that it doesn't obscure the screen.
2713 if( DXUTGetHWNDDeviceFullScreen() != DXUTGetHWNDDeviceWindowed() )
2714 ShowWindow( DXUTGetHWNDDeviceFullScreen(), SW_HIDE );
2715
2716 // If using the same window for windowed and fullscreen mode, reattach menu if one exists
2717 if( DXUTGetHWNDDeviceFullScreen() == DXUTGetHWNDDeviceWindowed() )
2718 {
2719 if( GetDXUTState().GetMenu() != NULL )
2720 SetMenu( DXUTGetHWNDDeviceWindowed(), GetDXUTState().GetMenu() );
2721 }
2722 }
2723 else
2724 {
2725 // Going to fullscreen mode
2726
2727 if( pOldDeviceSettings == NULL || (pOldDeviceSettings && pOldDeviceSettings->pp.Windowed) )
2728 {
2729 // Transistioning to full screen mode from a standard window so
2730 // save current window position/size/style now in case the user toggles to windowed mode later
2731 WINDOWPLACEMENT* pwp = GetDXUTState().GetWindowedPlacement();
2732 ZeroMemory( pwp, sizeof(WINDOWPLACEMENT) );
2733 pwp->length = sizeof(WINDOWPLACEMENT);
2734 GetWindowPlacement( DXUTGetHWNDDeviceWindowed(), pwp );
2735 bool bIsTopmost = ( (GetWindowLong(DXUTGetHWNDDeviceWindowed(),GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
2736 GetDXUTState().SetTopmostWhileWindowed( bIsTopmost );
2737 DWORD dwStyle = GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE );
2738 dwStyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style
2739 GetDXUTState().SetWindowedStyleAtModeChange( dwStyle );
2740 if( pOldDeviceSettings )
2741 {
2742 GetDXUTState().SetWindowBackBufferWidthAtModeChange( pOldDeviceSettings->pp.BackBufferWidth );
2743 GetDXUTState().SetWindowBackBufferHeightAtModeChange( pOldDeviceSettings->pp.BackBufferHeight );
2744 }
2745 }
2746
2747 // Hide the window to avoid animation of blank windows
2748 ShowWindow( DXUTGetHWNDDeviceFullScreen(), SW_HIDE );
2749
2750 // Set FS window style
2751 SetWindowLong( DXUTGetHWNDDeviceFullScreen(), GWL_STYLE, WS_POPUP|WS_SYSMENU );
2752
2753 // If using the same window for windowed and fullscreen mode, save and remove menu
2754 if( DXUTGetHWNDDeviceFullScreen() == DXUTGetHWNDDeviceWindowed() )
2755 {
2756 HMENU hMenu = GetMenu( DXUTGetHWNDDeviceFullScreen() );
2757 GetDXUTState().SetMenu( hMenu );
2758 SetMenu( DXUTGetHWNDDeviceFullScreen(), NULL );
2759 }
2760
2761 WINDOWPLACEMENT wpFullscreen;
2762 ZeroMemory( &wpFullscreen, sizeof(WINDOWPLACEMENT) );
2763 wpFullscreen.length = sizeof(WINDOWPLACEMENT);
2764 GetWindowPlacement( DXUTGetHWNDDeviceFullScreen(), &wpFullscreen );
2765 if( (wpFullscreen.flags & WPF_RESTORETOMAXIMIZED) != 0 )
2766 {
2767 // Restore the window to normal if the window was maximized then minimized. This causes the
2768 // WPF_RESTORETOMAXIMIZED flag to be set which will cause SW_RESTORE to restore the
2769 // window from minimized to maxmized which isn't what we want
2770 wpFullscreen.flags &= ~WPF_RESTORETOMAXIMIZED;
2771 wpFullscreen.showCmd = SW_RESTORE;
2772 SetWindowPlacement( DXUTGetHWNDDeviceFullScreen(), &wpFullscreen );
2773 }
2774 }
2775
2776 // If AdapterOrdinal and DeviceType are the same, we can just do a Reset().
2777 // If they've changed, we need to do a complete device tear down/rebuild.
2778 // Also only allow a reset if pd3dDevice is the same as the current device
2779 if( !bForceRecreate &&
2780 (pd3dDeviceFromApp == NULL || pd3dDeviceFromApp == DXUTGetD3DDevice()) &&
2781 DXUTGetD3DDevice() &&
2782 pOldDeviceSettings &&
2783 pOldDeviceSettings->AdapterOrdinal == pNewDeviceSettings->AdapterOrdinal &&
2784 pOldDeviceSettings->DeviceType == pNewDeviceSettings->DeviceType &&
2785 pOldDeviceSettings->BehaviorFlags == pNewDeviceSettings->BehaviorFlags )
2786 {
2787 // Reset the Direct3D device and call the app's device callbacks
2788 hr = DXUTReset3DEnvironment();
2789 if( FAILED(hr) )
2790 {
2791 if( D3DERR_DEVICELOST == hr )
2792 {
2793 // The device is lost, just mark it as so and continue on with
2794 // capturing the state and resizing the window/etc.
2795 GetDXUTState().SetDeviceLost( true );
2796 }
2797 else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr ||
2798 DXUTERR_MEDIANOTFOUND == hr )
2799 {
2800 // Something bad happened in the app callbacks
2801 SAFE_DELETE( pOldDeviceSettings );
2802 DXUTDisplayErrorMessage( hr );
2803 DXUTShutdown();
2804 return hr;
2805 }
2806 else // DXUTERR_RESETTINGDEVICE
2807 {
2808 // Reset failed and the device wasn't lost and it wasn't the apps fault,
2809 // so recreate the device to try to recover
2810 GetDXUTState().SetCurrentDeviceSettings( pOldDeviceSettings );
2811 if( FAILED( DXUTChangeDevice( pNewDeviceSettings, pd3dDeviceFromApp, true, bClipWindowToSingleAdapter ) ) )
2812 {
2813 // If that fails, then shutdown
2814 SAFE_DELETE( pOldDeviceSettings );
2815 DXUTShutdown();
2816 return DXUTERR_CREATINGDEVICE;
2817 }
2818 else
2819 {
2820 SAFE_DELETE( pOldDeviceSettings );
2821 return S_OK;
2822 }
2823 }
2824 }
2825 }
2826 else
2827 {
2828 // Cleanup if not first device created
2829 if( pOldDeviceSettings )
2830 DXUTCleanup3DEnvironment( false );
2831
2832 // Create the D3D device and call the app's device callbacks
2833 hr = DXUTCreate3DEnvironment( pd3dDeviceFromApp );
2834 if( FAILED(hr) )
2835 {
2836 SAFE_DELETE( pOldDeviceSettings );
2837 DXUTCleanup3DEnvironment();
2838 DXUTDisplayErrorMessage( hr );
2839 DXUTPause( false, false );
2840 GetDXUTState().SetIgnoreSizeChange( false );
2841 return hr;
2842 }
2843 }
2844
2845 // Enable/disable StickKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut, and Windows key
2846 // to prevent accidental task switching
2847 DXUTAllowShortcutKeys( ( pNewDeviceSettings->pp.Windowed ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() : GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
2848
2849 IDirect3D9* pD3D = DXUTGetD3DObject();
2850 HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal );
2851 GetDXUTState().SetAdapterMonitor( hAdapterMonitor );
2852
2853 // Update the device stats text
2854 DXUTUpdateStaticFrameStats();
2855
2856 if( pOldDeviceSettings && !pOldDeviceSettings->pp.Windowed && pNewDeviceSettings->pp.Windowed )
2857 {
2858 // Going from fullscreen -> windowed
2859
2860 // Restore the show state, and positions/size of the window to what it was
2861 // It is important to adjust the window size
2862 // after resetting the device rather than beforehand to ensure
2863 // that the monitor resolution is correct and does not limit the size of the new window.
2864 WINDOWPLACEMENT* pwp = GetDXUTState().GetWindowedPlacement();
2865 SetWindowPlacement( DXUTGetHWNDDeviceWindowed(), pwp );
2866
2867 // Also restore the z-order of window to previous state
2868 HWND hWndInsertAfter = GetDXUTState().GetTopmostWhileWindowed() ? HWND_TOPMOST : HWND_NOTOPMOST;
2869 SetWindowPos( DXUTGetHWNDDeviceWindowed(), hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE );
2870 }
2871
2872 // Check to see if the window needs to be resized.
2873 // Handle cases where the window is minimized and maxmimized as well.
2874 bool bNeedToResize = false;
2875 if( pNewDeviceSettings->pp.Windowed && // only resize if in windowed mode
2876 !bKeepCurrentWindowSize ) // only resize if pp.BackbufferWidth/Height were not 0
2877 {
2878 UINT nClientWidth;
2879 UINT nClientHeight;
2880 if( IsIconic(DXUTGetHWNDDeviceWindowed()) )
2881 {
2882 // Window is currently minimized. To tell if it needs to resize,
2883 // get the client rect of window when its restored the
2884 // hard way using GetWindowPlacement()
2885 WINDOWPLACEMENT wp;
2886 ZeroMemory( &wp, sizeof(WINDOWPLACEMENT) );
2887 wp.length = sizeof(WINDOWPLACEMENT);
2888 GetWindowPlacement( DXUTGetHWNDDeviceWindowed(), &wp );
2889
2890 if( (wp.flags & WPF_RESTORETOMAXIMIZED) != 0 && wp.showCmd == SW_SHOWMINIMIZED )
2891 {
2892 // WPF_RESTORETOMAXIMIZED means that when the window is restored it will
2893 // be maximized. So maximize the window temporarily to get the client rect
2894 // when the window is maximized. GetSystemMetrics( SM_CXMAXIMIZED ) will give this
2895 // information if the window is on the primary but this will work on multimon.
2896 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
2897 RECT rcClient;
2898 GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
2899 nClientWidth = (UINT)(rcClient.right - rcClient.left);
2900 nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
2901 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_MINIMIZE );
2902 }
2903 else
2904 {
2905 // Use wp.rcNormalPosition to get the client rect, but wp.rcNormalPosition
2906 // includes the window frame so subtract it
2907 RECT rcFrame = {0};
2908 AdjustWindowRect( &rcFrame, GetDXUTState().GetWindowedStyleAtModeChange(), GetDXUTState().GetMenu() != NULL );
2909 LONG nFrameWidth = rcFrame.right - rcFrame.left;
2910 LONG nFrameHeight = rcFrame.bottom - rcFrame.top;
2911 nClientWidth = (UINT)(wp.rcNormalPosition.right - wp.rcNormalPosition.left - nFrameWidth);
2912 nClientHeight = (UINT)(wp.rcNormalPosition.bottom - wp.rcNormalPosition.top - nFrameHeight);
2913 }
2914 }
2915 else
2916 {
2917 // Window is restored or maximized so just get its client rect
2918 RECT rcClient;
2919 GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
2920 nClientWidth = (UINT)(rcClient.right - rcClient.left);
2921 nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
2922 }
2923
2924 // Now that we know the client rect, compare it against the back buffer size
2925 // to see if the client rect is already the right size
2926 if( nClientWidth != pNewDeviceSettings->pp.BackBufferWidth ||
2927 nClientHeight != pNewDeviceSettings->pp.BackBufferHeight )
2928 {
2929 bNeedToResize = true;
2930 }
2931
2932 if( bClipWindowToSingleAdapter && !IsIconic(DXUTGetHWNDDeviceWindowed()) )
2933 {
2934 // Get the rect of the monitor attached to the adapter
2935 MONITORINFO miAdapter;
2936 miAdapter.cbSize = sizeof(MONITORINFO);
2937 HMONITOR hAdapterMonitor = DXUTGetD3DObject()->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal );
2938 DXUTGetMonitorInfo( hAdapterMonitor, &miAdapter );
2939 HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
2940
2941 // Get the rect of the window
2942 RECT rcWindow;
2943 GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow );
2944
2945 // Check if the window rect is fully inside the adapter's vitural screen rect
2946 if( (rcWindow.left < miAdapter.rcWork.left ||
2947 rcWindow.right > miAdapter.rcWork.right ||
2948 rcWindow.top < miAdapter.rcWork.top ||
2949 rcWindow.bottom > miAdapter.rcWork.bottom) )
2950 {
2951 if( hWindowMonitor == hAdapterMonitor && IsZoomed(DXUTGetHWNDDeviceWindowed()) )
2952 {
2953 // If the window is maximized and on the same monitor as the adapter, then
2954 // no need to clip to single adapter as the window is already clipped
2955 // even though the rcWindow rect is outside of the miAdapter.rcWork
2956 }
2957 else
2958 {
2959 bNeedToResize = true;
2960 }
2961 }
2962 }
2963 }
2964
2965 // Only resize window if needed
2966 if( bNeedToResize )
2967 {
2968 // Need to resize, so if window is maximized or minimized then restore the window
2969 if( IsIconic(DXUTGetHWNDDeviceWindowed()) )
2970 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
2971 if( IsZoomed(DXUTGetHWNDDeviceWindowed()) ) // doing the IsIconic() check first also handles the WPF_RESTORETOMAXIMIZED case
2972 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
2973
2974 if( bClipWindowToSingleAdapter )
2975 {
2976 // Get the rect of the monitor attached to the adapter
2977 MONITORINFO miAdapter;
2978 miAdapter.cbSize = sizeof(MONITORINFO);
2979 DXUTGetMonitorInfo( DXUTGetD3DObject()->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal ), &miAdapter );
2980
2981 // Get the rect of the monitor attached to the window
2982 MONITORINFO miWindow;
2983 miWindow.cbSize = sizeof(MONITORINFO);
2984 DXUTGetMonitorInfo( DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY ), &miWindow );
2985
2986 // Do something reasonable if the BackBuffer size is greater than the monitor size
2987 int nAdapterMonitorWidth = miAdapter.rcWork.right - miAdapter.rcWork.left;
2988 int nAdapterMonitorHeight = miAdapter.rcWork.bottom - miAdapter.rcWork.top;
2989
2990 int nClientWidth = pNewDeviceSettings->pp.BackBufferWidth;
2991 int nClientHeight = pNewDeviceSettings->pp.BackBufferHeight;
2992
2993 // Get the rect of the window
2994 RECT rcWindow;
2995 GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow );
2996
2997 // Make a window rect with a client rect that is the same size as the backbuffer
2998 RECT rcResizedWindow;
2999 rcResizedWindow.left = 0;
3000 rcResizedWindow.right = nClientWidth;
3001 rcResizedWindow.top = 0;
3002 rcResizedWindow.bottom = nClientHeight;
3003 AdjustWindowRect( &rcResizedWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != NULL );
3004
3005 int nWindowWidth = rcResizedWindow.right - rcResizedWindow.left;
3006 int nWindowHeight = rcResizedWindow.bottom - rcResizedWindow.top;
3007
3008 if( nWindowWidth > nAdapterMonitorWidth )
3009 nWindowWidth = (nAdapterMonitorWidth - 0);
3010 if( nWindowHeight > nAdapterMonitorHeight )
3011 nWindowHeight = (nAdapterMonitorHeight - 0);
3012
3013 if( rcResizedWindow.left < miAdapter.rcWork.left ||
3014 rcResizedWindow.top < miAdapter.rcWork.top ||
3015 rcResizedWindow.right > miAdapter.rcWork.right ||
3016 rcResizedWindow.bottom > miAdapter.rcWork.bottom )
3017 {
3018 int nWindowOffsetX = (nAdapterMonitorWidth - nWindowWidth) / 2;
3019 int nWindowOffsetY = (nAdapterMonitorHeight - nWindowHeight) / 2;
3020
3021 rcResizedWindow.left = miAdapter.rcWork.left + nWindowOffsetX;
3022 rcResizedWindow.top = miAdapter.rcWork.top + nWindowOffsetY;
3023 rcResizedWindow.right = miAdapter.rcWork.left + nWindowOffsetX + nWindowWidth;
3024 rcResizedWindow.bottom = miAdapter.rcWork.top + nWindowOffsetY + nWindowHeight;
3025 }
3026
3027 // Resize the window. It is important to adjust the window size
3028 // after resetting the device rather than beforehand to ensure
3029 // that the monitor resolution is correct and does not limit the size of the new window.
3030 SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, rcResizedWindow.left, rcResizedWindow.top, nWindowWidth, nWindowHeight, SWP_NOZORDER );
3031 }
3032 else
3033 {
3034 // Make a window rect with a client rect that is the same size as the backbuffer
3035 RECT rcWindow = {0};
3036 rcWindow.right = (long)(pNewDeviceSettings->pp.BackBufferWidth);
3037 rcWindow.bottom = (long)(pNewDeviceSettings->pp.BackBufferHeight);
3038 AdjustWindowRect( &rcWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != NULL );
3039
3040 // Resize the window. It is important to adjust the window size
3041 // after resetting the device rather than beforehand to ensure
3042 // that the monitor resolution is correct and does not limit the size of the new window.
3043 int cx = (int)(rcWindow.right - rcWindow.left);
3044 int cy = (int)(rcWindow.bottom - rcWindow.top);
3045 SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, 0, 0, cx, cy, SWP_NOZORDER|SWP_NOMOVE );
3046 }
3047
3048 // Its possible that the new window size is not what we asked for.
3049 // No window can be sized larger than the desktop, so see see if the Windows OS resized the
3050 // window to something smaller to fit on the desktop. Also if WM_GETMINMAXINFO
3051 // will put a limit on the smallest/largest window size.
3052 RECT rcClient;
3053 GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
3054 UINT nClientWidth = (UINT)(rcClient.right - rcClient.left);
3055 UINT nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
3056 if( nClientWidth != pNewDeviceSettings->pp.BackBufferWidth ||
3057 nClientHeight != pNewDeviceSettings->pp.BackBufferHeight )
3058 {
3059 // If its different, then resize the backbuffer again. This time create a backbuffer that matches the
3060 // client rect of the current window w/o resizing the window.
3061 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
3062 deviceSettings.pp.BackBufferWidth = 0;
3063 deviceSettings.pp.BackBufferHeight = 0;
3064 hr = DXUTChangeDevice( &deviceSettings, NULL, false, bClipWindowToSingleAdapter );
3065 if( FAILED( hr ) )
3066 {
3067 SAFE_DELETE( pOldDeviceSettings );
3068 DXUTCleanup3DEnvironment();
3069 DXUTPause( false, false );
3070 GetDXUTState().SetIgnoreSizeChange( false );
3071 return hr;
3072 }
3073 }
3074 }
3075
3076 // Make the window visible
3077 if( !IsWindowVisible( DXUTGetHWND() ) )
3078 ShowWindow( DXUTGetHWND(), SW_SHOW );
3079
3080 // Make the window visible
3081 if( !IsWindowVisible( DXUTGetHWND() ) )
3082 ShowWindow( DXUTGetHWND(), SW_SHOW );
3083
3084 // Ensure that the display doesn't power down when fullscreen but does when windowed
3085 if( !DXUTIsWindowed() )
3086 SetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
3087 else
3088 SetThreadExecutionState( ES_CONTINUOUS );
3089
3090 SAFE_DELETE( pOldDeviceSettings );
3091 GetDXUTState().SetIgnoreSizeChange( false );
3092 DXUTPause( false, false );
3093 GetDXUTState().SetDeviceCreated( true );
3094
3095 return S_OK;
3096 }
3097
3098
3099 //--------------------------------------------------------------------------------------
3100 // Low level keyboard hook to disable Windows key to prevent accidental task switching.
3101 //--------------------------------------------------------------------------------------
LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)3102 LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
3103 {
3104 if (nCode < 0 || nCode != HC_ACTION) // do not process message
3105 return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam);
3106
3107 bool bEatKeystroke = false;
3108 KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
3109 switch (wParam)
3110 {
3111 case WM_KEYDOWN:
3112 case WM_KEYUP:
3113 {
3114 bEatKeystroke = ( !GetDXUTState().GetAllowShortcutKeys() &&
3115 (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) );
3116 break;
3117 }
3118 }
3119
3120 if( bEatKeystroke )
3121 return 1;
3122 else
3123 return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam );
3124 }
3125
3126
3127
3128 //--------------------------------------------------------------------------------------
3129 // Controls how DXUT behaves when fullscreen and windowed mode with regard to
3130 // shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut)
3131 //--------------------------------------------------------------------------------------
DXUTSetShortcutKeySettings(bool bAllowWhenFullscreen,bool bAllowWhenWindowed)3132 void DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen, bool bAllowWhenWindowed )
3133 {
3134 GetDXUTState().SetAllowShortcutKeysWhenWindowed( bAllowWhenWindowed );
3135 GetDXUTState().SetAllowShortcutKeysWhenFullscreen( bAllowWhenFullscreen );
3136
3137 // DXUTInit() records initial accessibility states so don't change them until then
3138 if( GetDXUTState().GetDXUTInited() )
3139 {
3140 if( DXUTIsWindowed() )
3141 DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() );
3142 else
3143 DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
3144 }
3145 }
3146
3147
3148 //--------------------------------------------------------------------------------------
3149 // Enables/disables Windows keys, and disables or restores the StickyKeys/ToggleKeys/FilterKeys
3150 // shortcut to help prevent accidental task switching
3151 //--------------------------------------------------------------------------------------
DXUTAllowShortcutKeys(bool bAllowKeys)3152 void DXUTAllowShortcutKeys( bool bAllowKeys )
3153 {
3154 GetDXUTState().SetAllowShortcutKeys( bAllowKeys );
3155
3156 if( bAllowKeys )
3157 {
3158 // Restore StickyKeys/etc to original state and enable Windows key
3159 STICKYKEYS sk = GetDXUTState().GetStartupStickyKeys();
3160 TOGGLEKEYS tk = GetDXUTState().GetStartupToggleKeys();
3161 FILTERKEYS fk = GetDXUTState().GetStartupFilterKeys();
3162
3163 SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0);
3164 SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0);
3165 SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0);
3166
3167 // Remove the keyboard hoook when it isn't needed to prevent any slow down of other apps
3168 if( GetDXUTState().GetKeyboardHook() )
3169 {
3170 UnhookWindowsHookEx( GetDXUTState().GetKeyboardHook() );
3171 GetDXUTState().SetKeyboardHook( NULL );
3172 }
3173 }
3174 else
3175 {
3176 // Set low level keyboard hook if haven't already
3177 if( GetDXUTState().GetKeyboardHook() == NULL )
3178 {
3179 // Set the low-level hook procedure. Only works on Windows 2000 and above
3180 OSVERSIONINFO OSVersionInfo;
3181 OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
3182 GetVersionEx(&OSVersionInfo);
3183 if( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion > 4 )
3184 {
3185 HHOOK hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
3186 GetDXUTState().SetKeyboardHook( hKeyboardHook );
3187 }
3188 }
3189
3190 // Disable StickyKeys/etc shortcuts but if the accessibility feature is on,
3191 // then leave the settings alone as its probably being usefully used
3192
3193 STICKYKEYS skOff = GetDXUTState().GetStartupStickyKeys();
3194 if( (skOff.dwFlags & SKF_STICKYKEYSON) == 0 )
3195 {
3196 // Disable the hotkey and the confirmation
3197 skOff.dwFlags &= ~SKF_HOTKEYACTIVE;
3198 skOff.dwFlags &= ~SKF_CONFIRMHOTKEY;
3199
3200 SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &skOff, 0);
3201 }
3202
3203 TOGGLEKEYS tkOff = GetDXUTState().GetStartupToggleKeys();
3204 if( (tkOff.dwFlags & TKF_TOGGLEKEYSON) == 0 )
3205 {
3206 // Disable the hotkey and the confirmation
3207 tkOff.dwFlags &= ~TKF_HOTKEYACTIVE;
3208 tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY;
3209
3210 SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tkOff, 0);
3211 }
3212
3213 FILTERKEYS fkOff = GetDXUTState().GetStartupFilterKeys();
3214 if( (fkOff.dwFlags & FKF_FILTERKEYSON) == 0 )
3215 {
3216 // Disable the hotkey and the confirmation
3217 fkOff.dwFlags &= ~FKF_HOTKEYACTIVE;
3218 fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY;
3219
3220 SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fkOff, 0);
3221 }
3222 }
3223 }
3224
3225
3226 //--------------------------------------------------------------------------------------
3227 // Updates the device settings struct based on the cmd line args.
3228 //--------------------------------------------------------------------------------------
DXUTUpdateDeviceSettingsWithOverrides(DXUTDeviceSettings * pDeviceSettings)3229 void DXUTUpdateDeviceSettingsWithOverrides( DXUTDeviceSettings* pDeviceSettings )
3230 {
3231 if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 )
3232 pDeviceSettings->AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal();
3233
3234 if( GetDXUTState().GetOverrideFullScreen() )
3235 pDeviceSettings->pp.Windowed = false;
3236 if( GetDXUTState().GetOverrideWindowed() )
3237 pDeviceSettings->pp.Windowed = true;
3238
3239 if( GetDXUTState().GetOverrideForceREF() )
3240 pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
3241 else if( GetDXUTState().GetOverrideForceHAL() )
3242 pDeviceSettings->DeviceType = D3DDEVTYPE_HAL;
3243
3244 if( GetDXUTState().GetOverrideWidth() != 0 )
3245 pDeviceSettings->pp.BackBufferWidth = GetDXUTState().GetOverrideWidth();
3246 if( GetDXUTState().GetOverrideHeight() != 0 )
3247 pDeviceSettings->pp.BackBufferHeight = GetDXUTState().GetOverrideHeight();
3248
3249 if( GetDXUTState().GetOverrideForcePureHWVP() )
3250 {
3251 pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
3252 pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
3253 pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
3254 }
3255 else if( GetDXUTState().GetOverrideForceHWVP() )
3256 {
3257 pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
3258 pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
3259 pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
3260 }
3261 else if( GetDXUTState().GetOverrideForceSWVP() )
3262 {
3263 pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
3264 pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
3265 pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
3266 }
3267 }
3268
3269
3270 //--------------------------------------------------------------------------------------
3271 // Creates the 3D environment
3272 //--------------------------------------------------------------------------------------
DXUTCreate3DEnvironment(IDirect3DDevice9 * pd3dDeviceFromApp)3273 HRESULT DXUTCreate3DEnvironment( IDirect3DDevice9* pd3dDeviceFromApp )
3274 {
3275 HRESULT hr = S_OK;
3276
3277 IDirect3DDevice9* pd3dDevice = NULL;
3278 DXUTDeviceSettings* pNewDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3279
3280 // Only create a Direct3D device if one hasn't been supplied by the app
3281 if( pd3dDeviceFromApp == NULL )
3282 {
3283 // Try to create the device with the chosen settings
3284 IDirect3D9* pD3D = DXUTGetD3DObject();
3285 hr = pD3D->CreateDevice( pNewDeviceSettings->AdapterOrdinal, pNewDeviceSettings->DeviceType,
3286 DXUTGetHWNDFocus(), pNewDeviceSettings->BehaviorFlags,
3287 &pNewDeviceSettings->pp, &pd3dDevice );
3288 if( hr == D3DERR_DEVICELOST )
3289 {
3290 GetDXUTState().SetDeviceLost( true );
3291 return S_OK;
3292 }
3293 else if( FAILED(hr) )
3294 {
3295 DXUT_ERR( L"CreateDevice", hr );
3296 return DXUTERR_CREATINGDEVICE;
3297 }
3298 }
3299 else
3300 {
3301 pd3dDeviceFromApp->AddRef();
3302 pd3dDevice = pd3dDeviceFromApp;
3303 }
3304
3305 GetDXUTState().SetD3DDevice( pd3dDevice );
3306
3307 // If switching to REF, set the exit code to 11. If switching to HAL and exit code was 11, then set it back to 0.
3308 if( pNewDeviceSettings->DeviceType == D3DDEVTYPE_REF && GetDXUTState().GetExitCode() == 0 )
3309 GetDXUTState().SetExitCode(11);
3310 else if( pNewDeviceSettings->DeviceType == D3DDEVTYPE_HAL && GetDXUTState().GetExitCode() == 11 )
3311 GetDXUTState().SetExitCode(0);
3312
3313 // Update back buffer desc before calling app's device callbacks
3314 DXUTUpdateBackBufferDesc();
3315
3316 // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
3317 DXUTSetupCursor();
3318
3319 // Update GetDXUTState()'s copy of D3D caps
3320 D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
3321 DXUTGetD3DDevice()->GetDeviceCaps( pd3dCaps );
3322
3323 // Update the device stats text
3324 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
3325 CD3DEnumAdapterInfo* pAdapterInfo = pd3dEnum->GetAdapterInfo( pNewDeviceSettings->AdapterOrdinal );
3326 DXUTUpdateDeviceStats( pNewDeviceSettings->DeviceType,
3327 pNewDeviceSettings->BehaviorFlags,
3328 &pAdapterInfo->AdapterIdentifier );
3329
3330 // Call the resource cache created function
3331 hr = DXUTGetGlobalResourceCache().OnCreateDevice( pd3dDevice );
3332 if( FAILED(hr) )
3333 return DXUT_ERR( L"OnCreateDevice", ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_CREATINGDEVICEOBJECTS );
3334
3335 // Call the app's device created callback if non-NULL
3336 const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
3337 GetDXUTState().SetInsideDeviceCallback( true );
3338 LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated = GetDXUTState().GetDeviceCreatedFunc();
3339 hr = S_OK;
3340 if( pCallbackDeviceCreated != NULL )
3341 hr = pCallbackDeviceCreated( DXUTGetD3DDevice(), pbackBufferSurfaceDesc, GetDXUTState().GetDeviceCreatedFuncUserContext() );
3342 GetDXUTState().SetInsideDeviceCallback( false );
3343 if( DXUTGetD3DDevice() == NULL ) // Handle DXUTShutdown from inside callback
3344 return E_FAIL;
3345 if( FAILED(hr) )
3346 {
3347 DXUT_ERR( L"DeviceCreated callback", hr );
3348 return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_CREATINGDEVICEOBJECTS;
3349 }
3350 GetDXUTState().SetDeviceObjectsCreated( true );
3351
3352 // Call the resource cache device reset function
3353 hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
3354 if( FAILED(hr) )
3355 return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
3356
3357 // Call the app's device reset callback if non-NULL
3358 GetDXUTState().SetInsideDeviceCallback( true );
3359 LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
3360 hr = S_OK;
3361 if( pCallbackDeviceReset != NULL )
3362 hr = pCallbackDeviceReset( DXUTGetD3DDevice(), pbackBufferSurfaceDesc, GetDXUTState().GetDeviceResetFuncUserContext() );
3363 GetDXUTState().SetInsideDeviceCallback( false );
3364 if( DXUTGetD3DDevice() == NULL ) // Handle DXUTShutdown from inside callback
3365 return E_FAIL;
3366 if( FAILED(hr) )
3367 {
3368 DXUT_ERR( L"DeviceReset callback", hr );
3369 return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_RESETTINGDEVICEOBJECTS;
3370 }
3371 GetDXUTState().SetDeviceObjectsReset( true );
3372
3373 return S_OK;
3374 }
3375
3376
3377 //--------------------------------------------------------------------------------------
3378 // Resets the 3D environment by:
3379 // - Calls the device lost callback
3380 // - Resets the device
3381 // - Stores the back buffer description
3382 // - Sets up the full screen Direct3D cursor if requested
3383 // - Calls the device reset callback
3384 //--------------------------------------------------------------------------------------
DXUTReset3DEnvironment()3385 HRESULT DXUTReset3DEnvironment()
3386 {
3387 HRESULT hr;
3388
3389 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
3390 assert( pd3dDevice != NULL );
3391
3392 // Call the app's device lost callback
3393 if( GetDXUTState().GetDeviceObjectsReset() == true )
3394 {
3395 GetDXUTState().SetInsideDeviceCallback( true );
3396 LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
3397 if( pCallbackDeviceLost != NULL )
3398 pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
3399 GetDXUTState().SetDeviceObjectsReset( false );
3400 GetDXUTState().SetInsideDeviceCallback( false );
3401
3402 // Call the resource cache device lost function
3403 DXUTGetGlobalResourceCache().OnLostDevice();
3404 }
3405
3406 // Reset the device
3407 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3408 hr = pd3dDevice->Reset( &pDeviceSettings->pp );
3409 if( FAILED(hr) )
3410 {
3411 if( hr == D3DERR_DEVICELOST )
3412 return D3DERR_DEVICELOST; // Reset could legitimately fail if the device is lost
3413 else
3414 return DXUT_ERR( L"Reset", DXUTERR_RESETTINGDEVICE );
3415 }
3416
3417 // Update back buffer desc before calling app's device callbacks
3418 DXUTUpdateBackBufferDesc();
3419
3420 // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
3421 DXUTSetupCursor();
3422
3423 hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
3424 if( FAILED(hr) )
3425 return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
3426
3427 // Call the app's OnDeviceReset callback
3428 GetDXUTState().SetInsideDeviceCallback( true );
3429 const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
3430 LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
3431 hr = S_OK;
3432 if( pCallbackDeviceReset != NULL )
3433 hr = pCallbackDeviceReset( pd3dDevice, pbackBufferSurfaceDesc, GetDXUTState().GetDeviceResetFuncUserContext() );
3434 GetDXUTState().SetInsideDeviceCallback( false );
3435 if( FAILED(hr) )
3436 {
3437 // If callback failed, cleanup
3438 DXUT_ERR( L"DeviceResetCallback", hr );
3439 if( hr != DXUTERR_MEDIANOTFOUND )
3440 hr = DXUTERR_RESETTINGDEVICEOBJECTS;
3441
3442 GetDXUTState().SetInsideDeviceCallback( true );
3443 LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
3444 if( pCallbackDeviceLost != NULL )
3445 pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
3446 GetDXUTState().SetInsideDeviceCallback( false );
3447
3448 DXUTGetGlobalResourceCache().OnLostDevice();
3449 return hr;
3450 }
3451
3452 // Success
3453 GetDXUTState().SetDeviceObjectsReset( true );
3454
3455 return S_OK;
3456 }
3457
3458
3459 //--------------------------------------------------------------------------------------
3460 // Pauses time or rendering. Keeps a ref count so pausing can be layered
3461 //--------------------------------------------------------------------------------------
DXUTPause(bool bPauseTime,bool bPauseRendering)3462 void DXUTPause( bool bPauseTime, bool bPauseRendering )
3463 {
3464 int nPauseTimeCount = GetDXUTState().GetPauseTimeCount();
3465 nPauseTimeCount += ( bPauseTime ? +1 : -1 );
3466 if( nPauseTimeCount < 0 )
3467 nPauseTimeCount = 0;
3468 GetDXUTState().SetPauseTimeCount( nPauseTimeCount );
3469
3470 int nPauseRenderingCount = GetDXUTState().GetPauseRenderingCount();
3471 nPauseRenderingCount += ( bPauseRendering ? +1 : -1 );
3472 if( nPauseRenderingCount < 0 )
3473 nPauseRenderingCount = 0;
3474 GetDXUTState().SetPauseRenderingCount( nPauseRenderingCount );
3475
3476 if( nPauseTimeCount > 0 )
3477 {
3478 // Stop the scene from animating
3479 DXUTGetGlobalTimer()->Stop();
3480 }
3481 else
3482 {
3483 // Restart the timer
3484 DXUTGetGlobalTimer()->Start();
3485 }
3486
3487 GetDXUTState().SetRenderingPaused( nPauseRenderingCount > 0 );
3488 GetDXUTState().SetTimePaused( nPauseTimeCount > 0 );
3489 }
3490
3491
3492 //--------------------------------------------------------------------------------------
3493 // Checks if the window client rect has changed and if it has, then reset the device
3494 //--------------------------------------------------------------------------------------
DXUTCheckForWindowSizeChange()3495 void DXUTCheckForWindowSizeChange()
3496 {
3497 // Skip the check for various reasons
3498 if( GetDXUTState().GetIgnoreSizeChange() ||
3499 !GetDXUTState().GetDeviceCreated() ||
3500 !GetDXUTState().GetCurrentDeviceSettings()->pp.Windowed )
3501 return;
3502
3503 RECT rcCurrentClient;
3504 GetClientRect( DXUTGetHWND(), &rcCurrentClient );
3505
3506 if( (UINT)rcCurrentClient.right != GetDXUTState().GetCurrentDeviceSettings()->pp.BackBufferWidth ||
3507 (UINT)rcCurrentClient.bottom != GetDXUTState().GetCurrentDeviceSettings()->pp.BackBufferHeight )
3508 {
3509 // A new window size will require a new backbuffer size
3510 // size, so the device must be reset and the D3D structures updated accordingly.
3511
3512 // Tell DXUTChangeDevice and D3D to size according to the HWND's client rect
3513 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
3514 deviceSettings.pp.BackBufferWidth = 0;
3515 deviceSettings.pp.BackBufferHeight = 0;
3516 DXUTChangeDevice( &deviceSettings, NULL, false, false );
3517 }
3518 }
3519
3520
3521 //--------------------------------------------------------------------------------------
3522 // Handles app's message loop and rendering when idle. If DXUTCreateDevice*() or DXUTSetDevice()
3523 // has not already been called, it will call DXUTCreateWindow() with the default parameters.
3524 //--------------------------------------------------------------------------------------
DXUTMainLoop(HACCEL hAccel)3525 HRESULT DXUTMainLoop( HACCEL hAccel )
3526 {
3527 HRESULT hr;
3528
3529 // Not allowed to call this from inside the device callbacks or reenter
3530 if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() )
3531 {
3532 if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
3533 GetDXUTState().SetExitCode(1);
3534 return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
3535 }
3536
3537 GetDXUTState().SetInsideMainloop( true );
3538
3539 // If DXUTCreateDevice*() or DXUTSetDevice() has not already been called,
3540 // then call DXUTCreateDevice() with the default parameters.
3541 if( !GetDXUTState().GetDeviceCreated() )
3542 {
3543 if( GetDXUTState().GetDeviceCreateCalled() )
3544 {
3545 if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
3546 GetDXUTState().SetExitCode(1);
3547 return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed
3548 }
3549
3550 hr = DXUTCreateDevice();
3551 if( FAILED(hr) )
3552 {
3553 if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
3554 GetDXUTState().SetExitCode(1);
3555 return hr;
3556 }
3557 }
3558
3559 HWND hWnd = DXUTGetHWND();
3560
3561 // DXUTInit() must have been called and succeeded for this function to proceed
3562 // DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed
3563 // DXUTCreateDevice() or DXUTCreateDeviceFromSettings() or DXUTSetDevice() must have been called and succeeded for this function to proceed
3564 if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() )
3565 {
3566 if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
3567 GetDXUTState().SetExitCode(1);
3568 return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
3569 }
3570
3571 // Now we're ready to receive and process Windows messages.
3572 bool bGotMsg;
3573 MSG msg;
3574 msg.message = WM_NULL;
3575 PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
3576
3577 while( WM_QUIT != msg.message )
3578 {
3579 // Use PeekMessage() so we can use idle time to render the scene.
3580 bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
3581
3582 if( bGotMsg )
3583 {
3584 // Translate and dispatch the message
3585 if( hAccel == NULL || hWnd == NULL ||
3586 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
3587 {
3588 TranslateMessage( &msg );
3589 DispatchMessage( &msg );
3590 }
3591 }
3592 else
3593 {
3594 // Render a frame during idle time (no messages are waiting)
3595 DXUTRender3DEnvironment();
3596 }
3597 }
3598
3599 // Cleanup the accelerator table
3600 if( hAccel != NULL )
3601 DestroyAcceleratorTable( hAccel );
3602
3603 GetDXUTState().SetInsideMainloop( false );
3604
3605 return S_OK;
3606 }
3607
3608
3609 //--------------------------------------------------------------------------------------
3610 // Render the 3D environment by:
3611 // - Checking if the device is lost and trying to reset it if it is
3612 // - Get the elapsed time since the last frame
3613 // - Calling the app's framemove and render callback
3614 // - Calling Present()
3615 //--------------------------------------------------------------------------------------
DXUTRender3DEnvironment()3616 void DXUTRender3DEnvironment()
3617 {
3618 HRESULT hr;
3619
3620 if( GetDXUTState().GetDeviceLost() || DXUTIsRenderingPaused() || !DXUTIsActive() )
3621 {
3622 // Window is minimized or paused so yield CPU time to other processes
3623 Sleep( 50 );
3624 }
3625
3626 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
3627 if( NULL == pd3dDevice )
3628 {
3629 if( GetDXUTState().GetDeviceLost() )
3630 {
3631 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
3632 DXUTChangeDevice( &deviceSettings, NULL, false, true );
3633 }
3634
3635 return;
3636 }
3637
3638 if( GetDXUTState().GetDeviceLost() && !GetDXUTState().GetRenderingPaused() )
3639 {
3640 // Test the cooperative level to see if it's okay to render
3641 if( FAILED( hr = pd3dDevice->TestCooperativeLevel() ) )
3642 {
3643 if( D3DERR_DEVICELOST == hr )
3644 {
3645 // The device has been lost but cannot be reset at this time.
3646 // So wait until it can be reset.
3647 return;
3648 }
3649
3650 // If we are windowed, read the desktop format and
3651 // ensure that the Direct3D device is using the same format
3652 // since the user could have changed the desktop bitdepth
3653 if( DXUTIsWindowed() )
3654 {
3655 D3DDISPLAYMODE adapterDesktopDisplayMode;
3656 IDirect3D9* pD3D = DXUTGetD3DObject();
3657 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3658 pD3D->GetAdapterDisplayMode( pDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
3659 if( pDeviceSettings->AdapterFormat != adapterDesktopDisplayMode.Format )
3660 {
3661 DXUTMatchOptions matchOptions;
3662 matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
3663 matchOptions.eDeviceType = DXUTMT_PRESERVE_INPUT;
3664 matchOptions.eWindowed = DXUTMT_PRESERVE_INPUT;
3665 matchOptions.eAdapterFormat = DXUTMT_PRESERVE_INPUT;
3666 matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
3667 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
3668 matchOptions.eBackBufferFormat = DXUTMT_CLOSEST_TO_INPUT;
3669 matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
3670 matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
3671 matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
3672 matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
3673 matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
3674 matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
3675 matchOptions.eRefreshRate = DXUTMT_CLOSEST_TO_INPUT;
3676 matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;
3677
3678 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
3679 deviceSettings.AdapterFormat = adapterDesktopDisplayMode.Format;
3680
3681 hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
3682 if( FAILED(hr) ) // the call will fail if no valid devices were found
3683 {
3684 DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES );
3685 DXUTShutdown();
3686 }
3687
3688 // Change to a Direct3D device created from the new device settings.
3689 // If there is an existing device, then either reset or recreate the scene
3690 hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
3691 if( FAILED(hr) )
3692 {
3693 // If this fails, try to go fullscreen and if this fails also shutdown.
3694 if( FAILED(DXUTToggleFullScreen()) )
3695 DXUTShutdown();
3696 }
3697
3698 return;
3699 }
3700 }
3701
3702 // Try to reset the device
3703 if( FAILED( hr = DXUTReset3DEnvironment() ) )
3704 {
3705 if( D3DERR_DEVICELOST == hr )
3706 {
3707 // The device was lost again, so continue waiting until it can be reset.
3708 return;
3709 }
3710 else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr ||
3711 DXUTERR_MEDIANOTFOUND == hr )
3712 {
3713 DXUTDisplayErrorMessage( hr );
3714 DXUTShutdown();
3715 return;
3716 }
3717 else
3718 {
3719 // Reset failed, but the device wasn't lost so something bad happened,
3720 // so recreate the device to try to recover
3721 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3722 if( FAILED( DXUTChangeDevice( pDeviceSettings, NULL, true, false ) ) )
3723 {
3724 DXUTShutdown();
3725 return;
3726 }
3727 }
3728 }
3729 }
3730
3731 GetDXUTState().SetDeviceLost( false );
3732 }
3733
3734 // Get the app's time, in seconds. Skip rendering if no time elapsed
3735 double fTime, fAbsTime; float fElapsedTime;
3736 DXUTGetGlobalTimer()->GetTimeValues( &fTime, &fAbsTime, &fElapsedTime );
3737
3738 // Store the time for the app
3739 if( GetDXUTState().GetConstantFrameTime() )
3740 {
3741 fElapsedTime = GetDXUTState().GetTimePerFrame();
3742 fTime = DXUTGetTime() + fElapsedTime;
3743 }
3744
3745 GetDXUTState().SetTime( fTime );
3746 GetDXUTState().SetAbsoluteTime( fAbsTime );
3747 GetDXUTState().SetElapsedTime( fElapsedTime );
3748
3749 // Update the FPS stats
3750 DXUTUpdateFrameStats();
3751
3752 DXUTHandleTimers();
3753
3754 // Animate the scene by calling the app's frame move callback
3755 LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove = GetDXUTState().GetFrameMoveFunc();
3756 if( pCallbackFrameMove != NULL )
3757 {
3758 pCallbackFrameMove( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameMoveFuncUserContext() );
3759 pd3dDevice = DXUTGetD3DDevice();
3760 if( NULL == pd3dDevice ) // Handle DXUTShutdown from inside callback
3761 return;
3762 }
3763
3764 if( !GetDXUTState().GetRenderingPaused() )
3765 {
3766 // Render the scene by calling the app's render callback
3767 LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
3768 if( pCallbackFrameRender != NULL )
3769 {
3770 pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameRenderFuncUserContext() );
3771 pd3dDevice = DXUTGetD3DDevice();
3772 if( NULL == pd3dDevice ) // Handle DXUTShutdown from inside callback
3773 return;
3774 }
3775
3776 #if defined(DEBUG) || defined(_DEBUG)
3777 // The back buffer should always match the client rect
3778 // if the Direct3D backbuffer covers the entire window
3779 RECT rcClient;
3780 GetClientRect( DXUTGetHWND(), &rcClient );
3781 if( !IsIconic( DXUTGetHWND() ) )
3782 {
3783 GetClientRect( DXUTGetHWND(), &rcClient );
3784 assert( DXUTGetBackBufferSurfaceDesc()->Width == (UINT)rcClient.right );
3785 assert( DXUTGetBackBufferSurfaceDesc()->Height == (UINT)rcClient.bottom );
3786 }
3787 #endif
3788
3789 // Show the frame on the primary surface.
3790 hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
3791 if( FAILED(hr) )
3792 {
3793 if( D3DERR_DEVICELOST == hr )
3794 {
3795 GetDXUTState().SetDeviceLost( true );
3796 }
3797 else if( D3DERR_DRIVERINTERNALERROR == hr )
3798 {
3799 // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
3800 // the application can do one of the following:
3801 //
3802 // - End, with the pop-up window saying that the application cannot continue
3803 // because of problems in the display adapter and that the user should
3804 // contact the adapter manufacturer.
3805 //
3806 // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same
3807 // path as recovering from a lost device. If IDirect3DDevice9::Reset fails with
3808 // D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message
3809 // that the user should contact the adapter manufacturer.
3810 //
3811 // The framework attempts the path of resetting the device
3812 //
3813 GetDXUTState().SetDeviceLost( true );
3814 }
3815 }
3816 }
3817
3818 // Update current frame #
3819 int nFrame = GetDXUTState().GetCurrentFrameNumber();
3820 nFrame++;
3821 GetDXUTState().SetCurrentFrameNumber( nFrame );
3822
3823 // Check to see if the app should shutdown due to cmdline
3824 if( GetDXUTState().GetOverrideQuitAfterFrame() != 0 )
3825 {
3826 if( nFrame > GetDXUTState().GetOverrideQuitAfterFrame() )
3827 DXUTShutdown();
3828 }
3829
3830 return;
3831 }
3832
3833
3834 //--------------------------------------------------------------------------------------
3835 // Updates the string which describes the device
3836 //--------------------------------------------------------------------------------------
DXUTUpdateDeviceStats(D3DDEVTYPE DeviceType,DWORD BehaviorFlags,D3DADAPTER_IDENTIFIER9 * pAdapterIdentifier)3837 void DXUTUpdateDeviceStats( D3DDEVTYPE DeviceType, DWORD BehaviorFlags, D3DADAPTER_IDENTIFIER9* pAdapterIdentifier )
3838 {
3839 if( GetDXUTState().GetNoStats() )
3840 return;
3841
3842 // Store device description
3843 WCHAR* pstrDeviceStats = GetDXUTState().GetDeviceStats();
3844 if( DeviceType == D3DDEVTYPE_REF )
3845 StringCchCopy( pstrDeviceStats, 256, L"REF" );
3846 else if( DeviceType == D3DDEVTYPE_HAL )
3847 StringCchCopy( pstrDeviceStats, 256, L"HAL" );
3848 else if( DeviceType == D3DDEVTYPE_SW )
3849 StringCchCopy( pstrDeviceStats, 256, L"SW" );
3850
3851 if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
3852 BehaviorFlags & D3DCREATE_PUREDEVICE )
3853 {
3854 if( DeviceType == D3DDEVTYPE_HAL )
3855 StringCchCat( pstrDeviceStats, 256, L" (pure hw vp)" );
3856 else
3857 StringCchCat( pstrDeviceStats, 256, L" (simulated pure hw vp)" );
3858 }
3859 else if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
3860 {
3861 if( DeviceType == D3DDEVTYPE_HAL )
3862 StringCchCat( pstrDeviceStats, 256, L" (hw vp)" );
3863 else
3864 StringCchCat( pstrDeviceStats, 256, L" (simulated hw vp)" );
3865 }
3866 else if( BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
3867 {
3868 if( DeviceType == D3DDEVTYPE_HAL )
3869 StringCchCat( pstrDeviceStats, 256, L" (mixed vp)" );
3870 else
3871 StringCchCat( pstrDeviceStats, 256, L" (simulated mixed vp)" );
3872 }
3873 else if( BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
3874 {
3875 StringCchCat( pstrDeviceStats, 256, L" (sw vp)" );
3876 }
3877
3878 if( DeviceType == D3DDEVTYPE_HAL )
3879 {
3880 // Be sure not to overflow m_strDeviceStats when appending the adapter
3881 // description, since it can be long.
3882 StringCchCat( pstrDeviceStats, 256, L": " );
3883
3884 // Try to get a unique description from the CD3DEnumDeviceSettingsCombo
3885 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3886 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
3887 CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, pDeviceSettings->AdapterFormat, pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed );
3888 if( pDeviceSettingsCombo )
3889 {
3890 StringCchCat( pstrDeviceStats, 256, pDeviceSettingsCombo->pAdapterInfo->szUniqueDescription );
3891 }
3892 else
3893 {
3894 const int cchDesc = sizeof(pAdapterIdentifier->Description);
3895 WCHAR szDescription[cchDesc];
3896 MultiByteToWideChar( CP_ACP, 0, pAdapterIdentifier->Description, -1, szDescription, cchDesc );
3897 szDescription[cchDesc-1] = 0;
3898 StringCchCat( pstrDeviceStats, 256, szDescription );
3899 }
3900 }
3901 }
3902
3903
3904 //--------------------------------------------------------------------------------------
3905 // Updates the frames/sec stat once per second
3906 //--------------------------------------------------------------------------------------
DXUTUpdateFrameStats()3907 void DXUTUpdateFrameStats()
3908 {
3909 if( GetDXUTState().GetNoStats() )
3910 return;
3911
3912 // Keep track of the frame count
3913 double fLastTime = GetDXUTState().GetLastStatsUpdateTime();
3914 DWORD dwFrames = GetDXUTState().GetLastStatsUpdateFrames();
3915 double fAbsTime = GetDXUTState().GetAbsoluteTime();
3916 dwFrames++;
3917 GetDXUTState().SetLastStatsUpdateFrames( dwFrames );
3918
3919 // Update the scene stats once per second
3920 if( fAbsTime - fLastTime > 1.0f )
3921 {
3922 float fFPS = (float) (dwFrames / (fAbsTime - fLastTime));
3923 GetDXUTState().SetFPS( fFPS );
3924 GetDXUTState().SetLastStatsUpdateTime( fAbsTime );
3925 GetDXUTState().SetLastStatsUpdateFrames( 0 );
3926
3927 WCHAR* pstrFPS = GetDXUTState().GetFPSStats();
3928 StringCchPrintf( pstrFPS, 64, L"%0.2f fps ", fFPS );
3929 }
3930 }
3931
3932
3933 //--------------------------------------------------------------------------------------
3934 // Updates the static part of the frame stats so it doesn't have be generated every frame
3935 //--------------------------------------------------------------------------------------
DXUTUpdateStaticFrameStats()3936 void DXUTUpdateStaticFrameStats()
3937 {
3938 if( GetDXUTState().GetNoStats() )
3939 return;
3940
3941 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
3942 if( NULL == pDeviceSettings )
3943 return;
3944 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
3945 if( NULL == pd3dEnum )
3946 return;
3947
3948 CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, pDeviceSettings->AdapterFormat, pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed );
3949 if( NULL == pDeviceSettingsCombo )
3950 return;
3951
3952 WCHAR strFmt[100];
3953 D3DPRESENT_PARAMETERS* pPP = &pDeviceSettings->pp;
3954
3955 if( pDeviceSettingsCombo->AdapterFormat == pDeviceSettingsCombo->BackBufferFormat )
3956 {
3957 StringCchCopy( strFmt, 100, DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ) );
3958 }
3959 else
3960 {
3961 StringCchPrintf( strFmt, 100, L"backbuf %s, adapter %s",
3962 DXUTD3DFormatToString( pDeviceSettingsCombo->BackBufferFormat, false ),
3963 DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ) );
3964 }
3965
3966 WCHAR strDepthFmt[100];
3967 if( pPP->EnableAutoDepthStencil )
3968 {
3969 StringCchPrintf( strDepthFmt, 100, L" (%s)", DXUTD3DFormatToString( pPP->AutoDepthStencilFormat, false ) );
3970 }
3971 else
3972 {
3973 // No depth buffer
3974 strDepthFmt[0] = 0;
3975 }
3976
3977 WCHAR strMultiSample[100];
3978 switch( pPP->MultiSampleType )
3979 {
3980 case D3DMULTISAMPLE_NONMASKABLE: StringCchCopy( strMultiSample, 100, L" (Nonmaskable Multisample)" ); break;
3981 case D3DMULTISAMPLE_NONE: StringCchCopy( strMultiSample, 100, L"" ); break;
3982 default: StringCchPrintf( strMultiSample, 100, L" (%dx Multisample)", pPP->MultiSampleType ); break;
3983 }
3984
3985 WCHAR* pstrStaticFrameStats = GetDXUTState().GetStaticFrameStats();
3986 StringCchPrintf( pstrStaticFrameStats, 256, L"%%sVsync %s (%dx%d), %s%s%s",
3987 ( pPP->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE ) ? L"off" : L"on",
3988 pPP->BackBufferWidth, pPP->BackBufferHeight,
3989 strFmt, strDepthFmt, strMultiSample );
3990 }
3991
3992
3993 //--------------------------------------------------------------------------------------
DXUTGetFrameStats(bool bShowFPS)3994 LPCWSTR DXUTGetFrameStats( bool bShowFPS )
3995 {
3996 WCHAR* pstrFrameStats = GetDXUTState().GetFrameStats();
3997 WCHAR* pstrFPS = ( bShowFPS ) ? GetDXUTState().GetFPSStats() : L"";
3998 StringCchPrintf( pstrFrameStats, 256, GetDXUTState().GetStaticFrameStats(), pstrFPS );
3999 return pstrFrameStats;
4000 }
4001
4002
4003 //--------------------------------------------------------------------------------------
4004 // Handles window messages
4005 //--------------------------------------------------------------------------------------
DXUTStaticWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)4006 LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
4007 {
4008 // Consolidate the keyboard messages and pass them to the app's keyboard callback
4009 if( uMsg == WM_KEYDOWN ||
4010 uMsg == WM_SYSKEYDOWN ||
4011 uMsg == WM_KEYUP ||
4012 uMsg == WM_SYSKEYUP )
4013 {
4014 bool bKeyDown = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
4015 DWORD dwMask = (1 << 29);
4016 bool bAltDown = ( (lParam & dwMask) != 0 );
4017
4018 bool* bKeys = GetDXUTState().GetKeys();
4019 bKeys[ (BYTE) (wParam & 0xFF) ] = bKeyDown;
4020
4021 LPDXUTCALLBACKKEYBOARD pCallbackKeyboard = GetDXUTState().GetKeyboardFunc();
4022 if( pCallbackKeyboard )
4023 pCallbackKeyboard( (UINT)wParam, bKeyDown, bAltDown, GetDXUTState().GetKeyboardFuncUserContext() );
4024 }
4025
4026 // Consolidate the mouse button messages and pass them to the app's mouse callback
4027 if( uMsg == WM_LBUTTONDOWN ||
4028 uMsg == WM_LBUTTONUP ||
4029 uMsg == WM_LBUTTONDBLCLK ||
4030 uMsg == WM_MBUTTONDOWN ||
4031 uMsg == WM_MBUTTONUP ||
4032 uMsg == WM_MBUTTONDBLCLK ||
4033 uMsg == WM_RBUTTONDOWN ||
4034 uMsg == WM_RBUTTONUP ||
4035 uMsg == WM_RBUTTONDBLCLK ||
4036 uMsg == WM_XBUTTONDOWN ||
4037 uMsg == WM_XBUTTONUP ||
4038 uMsg == WM_XBUTTONDBLCLK ||
4039 uMsg == WM_MOUSEWHEEL ||
4040 (GetDXUTState().GetNotifyOnMouseMove() && uMsg == WM_MOUSEMOVE) )
4041 {
4042 int xPos = (short)LOWORD(lParam);
4043 int yPos = (short)HIWORD(lParam);
4044
4045 if( uMsg == WM_MOUSEWHEEL )
4046 {
4047 // WM_MOUSEWHEEL passes screen mouse coords
4048 // so convert them to client coords
4049 POINT pt;
4050 pt.x = xPos; pt.y = yPos;
4051 ScreenToClient( hWnd, &pt );
4052 xPos = pt.x; yPos = pt.y;
4053 }
4054
4055 int nMouseWheelDelta = 0;
4056 if( uMsg == WM_MOUSEWHEEL )
4057 nMouseWheelDelta = (short) HIWORD(wParam);
4058
4059 int nMouseButtonState = LOWORD(wParam);
4060 bool bLeftButton = ((nMouseButtonState & MK_LBUTTON) != 0);
4061 bool bRightButton = ((nMouseButtonState & MK_RBUTTON) != 0);
4062 bool bMiddleButton = ((nMouseButtonState & MK_MBUTTON) != 0);
4063 bool bSideButton1 = ((nMouseButtonState & MK_XBUTTON1) != 0);
4064 bool bSideButton2 = ((nMouseButtonState & MK_XBUTTON2) != 0);
4065
4066 bool* bMouseButtons = GetDXUTState().GetMouseButtons();
4067 bMouseButtons[0] = bLeftButton;
4068 bMouseButtons[1] = bMiddleButton;
4069 bMouseButtons[2] = bRightButton;
4070 bMouseButtons[3] = bSideButton1;
4071 bMouseButtons[4] = bSideButton2;
4072
4073 LPDXUTCALLBACKMOUSE pCallbackMouse = GetDXUTState().GetMouseFunc();
4074 if( pCallbackMouse )
4075 pCallbackMouse( bLeftButton, bRightButton, bMiddleButton, bSideButton1, bSideButton2, nMouseWheelDelta, xPos, yPos, GetDXUTState().GetMouseFuncUserContext() );
4076 }
4077
4078 // Pass all messages to the app's MsgProc callback, and don't
4079 // process further messages if the apps says not to.
4080 LPDXUTCALLBACKMSGPROC pCallbackMsgProc = GetDXUTState().GetWindowMsgFunc();
4081 if( pCallbackMsgProc )
4082 {
4083 bool bNoFurtherProcessing = false;
4084 LRESULT nResult = pCallbackMsgProc( hWnd, uMsg, wParam, lParam, &bNoFurtherProcessing, GetDXUTState().GetWindowMsgFuncUserContext() );
4085 if( bNoFurtherProcessing )
4086 return nResult;
4087 }
4088
4089 switch( uMsg )
4090 {
4091 case WM_PAINT:
4092 {
4093 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4094
4095 // Handle paint messages when the app is paused
4096 if( pd3dDevice && DXUTIsRenderingPaused() &&
4097 GetDXUTState().GetDeviceObjectsCreated() && GetDXUTState().GetDeviceObjectsReset() )
4098 {
4099 HRESULT hr;
4100 double fTime = DXUTGetTime();
4101 float fElapsedTime = DXUTGetElapsedTime();
4102
4103 LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
4104 if( pCallbackFrameRender != NULL )
4105 pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameRenderFuncUserContext() );
4106
4107 hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
4108 if( D3DERR_DEVICELOST == hr )
4109 {
4110 GetDXUTState().SetDeviceLost( true );
4111 }
4112 else if( D3DERR_DRIVERINTERNALERROR == hr )
4113 {
4114 // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
4115 // the application can do one of the following:
4116 //
4117 // - End, with the pop-up window saying that the application cannot continue
4118 // because of problems in the display adapter and that the user should
4119 // contact the adapter manufacturer.
4120 //
4121 // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same
4122 // path as recovering from a lost device. If IDirect3DDevice9::Reset fails with
4123 // D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message
4124 // that the user should contact the adapter manufacturer.
4125 //
4126 // The framework attempts the path of resetting the device
4127 //
4128 GetDXUTState().SetDeviceLost( true );
4129 }
4130 }
4131 break;
4132 }
4133
4134 case WM_SIZE:
4135 if( SIZE_MINIMIZED == wParam )
4136 {
4137 DXUTPause( true, true ); // Pause while we're minimized
4138
4139 GetDXUTState().SetMinimized( true );
4140 GetDXUTState().SetMaximized( false );
4141 }
4142 else
4143 {
4144 RECT rcCurrentClient;
4145 GetClientRect( DXUTGetHWND(), &rcCurrentClient );
4146 if( rcCurrentClient.top == 0 && rcCurrentClient.bottom == 0 )
4147 {
4148 // Rapidly clicking the task bar to minimize and restore a window
4149 // can cause a WM_SIZE message with SIZE_RESTORED when
4150 // the window has actually become minimized due to rapid change
4151 // so just ignore this message
4152 }
4153 else if( SIZE_MAXIMIZED == wParam )
4154 {
4155 if( GetDXUTState().GetMinimized() )
4156 DXUTPause( false, false ); // Unpause since we're no longer minimized
4157 GetDXUTState().SetMinimized( false );
4158 GetDXUTState().SetMaximized( true );
4159 DXUTCheckForWindowSizeChange();
4160 DXUTCheckForWindowChangingMonitors();
4161 }
4162 else if( SIZE_RESTORED == wParam )
4163 {
4164 if( GetDXUTState().GetMaximized() )
4165 {
4166 GetDXUTState().SetMaximized( false );
4167 DXUTCheckForWindowSizeChange();
4168 DXUTCheckForWindowChangingMonitors();
4169 }
4170 else if( GetDXUTState().GetMinimized() )
4171 {
4172 DXUTPause( false, false ); // Unpause since we're no longer minimized
4173 GetDXUTState().SetMinimized( false );
4174 DXUTCheckForWindowSizeChange();
4175 DXUTCheckForWindowChangingMonitors();
4176 }
4177 else if( GetDXUTState().GetInSizeMove() )
4178 {
4179 // If we're neither maximized nor minimized, the window size
4180 // is changing by the user dragging the window edges. In this
4181 // case, we don't reset the device yet -- we wait until the
4182 // user stops dragging, and a WM_EXITSIZEMOVE message comes.
4183 }
4184 else
4185 {
4186 // This WM_SIZE come from resizing the window via an API like SetWindowPos() so
4187 // resize and reset the device now.
4188 DXUTCheckForWindowSizeChange();
4189 DXUTCheckForWindowChangingMonitors();
4190 }
4191 }
4192 }
4193 break;
4194
4195 case WM_GETMINMAXINFO:
4196 ((MINMAXINFO*)lParam)->ptMinTrackSize.x = DXUT_MIN_WINDOW_SIZE_X;
4197 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = DXUT_MIN_WINDOW_SIZE_Y;
4198 break;
4199
4200 case WM_ENTERSIZEMOVE:
4201 // Halt frame movement while the app is sizing or moving
4202 DXUTPause( true, true );
4203 GetDXUTState().SetInSizeMove( true );
4204 break;
4205
4206 case WM_EXITSIZEMOVE:
4207 DXUTPause( false, false );
4208 DXUTCheckForWindowSizeChange();
4209 DXUTCheckForWindowChangingMonitors();
4210 GetDXUTState().SetInSizeMove( false );
4211 break;
4212
4213 case WM_MOUSEMOVE:
4214 if( DXUTIsActive() && !DXUTIsWindowed() )
4215 {
4216 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4217 if( pd3dDevice )
4218 {
4219 POINT ptCursor;
4220 GetCursorPos( &ptCursor );
4221 pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
4222 }
4223 }
4224 break;
4225
4226 case WM_SETCURSOR:
4227 if( DXUTIsActive() && !DXUTIsWindowed() )
4228 {
4229 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4230 if( pd3dDevice && GetDXUTState().GetShowCursorWhenFullScreen() )
4231 pd3dDevice->ShowCursor( true );
4232 return true; // prevent Windows from setting cursor to window class cursor
4233 }
4234 break;
4235
4236 case WM_ACTIVATEAPP:
4237 if( wParam == TRUE && !DXUTIsActive() ) // Handle only if previously not active
4238 {
4239 GetDXUTState().SetActive( true );
4240
4241 // Disable any controller rumble & input when de-activating app
4242 DXUTEnableXInput( true );
4243
4244 // The GetMinimizedWhileFullscreen() varible is used instead of !DXUTIsWindowed()
4245 // to handle the rare case toggling to windowed mode while the fullscreen application
4246 // is minimized and thus making the pause count wrong
4247 if( GetDXUTState().GetMinimizedWhileFullscreen() )
4248 {
4249 DXUTPause( false, false ); // Unpause since we're no longer minimized
4250 GetDXUTState().SetMinimizedWhileFullscreen( false );
4251 }
4252
4253 // Upon returning to this app, potentially disable shortcut keys
4254 // (Windows key, accessibility shortcuts)
4255 DXUTAllowShortcutKeys( ( DXUTIsWindowed() ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() :
4256 GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
4257
4258 }
4259 else if( wParam == FALSE && DXUTIsActive() ) // Handle only if previously active
4260 {
4261 GetDXUTState().SetActive( false );
4262
4263 // Disable any controller rumble & input when de-activating app
4264 DXUTEnableXInput( false );
4265
4266 if( !DXUTIsWindowed() )
4267 {
4268 // Going from full screen to a minimized state
4269 ClipCursor( NULL ); // don't limit the cursor anymore
4270 DXUTPause( true, true ); // Pause while we're minimized (take care not to pause twice by handling this message twice)
4271 GetDXUTState().SetMinimizedWhileFullscreen( true );
4272 }
4273
4274 // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
4275 //
4276 // This is important to call here if the shortcuts are disabled,
4277 // because if this is not done then the Windows key will continue to
4278 // be disabled while this app is running which is very bad.
4279 // If the app crashes, the Windows key will return to normal.
4280 DXUTAllowShortcutKeys( true );
4281 }
4282 break;
4283
4284 case WM_ENTERMENULOOP:
4285 // Pause the app when menus are displayed
4286 DXUTPause( true, true );
4287 break;
4288
4289 case WM_EXITMENULOOP:
4290 DXUTPause( false, false );
4291 break;
4292
4293 case WM_MENUCHAR:
4294 // A menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key
4295 // So just ignore and don't beep
4296 return MAKELRESULT(0,MNC_CLOSE);
4297 break;
4298
4299 case WM_NCHITTEST:
4300 // Prevent the user from selecting the menu in full screen mode
4301 if( !DXUTIsWindowed() )
4302 return HTCLIENT;
4303 break;
4304
4305 case WM_POWERBROADCAST:
4306 switch( wParam )
4307 {
4308 #ifndef PBT_APMQUERYSUSPEND
4309 #define PBT_APMQUERYSUSPEND 0x0000
4310 #endif
4311 case PBT_APMQUERYSUSPEND:
4312 // At this point, the app should save any data for open
4313 // network connections, files, etc., and prepare to go into
4314 // a suspended mode. The app can use the MsgProc callback
4315 // to handle this if desired.
4316 return true;
4317
4318 #ifndef PBT_APMRESUMESUSPEND
4319 #define PBT_APMRESUMESUSPEND 0x0007
4320 #endif
4321 case PBT_APMRESUMESUSPEND:
4322 // At this point, the app should recover any data, network
4323 // connections, files, etc., and resume running from when
4324 // the app was suspended. The app can use the MsgProc callback
4325 // to handle this if desired.
4326
4327 // QPC may lose consistency when suspending, so reset the timer
4328 // upon resume.
4329 DXUTGetGlobalTimer()->Reset();
4330 GetDXUTState().SetLastStatsUpdateTime( 0 );
4331 return true;
4332 }
4333 break;
4334
4335 case WM_SYSCOMMAND:
4336 // Prevent moving/sizing in full screen mode
4337 switch( wParam )
4338 {
4339 case SC_MOVE:
4340 case SC_SIZE:
4341 case SC_MAXIMIZE:
4342 case SC_KEYMENU:
4343 if( !DXUTIsWindowed() )
4344 return 0;
4345 break;
4346 }
4347 break;
4348
4349 case WM_SYSKEYDOWN:
4350 {
4351 switch( wParam )
4352 {
4353 case VK_RETURN:
4354 {
4355 if( GetDXUTState().GetHandleAltEnter() )
4356 {
4357 // Toggle full screen upon alt-enter
4358 DWORD dwMask = (1 << 29);
4359 if( (lParam & dwMask) != 0 ) // Alt is down also
4360 {
4361 // Toggle the full screen/window mode
4362 DXUTPause( true, true );
4363 DXUTToggleFullScreen();
4364 DXUTPause( false, false );
4365 return 0;
4366 }
4367 }
4368 }
4369 }
4370 break;
4371 }
4372
4373 case WM_KEYDOWN:
4374 {
4375 if( GetDXUTState().GetHandleDefaultHotkeys() )
4376 {
4377 switch( wParam )
4378 {
4379 case VK_F3:
4380 {
4381 DXUTPause( true, true );
4382 DXUTToggleREF();
4383 DXUTPause( false, false );
4384 break;
4385 }
4386
4387 case VK_F8:
4388 {
4389 bool bWireFrame = GetDXUTState().GetWireframeMode();
4390 bWireFrame = !bWireFrame;
4391 GetDXUTState().SetWireframeMode( bWireFrame );
4392
4393 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4394 if( pd3dDevice )
4395 pd3dDevice->SetRenderState( D3DRS_FILLMODE, (bWireFrame) ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
4396 break;
4397 }
4398
4399 case VK_ESCAPE:
4400 {
4401 // Received key to exit app
4402 SendMessage( hWnd, WM_CLOSE, 0, 0 );
4403 }
4404
4405 case VK_PAUSE:
4406 {
4407 bool bTimePaused = DXUTIsTimePaused();
4408 bTimePaused = !bTimePaused;
4409 if( bTimePaused )
4410 DXUTPause( true, false );
4411 else
4412 DXUTPause( false, false );
4413 break;
4414 }
4415 }
4416 }
4417 break;
4418 }
4419
4420 case WM_CLOSE:
4421 {
4422 HMENU hMenu;
4423 hMenu = GetMenu(hWnd);
4424 if( hMenu != NULL )
4425 DestroyMenu( hMenu );
4426 DestroyWindow( hWnd );
4427 UnregisterClass( L"Direct3DWindowClass", NULL );
4428 GetDXUTState().SetHWNDFocus( NULL );
4429 GetDXUTState().SetHWNDDeviceFullScreen( NULL );
4430 GetDXUTState().SetHWNDDeviceWindowed( NULL );
4431 return 0;
4432 }
4433
4434 case WM_DESTROY:
4435 PostQuitMessage(0);
4436 break;
4437 }
4438
4439 // Don't allow the F10 key to act as a shortcut to the menu bar
4440 // by not passing these messages to the DefWindowProc only when
4441 // there's no menu present
4442 if( !GetDXUTState().GetCallDefWindowProc() || GetDXUTState().GetMenu() == NULL && (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) && wParam == VK_F10 )
4443 return 0;
4444 else
4445 return DefWindowProc( hWnd, uMsg, wParam, lParam );
4446 }
4447
4448
4449 //--------------------------------------------------------------------------------------
4450 // Resets the state associated with DXUT
4451 //--------------------------------------------------------------------------------------
DXUTResetFrameworkState()4452 void DXUTResetFrameworkState()
4453 {
4454 GetDXUTState().Destroy();
4455 GetDXUTState().Create();
4456 }
4457
4458
4459 //--------------------------------------------------------------------------------------
4460 // Closes down the window. When the window closes, it will cleanup everything
4461 //--------------------------------------------------------------------------------------
DXUTShutdown(int nExitCode)4462 void DXUTShutdown( int nExitCode )
4463 {
4464 HWND hWnd = DXUTGetHWND();
4465 if( hWnd != NULL )
4466 SendMessage( hWnd, WM_CLOSE, 0, 0 );
4467
4468 GetDXUTState().SetExitCode(nExitCode);
4469
4470 DXUTCleanup3DEnvironment( true );
4471
4472 // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
4473 // This is important to call here if the shortcuts are disabled,
4474 // because accessibility setting changes are permanent.
4475 // This means that if this is not done then the accessibility settings
4476 // might not be the same as when the app was started.
4477 // If the app crashes without restoring the settings, this is also true so it
4478 // would be wise to backup/restore the settings from a file so they can be
4479 // restored when the crashed app is run again.
4480 DXUTAllowShortcutKeys( true );
4481
4482 GetDXUTState().SetD3DEnumeration( NULL );
4483
4484 IDirect3D9* pD3D = DXUTGetD3DObject();
4485 SAFE_RELEASE( pD3D );
4486 GetDXUTState().SetD3D( NULL );
4487
4488 if( GetDXUTState().GetOverrideRelaunchMCE() )
4489 DXUTReLaunchMediaCenter();
4490 }
4491
4492
4493 //--------------------------------------------------------------------------------------
4494 // Cleans up the 3D environment by:
4495 // - Calls the device lost callback
4496 // - Calls the device destroyed callback
4497 // - Releases the D3D device
4498 //--------------------------------------------------------------------------------------
DXUTCleanup3DEnvironment(bool bReleaseSettings)4499 void DXUTCleanup3DEnvironment( bool bReleaseSettings )
4500 {
4501 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4502 if( pd3dDevice != NULL )
4503 {
4504 GetDXUTState().SetInsideDeviceCallback( true );
4505
4506 // Call the app's device lost callback
4507 if( GetDXUTState().GetDeviceObjectsReset() == true )
4508 {
4509 LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
4510 if( pCallbackDeviceLost != NULL )
4511 pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
4512 GetDXUTState().SetDeviceObjectsReset( false );
4513
4514 // Call the resource cache device lost function
4515 DXUTGetGlobalResourceCache().OnLostDevice();
4516 }
4517
4518 // Call the app's device destroyed callback
4519 if( GetDXUTState().GetDeviceObjectsCreated() == true )
4520 {
4521 LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed = GetDXUTState().GetDeviceDestroyedFunc();
4522 if( pCallbackDeviceDestroyed != NULL )
4523 pCallbackDeviceDestroyed( GetDXUTState().GetDeviceDestroyedFuncUserContext() );
4524 GetDXUTState().SetDeviceObjectsCreated( false );
4525
4526 // Call the resource cache device destory function
4527 DXUTGetGlobalResourceCache().OnDestroyDevice();
4528 }
4529
4530 GetDXUTState().SetInsideDeviceCallback( false );
4531
4532 // Release the D3D device and in debug configs, displays a message box if there
4533 // are unrelease objects.
4534 if( pd3dDevice )
4535 {
4536 if( pd3dDevice->Release() > 0 )
4537 {
4538 DXUTDisplayErrorMessage( DXUTERR_NONZEROREFCOUNT );
4539 DXUT_ERR( L"DXUTCleanup3DEnvironment", DXUTERR_NONZEROREFCOUNT );
4540 }
4541 }
4542 GetDXUTState().SetD3DDevice( NULL );
4543
4544 if( bReleaseSettings )
4545 {
4546 DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
4547 SAFE_DELETE(pOldDeviceSettings);
4548 GetDXUTState().SetCurrentDeviceSettings( NULL );
4549 }
4550
4551 D3DSURFACE_DESC* pbackBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
4552 ZeroMemory( pbackBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
4553
4554 D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
4555 ZeroMemory( pd3dCaps, sizeof(D3DCAPS9) );
4556
4557 GetDXUTState().SetDeviceCreated( false );
4558 }
4559 }
4560
4561
4562 //--------------------------------------------------------------------------------------
4563 // Stores back buffer surface desc in GetDXUTState().GetBackBufferSurfaceDesc()
4564 //--------------------------------------------------------------------------------------
DXUTUpdateBackBufferDesc()4565 void DXUTUpdateBackBufferDesc()
4566 {
4567 HRESULT hr;
4568 IDirect3DSurface9* pBackBuffer;
4569 hr = GetDXUTState().GetD3DDevice()->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
4570 D3DSURFACE_DESC* pBBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
4571 ZeroMemory( pBBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
4572 if( SUCCEEDED(hr) )
4573 {
4574 pBackBuffer->GetDesc( pBBufferSurfaceDesc );
4575 SAFE_RELEASE( pBackBuffer );
4576 }
4577 }
4578
4579
4580 //--------------------------------------------------------------------------------------
4581 // Starts a user defined timer callback
4582 //--------------------------------------------------------------------------------------
DXUTSetTimer(LPDXUTCALLBACKTIMER pCallbackTimer,float fTimeoutInSecs,UINT * pnIDEvent,void * pCallbackUserContext)4583 HRESULT DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs, UINT* pnIDEvent, void* pCallbackUserContext )
4584 {
4585 if( pCallbackTimer == NULL )
4586 return DXUT_ERR_MSGBOX( L"DXUTSetTimer", E_INVALIDARG );
4587
4588 HRESULT hr;
4589 DXUT_TIMER DXUTTimer;
4590 DXUTTimer.pCallbackTimer = pCallbackTimer;
4591 DXUTTimer.pCallbackUserContext = pCallbackUserContext;
4592 DXUTTimer.fTimeoutInSecs = fTimeoutInSecs;
4593 DXUTTimer.fCountdown = fTimeoutInSecs;
4594 DXUTTimer.bEnabled = true;
4595 DXUTTimer.nID = GetDXUTState().GetTimerLastID() + 1;
4596 GetDXUTState().SetTimerLastID( DXUTTimer.nID );
4597
4598 CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
4599 if( pTimerList == NULL )
4600 {
4601 pTimerList = new CGrowableArray<DXUT_TIMER>;
4602 if( pTimerList == NULL )
4603 return E_OUTOFMEMORY;
4604 GetDXUTState().SetTimerList( pTimerList );
4605 }
4606
4607 if( FAILED( hr = pTimerList->Add( DXUTTimer ) ) )
4608 return hr;
4609
4610 if( pnIDEvent )
4611 *pnIDEvent = DXUTTimer.nID;
4612
4613 return S_OK;
4614 }
4615
4616
4617 //--------------------------------------------------------------------------------------
4618 // Stops a user defined timer callback
4619 //--------------------------------------------------------------------------------------
DXUTKillTimer(UINT nIDEvent)4620 HRESULT DXUTKillTimer( UINT nIDEvent )
4621 {
4622 CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
4623 if( pTimerList == NULL )
4624 return S_FALSE;
4625
4626 bool bFound = false;
4627
4628 for( int i=0; i<pTimerList->GetSize(); i++ )
4629 {
4630 DXUT_TIMER DXUTTimer = pTimerList->GetAt(i);
4631 if( DXUTTimer.nID == nIDEvent )
4632 {
4633 DXUTTimer.bEnabled = false;
4634 pTimerList->SetAt(i, DXUTTimer);
4635 bFound = true;
4636 break;
4637 }
4638 }
4639
4640 if( !bFound )
4641 return DXUT_ERR_MSGBOX( L"DXUTKillTimer", E_INVALIDARG );
4642
4643 return S_OK;
4644 }
4645
4646
4647 //--------------------------------------------------------------------------------------
4648 // Internal helper function to handle calling the user defined timer callbacks
4649 //--------------------------------------------------------------------------------------
DXUTHandleTimers()4650 void DXUTHandleTimers()
4651 {
4652 float fElapsedTime = DXUTGetElapsedTime();
4653
4654 CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
4655 if( pTimerList == NULL )
4656 return;
4657
4658 // Walk through the list of timer callbacks
4659 for( int i=0; i<pTimerList->GetSize(); i++ )
4660 {
4661 DXUT_TIMER DXUTTimer = pTimerList->GetAt(i);
4662 if( DXUTTimer.bEnabled )
4663 {
4664 DXUTTimer.fCountdown -= fElapsedTime;
4665
4666 // Call the callback if count down expired
4667 if( DXUTTimer.fCountdown < 0 )
4668 {
4669 DXUTTimer.pCallbackTimer( i, DXUTTimer.pCallbackUserContext );
4670 DXUTTimer.fCountdown = DXUTTimer.fTimeoutInSecs;
4671 }
4672 pTimerList->SetAt(i, DXUTTimer);
4673 }
4674 }
4675 }
4676
4677
4678 //--------------------------------------------------------------------------------------
4679 // External state access functions
4680 //--------------------------------------------------------------------------------------
DXUTGetD3DObject()4681 IDirect3D9* DXUTGetD3DObject() { return GetDXUTState().GetD3D(); }
DXUTGetD3DDevice()4682 IDirect3DDevice9* DXUTGetD3DDevice() { return GetDXUTState().GetD3DDevice(); }
DXUTGetBackBufferSurfaceDesc()4683 const D3DSURFACE_DESC* DXUTGetBackBufferSurfaceDesc() { return GetDXUTState().GetBackBufferSurfaceDesc(); }
DXUTGetDeviceCaps()4684 const D3DCAPS9* DXUTGetDeviceCaps() { return GetDXUTState().GetCaps(); }
DXUTGetHINSTANCE()4685 HINSTANCE DXUTGetHINSTANCE() { return GetDXUTState().GetHInstance(); }
DXUTGetHWND()4686 HWND DXUTGetHWND() { return DXUTIsWindowed() ? GetDXUTState().GetHWNDDeviceWindowed() : GetDXUTState().GetHWNDDeviceFullScreen(); }
DXUTGetHWNDFocus()4687 HWND DXUTGetHWNDFocus() { return GetDXUTState().GetHWNDFocus(); }
DXUTGetHWNDDeviceFullScreen()4688 HWND DXUTGetHWNDDeviceFullScreen() { return GetDXUTState().GetHWNDDeviceFullScreen(); }
DXUTGetHWNDDeviceWindowed()4689 HWND DXUTGetHWNDDeviceWindowed() { return GetDXUTState().GetHWNDDeviceWindowed(); }
DXUTGetWindowClientRect()4690 RECT DXUTGetWindowClientRect() { RECT rc; GetClientRect( DXUTGetHWND(), &rc ); return rc; }
DXUTGetWindowClientRectAtModeChange()4691 RECT DXUTGetWindowClientRectAtModeChange() { RECT rc = { 0, 0, GetDXUTState().GetWindowBackBufferWidthAtModeChange(), GetDXUTState().GetWindowBackBufferHeightAtModeChange() }; return rc; }
DXUTGetFullsceenClientRectAtModeChange()4692 RECT DXUTGetFullsceenClientRectAtModeChange() { RECT rc = { 0, 0, GetDXUTState().GetFullScreenBackBufferWidthAtModeChange(), GetDXUTState().GetFullScreenBackBufferHeightAtModeChange() }; return rc; }
DXUTGetTime()4693 double DXUTGetTime() { return GetDXUTState().GetTime(); }
DXUTGetElapsedTime()4694 float DXUTGetElapsedTime() { return GetDXUTState().GetElapsedTime(); }
DXUTGetFPS()4695 float DXUTGetFPS() { return GetDXUTState().GetFPS(); }
DXUTGetWindowTitle()4696 LPCWSTR DXUTGetWindowTitle() { return GetDXUTState().GetWindowTitle(); }
DXUTGetDeviceStats()4697 LPCWSTR DXUTGetDeviceStats() { return GetDXUTState().GetDeviceStats(); }
DXUTIsRenderingPaused()4698 bool DXUTIsRenderingPaused() { return GetDXUTState().GetPauseRenderingCount() > 0; }
DXUTIsTimePaused()4699 bool DXUTIsTimePaused() { return GetDXUTState().GetPauseTimeCount() > 0; }
DXUTIsActive()4700 bool DXUTIsActive() { return GetDXUTState().GetActive(); }
DXUTGetExitCode()4701 int DXUTGetExitCode() { return GetDXUTState().GetExitCode(); }
DXUTGetShowMsgBoxOnError()4702 bool DXUTGetShowMsgBoxOnError() { return GetDXUTState().GetShowMsgBoxOnError(); }
DXUTGetAutomation()4703 bool DXUTGetAutomation() { return GetDXUTState().GetAutomation(); }
DXUTGetHandleDefaultHotkeys()4704 bool DXUTGetHandleDefaultHotkeys() { return GetDXUTState().GetHandleDefaultHotkeys(); }
DXUTIsKeyDown(BYTE vKey)4705 bool DXUTIsKeyDown( BYTE vKey )
4706 {
4707 bool* bKeys = GetDXUTState().GetKeys();
4708 if( vKey >= 0xA0 && vKey <= 0xA5 ) // VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU
4709 return GetAsyncKeyState( vKey ) != 0; // these keys only are tracked via GetAsyncKeyState()
4710 else if( vKey >= 0x01 && vKey <= 0x06 && vKey != 0x03 ) // mouse buttons (VK_*BUTTON)
4711 return DXUTIsMouseButtonDown(vKey);
4712 else
4713 return bKeys[vKey];
4714 }
DXUTIsMouseButtonDown(BYTE vButton)4715 bool DXUTIsMouseButtonDown( BYTE vButton )
4716 {
4717 bool* bMouseButtons = GetDXUTState().GetMouseButtons();
4718 int nIndex = DXUTMapButtonToArrayIndex(vButton);
4719 return bMouseButtons[nIndex];
4720 }
DXUTSetMultimonSettings(bool bAutoChangeAdapter)4721 void DXUTSetMultimonSettings( bool bAutoChangeAdapter )
4722 {
4723 GetDXUTState().SetAutoChangeAdapter( bAutoChangeAdapter );
4724 }
DXUTSetCursorSettings(bool bShowCursorWhenFullScreen,bool bClipCursorWhenFullScreen)4725 void DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen )
4726 {
4727 GetDXUTState().SetClipCursorWhenFullScreen(bClipCursorWhenFullScreen);
4728 GetDXUTState().SetShowCursorWhenFullScreen(bShowCursorWhenFullScreen);
4729 DXUTSetupCursor();
4730 }
DXUTSetWindowSettings(bool bCallDefWindowProc)4731 void DXUTSetWindowSettings( bool bCallDefWindowProc )
4732 {
4733 GetDXUTState().SetCallDefWindowProc( bCallDefWindowProc );
4734 }
DXUTSetConstantFrameTime(bool bEnabled,float fTimePerFrame)4735 void DXUTSetConstantFrameTime( bool bEnabled, float fTimePerFrame )
4736 {
4737 if( GetDXUTState().GetOverrideConstantFrameTime() )
4738 {
4739 bEnabled = GetDXUTState().GetOverrideConstantFrameTime();
4740 fTimePerFrame = GetDXUTState().GetOverrideConstantTimePerFrame();
4741 }
4742 GetDXUTState().SetConstantFrameTime(bEnabled);
4743 GetDXUTState().SetTimePerFrame(fTimePerFrame);
4744 }
4745
4746
4747 //--------------------------------------------------------------------------------------
4748 // Return if windowed in the current device. If no device exists yet, then returns false
4749 //--------------------------------------------------------------------------------------
DXUTIsWindowed()4750 bool DXUTIsWindowed()
4751 {
4752 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
4753 if(pDeviceSettings)
4754 return (pDeviceSettings->pp.Windowed != 0);
4755 else
4756 return false;
4757 }
4758
4759
4760 //--------------------------------------------------------------------------------------
4761 // Return the present params of the current device. If no device exists yet, then
4762 // return blank present params
4763 //--------------------------------------------------------------------------------------
DXUTGetPresentParameters()4764 D3DPRESENT_PARAMETERS DXUTGetPresentParameters()
4765 {
4766 DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings();
4767 if( pDS )
4768 {
4769 return pDS->pp;
4770 }
4771 else
4772 {
4773 D3DPRESENT_PARAMETERS pp;
4774 ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS) );
4775 return pp;
4776 }
4777 }
4778
4779
4780 //--------------------------------------------------------------------------------------
4781 // Return the device settings of the current device. If no device exists yet, then
4782 // return blank device settings
4783 //--------------------------------------------------------------------------------------
DXUTGetDeviceSettings()4784 DXUTDeviceSettings DXUTGetDeviceSettings()
4785 {
4786 DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings();
4787 if( pDS )
4788 {
4789 return *pDS;
4790 }
4791 else
4792 {
4793 DXUTDeviceSettings ds;
4794 ZeroMemory( &ds, sizeof(DXUTDeviceSettings) );
4795 return ds;
4796 }
4797 }
4798
4799 #ifndef SM_REMOTESESSION // needs WINVER >= 0x0500
4800 #define SM_REMOTESESSION 0x1000
4801 #endif
4802
4803
4804 //--------------------------------------------------------------------------------------
4805 // Display an custom error msg box
4806 //--------------------------------------------------------------------------------------
DXUTDisplayErrorMessage(HRESULT hr)4807 void DXUTDisplayErrorMessage( HRESULT hr )
4808 {
4809 WCHAR strBuffer[512];
4810
4811 int nExitCode;
4812 bool bFound = true;
4813 switch( hr )
4814 {
4815 case DXUTERR_NODIRECT3D: nExitCode = 2; StringCchCopy( strBuffer, 512, L"Could not initialize Direct3D. You may want to check that the latest version of DirectX is correctly installed on your system. Also make sure that this program was compiled with header files that match the installed DirectX DLLs." ); break;
4816 case DXUTERR_INCORRECTVERSION: nExitCode = 10; StringCchCopy( strBuffer, 512, L"Incorrect version of Direct3D and/or D3DX." ); break;
4817 case DXUTERR_MEDIANOTFOUND: nExitCode = 4; StringCchCopy( strBuffer, 512, L"Could not find required media. Ensure that the DirectX SDK is correctly installed." ); break;
4818 case DXUTERR_NONZEROREFCOUNT: nExitCode = 5; StringCchCopy( strBuffer, 512, L"The D3D device has a non-zero reference count, meaning some objects were not released." ); break;
4819 case DXUTERR_CREATINGDEVICE: nExitCode = 6; StringCchCopy( strBuffer, 512, L"Failed creating the Direct3D device." ); break;
4820 case DXUTERR_RESETTINGDEVICE: nExitCode = 7; StringCchCopy( strBuffer, 512, L"Failed resetting the Direct3D device." ); break;
4821 case DXUTERR_CREATINGDEVICEOBJECTS: nExitCode = 8; StringCchCopy( strBuffer, 512, L"Failed creating Direct3D device objects." ); break;
4822 case DXUTERR_RESETTINGDEVICEOBJECTS: nExitCode = 9; StringCchCopy( strBuffer, 512, L"Failed resetting Direct3D device objects." ); break;
4823 case DXUTERR_NOCOMPATIBLEDEVICES:
4824 nExitCode = 3;
4825 if( GetSystemMetrics(SM_REMOTESESSION) != 0 )
4826 StringCchCopy( strBuffer, 512, L"Direct3D does not work over a remote session." );
4827 else
4828 StringCchCopy( strBuffer, 512, L"Could not find any compatible Direct3D devices." );
4829 break;
4830 default: bFound = false; nExitCode = 1;break;
4831 }
4832
4833 GetDXUTState().SetExitCode(nExitCode);
4834
4835 bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
4836 if( bFound && bShowMsgBoxOnError )
4837 {
4838 if( DXUTGetWindowTitle()[0] == 0 )
4839 MessageBox( DXUTGetHWND(), strBuffer, L"DirectX Application", MB_ICONERROR|MB_OK );
4840 else
4841 MessageBox( DXUTGetHWND(), strBuffer, DXUTGetWindowTitle(), MB_ICONERROR|MB_OK );
4842 }
4843 }
4844
4845
4846 //--------------------------------------------------------------------------------------
4847 // Display error msg box to help debug
4848 //--------------------------------------------------------------------------------------
DXUTTrace(const CHAR * strFile,DWORD dwLine,HRESULT hr,const WCHAR * strMsg,bool bPopMsgBox)4849 HRESULT WINAPI DXUTTrace( const CHAR* strFile, DWORD dwLine, HRESULT hr,
4850 const WCHAR* strMsg, bool bPopMsgBox )
4851 {
4852 bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
4853 if( bPopMsgBox && bShowMsgBoxOnError == false )
4854 bPopMsgBox = false;
4855
4856 return DXTrace( strFile, dwLine, hr, strMsg, bPopMsgBox );
4857 }
4858
4859
4860 //--------------------------------------------------------------------------------------
4861 // Checks to see if the HWND changed monitors, and if it did it creates a device
4862 // from the monitor's adapter and recreates the scene.
4863 //--------------------------------------------------------------------------------------
DXUTCheckForWindowChangingMonitors()4864 void DXUTCheckForWindowChangingMonitors()
4865 {
4866 // Skip this check for various reasons
4867 if( !GetDXUTState().GetAutoChangeAdapter() ||
4868 GetDXUTState().GetIgnoreSizeChange() ||
4869 !GetDXUTState().GetDeviceCreated() ||
4870 !GetDXUTState().GetCurrentDeviceSettings()->pp.Windowed )
4871 {
4872 return;
4873 }
4874
4875 HRESULT hr;
4876 HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
4877 HMONITOR hAdapterMonitor = GetDXUTState().GetAdapterMonitor();
4878 if( hWindowMonitor != hAdapterMonitor )
4879 {
4880 UINT newOrdinal;
4881 if( SUCCEEDED( DXUTGetAdapterOrdinalFromMonitor( hWindowMonitor, &newOrdinal ) ) )
4882 {
4883 // Find the closest valid device settings with the new ordinal
4884 DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
4885 deviceSettings.AdapterOrdinal = newOrdinal;
4886
4887 DXUTMatchOptions matchOptions;
4888 matchOptions.eAdapterOrdinal = DXUTMT_PRESERVE_INPUT;
4889 matchOptions.eDeviceType = DXUTMT_CLOSEST_TO_INPUT;
4890 matchOptions.eWindowed = DXUTMT_CLOSEST_TO_INPUT;
4891 matchOptions.eAdapterFormat = DXUTMT_CLOSEST_TO_INPUT;
4892 matchOptions.eVertexProcessing = DXUTMT_CLOSEST_TO_INPUT;
4893 matchOptions.eResolution = DXUTMT_CLOSEST_TO_INPUT;
4894 matchOptions.eBackBufferFormat = DXUTMT_CLOSEST_TO_INPUT;
4895 matchOptions.eBackBufferCount = DXUTMT_CLOSEST_TO_INPUT;
4896 matchOptions.eMultiSample = DXUTMT_CLOSEST_TO_INPUT;
4897 matchOptions.eSwapEffect = DXUTMT_CLOSEST_TO_INPUT;
4898 matchOptions.eDepthFormat = DXUTMT_CLOSEST_TO_INPUT;
4899 matchOptions.eStencilFormat = DXUTMT_CLOSEST_TO_INPUT;
4900 matchOptions.ePresentFlags = DXUTMT_CLOSEST_TO_INPUT;
4901 matchOptions.eRefreshRate = DXUTMT_CLOSEST_TO_INPUT;
4902 matchOptions.ePresentInterval = DXUTMT_CLOSEST_TO_INPUT;
4903
4904 hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
4905 if( SUCCEEDED(hr) )
4906 {
4907 // Create a Direct3D device using the new device settings.
4908 // If there is an existing device, then it will either reset or recreate the scene.
4909 hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
4910
4911 // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback
4912 if( hr == E_ABORT )
4913 {
4914 // so nothing changed and keep from attempting to switch adapters next time
4915 GetDXUTState().SetAutoChangeAdapter( false );
4916 }
4917 else if( FAILED(hr) )
4918 {
4919 DXUTShutdown();
4920 DXUTPause( false, false );
4921 return;
4922 }
4923 }
4924 }
4925 }
4926 }
4927
4928
4929 //--------------------------------------------------------------------------------------
4930 // Look for an adapter ordinal that is tied to a HMONITOR
4931 //--------------------------------------------------------------------------------------
DXUTGetAdapterOrdinalFromMonitor(HMONITOR hMonitor,UINT * pAdapterOrdinal)4932 HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal )
4933 {
4934 *pAdapterOrdinal = 0;
4935
4936 CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
4937 IDirect3D9* pD3D = DXUTGetD3DObject();
4938
4939 CGrowableArray<CD3DEnumAdapterInfo*>* pAdapterList = pd3dEnum->GetAdapterInfoList();
4940 for( int iAdapter=0; iAdapter<pAdapterList->GetSize(); iAdapter++ )
4941 {
4942 CD3DEnumAdapterInfo* pAdapterInfo = pAdapterList->GetAt(iAdapter);
4943 HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pAdapterInfo->AdapterOrdinal );
4944 if( hAdapterMonitor == hMonitor )
4945 {
4946 *pAdapterOrdinal = pAdapterInfo->AdapterOrdinal;
4947 return S_OK;
4948 }
4949 }
4950
4951 return E_FAIL;
4952 }
4953
4954
4955 //--------------------------------------------------------------------------------------
4956 // Internal function to map MK_* to an array index
4957 //--------------------------------------------------------------------------------------
DXUTMapButtonToArrayIndex(BYTE vButton)4958 int DXUTMapButtonToArrayIndex( BYTE vButton )
4959 {
4960 switch( vButton )
4961 {
4962 case MK_LBUTTON: return 0;
4963 case VK_MBUTTON:
4964 case MK_MBUTTON: return 1;
4965 case MK_RBUTTON: return 2;
4966 case VK_XBUTTON1:
4967 case MK_XBUTTON1: return 3;
4968 case VK_XBUTTON2:
4969 case MK_XBUTTON2: return 4;
4970 }
4971
4972 return 0;
4973 }
4974
4975
4976 //--------------------------------------------------------------------------------------
4977 // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
4978 //--------------------------------------------------------------------------------------
DXUTSetupCursor()4979 void DXUTSetupCursor()
4980 {
4981 // Show the cursor again if returning to fullscreen
4982 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
4983 if( !DXUTIsWindowed() && pd3dDevice )
4984 {
4985 if( GetDXUTState().GetShowCursorWhenFullScreen() )
4986 {
4987 SetCursor( NULL ); // Turn off Windows cursor in full screen mode
4988 HCURSOR hCursor = (HCURSOR)(ULONG_PTR)GetClassLongPtr( DXUTGetHWNDDeviceFullScreen(), GCLP_HCURSOR );
4989 DXUTSetDeviceCursor( pd3dDevice, hCursor, false );
4990 DXUTGetD3DDevice()->ShowCursor( true );
4991 }
4992 else
4993 {
4994 SetCursor( NULL ); // Turn off Windows cursor in full screen mode
4995 DXUTGetD3DDevice()->ShowCursor( false );
4996 }
4997 }
4998
4999 // Clip cursor if requested
5000 if( !DXUTIsWindowed() && GetDXUTState().GetClipCursorWhenFullScreen() )
5001 {
5002 // Confine cursor to full screen window
5003 RECT rcWindow;
5004 GetWindowRect( DXUTGetHWNDDeviceFullScreen(), &rcWindow );
5005 ClipCursor( &rcWindow );
5006 }
5007 else
5008 {
5009 ClipCursor( NULL );
5010 }
5011 }
5012
5013 //--------------------------------------------------------------------------------------
5014 // Gives the D3D device a cursor with image and hotspot from hCursor.
5015 //--------------------------------------------------------------------------------------
DXUTSetDeviceCursor(IDirect3DDevice9 * pd3dDevice,HCURSOR hCursor,bool bAddWatermark)5016 HRESULT DXUTSetDeviceCursor( IDirect3DDevice9* pd3dDevice, HCURSOR hCursor, bool bAddWatermark )
5017 {
5018 HRESULT hr = E_FAIL;
5019 ICONINFO iconinfo;
5020 bool bBWCursor;
5021 LPDIRECT3DSURFACE9 pCursorSurface = NULL;
5022 HDC hdcColor = NULL;
5023 HDC hdcMask = NULL;
5024 HDC hdcScreen = NULL;
5025 BITMAP bm;
5026 DWORD dwWidth;
5027 DWORD dwHeightSrc;
5028 DWORD dwHeightDest;
5029 COLORREF crColor;
5030 COLORREF crMask;
5031 UINT x;
5032 UINT y;
5033 BITMAPINFO bmi;
5034 COLORREF* pcrArrayColor = NULL;
5035 COLORREF* pcrArrayMask = NULL;
5036 DWORD* pBitmap;
5037 HGDIOBJ hgdiobjOld;
5038
5039 ZeroMemory( &iconinfo, sizeof(iconinfo) );
5040 if( !GetIconInfo( hCursor, &iconinfo ) )
5041 goto End;
5042
5043 if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
5044 goto End;
5045 dwWidth = bm.bmWidth;
5046 dwHeightSrc = bm.bmHeight;
5047
5048 if( iconinfo.hbmColor == NULL )
5049 {
5050 bBWCursor = TRUE;
5051 dwHeightDest = dwHeightSrc / 2;
5052 }
5053 else
5054 {
5055 bBWCursor = FALSE;
5056 dwHeightDest = dwHeightSrc;
5057 }
5058
5059 // Create a surface for the fullscreen cursor
5060 if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest,
5061 D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCursorSurface, NULL ) ) )
5062 {
5063 goto End;
5064 }
5065
5066 pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
5067
5068 ZeroMemory(&bmi, sizeof(bmi));
5069 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
5070 bmi.bmiHeader.biWidth = dwWidth;
5071 bmi.bmiHeader.biHeight = dwHeightSrc;
5072 bmi.bmiHeader.biPlanes = 1;
5073 bmi.bmiHeader.biBitCount = 32;
5074 bmi.bmiHeader.biCompression = BI_RGB;
5075
5076 hdcScreen = GetDC( NULL );
5077 hdcMask = CreateCompatibleDC( hdcScreen );
5078 if( hdcMask == NULL )
5079 {
5080 hr = E_FAIL;
5081 goto End;
5082 }
5083 hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
5084 GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc,
5085 pcrArrayMask, &bmi, DIB_RGB_COLORS);
5086 SelectObject(hdcMask, hgdiobjOld);
5087
5088 if (!bBWCursor)
5089 {
5090 pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
5091 hdcColor = CreateCompatibleDC( hdcScreen );
5092 if( hdcColor == NULL )
5093 {
5094 hr = E_FAIL;
5095 goto End;
5096 }
5097 SelectObject(hdcColor, iconinfo.hbmColor);
5098 GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest,
5099 pcrArrayColor, &bmi, DIB_RGB_COLORS);
5100 }
5101
5102 // Transfer cursor image into the surface
5103 D3DLOCKED_RECT lr;
5104 pCursorSurface->LockRect( &lr, NULL, 0 );
5105 pBitmap = (DWORD*)lr.pBits;
5106 for( y = 0; y < dwHeightDest; y++ )
5107 {
5108 for( x = 0; x < dwWidth; x++ )
5109 {
5110 if (bBWCursor)
5111 {
5112 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
5113 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
5114 }
5115 else
5116 {
5117 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
5118 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
5119 }
5120 if (crMask == 0)
5121 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
5122 else
5123 pBitmap[dwWidth*y + x] = 0x00000000;
5124
5125 // It may be helpful to make the D3D cursor look slightly
5126 // different from the Windows cursor so you can distinguish
5127 // between the two when developing/testing code. When
5128 // bAddWatermark is TRUE, the following code adds some
5129 // small grey "D3D" characters to the upper-left corner of
5130 // the D3D cursor image.
5131 if( bAddWatermark && x < 12 && y < 5 )
5132 {
5133 // 11.. 11.. 11.. .... CCC0
5134 // 1.1. ..1. 1.1. .... A2A0
5135 // 1.1. .1.. 1.1. .... A4A0
5136 // 1.1. ..1. 1.1. .... A2A0
5137 // 11.. 11.. 11.. .... CCC0
5138
5139 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
5140 if( wMask[y] & (1 << (15 - x)) )
5141 {
5142 pBitmap[dwWidth*y + x] |= 0xff808080;
5143 }
5144 }
5145 }
5146 }
5147 pCursorSurface->UnlockRect();
5148
5149 // Set the device cursor
5150 if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot,
5151 iconinfo.yHotspot, pCursorSurface ) ) )
5152 {
5153 goto End;
5154 }
5155
5156 hr = S_OK;
5157
5158 End:
5159 if( iconinfo.hbmMask != NULL )
5160 DeleteObject( iconinfo.hbmMask );
5161 if( iconinfo.hbmColor != NULL )
5162 DeleteObject( iconinfo.hbmColor );
5163 if( hdcScreen != NULL )
5164 ReleaseDC( NULL, hdcScreen );
5165 if( hdcColor != NULL )
5166 DeleteDC( hdcColor );
5167 if( hdcMask != NULL )
5168 DeleteDC( hdcMask );
5169 SAFE_DELETE_ARRAY( pcrArrayColor );
5170 SAFE_DELETE_ARRAY( pcrArrayMask );
5171 SAFE_RELEASE( pCursorSurface );
5172 return hr;
5173 }
5174
5175
5176
5177