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

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