source: GTP/trunk/App/Demos/Illum/Glow/Common/DXUT.cpp @ 846

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