source: GTP/trunk/App/Games/Jungle_Rumble/src/common/dxut.cpp @ 1378

Revision 1378, 226.4 KB checked in by giegl, 18 years ago (diff)

GTPD - Jungle Rumble - integrate into GTP SVN structure

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