source: GTP/trunk/App/Demos/Illum/StochasticIteration/Common/DXUT.cpp @ 1808

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