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