source: GTP-Internal/trunk/App/Demos/Illum/Ocean/Common/DXUT.cpp @ 1777

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