source: GTP/trunk/App/Demos/Illum/pathmap/Common/DXUT.cpp @ 2197

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