source: GTP/branches/IllumWPdeliver2008dec/IlluminationWP/demos/Standalone/RayTraceEffects [DirectX]/Common/DXUT.cpp @ 3255

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