DXUT.cpp
上传用户:junlon
上传日期:2022-01-05
资源大小:39075k
文件大小:227k
源码类别:

DirextX编程

开发平台:

Visual C++

  1.     return S_OK;
  2. }
  3. //--------------------------------------------------------------------------------------
  4. // Internal helper function to return the adapter format from the first device settings 
  5. // combo that matches the passed adapter ordinal, device type, backbuffer format, and windowed.  
  6. //--------------------------------------------------------------------------------------
  7. HRESULT DXUTFindAdapterFormat( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT BackBufferFormat, 
  8.                                BOOL Windowed, D3DFORMAT* pAdapterFormat )
  9. {
  10.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  11.     CD3DEnumDeviceInfo* pDeviceInfo = pd3dEnum->GetDeviceInfo( AdapterOrdinal, DeviceType );
  12.     if( pDeviceInfo )
  13.     {
  14.         for( int iDeviceCombo=0; iDeviceCombo<pDeviceInfo->deviceSettingsComboList.GetSize(); iDeviceCombo++ )
  15.         {
  16.             CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pDeviceInfo->deviceSettingsComboList.GetAt(iDeviceCombo);
  17.             if( pDeviceSettingsCombo->BackBufferFormat == BackBufferFormat &&
  18.                 pDeviceSettingsCombo->Windowed == Windowed )
  19.             {
  20.                 // Return the adapter format from the first match
  21.                 *pAdapterFormat = pDeviceSettingsCombo->AdapterFormat;
  22.                 return S_OK;
  23.             }
  24.         }
  25.     }
  26.     *pAdapterFormat = BackBufferFormat;
  27.     return E_FAIL;
  28. }
  29. //--------------------------------------------------------------------------------------
  30. // Change to a Direct3D device created from the device settings or passed in.
  31. // The framework will only reset if the device is similar to the previous device 
  32. // otherwise it will cleanup the previous device (if there is one) and recreate the 
  33. // scene using the app's device callbacks.
  34. //--------------------------------------------------------------------------------------
  35. HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, IDirect3DDevice9* pd3dDeviceFromApp, bool bForceRecreate, bool bClipWindowToSingleAdapter )
  36. {
  37.     HRESULT hr;
  38.     DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  39.     if( DXUTGetD3DObject() == NULL )
  40.         return S_FALSE;
  41.     // Make a copy of the pNewDeviceSettings on the heap
  42.     DXUTDeviceSettings* pNewDeviceSettingsOnHeap = new DXUTDeviceSettings;
  43.     if( pNewDeviceSettingsOnHeap == NULL )
  44.         return E_OUTOFMEMORY;
  45.     memcpy( pNewDeviceSettingsOnHeap, pNewDeviceSettings, sizeof(DXUTDeviceSettings) );
  46.     pNewDeviceSettings = pNewDeviceSettingsOnHeap;
  47.     // If the ModifyDeviceSettings callback is non-NULL, then call it to let the app 
  48.     // change the settings or reject the device change by returning false.
  49.     LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = GetDXUTState().GetModifyDeviceSettingsFunc();
  50.     if( pCallbackModifyDeviceSettings )
  51.     {
  52.         D3DCAPS9 caps;
  53.         IDirect3D9* pD3D = DXUTGetD3DObject();
  54.         pD3D->GetDeviceCaps( pNewDeviceSettings->AdapterOrdinal, pNewDeviceSettings->DeviceType, &caps );
  55.         bool bContinue = pCallbackModifyDeviceSettings( pNewDeviceSettings, &caps, GetDXUTState().GetModifyDeviceSettingsFuncUserContext() );
  56.         if( !bContinue )
  57.         {
  58.             // The app rejected the device change by returning false, so just use the current device if there is one.
  59.             if( pOldDeviceSettings == NULL )
  60.                 DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES );
  61.             SAFE_DELETE( pNewDeviceSettings );
  62.             return E_ABORT;
  63.         }
  64.         if( GetDXUTState().GetD3D() == NULL )
  65.         {
  66.             SAFE_DELETE( pNewDeviceSettings );
  67.             return S_FALSE;
  68.         }
  69.     }
  70.     GetDXUTState().SetCurrentDeviceSettings( pNewDeviceSettings );
  71.     DXUTPause( true, true );
  72.     // When a WM_SIZE message is received, it calls DXUTCheckForWindowSizeChange().
  73.     // A WM_SIZE message might be sent when adjusting the window, so tell 
  74.     // DXUTCheckForWindowSizeChange() to ignore size changes temporarily
  75.     GetDXUTState().SetIgnoreSizeChange( true );
  76.     // Update thread safety on/off depending on Direct3D device's thread safety
  77.     g_bThreadSafe = ((pNewDeviceSettings->BehaviorFlags & D3DCREATE_MULTITHREADED) != 0 );
  78.     // Only apply the cmd line overrides if this is the first device created
  79.     // and DXUTSetDevice() isn't used
  80.     if( NULL == pd3dDeviceFromApp && NULL == pOldDeviceSettings )
  81.     {
  82.         // Updates the device settings struct based on the cmd line args.  
  83.         // Warning: if the device doesn't support these new settings then CreateDevice() will fail.
  84.         DXUTUpdateDeviceSettingsWithOverrides( pNewDeviceSettings );
  85.     }
  86.     // Take note if the backbuffer width & height are 0 now as they will change after pd3dDevice->Reset()
  87.     bool bKeepCurrentWindowSize = false;
  88.     if( pNewDeviceSettings->pp.BackBufferWidth == 0 && pNewDeviceSettings->pp.BackBufferHeight == 0 )
  89.         bKeepCurrentWindowSize = true;
  90.     //////////////////////////
  91.     // Before reset
  92.     /////////////////////////
  93.     if( pNewDeviceSettings->pp.Windowed )
  94.     {
  95.         // Going to windowed mode
  96.         if( pOldDeviceSettings && !pOldDeviceSettings->pp.Windowed )
  97.         {
  98.             // Going from fullscreen -> windowed
  99.             GetDXUTState().SetFullScreenBackBufferWidthAtModeChange( pOldDeviceSettings->pp.BackBufferWidth );
  100.             GetDXUTState().SetFullScreenBackBufferHeightAtModeChange( pOldDeviceSettings->pp.BackBufferHeight );
  101.             // Restore windowed mode style
  102.             SetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE, GetDXUTState().GetWindowedStyleAtModeChange() );
  103.         }
  104.         // If different device windows are used for windowed mode and fullscreen mode,
  105.         // hide the fullscreen window so that it doesn't obscure the screen.
  106.         if( DXUTGetHWNDDeviceFullScreen() != DXUTGetHWNDDeviceWindowed() )
  107.             ShowWindow( DXUTGetHWNDDeviceFullScreen(), SW_HIDE );
  108.         // If using the same window for windowed and fullscreen mode, reattach menu if one exists
  109.         if( DXUTGetHWNDDeviceFullScreen() == DXUTGetHWNDDeviceWindowed() )
  110.         {
  111.             if( GetDXUTState().GetMenu() != NULL )
  112.                 SetMenu( DXUTGetHWNDDeviceWindowed(), GetDXUTState().GetMenu() );
  113.         }
  114.     }
  115.     else 
  116.     {
  117.         // Going to fullscreen mode
  118.         if( pOldDeviceSettings == NULL || (pOldDeviceSettings && pOldDeviceSettings->pp.Windowed) )
  119.         {
  120.             // Transistioning to full screen mode from a standard window so 
  121.             // save current window position/size/style now in case the user toggles to windowed mode later 
  122.             WINDOWPLACEMENT* pwp = GetDXUTState().GetWindowedPlacement();
  123.             ZeroMemory( pwp, sizeof(WINDOWPLACEMENT) );
  124.             pwp->length = sizeof(WINDOWPLACEMENT);
  125.             GetWindowPlacement( DXUTGetHWNDDeviceWindowed(), pwp );
  126.             bool bIsTopmost = ( (GetWindowLong(DXUTGetHWNDDeviceWindowed(),GWL_EXSTYLE) & WS_EX_TOPMOST) != 0); 
  127.             GetDXUTState().SetTopmostWhileWindowed( bIsTopmost );
  128.             DWORD dwStyle = GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE );
  129.             dwStyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style
  130.             GetDXUTState().SetWindowedStyleAtModeChange( dwStyle );
  131.             if( pOldDeviceSettings )
  132.             {
  133.                 GetDXUTState().SetWindowBackBufferWidthAtModeChange( pOldDeviceSettings->pp.BackBufferWidth );
  134.                 GetDXUTState().SetWindowBackBufferHeightAtModeChange( pOldDeviceSettings->pp.BackBufferHeight );
  135.             }
  136.         }
  137.         // Hide the window to avoid animation of blank windows
  138.         ShowWindow( DXUTGetHWNDDeviceFullScreen(), SW_HIDE );
  139.         // Set FS window style
  140.         SetWindowLong( DXUTGetHWNDDeviceFullScreen(), GWL_STYLE, WS_POPUP|WS_SYSMENU );
  141.         // If using the same window for windowed and fullscreen mode, save and remove menu 
  142.         if( DXUTGetHWNDDeviceFullScreen() == DXUTGetHWNDDeviceWindowed() )
  143.         {
  144.             HMENU hMenu = GetMenu( DXUTGetHWNDDeviceFullScreen() );
  145.             GetDXUTState().SetMenu( hMenu );
  146.             SetMenu( DXUTGetHWNDDeviceFullScreen(), NULL );
  147.         }
  148.       
  149.         WINDOWPLACEMENT wpFullscreen;
  150.         ZeroMemory( &wpFullscreen, sizeof(WINDOWPLACEMENT) );
  151.         wpFullscreen.length = sizeof(WINDOWPLACEMENT);
  152.         GetWindowPlacement( DXUTGetHWNDDeviceFullScreen(), &wpFullscreen );
  153.         if( (wpFullscreen.flags & WPF_RESTORETOMAXIMIZED) != 0 )
  154.         {
  155.             // Restore the window to normal if the window was maximized then minimized.  This causes the 
  156.             // WPF_RESTORETOMAXIMIZED flag to be set which will cause SW_RESTORE to restore the 
  157.             // window from minimized to maxmized which isn't what we want
  158.             wpFullscreen.flags &= ~WPF_RESTORETOMAXIMIZED;
  159.             wpFullscreen.showCmd = SW_RESTORE;
  160.             SetWindowPlacement( DXUTGetHWNDDeviceFullScreen(), &wpFullscreen );
  161.         }
  162.     }
  163.     // If AdapterOrdinal and DeviceType are the same, we can just do a Reset().
  164.     // If they've changed, we need to do a complete device tear down/rebuild.
  165.     // Also only allow a reset if pd3dDevice is the same as the current device 
  166.     if( !bForceRecreate && 
  167.         (pd3dDeviceFromApp == NULL || pd3dDeviceFromApp == DXUTGetD3DDevice()) && 
  168.         DXUTGetD3DDevice() &&
  169.         pOldDeviceSettings &&
  170.         pOldDeviceSettings->AdapterOrdinal == pNewDeviceSettings->AdapterOrdinal &&
  171.         pOldDeviceSettings->DeviceType == pNewDeviceSettings->DeviceType &&
  172.         pOldDeviceSettings->BehaviorFlags == pNewDeviceSettings->BehaviorFlags )
  173.     {
  174.         // Reset the Direct3D device and call the app's device callbacks
  175.         hr = DXUTReset3DEnvironment();
  176.         if( FAILED(hr) )
  177.         {
  178.             if( D3DERR_DEVICELOST == hr )
  179.             {
  180.                 // The device is lost, just mark it as so and continue on with 
  181.                 // capturing the state and resizing the window/etc.
  182.                 GetDXUTState().SetDeviceLost( true );
  183.             }
  184.             else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || 
  185.                      DXUTERR_MEDIANOTFOUND == hr )
  186.             {
  187.                 // Something bad happened in the app callbacks
  188.                 SAFE_DELETE( pOldDeviceSettings );
  189.                 DXUTDisplayErrorMessage( hr );
  190.                 DXUTShutdown();
  191.                 return hr;
  192.             }
  193.             else // DXUTERR_RESETTINGDEVICE
  194.             {
  195.                 // Reset failed and the device wasn't lost and it wasn't the apps fault, 
  196.                 // so recreate the device to try to recover
  197.                 GetDXUTState().SetCurrentDeviceSettings( pOldDeviceSettings );
  198.                 if( FAILED( DXUTChangeDevice( pNewDeviceSettings, pd3dDeviceFromApp, true, bClipWindowToSingleAdapter ) ) )
  199.                 {
  200.                     // If that fails, then shutdown
  201.                     SAFE_DELETE( pOldDeviceSettings );
  202.                     DXUTShutdown();
  203.                     return DXUTERR_CREATINGDEVICE;
  204.                 }
  205.                 else
  206.                 {
  207.                     SAFE_DELETE( pOldDeviceSettings );
  208.                     return S_OK;
  209.                 }
  210.             }
  211.         }
  212.     }
  213.     else
  214.     {
  215.         // Cleanup if not first device created
  216.         if( pOldDeviceSettings )
  217.             DXUTCleanup3DEnvironment( false );
  218.         // Create the D3D device and call the app's device callbacks
  219.         hr = DXUTCreate3DEnvironment( pd3dDeviceFromApp );
  220.         if( FAILED(hr) )
  221.         {
  222.             SAFE_DELETE( pOldDeviceSettings );
  223.             DXUTCleanup3DEnvironment();
  224.             DXUTDisplayErrorMessage( hr );
  225.             DXUTPause( false, false );
  226.             GetDXUTState().SetIgnoreSizeChange( false );
  227.             return hr;
  228.         }
  229.     }
  230.     // Enable/disable StickKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut, and Windows key 
  231.     // to prevent accidental task switching
  232.     DXUTAllowShortcutKeys( ( pNewDeviceSettings->pp.Windowed  ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() : GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  233.     IDirect3D9* pD3D = DXUTGetD3DObject();
  234.     HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal );
  235.     GetDXUTState().SetAdapterMonitor( hAdapterMonitor );
  236.     // Update the device stats text
  237.     DXUTUpdateStaticFrameStats();
  238.     if( pOldDeviceSettings && !pOldDeviceSettings->pp.Windowed && pNewDeviceSettings->pp.Windowed )
  239.     {
  240.         // Going from fullscreen -> windowed
  241.         // Restore the show state, and positions/size of the window to what it was
  242.         // It is important to adjust the window size 
  243.         // after resetting the device rather than beforehand to ensure 
  244.         // that the monitor resolution is correct and does not limit the size of the new window.
  245.         WINDOWPLACEMENT* pwp = GetDXUTState().GetWindowedPlacement();
  246.         SetWindowPlacement( DXUTGetHWNDDeviceWindowed(), pwp );
  247.         // Also restore the z-order of window to previous state
  248.         HWND hWndInsertAfter = GetDXUTState().GetTopmostWhileWindowed() ? HWND_TOPMOST : HWND_NOTOPMOST;
  249.         SetWindowPos( DXUTGetHWNDDeviceWindowed(), hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE );
  250.     }
  251.     // Check to see if the window needs to be resized.  
  252.     // Handle cases where the window is minimized and maxmimized as well.
  253.     bool bNeedToResize = false;
  254.     if( pNewDeviceSettings->pp.Windowed && // only resize if in windowed mode
  255.         !bKeepCurrentWindowSize )          // only resize if pp.BackbufferWidth/Height were not 0
  256.     {
  257.         UINT nClientWidth;
  258.         UINT nClientHeight;    
  259.         if( IsIconic(DXUTGetHWNDDeviceWindowed()) )
  260.         {
  261.             // Window is currently minimized. To tell if it needs to resize, 
  262.             // get the client rect of window when its restored the 
  263.             // hard way using GetWindowPlacement()
  264.             WINDOWPLACEMENT wp;
  265.             ZeroMemory( &wp, sizeof(WINDOWPLACEMENT) );
  266.             wp.length = sizeof(WINDOWPLACEMENT);
  267.             GetWindowPlacement( DXUTGetHWNDDeviceWindowed(), &wp );
  268.             if( (wp.flags & WPF_RESTORETOMAXIMIZED) != 0 && wp.showCmd == SW_SHOWMINIMIZED )
  269.             {
  270.                 // WPF_RESTORETOMAXIMIZED means that when the window is restored it will
  271.                 // be maximized.  So maximize the window temporarily to get the client rect 
  272.                 // when the window is maximized.  GetSystemMetrics( SM_CXMAXIMIZED ) will give this 
  273.                 // information if the window is on the primary but this will work on multimon.
  274.                 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
  275.                 RECT rcClient;
  276.                 GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
  277.                 nClientWidth  = (UINT)(rcClient.right - rcClient.left);
  278.                 nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
  279.                 ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_MINIMIZE );
  280.             }
  281.             else
  282.             {
  283.                 // Use wp.rcNormalPosition to get the client rect, but wp.rcNormalPosition 
  284.                 // includes the window frame so subtract it
  285.                 RECT rcFrame = {0};
  286.                 AdjustWindowRect( &rcFrame, GetDXUTState().GetWindowedStyleAtModeChange(), GetDXUTState().GetMenu() != NULL );
  287.                 LONG nFrameWidth = rcFrame.right - rcFrame.left;
  288.                 LONG nFrameHeight = rcFrame.bottom - rcFrame.top;
  289.                 nClientWidth  = (UINT)(wp.rcNormalPosition.right - wp.rcNormalPosition.left - nFrameWidth);
  290.                 nClientHeight = (UINT)(wp.rcNormalPosition.bottom - wp.rcNormalPosition.top - nFrameHeight);
  291.             }
  292.         }
  293.         else
  294.         {
  295.             // Window is restored or maximized so just get its client rect
  296.             RECT rcClient;
  297.             GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
  298.             nClientWidth  = (UINT)(rcClient.right - rcClient.left);
  299.             nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
  300.         }
  301.         // Now that we know the client rect, compare it against the back buffer size
  302.         // to see if the client rect is already the right size
  303.         if( nClientWidth  != pNewDeviceSettings->pp.BackBufferWidth ||
  304.             nClientHeight != pNewDeviceSettings->pp.BackBufferHeight )
  305.         {
  306.             bNeedToResize = true;
  307.         }       
  308.         if( bClipWindowToSingleAdapter && !IsIconic(DXUTGetHWNDDeviceWindowed()) )
  309.         {
  310.             // Get the rect of the monitor attached to the adapter
  311.             MONITORINFO miAdapter;
  312.             miAdapter.cbSize = sizeof(MONITORINFO);
  313.             HMONITOR hAdapterMonitor = DXUTGetD3DObject()->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal );
  314.             DXUTGetMonitorInfo( hAdapterMonitor, &miAdapter );
  315.             HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
  316.             // Get the rect of the window
  317.             RECT rcWindow;
  318.             GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow );
  319.             // Check if the window rect is fully inside the adapter's vitural screen rect
  320.             if( (rcWindow.left   < miAdapter.rcWork.left  ||
  321.                  rcWindow.right  > miAdapter.rcWork.right ||
  322.                  rcWindow.top    < miAdapter.rcWork.top   ||
  323.                  rcWindow.bottom > miAdapter.rcWork.bottom) )
  324.             {
  325.                 if( hWindowMonitor == hAdapterMonitor && IsZoomed(DXUTGetHWNDDeviceWindowed()) )
  326.                 {
  327.                     // If the window is maximized and on the same monitor as the adapter, then 
  328.                     // no need to clip to single adapter as the window is already clipped 
  329.                     // even though the rcWindow rect is outside of the miAdapter.rcWork
  330.                 }
  331.                 else
  332.                 {
  333.                     bNeedToResize = true;
  334.                 }
  335.             }
  336.         }
  337.     }
  338.     // Only resize window if needed 
  339.     if( bNeedToResize ) 
  340.     {
  341.         // Need to resize, so if window is maximized or minimized then restore the window
  342.         if( IsIconic(DXUTGetHWNDDeviceWindowed()) ) 
  343.             ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
  344.         if( IsZoomed(DXUTGetHWNDDeviceWindowed()) ) // doing the IsIconic() check first also handles the WPF_RESTORETOMAXIMIZED case
  345.             ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE );
  346.         if( bClipWindowToSingleAdapter )
  347.         {
  348.             // Get the rect of the monitor attached to the adapter
  349.             MONITORINFO miAdapter;
  350.             miAdapter.cbSize = sizeof(MONITORINFO);
  351.             DXUTGetMonitorInfo( DXUTGetD3DObject()->GetAdapterMonitor( pNewDeviceSettings->AdapterOrdinal ), &miAdapter );
  352.             // Get the rect of the monitor attached to the window
  353.             MONITORINFO miWindow;
  354.             miWindow.cbSize = sizeof(MONITORINFO);
  355.             DXUTGetMonitorInfo( DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY ), &miWindow );
  356.             // Do something reasonable if the BackBuffer size is greater than the monitor size
  357.             int nAdapterMonitorWidth = miAdapter.rcWork.right - miAdapter.rcWork.left;
  358.             int nAdapterMonitorHeight = miAdapter.rcWork.bottom - miAdapter.rcWork.top;
  359.             int nClientWidth = pNewDeviceSettings->pp.BackBufferWidth;
  360.             int nClientHeight = pNewDeviceSettings->pp.BackBufferHeight;
  361.             // Get the rect of the window
  362.             RECT rcWindow;
  363.             GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow );
  364.             // Make a window rect with a client rect that is the same size as the backbuffer
  365.             RECT rcResizedWindow;
  366.             rcResizedWindow.left = 0;
  367.             rcResizedWindow.right = nClientWidth;
  368.             rcResizedWindow.top = 0;
  369.             rcResizedWindow.bottom = nClientHeight;
  370.             AdjustWindowRect( &rcResizedWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != NULL );
  371.             int nWindowWidth = rcResizedWindow.right - rcResizedWindow.left;
  372.             int nWindowHeight = rcResizedWindow.bottom - rcResizedWindow.top;
  373.             if( nWindowWidth > nAdapterMonitorWidth )
  374.                 nWindowWidth = (nAdapterMonitorWidth - 0);
  375.             if( nWindowHeight > nAdapterMonitorHeight )
  376.                 nWindowHeight = (nAdapterMonitorHeight - 0);
  377.             if( rcResizedWindow.left < miAdapter.rcWork.left ||
  378.                 rcResizedWindow.top < miAdapter.rcWork.top ||
  379.                 rcResizedWindow.right > miAdapter.rcWork.right ||
  380.                 rcResizedWindow.bottom > miAdapter.rcWork.bottom )
  381.             {
  382.                 int nWindowOffsetX = (nAdapterMonitorWidth - nWindowWidth) / 2;
  383.                 int nWindowOffsetY = (nAdapterMonitorHeight - nWindowHeight) / 2;
  384.                 rcResizedWindow.left = miAdapter.rcWork.left + nWindowOffsetX;
  385.                 rcResizedWindow.top = miAdapter.rcWork.top + nWindowOffsetY;
  386.                 rcResizedWindow.right = miAdapter.rcWork.left + nWindowOffsetX + nWindowWidth;
  387.                 rcResizedWindow.bottom = miAdapter.rcWork.top + nWindowOffsetY + nWindowHeight;
  388.             }
  389.             // Resize the window.  It is important to adjust the window size 
  390.             // after resetting the device rather than beforehand to ensure 
  391.             // that the monitor resolution is correct and does not limit the size of the new window.
  392.             SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, rcResizedWindow.left, rcResizedWindow.top, nWindowWidth, nWindowHeight, SWP_NOZORDER );
  393.         }        
  394.         else
  395.         {      
  396.             // Make a window rect with a client rect that is the same size as the backbuffer
  397.             RECT rcWindow = {0};
  398.             rcWindow.right = (long)(pNewDeviceSettings->pp.BackBufferWidth);
  399.             rcWindow.bottom = (long)(pNewDeviceSettings->pp.BackBufferHeight);
  400.             AdjustWindowRect( &rcWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != NULL );
  401.             // Resize the window.  It is important to adjust the window size 
  402.             // after resetting the device rather than beforehand to ensure 
  403.             // that the monitor resolution is correct and does not limit the size of the new window.
  404.             int cx = (int)(rcWindow.right - rcWindow.left);
  405.             int cy = (int)(rcWindow.bottom - rcWindow.top);
  406.             SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, 0, 0, cx, cy, SWP_NOZORDER|SWP_NOMOVE );
  407.         }
  408.         // Its possible that the new window size is not what we asked for.  
  409.         // No window can be sized larger than the desktop, so see see if the Windows OS resized the 
  410.         // window to something smaller to fit on the desktop.  Also if WM_GETMINMAXINFO
  411.         // will put a limit on the smallest/largest window size.
  412.         RECT rcClient;
  413.         GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient );
  414.         UINT nClientWidth  = (UINT)(rcClient.right - rcClient.left);
  415.         UINT nClientHeight = (UINT)(rcClient.bottom - rcClient.top);
  416.         if( nClientWidth  != pNewDeviceSettings->pp.BackBufferWidth ||
  417.             nClientHeight != pNewDeviceSettings->pp.BackBufferHeight )
  418.         {
  419.             // If its different, then resize the backbuffer again.  This time create a backbuffer that matches the 
  420.             // client rect of the current window w/o resizing the window.
  421.             DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  422.             deviceSettings.pp.BackBufferWidth  = 0; 
  423.             deviceSettings.pp.BackBufferHeight = 0;
  424.             hr = DXUTChangeDevice( &deviceSettings, NULL, false, bClipWindowToSingleAdapter );
  425.             if( FAILED( hr ) )
  426.             {
  427.                 SAFE_DELETE( pOldDeviceSettings );
  428.                 DXUTCleanup3DEnvironment();
  429.                 DXUTPause( false, false );
  430.                 GetDXUTState().SetIgnoreSizeChange( false );
  431.                 return hr;
  432.             }
  433.         }
  434.     }
  435.     // Make the window visible
  436.     if( !IsWindowVisible( DXUTGetHWND() ) )
  437.         ShowWindow( DXUTGetHWND(), SW_SHOW );
  438.     // Make the window visible
  439.     if( !IsWindowVisible( DXUTGetHWND() ) )
  440.         ShowWindow( DXUTGetHWND(), SW_SHOW );
  441.     // Ensure that the display doesn't power down when fullscreen but does when windowed
  442.     if( !DXUTIsWindowed() )
  443.         SetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS ); 
  444.     else
  445.         SetThreadExecutionState( ES_CONTINUOUS );   
  446.     SAFE_DELETE( pOldDeviceSettings );
  447.     GetDXUTState().SetIgnoreSizeChange( false );
  448.     DXUTPause( false, false );
  449.     GetDXUTState().SetDeviceCreated( true );
  450.     return S_OK;
  451. }
  452. //--------------------------------------------------------------------------------------
  453. // Low level keyboard hook to disable Windows key to prevent accidental task switching.  
  454. //--------------------------------------------------------------------------------------
  455. LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
  456. {
  457.     if (nCode < 0 || nCode != HC_ACTION)  // do not process message 
  458.         return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam); 
  459.     bool bEatKeystroke = false;
  460.     KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
  461.     switch (wParam) 
  462.     {
  463.         case WM_KEYDOWN:  
  464.         case WM_KEYUP:    
  465.         {
  466.             bEatKeystroke = ( !GetDXUTState().GetAllowShortcutKeys() && 
  467.                             (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) );
  468.             break;
  469.         }
  470.     }
  471.     if( bEatKeystroke )
  472.         return 1;
  473.     else
  474.         return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam );
  475. }
  476. //--------------------------------------------------------------------------------------
  477. // Controls how DXUT behaves when fullscreen and windowed mode with regard to 
  478. // shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) 
  479. //--------------------------------------------------------------------------------------
  480. void DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen, bool bAllowWhenWindowed )
  481. {
  482.     GetDXUTState().SetAllowShortcutKeysWhenWindowed( bAllowWhenWindowed );
  483.     GetDXUTState().SetAllowShortcutKeysWhenFullscreen( bAllowWhenFullscreen );
  484.     // DXUTInit() records initial accessibility states so don't change them until then
  485.     if( GetDXUTState().GetDXUTInited() )
  486.     {
  487.         if( DXUTIsWindowed() )
  488.             DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() );
  489.         else
  490.             DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  491.     }
  492. }
  493. //--------------------------------------------------------------------------------------
  494. // Enables/disables Windows keys, and disables or restores the StickyKeys/ToggleKeys/FilterKeys 
  495. // shortcut to help prevent accidental task switching
  496. //--------------------------------------------------------------------------------------
  497. void DXUTAllowShortcutKeys( bool bAllowKeys )
  498. {
  499.     GetDXUTState().SetAllowShortcutKeys( bAllowKeys );
  500.     if( bAllowKeys )
  501.     {
  502.         // Restore StickyKeys/etc to original state and enable Windows key      
  503.         STICKYKEYS sk = GetDXUTState().GetStartupStickyKeys();
  504.         TOGGLEKEYS tk = GetDXUTState().GetStartupToggleKeys();
  505.         FILTERKEYS fk = GetDXUTState().GetStartupFilterKeys();
  506.         
  507.         SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0);
  508.         SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0);
  509.         SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0);
  510.         // Remove the keyboard hoook when it isn't needed to prevent any slow down of other apps
  511.         if( GetDXUTState().GetKeyboardHook() )
  512.         {
  513.             UnhookWindowsHookEx( GetDXUTState().GetKeyboardHook() );
  514.             GetDXUTState().SetKeyboardHook( NULL );
  515.         }                
  516.     }
  517.     else
  518.     {
  519.         // Set low level keyboard hook if haven't already
  520.         if( GetDXUTState().GetKeyboardHook() == NULL )
  521.         {
  522.             // Set the low-level hook procedure.  Only works on Windows 2000 and above
  523.             OSVERSIONINFO OSVersionInfo;
  524.             OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
  525.             GetVersionEx(&OSVersionInfo);
  526.             if( OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && OSVersionInfo.dwMajorVersion > 4 )
  527.             {
  528.                 HHOOK hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
  529.                 GetDXUTState().SetKeyboardHook( hKeyboardHook );
  530.             }
  531.         }
  532.         // Disable StickyKeys/etc shortcuts but if the accessibility feature is on, 
  533.         // then leave the settings alone as its probably being usefully used
  534.         STICKYKEYS skOff = GetDXUTState().GetStartupStickyKeys();
  535.         if( (skOff.dwFlags & SKF_STICKYKEYSON) == 0 )
  536.         {
  537.             // Disable the hotkey and the confirmation
  538.             skOff.dwFlags &= ~SKF_HOTKEYACTIVE;
  539.             skOff.dwFlags &= ~SKF_CONFIRMHOTKEY;
  540.             SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &skOff, 0);
  541.         }
  542.         TOGGLEKEYS tkOff = GetDXUTState().GetStartupToggleKeys();
  543.         if( (tkOff.dwFlags & TKF_TOGGLEKEYSON) == 0 )
  544.         {
  545.             // Disable the hotkey and the confirmation
  546.             tkOff.dwFlags &= ~TKF_HOTKEYACTIVE;
  547.             tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY;
  548.             SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tkOff, 0);
  549.         }
  550.         FILTERKEYS fkOff = GetDXUTState().GetStartupFilterKeys();
  551.         if( (fkOff.dwFlags & FKF_FILTERKEYSON) == 0 )
  552.         {
  553.             // Disable the hotkey and the confirmation
  554.             fkOff.dwFlags &= ~FKF_HOTKEYACTIVE;
  555.             fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY;
  556.             SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fkOff, 0);
  557.         }
  558.     }
  559. }
  560. //--------------------------------------------------------------------------------------
  561. // Updates the device settings struct based on the cmd line args.  
  562. //--------------------------------------------------------------------------------------
  563. void DXUTUpdateDeviceSettingsWithOverrides( DXUTDeviceSettings* pDeviceSettings )
  564. {
  565.     if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 )
  566.         pDeviceSettings->AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal();
  567.     if( GetDXUTState().GetOverrideFullScreen() )
  568.         pDeviceSettings->pp.Windowed = false;
  569.     if( GetDXUTState().GetOverrideWindowed() )
  570.         pDeviceSettings->pp.Windowed = true;
  571.     if( GetDXUTState().GetOverrideForceREF() )
  572.         pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  573.     else if( GetDXUTState().GetOverrideForceHAL() )
  574.         pDeviceSettings->DeviceType = D3DDEVTYPE_HAL;
  575.     if( GetDXUTState().GetOverrideWidth() != 0 )
  576.         pDeviceSettings->pp.BackBufferWidth = GetDXUTState().GetOverrideWidth();
  577.     if( GetDXUTState().GetOverrideHeight() != 0 )
  578.         pDeviceSettings->pp.BackBufferHeight = GetDXUTState().GetOverrideHeight();
  579.     if( GetDXUTState().GetOverrideForcePureHWVP() )
  580.     {
  581.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  582.         pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  583.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  584.     }
  585.     else if( GetDXUTState().GetOverrideForceHWVP() )
  586.     {
  587.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  588.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  589.         pDeviceSettings->BehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  590.     }
  591.     else if( GetDXUTState().GetOverrideForceSWVP() )
  592.     {
  593.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  594.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  595.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  596.     }
  597. }
  598. //--------------------------------------------------------------------------------------
  599. // Creates the 3D environment
  600. //--------------------------------------------------------------------------------------
  601. HRESULT DXUTCreate3DEnvironment( IDirect3DDevice9* pd3dDeviceFromApp )
  602. {
  603.     HRESULT hr = S_OK;
  604.     IDirect3DDevice9* pd3dDevice = NULL;
  605.     DXUTDeviceSettings* pNewDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  606.     // Only create a Direct3D device if one hasn't been supplied by the app
  607.     if( pd3dDeviceFromApp == NULL )
  608.     {
  609.         // Try to create the device with the chosen settings
  610.         IDirect3D9* pD3D = DXUTGetD3DObject();
  611.         hr = pD3D->CreateDevice( pNewDeviceSettings->AdapterOrdinal, pNewDeviceSettings->DeviceType, 
  612.                                  DXUTGetHWNDFocus(), pNewDeviceSettings->BehaviorFlags,
  613.                                  &pNewDeviceSettings->pp, &pd3dDevice );
  614.         if( hr == D3DERR_DEVICELOST ) 
  615.         {
  616.             GetDXUTState().SetDeviceLost( true );
  617.             return S_OK;
  618.         }
  619.         else if( FAILED(hr) )
  620.         {
  621.             DXUT_ERR( L"CreateDevice", hr );
  622.             return DXUTERR_CREATINGDEVICE;
  623.         }
  624.     }
  625.     else
  626.     {
  627.         pd3dDeviceFromApp->AddRef();
  628.         pd3dDevice = pd3dDeviceFromApp;
  629.     }
  630.     GetDXUTState().SetD3DDevice( pd3dDevice );
  631.     // If switching to REF, set the exit code to 11.  If switching to HAL and exit code was 11, then set it back to 0.
  632.     if( pNewDeviceSettings->DeviceType == D3DDEVTYPE_REF && GetDXUTState().GetExitCode() == 0 )
  633.         GetDXUTState().SetExitCode(11);
  634.     else if( pNewDeviceSettings->DeviceType == D3DDEVTYPE_HAL && GetDXUTState().GetExitCode() == 11 )
  635.         GetDXUTState().SetExitCode(0);
  636.     // Update back buffer desc before calling app's device callbacks
  637.     DXUTUpdateBackBufferDesc();
  638.     // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
  639.     DXUTSetupCursor();
  640.     // Update GetDXUTState()'s copy of D3D caps 
  641.     D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
  642.     DXUTGetD3DDevice()->GetDeviceCaps( pd3dCaps );
  643.     // Update the device stats text
  644.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  645.     CD3DEnumAdapterInfo* pAdapterInfo = pd3dEnum->GetAdapterInfo( pNewDeviceSettings->AdapterOrdinal );
  646.     DXUTUpdateDeviceStats( pNewDeviceSettings->DeviceType, 
  647.                         pNewDeviceSettings->BehaviorFlags, 
  648.                         &pAdapterInfo->AdapterIdentifier );
  649.     // Call the resource cache created function
  650.     hr = DXUTGetGlobalResourceCache().OnCreateDevice( pd3dDevice );
  651.     if( FAILED(hr) )
  652.         return DXUT_ERR( L"OnCreateDevice", ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_CREATINGDEVICEOBJECTS );
  653.     // Call the app's device created callback if non-NULL
  654.     const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
  655.     GetDXUTState().SetInsideDeviceCallback( true );
  656.     LPDXUTCALLBACKDEVICECREATED pCallbackDeviceCreated = GetDXUTState().GetDeviceCreatedFunc();
  657.     hr = S_OK;
  658.     if( pCallbackDeviceCreated != NULL )
  659.         hr = pCallbackDeviceCreated( DXUTGetD3DDevice(), pbackBufferSurfaceDesc, GetDXUTState().GetDeviceCreatedFuncUserContext() );
  660.     GetDXUTState().SetInsideDeviceCallback( false );
  661.     if( DXUTGetD3DDevice() == NULL ) // Handle DXUTShutdown from inside callback
  662.         return E_FAIL;
  663.     if( FAILED(hr) )  
  664.     {
  665.         DXUT_ERR( L"DeviceCreated callback", hr );        
  666.         return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_CREATINGDEVICEOBJECTS;
  667.     }
  668.     GetDXUTState().SetDeviceObjectsCreated( true );
  669.     // Call the resource cache device reset function
  670.     hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
  671.     if( FAILED(hr) )
  672.         return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  673.     // Call the app's device reset callback if non-NULL
  674.     GetDXUTState().SetInsideDeviceCallback( true );
  675.     LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
  676.     hr = S_OK;
  677.     if( pCallbackDeviceReset != NULL )
  678.         hr = pCallbackDeviceReset( DXUTGetD3DDevice(), pbackBufferSurfaceDesc, GetDXUTState().GetDeviceResetFuncUserContext() );
  679.     GetDXUTState().SetInsideDeviceCallback( false );
  680.     if( DXUTGetD3DDevice() == NULL ) // Handle DXUTShutdown from inside callback
  681.         return E_FAIL;
  682.     if( FAILED(hr) )
  683.     {
  684.         DXUT_ERR( L"DeviceReset callback", hr );
  685.         return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_RESETTINGDEVICEOBJECTS;
  686.     }
  687.     GetDXUTState().SetDeviceObjectsReset( true );
  688.     return S_OK;
  689. }
  690. //--------------------------------------------------------------------------------------
  691. // Resets the 3D environment by:
  692. //      - Calls the device lost callback 
  693. //      - Resets the device
  694. //      - Stores the back buffer description
  695. //      - Sets up the full screen Direct3D cursor if requested
  696. //      - Calls the device reset callback 
  697. //--------------------------------------------------------------------------------------
  698. HRESULT DXUTReset3DEnvironment()
  699. {
  700.     HRESULT hr;
  701.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  702.     assert( pd3dDevice != NULL );
  703.     // Call the app's device lost callback
  704.     if( GetDXUTState().GetDeviceObjectsReset() == true )
  705.     {
  706.         GetDXUTState().SetInsideDeviceCallback( true );
  707.         LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  708.         if( pCallbackDeviceLost != NULL )
  709.             pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
  710.         GetDXUTState().SetDeviceObjectsReset( false );
  711.         GetDXUTState().SetInsideDeviceCallback( false );
  712.         // Call the resource cache device lost function
  713.         DXUTGetGlobalResourceCache().OnLostDevice();
  714.     }
  715.     // Reset the device
  716.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  717.     hr = pd3dDevice->Reset( &pDeviceSettings->pp );
  718.     if( FAILED(hr) )  
  719.     {
  720.         if( hr == D3DERR_DEVICELOST )
  721.             return D3DERR_DEVICELOST; // Reset could legitimately fail if the device is lost
  722.         else
  723.             return DXUT_ERR( L"Reset", DXUTERR_RESETTINGDEVICE );
  724.     }
  725.     // Update back buffer desc before calling app's device callbacks
  726.     DXUTUpdateBackBufferDesc();
  727.     // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
  728.     DXUTSetupCursor();
  729.     hr = DXUTGetGlobalResourceCache().OnResetDevice( pd3dDevice );
  730.     if( FAILED(hr) )
  731.         return DXUT_ERR( L"OnResetDevice", DXUTERR_RESETTINGDEVICEOBJECTS );
  732.     // Call the app's OnDeviceReset callback
  733.     GetDXUTState().SetInsideDeviceCallback( true );
  734.     const D3DSURFACE_DESC* pbackBufferSurfaceDesc = DXUTGetBackBufferSurfaceDesc();
  735.     LPDXUTCALLBACKDEVICERESET pCallbackDeviceReset = GetDXUTState().GetDeviceResetFunc();
  736.     hr = S_OK;
  737.     if( pCallbackDeviceReset != NULL )
  738.         hr = pCallbackDeviceReset( pd3dDevice, pbackBufferSurfaceDesc, GetDXUTState().GetDeviceResetFuncUserContext() );
  739.     GetDXUTState().SetInsideDeviceCallback( false );
  740.     if( FAILED(hr) )
  741.     {
  742.         // If callback failed, cleanup
  743.         DXUT_ERR( L"DeviceResetCallback", hr );
  744.         if( hr != DXUTERR_MEDIANOTFOUND )
  745.             hr = DXUTERR_RESETTINGDEVICEOBJECTS;
  746.         GetDXUTState().SetInsideDeviceCallback( true );
  747.         LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  748.         if( pCallbackDeviceLost != NULL )
  749.             pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
  750.         GetDXUTState().SetInsideDeviceCallback( false );
  751.         DXUTGetGlobalResourceCache().OnLostDevice();       
  752.         return hr;
  753.     }
  754.     // Success
  755.     GetDXUTState().SetDeviceObjectsReset( true );
  756.     return S_OK;
  757. }
  758. //--------------------------------------------------------------------------------------
  759. // Pauses time or rendering.  Keeps a ref count so pausing can be layered
  760. //--------------------------------------------------------------------------------------
  761. void DXUTPause( bool bPauseTime, bool bPauseRendering )
  762. {
  763.     int nPauseTimeCount = GetDXUTState().GetPauseTimeCount();
  764.     nPauseTimeCount += ( bPauseTime ? +1 : -1 );
  765.     if( nPauseTimeCount < 0 )
  766.         nPauseTimeCount = 0;
  767.     GetDXUTState().SetPauseTimeCount( nPauseTimeCount );
  768.     int nPauseRenderingCount = GetDXUTState().GetPauseRenderingCount();
  769.     nPauseRenderingCount += ( bPauseRendering ? +1 : -1 );
  770.     if( nPauseRenderingCount < 0 )
  771.         nPauseRenderingCount = 0;
  772.     GetDXUTState().SetPauseRenderingCount( nPauseRenderingCount );
  773.     if( nPauseTimeCount > 0 )
  774.     {
  775.         // Stop the scene from animating
  776.         DXUTGetGlobalTimer()->Stop();
  777.     }
  778.     else
  779.     {
  780.         // Restart the timer
  781.         DXUTGetGlobalTimer()->Start();
  782.     }
  783.     GetDXUTState().SetRenderingPaused( nPauseRenderingCount > 0 );
  784.     GetDXUTState().SetTimePaused( nPauseTimeCount > 0 );
  785. }
  786. //--------------------------------------------------------------------------------------
  787. // Checks if the window client rect has changed and if it has, then reset the device
  788. //--------------------------------------------------------------------------------------
  789. void DXUTCheckForWindowSizeChange()
  790. {
  791.     // Skip the check for various reasons
  792.     if( GetDXUTState().GetIgnoreSizeChange() || 
  793.         !GetDXUTState().GetDeviceCreated() || 
  794.         !GetDXUTState().GetCurrentDeviceSettings()->pp.Windowed )
  795.         return;
  796.     RECT rcCurrentClient;
  797.     GetClientRect( DXUTGetHWND(), &rcCurrentClient );
  798.     
  799.     if( (UINT)rcCurrentClient.right != GetDXUTState().GetCurrentDeviceSettings()->pp.BackBufferWidth ||
  800.         (UINT)rcCurrentClient.bottom != GetDXUTState().GetCurrentDeviceSettings()->pp.BackBufferHeight )
  801.     {
  802.         // A new window size will require a new backbuffer size
  803.         // size, so the device must be reset and the D3D structures updated accordingly.
  804.         // Tell DXUTChangeDevice and D3D to size according to the HWND's client rect
  805.         DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  806.         deviceSettings.pp.BackBufferWidth  = 0; 
  807.         deviceSettings.pp.BackBufferHeight = 0;
  808.         DXUTChangeDevice( &deviceSettings, NULL, false, false );
  809.     }
  810. }
  811. //--------------------------------------------------------------------------------------
  812. // Handles app's message loop and rendering when idle.  If DXUTCreateDevice*() or DXUTSetDevice() 
  813. // has not already been called, it will call DXUTCreateWindow() with the default parameters.  
  814. //--------------------------------------------------------------------------------------
  815. HRESULT DXUTMainLoop( HACCEL hAccel )
  816. {
  817.     HRESULT hr;
  818.     // Not allowed to call this from inside the device callbacks or reenter
  819.     if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() )
  820.     {
  821.         if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
  822.             GetDXUTState().SetExitCode(1);
  823.         return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
  824.     }
  825.     GetDXUTState().SetInsideMainloop( true );
  826.     // If DXUTCreateDevice*() or DXUTSetDevice() has not already been called, 
  827.     // then call DXUTCreateDevice() with the default parameters.         
  828.     if( !GetDXUTState().GetDeviceCreated() ) 
  829.     {
  830.         if( GetDXUTState().GetDeviceCreateCalled() )
  831.         {
  832.             if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
  833.                 GetDXUTState().SetExitCode(1);
  834.             return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed
  835.         }
  836.         hr = DXUTCreateDevice();
  837.         if( FAILED(hr) )
  838.         {
  839.             if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
  840.                 GetDXUTState().SetExitCode(1);
  841.             return hr;
  842.         }
  843.     }
  844.     HWND hWnd = DXUTGetHWND();
  845.     // DXUTInit() must have been called and succeeded for this function to proceed
  846.     // DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed
  847.     // DXUTCreateDevice() or DXUTCreateDeviceFromSettings() or DXUTSetDevice() must have been called and succeeded for this function to proceed
  848.     if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() )
  849.     {
  850.         if( (GetDXUTState().GetExitCode() == 0) || (GetDXUTState().GetExitCode() == 11) )
  851.             GetDXUTState().SetExitCode(1);
  852.         return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL );
  853.     }
  854.     // Now we're ready to receive and process Windows messages.
  855.     bool bGotMsg;
  856.     MSG  msg;
  857.     msg.message = WM_NULL;
  858.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  859.     while( WM_QUIT != msg.message  )
  860.     {
  861.         // Use PeekMessage() so we can use idle time to render the scene. 
  862.         bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
  863.         if( bGotMsg )
  864.         {
  865.             // Translate and dispatch the message
  866.             if( hAccel == NULL || hWnd == NULL || 
  867.                 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
  868.             {
  869.                 TranslateMessage( &msg );
  870.                 DispatchMessage( &msg );
  871.             }
  872.         }
  873.         else
  874.         {
  875.             // Render a frame during idle time (no messages are waiting)
  876.             DXUTRender3DEnvironment();
  877.         }
  878.     }
  879.     // Cleanup the accelerator table
  880.     if( hAccel != NULL )
  881.         DestroyAcceleratorTable( hAccel );
  882.     GetDXUTState().SetInsideMainloop( false );
  883.     return S_OK;
  884. }
  885. //--------------------------------------------------------------------------------------
  886. // Render the 3D environment by:
  887. //      - Checking if the device is lost and trying to reset it if it is
  888. //      - Get the elapsed time since the last frame
  889. //      - Calling the app's framemove and render callback
  890. //      - Calling Present()
  891. //--------------------------------------------------------------------------------------
  892. void DXUTRender3DEnvironment()
  893. {
  894.     HRESULT hr;
  895.    
  896.     if( GetDXUTState().GetDeviceLost() || DXUTIsRenderingPaused() || !DXUTIsActive() )
  897.     {
  898.         // Window is minimized or paused so yield CPU time to other processes
  899.         Sleep( 50 ); 
  900.     }
  901.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  902.     if( NULL == pd3dDevice )
  903.     {
  904.         if( GetDXUTState().GetDeviceLost() )
  905.         {
  906.             DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  907.             DXUTChangeDevice( &deviceSettings, NULL, false, true );
  908.         }
  909.         return;
  910.     }
  911.  
  912.     if( GetDXUTState().GetDeviceLost() && !GetDXUTState().GetRenderingPaused() )
  913.     {
  914.         // Test the cooperative level to see if it's okay to render
  915.         if( FAILED( hr = pd3dDevice->TestCooperativeLevel() ) )
  916.         {
  917.             if( D3DERR_DEVICELOST == hr )
  918.             {
  919.                 // The device has been lost but cannot be reset at this time.  
  920.                 // So wait until it can be reset.
  921.                 return;
  922.             }
  923.             // If we are windowed, read the desktop format and 
  924.             // ensure that the Direct3D device is using the same format 
  925.             // since the user could have changed the desktop bitdepth 
  926.             if( DXUTIsWindowed() )
  927.             {
  928.                 D3DDISPLAYMODE adapterDesktopDisplayMode;
  929.                 IDirect3D9* pD3D = DXUTGetD3DObject();
  930.                 DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  931.                 pD3D->GetAdapterDisplayMode( pDeviceSettings->AdapterOrdinal, &adapterDesktopDisplayMode );
  932.                 if( pDeviceSettings->AdapterFormat != adapterDesktopDisplayMode.Format )
  933.                 {
  934.                     DXUTMatchOptions matchOptions;
  935.                     matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  936.                     matchOptions.eDeviceType         = DXUTMT_PRESERVE_INPUT;
  937.                     matchOptions.eWindowed           = DXUTMT_PRESERVE_INPUT;
  938.                     matchOptions.eAdapterFormat      = DXUTMT_PRESERVE_INPUT;
  939.                     matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  940.                     matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  941.                     matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  942.                     matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  943.                     matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  944.                     matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  945.                     matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  946.                     matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  947.                     matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  948.                     matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  949.                     matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  950.                     DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  951.                     deviceSettings.AdapterFormat = adapterDesktopDisplayMode.Format;
  952.                     hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  953.                     if( FAILED(hr) ) // the call will fail if no valid devices were found
  954.                     {
  955.                         DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES );
  956.                         DXUTShutdown();
  957.                     }
  958.                     // Change to a Direct3D device created from the new device settings.  
  959.                     // If there is an existing device, then either reset or recreate the scene
  960.                     hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
  961.                     if( FAILED(hr) )  
  962.                     {
  963.                         // If this fails, try to go fullscreen and if this fails also shutdown.
  964.                         if( FAILED(DXUTToggleFullScreen()) )
  965.                             DXUTShutdown();
  966.                     }
  967.                     return;
  968.                 }
  969.             }
  970.             // Try to reset the device
  971.             if( FAILED( hr = DXUTReset3DEnvironment() ) )
  972.             {
  973.                 if( D3DERR_DEVICELOST == hr )
  974.                 {
  975.                     // The device was lost again, so continue waiting until it can be reset.
  976.                     return;
  977.                 }
  978.                 else if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || 
  979.                          DXUTERR_MEDIANOTFOUND == hr )
  980.                 {
  981.                     DXUTDisplayErrorMessage( hr );
  982.                     DXUTShutdown();
  983.                     return;
  984.                 }
  985.                 else
  986.                 {
  987.                     // Reset failed, but the device wasn't lost so something bad happened, 
  988.                     // so recreate the device to try to recover
  989.                     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  990.                     if( FAILED( DXUTChangeDevice( pDeviceSettings, NULL, true, false ) ) )
  991.                     {
  992.                         DXUTShutdown();
  993.                         return;
  994.                     }
  995.                 }
  996.             }
  997.         }
  998.         GetDXUTState().SetDeviceLost( false );
  999.     }
  1000.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  1001.     double fTime, fAbsTime; float fElapsedTime;
  1002.     DXUTGetGlobalTimer()->GetTimeValues( &fTime, &fAbsTime, &fElapsedTime );
  1003.     // Store the time for the app
  1004.     if( GetDXUTState().GetConstantFrameTime() )
  1005.     {        
  1006.         fElapsedTime = GetDXUTState().GetTimePerFrame();
  1007.         fTime     = DXUTGetTime() + fElapsedTime;
  1008.     }
  1009.     GetDXUTState().SetTime( fTime );
  1010.     GetDXUTState().SetAbsoluteTime( fAbsTime );
  1011.     GetDXUTState().SetElapsedTime( fElapsedTime );
  1012.     // Update the FPS stats
  1013.     DXUTUpdateFrameStats();
  1014.     DXUTHandleTimers();
  1015.     // Animate the scene by calling the app's frame move callback
  1016.     LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove = GetDXUTState().GetFrameMoveFunc();
  1017.     if( pCallbackFrameMove != NULL )
  1018.     {
  1019.         pCallbackFrameMove( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameMoveFuncUserContext() );
  1020.         pd3dDevice = DXUTGetD3DDevice();
  1021.         if( NULL == pd3dDevice ) // Handle DXUTShutdown from inside callback
  1022.             return;
  1023.     }
  1024.     if( !GetDXUTState().GetRenderingPaused() )
  1025.     {
  1026.         // Render the scene by calling the app's render callback
  1027.         LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
  1028.         if( pCallbackFrameRender != NULL )
  1029.         {
  1030.             pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameRenderFuncUserContext() );
  1031.             pd3dDevice = DXUTGetD3DDevice();
  1032.             if( NULL == pd3dDevice ) // Handle DXUTShutdown from inside callback
  1033.                 return;
  1034.         }
  1035. #if defined(DEBUG) || defined(_DEBUG)
  1036.         // The back buffer should always match the client rect 
  1037.         // if the Direct3D backbuffer covers the entire window
  1038.         RECT rcClient;
  1039.         GetClientRect( DXUTGetHWND(), &rcClient );
  1040.         if( !IsIconic( DXUTGetHWND() ) )
  1041.         {
  1042.             GetClientRect( DXUTGetHWND(), &rcClient );
  1043.             assert( DXUTGetBackBufferSurfaceDesc()->Width == (UINT)rcClient.right );
  1044.             assert( DXUTGetBackBufferSurfaceDesc()->Height == (UINT)rcClient.bottom );
  1045.         }        
  1046. #endif
  1047.         // Show the frame on the primary surface.
  1048.         hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1049.         if( FAILED(hr) )
  1050.         {
  1051.             if( D3DERR_DEVICELOST == hr )
  1052.             {
  1053.                 GetDXUTState().SetDeviceLost( true );
  1054.             }
  1055.             else if( D3DERR_DRIVERINTERNALERROR == hr )
  1056.             {
  1057.                 // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
  1058.                 // the application can do one of the following:
  1059.                 // 
  1060.                 // - End, with the pop-up window saying that the application cannot continue 
  1061.                 //   because of problems in the display adapter and that the user should 
  1062.                 //   contact the adapter manufacturer.
  1063.                 //
  1064.                 // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same 
  1065.                 //   path as recovering from a lost device. If IDirect3DDevice9::Reset fails with 
  1066.                 //   D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message 
  1067.                 //   that the user should contact the adapter manufacturer.
  1068.                 // 
  1069.                 // The framework attempts the path of resetting the device
  1070.                 // 
  1071.                 GetDXUTState().SetDeviceLost( true );
  1072.             }
  1073.         }
  1074.     }
  1075.     // Update current frame #
  1076.     int nFrame = GetDXUTState().GetCurrentFrameNumber();
  1077.     nFrame++;
  1078.     GetDXUTState().SetCurrentFrameNumber( nFrame );
  1079.     // Check to see if the app should shutdown due to cmdline
  1080.     if( GetDXUTState().GetOverrideQuitAfterFrame() != 0 )
  1081.     {
  1082.         if( nFrame > GetDXUTState().GetOverrideQuitAfterFrame() )
  1083.             DXUTShutdown();
  1084.     }
  1085.     return;
  1086. }
  1087. //--------------------------------------------------------------------------------------
  1088. // Updates the string which describes the device 
  1089. //--------------------------------------------------------------------------------------
  1090. void DXUTUpdateDeviceStats( D3DDEVTYPE DeviceType, DWORD BehaviorFlags, D3DADAPTER_IDENTIFIER9* pAdapterIdentifier )
  1091. {
  1092.     if( GetDXUTState().GetNoStats() )
  1093.         return;
  1094.     // Store device description
  1095.     WCHAR* pstrDeviceStats = GetDXUTState().GetDeviceStats();
  1096.     if( DeviceType == D3DDEVTYPE_REF )
  1097.         StringCchCopy( pstrDeviceStats, 256, L"REF" );
  1098.     else if( DeviceType == D3DDEVTYPE_HAL )
  1099.         StringCchCopy( pstrDeviceStats, 256, L"HAL" );
  1100.     else if( DeviceType == D3DDEVTYPE_SW )
  1101.         StringCchCopy( pstrDeviceStats, 256, L"SW" );
  1102.     if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  1103.         BehaviorFlags & D3DCREATE_PUREDEVICE )
  1104.     {
  1105.         if( DeviceType == D3DDEVTYPE_HAL )
  1106.             StringCchCat( pstrDeviceStats, 256, L" (pure hw vp)" );
  1107.         else
  1108.             StringCchCat( pstrDeviceStats, 256, L" (simulated pure hw vp)" );
  1109.     }
  1110.     else if( BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  1111.     {
  1112.         if( DeviceType == D3DDEVTYPE_HAL )
  1113.             StringCchCat( pstrDeviceStats, 256, L" (hw vp)" );
  1114.         else
  1115.             StringCchCat( pstrDeviceStats, 256, L" (simulated hw vp)" );
  1116.     }
  1117.     else if( BehaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
  1118.     {
  1119.         if( DeviceType == D3DDEVTYPE_HAL )
  1120.             StringCchCat( pstrDeviceStats, 256, L" (mixed vp)" );
  1121.         else
  1122.             StringCchCat( pstrDeviceStats, 256, L" (simulated mixed vp)" );
  1123.     }
  1124.     else if( BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  1125.     {
  1126.         StringCchCat( pstrDeviceStats, 256, L" (sw vp)" );
  1127.     }
  1128.     if( DeviceType == D3DDEVTYPE_HAL )
  1129.     {
  1130.         // Be sure not to overflow m_strDeviceStats when appending the adapter 
  1131.         // description, since it can be long.  
  1132.         StringCchCat( pstrDeviceStats, 256, L": " );
  1133.         // Try to get a unique description from the CD3DEnumDeviceSettingsCombo
  1134.         DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  1135.         CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  1136.         CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, pDeviceSettings->AdapterFormat, pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed );
  1137.         if( pDeviceSettingsCombo )
  1138.         {
  1139.             StringCchCat( pstrDeviceStats, 256, pDeviceSettingsCombo->pAdapterInfo->szUniqueDescription );
  1140.         }
  1141.         else
  1142.         {
  1143.             const int cchDesc = sizeof(pAdapterIdentifier->Description);
  1144.             WCHAR szDescription[cchDesc];
  1145.             MultiByteToWideChar( CP_ACP, 0, pAdapterIdentifier->Description, -1, szDescription, cchDesc );
  1146.             szDescription[cchDesc-1] = 0;
  1147.             StringCchCat( pstrDeviceStats, 256, szDescription );
  1148.         }
  1149.     }
  1150. }
  1151. //--------------------------------------------------------------------------------------
  1152. // Updates the frames/sec stat once per second
  1153. //--------------------------------------------------------------------------------------
  1154. void DXUTUpdateFrameStats()
  1155. {
  1156.     if( GetDXUTState().GetNoStats() )
  1157.         return;
  1158.     // Keep track of the frame count
  1159.     double fLastTime = GetDXUTState().GetLastStatsUpdateTime();
  1160.     DWORD dwFrames  = GetDXUTState().GetLastStatsUpdateFrames();
  1161.     double fAbsTime = GetDXUTState().GetAbsoluteTime();
  1162.     dwFrames++;
  1163.     GetDXUTState().SetLastStatsUpdateFrames( dwFrames );
  1164.     // Update the scene stats once per second
  1165.     if( fAbsTime - fLastTime > 1.0f )
  1166.     {
  1167.         float fFPS = (float) (dwFrames / (fAbsTime - fLastTime));
  1168.         GetDXUTState().SetFPS( fFPS );
  1169.         GetDXUTState().SetLastStatsUpdateTime( fAbsTime );
  1170.         GetDXUTState().SetLastStatsUpdateFrames( 0 );
  1171.         WCHAR* pstrFPS = GetDXUTState().GetFPSStats();
  1172.         StringCchPrintf( pstrFPS, 64, L"%0.2f fps ", fFPS );
  1173.     }
  1174. }
  1175. //--------------------------------------------------------------------------------------
  1176. // Updates the static part of the frame stats so it doesn't have be generated every frame
  1177. //--------------------------------------------------------------------------------------
  1178. void DXUTUpdateStaticFrameStats()
  1179. {
  1180.     if( GetDXUTState().GetNoStats() )
  1181.         return;
  1182.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  1183.     if( NULL == pDeviceSettings )
  1184.         return;
  1185.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  1186.     if( NULL == pd3dEnum )
  1187.         return;
  1188.     CD3DEnumDeviceSettingsCombo* pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->AdapterOrdinal, pDeviceSettings->DeviceType, pDeviceSettings->AdapterFormat, pDeviceSettings->pp.BackBufferFormat, pDeviceSettings->pp.Windowed );
  1189.     if( NULL == pDeviceSettingsCombo )
  1190.         return;
  1191.     WCHAR strFmt[100];
  1192.     D3DPRESENT_PARAMETERS* pPP = &pDeviceSettings->pp;
  1193.     if( pDeviceSettingsCombo->AdapterFormat == pDeviceSettingsCombo->BackBufferFormat )
  1194.     {
  1195.         StringCchCopy( strFmt, 100, DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ) );
  1196.     }
  1197.     else
  1198.     {
  1199.         StringCchPrintf( strFmt, 100, L"backbuf %s, adapter %s", 
  1200.             DXUTD3DFormatToString( pDeviceSettingsCombo->BackBufferFormat, false ), 
  1201.             DXUTD3DFormatToString( pDeviceSettingsCombo->AdapterFormat, false ) );
  1202.     }
  1203.     WCHAR strDepthFmt[100];
  1204.     if( pPP->EnableAutoDepthStencil )
  1205.     {
  1206.         StringCchPrintf( strDepthFmt, 100, L" (%s)", DXUTD3DFormatToString( pPP->AutoDepthStencilFormat, false ) );
  1207.     }
  1208.     else
  1209.     {
  1210.         // No depth buffer
  1211.         strDepthFmt[0] = 0;
  1212.     }
  1213.     WCHAR strMultiSample[100];
  1214.     switch( pPP->MultiSampleType )
  1215.     {
  1216.         case D3DMULTISAMPLE_NONMASKABLE: StringCchCopy( strMultiSample, 100, L" (Nonmaskable Multisample)" ); break;
  1217.         case D3DMULTISAMPLE_NONE:        StringCchCopy( strMultiSample, 100, L"" ); break;
  1218.         default:                         StringCchPrintf( strMultiSample, 100, L" (%dx Multisample)", pPP->MultiSampleType ); break;
  1219.     }
  1220.     WCHAR* pstrStaticFrameStats = GetDXUTState().GetStaticFrameStats();
  1221.     StringCchPrintf( pstrStaticFrameStats, 256, L"%%sVsync %s (%dx%d), %s%s%s", 
  1222.                 ( pPP->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE ) ? L"off" : L"on", 
  1223.                 pPP->BackBufferWidth, pPP->BackBufferHeight,
  1224.                 strFmt, strDepthFmt, strMultiSample );
  1225. }
  1226. //--------------------------------------------------------------------------------------
  1227. LPCWSTR DXUTGetFrameStats( bool bShowFPS )                         
  1228.     WCHAR* pstrFrameStats = GetDXUTState().GetFrameStats();
  1229.     WCHAR* pstrFPS = ( bShowFPS ) ? GetDXUTState().GetFPSStats() : L"";
  1230.     StringCchPrintf( pstrFrameStats, 256, GetDXUTState().GetStaticFrameStats(), pstrFPS );
  1231.     return pstrFrameStats;
  1232. }
  1233. //--------------------------------------------------------------------------------------
  1234. // Handles window messages 
  1235. //--------------------------------------------------------------------------------------
  1236. LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1237. {
  1238.     // Consolidate the keyboard messages and pass them to the app's keyboard callback
  1239.     if( uMsg == WM_KEYDOWN ||
  1240.         uMsg == WM_SYSKEYDOWN || 
  1241.         uMsg == WM_KEYUP ||
  1242.         uMsg == WM_SYSKEYUP )
  1243.     {
  1244.         bool bKeyDown = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
  1245.         DWORD dwMask = (1 << 29);
  1246.         bool bAltDown = ( (lParam & dwMask) != 0 );
  1247.         bool* bKeys = GetDXUTState().GetKeys();
  1248.         bKeys[ (BYTE) (wParam & 0xFF) ] = bKeyDown;
  1249.         LPDXUTCALLBACKKEYBOARD pCallbackKeyboard = GetDXUTState().GetKeyboardFunc();
  1250.         if( pCallbackKeyboard )
  1251.             pCallbackKeyboard( (UINT)wParam, bKeyDown, bAltDown, GetDXUTState().GetKeyboardFuncUserContext() );           
  1252.     }
  1253.     // Consolidate the mouse button messages and pass them to the app's mouse callback
  1254.     if( uMsg == WM_LBUTTONDOWN ||
  1255.         uMsg == WM_LBUTTONUP ||
  1256.         uMsg == WM_LBUTTONDBLCLK ||
  1257.         uMsg == WM_MBUTTONDOWN ||
  1258.         uMsg == WM_MBUTTONUP ||
  1259.         uMsg == WM_MBUTTONDBLCLK ||
  1260.         uMsg == WM_RBUTTONDOWN ||
  1261.         uMsg == WM_RBUTTONUP ||
  1262.         uMsg == WM_RBUTTONDBLCLK ||
  1263.         uMsg == WM_XBUTTONDOWN ||
  1264.         uMsg == WM_XBUTTONUP ||
  1265.         uMsg == WM_XBUTTONDBLCLK ||
  1266.         uMsg == WM_MOUSEWHEEL || 
  1267.         (GetDXUTState().GetNotifyOnMouseMove() && uMsg == WM_MOUSEMOVE) )
  1268.     {
  1269.         int xPos = (short)LOWORD(lParam);
  1270.         int yPos = (short)HIWORD(lParam);
  1271.         if( uMsg == WM_MOUSEWHEEL )
  1272.         {
  1273.             // WM_MOUSEWHEEL passes screen mouse coords
  1274.             // so convert them to client coords
  1275.             POINT pt;
  1276.             pt.x = xPos; pt.y = yPos;
  1277.             ScreenToClient( hWnd, &pt );
  1278.             xPos = pt.x; yPos = pt.y;
  1279.         }
  1280.         int nMouseWheelDelta = 0;
  1281.         if( uMsg == WM_MOUSEWHEEL ) 
  1282.             nMouseWheelDelta = (short) HIWORD(wParam);
  1283.         int nMouseButtonState = LOWORD(wParam);
  1284.         bool bLeftButton  = ((nMouseButtonState & MK_LBUTTON) != 0);
  1285.         bool bRightButton = ((nMouseButtonState & MK_RBUTTON) != 0);
  1286.         bool bMiddleButton = ((nMouseButtonState & MK_MBUTTON) != 0);
  1287.         bool bSideButton1 = ((nMouseButtonState & MK_XBUTTON1) != 0);
  1288.         bool bSideButton2 = ((nMouseButtonState & MK_XBUTTON2) != 0);
  1289.         bool* bMouseButtons = GetDXUTState().GetMouseButtons();
  1290.         bMouseButtons[0] = bLeftButton;
  1291.         bMouseButtons[1] = bMiddleButton;
  1292.         bMouseButtons[2] = bRightButton;
  1293.         bMouseButtons[3] = bSideButton1;
  1294.         bMouseButtons[4] = bSideButton2;
  1295.         LPDXUTCALLBACKMOUSE pCallbackMouse = GetDXUTState().GetMouseFunc();
  1296.         if( pCallbackMouse )
  1297.             pCallbackMouse( bLeftButton, bRightButton, bMiddleButton, bSideButton1, bSideButton2, nMouseWheelDelta, xPos, yPos, GetDXUTState().GetMouseFuncUserContext() );
  1298.     }
  1299.     // Pass all messages to the app's MsgProc callback, and don't 
  1300.     // process further messages if the apps says not to.
  1301.     LPDXUTCALLBACKMSGPROC pCallbackMsgProc = GetDXUTState().GetWindowMsgFunc();
  1302.     if( pCallbackMsgProc )
  1303.     {
  1304.         bool bNoFurtherProcessing = false;
  1305.         LRESULT nResult = pCallbackMsgProc( hWnd, uMsg, wParam, lParam, &bNoFurtherProcessing, GetDXUTState().GetWindowMsgFuncUserContext() );
  1306.         if( bNoFurtherProcessing )
  1307.             return nResult;
  1308.     }
  1309.     switch( uMsg )
  1310.     {
  1311.         case WM_PAINT:
  1312.         {
  1313.             IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1314.             // Handle paint messages when the app is paused
  1315.             if( pd3dDevice && DXUTIsRenderingPaused() && 
  1316.                 GetDXUTState().GetDeviceObjectsCreated() && GetDXUTState().GetDeviceObjectsReset() )
  1317.             {
  1318.                 HRESULT hr;
  1319.                 double fTime = DXUTGetTime();
  1320.                 float fElapsedTime = DXUTGetElapsedTime();
  1321.                 LPDXUTCALLBACKFRAMERENDER pCallbackFrameRender = GetDXUTState().GetFrameRenderFunc();
  1322.                 if( pCallbackFrameRender != NULL )
  1323.                     pCallbackFrameRender( pd3dDevice, fTime, fElapsedTime, GetDXUTState().GetFrameRenderFuncUserContext() );
  1324.                 hr = pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1325.                 if( D3DERR_DEVICELOST == hr )
  1326.                 {
  1327.                     GetDXUTState().SetDeviceLost( true );
  1328.                 }
  1329.                 else if( D3DERR_DRIVERINTERNALERROR == hr )
  1330.                 {
  1331.                     // When D3DERR_DRIVERINTERNALERROR is returned from Present(),
  1332.                     // the application can do one of the following:
  1333.                     // 
  1334.                     // - End, with the pop-up window saying that the application cannot continue 
  1335.                     //   because of problems in the display adapter and that the user should 
  1336.                     //   contact the adapter manufacturer.
  1337.                     //
  1338.                     // - Attempt to restart by calling IDirect3DDevice9::Reset, which is essentially the same 
  1339.                     //   path as recovering from a lost device. If IDirect3DDevice9::Reset fails with 
  1340.                     //   D3DERR_DRIVERINTERNALERROR, the application should end immediately with the message 
  1341.                     //   that the user should contact the adapter manufacturer.
  1342.                     // 
  1343.                     // The framework attempts the path of resetting the device
  1344.                     // 
  1345.                     GetDXUTState().SetDeviceLost( true );
  1346.                 }
  1347.             }
  1348.             break;
  1349.         }
  1350.         case WM_SIZE:
  1351.             if( SIZE_MINIMIZED == wParam )
  1352.             {
  1353.                 DXUTPause( true, true ); // Pause while we're minimized
  1354.                 GetDXUTState().SetMinimized( true );
  1355.                 GetDXUTState().SetMaximized( false );
  1356.             }
  1357.             else
  1358.             {
  1359.                 RECT rcCurrentClient;
  1360.                 GetClientRect( DXUTGetHWND(), &rcCurrentClient );
  1361.                 if( rcCurrentClient.top == 0 && rcCurrentClient.bottom == 0 )
  1362.                 {
  1363.                     // Rapidly clicking the task bar to minimize and restore a window
  1364.                     // can cause a WM_SIZE message with SIZE_RESTORED when 
  1365.                     // the window has actually become minimized due to rapid change
  1366.                     // so just ignore this message
  1367.                 }
  1368.                 else if( SIZE_MAXIMIZED == wParam )
  1369.                 {
  1370.                     if( GetDXUTState().GetMinimized() )
  1371.                         DXUTPause( false, false ); // Unpause since we're no longer minimized
  1372.                     GetDXUTState().SetMinimized( false );
  1373.                     GetDXUTState().SetMaximized( true );
  1374.                     DXUTCheckForWindowSizeChange();
  1375.                     DXUTCheckForWindowChangingMonitors();
  1376.                 }
  1377.                 else if( SIZE_RESTORED == wParam )
  1378.                 {      
  1379.                     if( GetDXUTState().GetMaximized() )
  1380.                     {
  1381.                         GetDXUTState().SetMaximized( false );
  1382.                         DXUTCheckForWindowSizeChange();
  1383.                         DXUTCheckForWindowChangingMonitors();
  1384.                     }
  1385.                     else if( GetDXUTState().GetMinimized() )
  1386.                     {
  1387.                         DXUTPause( false, false ); // Unpause since we're no longer minimized
  1388.                         GetDXUTState().SetMinimized( false );
  1389.                         DXUTCheckForWindowSizeChange();
  1390.                         DXUTCheckForWindowChangingMonitors();
  1391.                     }
  1392.                     else if( GetDXUTState().GetInSizeMove() )
  1393.                     {
  1394.                         // If we're neither maximized nor minimized, the window size 
  1395.                         // is changing by the user dragging the window edges.  In this 
  1396.                         // case, we don't reset the device yet -- we wait until the 
  1397.                         // user stops dragging, and a WM_EXITSIZEMOVE message comes.
  1398.                     }
  1399.                     else
  1400.                     {
  1401.                         // This WM_SIZE come from resizing the window via an API like SetWindowPos() so 
  1402.                         // resize and reset the device now.
  1403.                         DXUTCheckForWindowSizeChange();
  1404.                         DXUTCheckForWindowChangingMonitors();
  1405.                     }
  1406.                 }
  1407.             }
  1408.             break;
  1409.         case WM_GETMINMAXINFO:
  1410.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = DXUT_MIN_WINDOW_SIZE_X;
  1411.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = DXUT_MIN_WINDOW_SIZE_Y;
  1412.             break;
  1413.         case WM_ENTERSIZEMOVE:
  1414.             // Halt frame movement while the app is sizing or moving
  1415.             DXUTPause( true, true );
  1416.             GetDXUTState().SetInSizeMove( true );
  1417.             break;
  1418.         case WM_EXITSIZEMOVE:
  1419.             DXUTPause( false, false );
  1420.             DXUTCheckForWindowSizeChange();
  1421.             DXUTCheckForWindowChangingMonitors();
  1422.             GetDXUTState().SetInSizeMove( false );
  1423.             break;
  1424.          case WM_MOUSEMOVE:
  1425.             if( DXUTIsActive() && !DXUTIsWindowed() )
  1426.             {
  1427.                 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1428.                 if( pd3dDevice )
  1429.                 {
  1430.                     POINT ptCursor;
  1431.                     GetCursorPos( &ptCursor );
  1432.                     pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
  1433.                 }
  1434.             }
  1435.             break;
  1436.         case WM_SETCURSOR:
  1437.             if( DXUTIsActive() && !DXUTIsWindowed() )
  1438.             {
  1439.                 IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1440.                 if( pd3dDevice && GetDXUTState().GetShowCursorWhenFullScreen() )
  1441.                     pd3dDevice->ShowCursor( true );
  1442.                 return true; // prevent Windows from setting cursor to window class cursor
  1443.             }
  1444.             break;
  1445.        case WM_ACTIVATEAPP:
  1446.             if( wParam == TRUE && !DXUTIsActive() ) // Handle only if previously not active 
  1447.             {
  1448.                 GetDXUTState().SetActive( true );
  1449.                 // The GetMinimizedWhileFullscreen() varible is used instead of !DXUTIsWindowed()
  1450.                 // to handle the rare case toggling to windowed mode while the fullscreen application 
  1451.                 // is minimized and thus making the pause count wrong
  1452.                 if( GetDXUTState().GetMinimizedWhileFullscreen() ) 
  1453.                 {
  1454.                     DXUTPause( false, false ); // Unpause since we're no longer minimized
  1455.                     GetDXUTState().SetMinimizedWhileFullscreen( false );
  1456.                 }
  1457.                 // Upon returning to this app, potentially disable shortcut keys 
  1458.                 // (Windows key, accessibility shortcuts) 
  1459.                 DXUTAllowShortcutKeys( ( DXUTIsWindowed() ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() : 
  1460.                                                               GetDXUTState().GetAllowShortcutKeysWhenFullscreen() );
  1461.             }
  1462.             else if( wParam == FALSE && DXUTIsActive() ) // Handle only if previously active 
  1463.             {               
  1464.                 GetDXUTState().SetActive( false );
  1465.                 // Disable any controller rumble when de-activating app
  1466.                 DXUTStopRumbleOnAllControllers();
  1467.                 if( !DXUTIsWindowed() )
  1468.                 {
  1469.                     // Going from full screen to a minimized state 
  1470.                     ClipCursor( NULL );      // don't limit the cursor anymore
  1471.                     DXUTPause( true, true ); // Pause while we're minimized (take care not to pause twice by handling this message twice)
  1472.                     GetDXUTState().SetMinimizedWhileFullscreen( true ); 
  1473.                 }
  1474.                 // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
  1475.                 //
  1476.                 // This is important to call here if the shortcuts are disabled, 
  1477.                 // because if this is not done then the Windows key will continue to 
  1478.                 // be disabled while this app is running which is very bad.
  1479.                 // If the app crashes, the Windows key will return to normal.
  1480.                 DXUTAllowShortcutKeys( true );
  1481.             }
  1482.             break;
  1483.        case WM_ENTERMENULOOP:
  1484.             // Pause the app when menus are displayed
  1485.             DXUTPause( true, true );
  1486.             break;
  1487.         case WM_EXITMENULOOP:
  1488.             DXUTPause( false, false );
  1489.             break;
  1490.         case WM_MENUCHAR:
  1491.             // A menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key
  1492.             // So just ignore and don't beep
  1493.             return MAKELRESULT(0,MNC_CLOSE);
  1494.             break;
  1495.         case WM_NCHITTEST:
  1496.             // Prevent the user from selecting the menu in full screen mode
  1497.             if( !DXUTIsWindowed() )
  1498.                 return HTCLIENT;
  1499.             break;
  1500.         case WM_POWERBROADCAST:
  1501.             switch( wParam )
  1502.             {
  1503.                 #ifndef PBT_APMQUERYSUSPEND
  1504.                     #define PBT_APMQUERYSUSPEND 0x0000
  1505.                 #endif
  1506.                 case PBT_APMQUERYSUSPEND:
  1507.                     // At this point, the app should save any data for open
  1508.                     // network connections, files, etc., and prepare to go into
  1509.                     // a suspended mode.  The app can use the MsgProc callback
  1510.                     // to handle this if desired.
  1511.                     return true;
  1512.                 #ifndef PBT_APMRESUMESUSPEND
  1513.                     #define PBT_APMRESUMESUSPEND 0x0007
  1514.                 #endif
  1515.                 case PBT_APMRESUMESUSPEND:
  1516.                     // At this point, the app should recover any data, network
  1517.                     // connections, files, etc., and resume running from when
  1518.                     // the app was suspended. The app can use the MsgProc callback
  1519.                     // to handle this if desired.
  1520.                    
  1521.                    // QPC may lose consistency when suspending, so reset the timer
  1522.                    // upon resume.
  1523.                    DXUTGetGlobalTimer()->Reset();                   
  1524.                    GetDXUTState().SetLastStatsUpdateTime( 0 );
  1525.                    return true;
  1526.             }
  1527.             break;
  1528.         case WM_SYSCOMMAND:
  1529.             // Prevent moving/sizing in full screen mode
  1530.             switch( wParam )
  1531.             {
  1532.                 case SC_MOVE:
  1533.                 case SC_SIZE:
  1534.                 case SC_MAXIMIZE:
  1535.                 case SC_KEYMENU:
  1536.                     if( !DXUTIsWindowed() )
  1537.                         return 0;
  1538.                     break;
  1539.             }
  1540.             break;
  1541.         case WM_SYSKEYDOWN:
  1542.         {
  1543.             switch( wParam )
  1544.             {
  1545.                 case VK_RETURN:
  1546.                 {
  1547.                     if( GetDXUTState().GetHandleAltEnter() )
  1548.                     {
  1549.                         // Toggle full screen upon alt-enter 
  1550.                         DWORD dwMask = (1 << 29);
  1551.                         if( (lParam & dwMask) != 0 ) // Alt is down also
  1552.                         {
  1553.                             // Toggle the full screen/window mode
  1554.                             DXUTPause( true, true );
  1555.                             DXUTToggleFullScreen();
  1556.                             DXUTPause( false, false );                        
  1557.                             return 0;
  1558.                         }
  1559.                     }
  1560.                 }
  1561.             }
  1562.             break;
  1563.         }
  1564.         case WM_KEYDOWN:
  1565.         {
  1566.             if( GetDXUTState().GetHandleDefaultHotkeys() )
  1567.             {
  1568.                 switch( wParam )
  1569.                 {
  1570.                     case VK_F3:
  1571.                     {
  1572.                         DXUTPause( true, true );
  1573.                         DXUTToggleREF();
  1574.                         DXUTPause( false, false );                        
  1575.                         break;
  1576.                     }
  1577.                     case VK_F8:
  1578.                     {
  1579.                         bool bWireFrame = GetDXUTState().GetWireframeMode();
  1580.                         bWireFrame = !bWireFrame; 
  1581.                         GetDXUTState().SetWireframeMode( bWireFrame );
  1582.                         IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1583.                         if( pd3dDevice )
  1584.                             pd3dDevice->SetRenderState( D3DRS_FILLMODE, (bWireFrame) ? D3DFILL_WIREFRAME : D3DFILL_SOLID ); 
  1585.                         break;
  1586.                     }
  1587.                     case VK_ESCAPE:
  1588.                     {
  1589.                         // Received key to exit app
  1590.                         SendMessage( hWnd, WM_CLOSE, 0, 0 );
  1591.                     }
  1592.                     case VK_PAUSE: 
  1593.                     {
  1594.                         bool bTimePaused = DXUTIsTimePaused();
  1595.                         bTimePaused = !bTimePaused;
  1596.                         if( bTimePaused ) 
  1597.                             DXUTPause( true, false ); 
  1598.                         else
  1599.                             DXUTPause( false, false ); 
  1600.                         break; 
  1601.                     }
  1602.                 }
  1603.             }
  1604.             break;
  1605.         }
  1606.         case WM_CLOSE:
  1607.         {
  1608.             HMENU hMenu;
  1609.             hMenu = GetMenu(hWnd);
  1610.             if( hMenu != NULL )
  1611.                 DestroyMenu( hMenu );
  1612.             DestroyWindow( hWnd );
  1613.             UnregisterClass( L"Direct3DWindowClass", NULL );
  1614.             GetDXUTState().SetHWNDFocus( NULL );
  1615.             GetDXUTState().SetHWNDDeviceFullScreen( NULL );
  1616.             GetDXUTState().SetHWNDDeviceWindowed( NULL );
  1617.             return 0;
  1618.         }
  1619.         case WM_DESTROY:
  1620.             PostQuitMessage(0);
  1621.             break;
  1622.     }
  1623.     // Don't allow the F10 key to act as a shortcut to the menu bar
  1624.     // by not passing these messages to the DefWindowProc only when
  1625.     // there's no menu present
  1626.     if( !GetDXUTState().GetCallDefWindowProc() || GetDXUTState().GetMenu() == NULL && (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) && wParam == VK_F10 )
  1627.         return 0;
  1628.     else
  1629.         return DefWindowProc( hWnd, uMsg, wParam, lParam );
  1630. }
  1631. //--------------------------------------------------------------------------------------
  1632. // Resets the state associated with DXUT 
  1633. //--------------------------------------------------------------------------------------
  1634. void DXUTResetFrameworkState()
  1635. {
  1636.     GetDXUTState().Destroy();
  1637.     GetDXUTState().Create();
  1638. }
  1639. //--------------------------------------------------------------------------------------
  1640. // Closes down the window.  When the window closes, it will cleanup everything
  1641. //--------------------------------------------------------------------------------------
  1642. void DXUTShutdown( int nExitCode )
  1643. {
  1644.     HWND hWnd = DXUTGetHWND();
  1645.     if( hWnd != NULL )
  1646.         SendMessage( hWnd, WM_CLOSE, 0, 0 );
  1647.     GetDXUTState().SetExitCode(nExitCode);
  1648.     DXUTCleanup3DEnvironment( true );
  1649.     // Restore shortcut keys (Windows key, accessibility shortcuts) to original state
  1650.     // This is important to call here if the shortcuts are disabled, 
  1651.     // because accessibility setting changes are permanent.
  1652.     // This means that if this is not done then the accessibility settings 
  1653.     // might not be the same as when the app was started. 
  1654.     // If the app crashes without restoring the settings, this is also true so it
  1655.     // would be wise to backup/restore the settings from a file so they can be 
  1656.     // restored when the crashed app is run again.
  1657.     DXUTAllowShortcutKeys( true );
  1658.     
  1659.     GetDXUTState().SetD3DEnumeration( NULL );
  1660.     
  1661.     IDirect3D9* pD3D = DXUTGetD3DObject();
  1662.     SAFE_RELEASE( pD3D );
  1663.     GetDXUTState().SetD3D( NULL );
  1664.     if( GetDXUTState().GetOverrideRelaunchMCE() )
  1665.         DXUTReLaunchMediaCenter();
  1666. }
  1667. //--------------------------------------------------------------------------------------
  1668. // Cleans up the 3D environment by:
  1669. //      - Calls the device lost callback 
  1670. //      - Calls the device destroyed callback 
  1671. //      - Releases the D3D device
  1672. //--------------------------------------------------------------------------------------
  1673. void DXUTCleanup3DEnvironment( bool bReleaseSettings )
  1674. {
  1675.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  1676.     if( pd3dDevice != NULL )
  1677.     {
  1678.         GetDXUTState().SetInsideDeviceCallback( true );
  1679.         // Call the app's device lost callback
  1680.         if( GetDXUTState().GetDeviceObjectsReset() == true )
  1681.         {
  1682.             LPDXUTCALLBACKDEVICELOST pCallbackDeviceLost = GetDXUTState().GetDeviceLostFunc();
  1683.             if( pCallbackDeviceLost != NULL )
  1684.                 pCallbackDeviceLost( GetDXUTState().GetDeviceLostFuncUserContext() );
  1685.             GetDXUTState().SetDeviceObjectsReset( false );
  1686.             // Call the resource cache device lost function
  1687.             DXUTGetGlobalResourceCache().OnLostDevice();
  1688.         }
  1689.         // Call the app's device destroyed callback
  1690.         if( GetDXUTState().GetDeviceObjectsCreated() == true )
  1691.         {
  1692.             LPDXUTCALLBACKDEVICEDESTROYED pCallbackDeviceDestroyed = GetDXUTState().GetDeviceDestroyedFunc();
  1693.             if( pCallbackDeviceDestroyed != NULL )
  1694.                 pCallbackDeviceDestroyed( GetDXUTState().GetDeviceDestroyedFuncUserContext() );
  1695.             GetDXUTState().SetDeviceObjectsCreated( false );
  1696.             // Call the resource cache device destory function
  1697.             DXUTGetGlobalResourceCache().OnDestroyDevice();
  1698.         }
  1699.         GetDXUTState().SetInsideDeviceCallback( false );
  1700.         // Release the D3D device and in debug configs, displays a message box if there 
  1701.         // are unrelease objects.
  1702.         if( pd3dDevice )
  1703.         {
  1704.             if( pd3dDevice->Release() > 0 )  
  1705.             {
  1706.                 DXUTDisplayErrorMessage( DXUTERR_NONZEROREFCOUNT );
  1707.                 DXUT_ERR( L"DXUTCleanup3DEnvironment", DXUTERR_NONZEROREFCOUNT );
  1708.             }
  1709.         }
  1710.         GetDXUTState().SetD3DDevice( NULL );
  1711.         if( bReleaseSettings )
  1712.         {
  1713.             DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings();
  1714.             SAFE_DELETE(pOldDeviceSettings);  
  1715.             GetDXUTState().SetCurrentDeviceSettings( NULL );
  1716.         }
  1717.         D3DSURFACE_DESC* pbackBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
  1718.         ZeroMemory( pbackBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
  1719.         D3DCAPS9* pd3dCaps = GetDXUTState().GetCaps();
  1720.         ZeroMemory( pd3dCaps, sizeof(D3DCAPS9) );
  1721.         GetDXUTState().SetDeviceCreated( false );
  1722.     }
  1723. }
  1724. //--------------------------------------------------------------------------------------
  1725. // Stores back buffer surface desc in GetDXUTState().GetBackBufferSurfaceDesc()
  1726. //--------------------------------------------------------------------------------------
  1727. void DXUTUpdateBackBufferDesc()
  1728. {
  1729.     HRESULT hr;
  1730.     IDirect3DSurface9* pBackBuffer;
  1731.     hr = GetDXUTState().GetD3DDevice()->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1732.     D3DSURFACE_DESC* pBBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDesc();
  1733.     ZeroMemory( pBBufferSurfaceDesc, sizeof(D3DSURFACE_DESC) );
  1734.     if( SUCCEEDED(hr) )
  1735.     {
  1736.         pBackBuffer->GetDesc( pBBufferSurfaceDesc );
  1737.         SAFE_RELEASE( pBackBuffer );
  1738.     }
  1739. }
  1740. //--------------------------------------------------------------------------------------
  1741. // Starts a user defined timer callback
  1742. //--------------------------------------------------------------------------------------
  1743. HRESULT DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs, UINT* pnIDEvent, void* pCallbackUserContext ) 
  1744.     if( pCallbackTimer == NULL )
  1745.         return DXUT_ERR_MSGBOX( L"DXUTSetTimer", E_INVALIDARG ); 
  1746.     HRESULT hr;
  1747.     DXUT_TIMER DXUTTimer;
  1748.     DXUTTimer.pCallbackTimer = pCallbackTimer;
  1749.     DXUTTimer.pCallbackUserContext = pCallbackUserContext;
  1750.     DXUTTimer.fTimeoutInSecs = fTimeoutInSecs;
  1751.     DXUTTimer.fCountdown = fTimeoutInSecs;
  1752.     DXUTTimer.bEnabled = true;
  1753.     DXUTTimer.nID = GetDXUTState().GetTimerLastID() + 1;
  1754.     GetDXUTState().SetTimerLastID( DXUTTimer.nID );
  1755.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  1756.     if( pTimerList == NULL )
  1757.     {
  1758.         pTimerList = new CGrowableArray<DXUT_TIMER>;
  1759.         if( pTimerList == NULL )
  1760.             return E_OUTOFMEMORY; 
  1761.         GetDXUTState().SetTimerList( pTimerList );
  1762.     }
  1763.     if( FAILED( hr = pTimerList->Add( DXUTTimer ) ) )
  1764.         return hr;
  1765.     if( pnIDEvent )
  1766.         *pnIDEvent = DXUTTimer.nID;
  1767.     return S_OK; 
  1768. }
  1769. //--------------------------------------------------------------------------------------
  1770. // Stops a user defined timer callback
  1771. //--------------------------------------------------------------------------------------
  1772. HRESULT DXUTKillTimer( UINT nIDEvent ) 
  1773.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  1774.     if( pTimerList == NULL )
  1775.         return S_FALSE;
  1776.     bool bFound = false;
  1777.     for( int i=0; i<pTimerList->GetSize(); i++ )
  1778.     {
  1779.         DXUT_TIMER DXUTTimer = pTimerList->GetAt(i);
  1780.         if( DXUTTimer.nID == nIDEvent )
  1781.         {
  1782.             DXUTTimer.bEnabled = false;
  1783.             pTimerList->SetAt(i, DXUTTimer);
  1784.             bFound = true;
  1785.             break;
  1786.         }
  1787.     }
  1788.     if( !bFound ) 
  1789.         return DXUT_ERR_MSGBOX( L"DXUTKillTimer", E_INVALIDARG );
  1790.     return S_OK; 
  1791. }
  1792. //--------------------------------------------------------------------------------------
  1793. // Internal helper function to handle calling the user defined timer callbacks
  1794. //--------------------------------------------------------------------------------------
  1795. void DXUTHandleTimers()
  1796. {
  1797.     float fElapsedTime = DXUTGetElapsedTime();
  1798.     CGrowableArray<DXUT_TIMER>* pTimerList = GetDXUTState().GetTimerList();
  1799.     if( pTimerList == NULL )
  1800.         return;
  1801.     // Walk through the list of timer callbacks
  1802.     for( int i=0; i<pTimerList->GetSize(); i++ )
  1803.     {
  1804.         DXUT_TIMER DXUTTimer = pTimerList->GetAt(i);
  1805.         if( DXUTTimer.bEnabled )
  1806.         {
  1807.             DXUTTimer.fCountdown -= fElapsedTime;
  1808.             // Call the callback if count down expired
  1809.             if( DXUTTimer.fCountdown < 0 )
  1810.             {
  1811.                 DXUTTimer.pCallbackTimer( i, DXUTTimer.pCallbackUserContext );
  1812.                 DXUTTimer.fCountdown = DXUTTimer.fTimeoutInSecs;
  1813.             }
  1814.             pTimerList->SetAt(i, DXUTTimer);
  1815.         }
  1816.     }
  1817. }
  1818. //--------------------------------------------------------------------------------------
  1819. // External state access functions
  1820. //--------------------------------------------------------------------------------------
  1821. IDirect3D9* DXUTGetD3DObject()                      { return GetDXUTState().GetD3D(); }        
  1822. IDirect3DDevice9* DXUTGetD3DDevice()                { return GetDXUTState().GetD3DDevice(); }  
  1823. const D3DSURFACE_DESC* DXUTGetBackBufferSurfaceDesc() { return GetDXUTState().GetBackBufferSurfaceDesc(); }
  1824. const D3DCAPS9* DXUTGetDeviceCaps()                 { return GetDXUTState().GetCaps(); }
  1825. HINSTANCE DXUTGetHINSTANCE()                        { return GetDXUTState().GetHInstance(); }
  1826. HWND DXUTGetHWND()                                  { return DXUTIsWindowed() ? GetDXUTState().GetHWNDDeviceWindowed() : GetDXUTState().GetHWNDDeviceFullScreen(); }
  1827. HWND DXUTGetHWNDFocus()                             { return GetDXUTState().GetHWNDFocus(); }
  1828. HWND DXUTGetHWNDDeviceFullScreen()                  { return GetDXUTState().GetHWNDDeviceFullScreen(); }
  1829. HWND DXUTGetHWNDDeviceWindowed()                    { return GetDXUTState().GetHWNDDeviceWindowed(); }
  1830. RECT DXUTGetWindowClientRect()                      { RECT rc; GetClientRect( DXUTGetHWND(), &rc ); return rc; }
  1831. RECT DXUTGetWindowClientRectAtModeChange()          { RECT rc = { 0, 0, GetDXUTState().GetWindowBackBufferWidthAtModeChange(), GetDXUTState().GetWindowBackBufferHeightAtModeChange() }; return rc; }
  1832. RECT DXUTGetFullsceenClientRectAtModeChange()       { RECT rc = { 0, 0, GetDXUTState().GetFullScreenBackBufferWidthAtModeChange(), GetDXUTState().GetFullScreenBackBufferHeightAtModeChange() }; return rc; }
  1833. double DXUTGetTime()                                { return GetDXUTState().GetTime(); }
  1834. float DXUTGetElapsedTime()                          { return GetDXUTState().GetElapsedTime(); }
  1835. float DXUTGetFPS()                                  { return GetDXUTState().GetFPS(); }
  1836. LPCWSTR DXUTGetWindowTitle()                        { return GetDXUTState().GetWindowTitle(); }
  1837. LPCWSTR DXUTGetDeviceStats()                        { return GetDXUTState().GetDeviceStats(); }
  1838. bool DXUTIsRenderingPaused()                        { return GetDXUTState().GetPauseRenderingCount() > 0; }
  1839. bool DXUTIsTimePaused()                             { return GetDXUTState().GetPauseTimeCount() > 0; }
  1840. bool DXUTIsActive()                                 { return GetDXUTState().GetActive(); }
  1841. int DXUTGetExitCode()                               { return GetDXUTState().GetExitCode(); }
  1842. bool DXUTGetShowMsgBoxOnError()                     { return GetDXUTState().GetShowMsgBoxOnError(); }
  1843. bool DXUTGetAutomation()                            { return GetDXUTState().GetAutomation(); }
  1844. bool DXUTGetHandleDefaultHotkeys()                  { return GetDXUTState().GetHandleDefaultHotkeys(); }
  1845. bool DXUTIsKeyDown( BYTE vKey )
  1846.     bool* bKeys = GetDXUTState().GetKeys(); 
  1847.     if( vKey >= 0xA0 && vKey <= 0xA5 )  // VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU
  1848.         return GetAsyncKeyState( vKey ) != 0; // these keys only are tracked via GetAsyncKeyState()
  1849.     else if( vKey >= 0x01 && vKey <= 0x06 && vKey != 0x03 ) // mouse buttons (VK_*BUTTON)
  1850.         return DXUTIsMouseButtonDown(vKey);
  1851.     else
  1852.         return bKeys[vKey];
  1853. }
  1854. bool DXUTIsMouseButtonDown( BYTE vButton )          
  1855.     bool* bMouseButtons = GetDXUTState().GetMouseButtons(); 
  1856.     int nIndex = DXUTMapButtonToArrayIndex(vButton); 
  1857.     return bMouseButtons[nIndex]; 
  1858. }
  1859. void DXUTSetMultimonSettings( bool bAutoChangeAdapter )
  1860. {
  1861.     GetDXUTState().SetAutoChangeAdapter( bAutoChangeAdapter );
  1862. }
  1863. void DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen ) 
  1864.     GetDXUTState().SetClipCursorWhenFullScreen(bClipCursorWhenFullScreen); 
  1865.     GetDXUTState().SetShowCursorWhenFullScreen(bShowCursorWhenFullScreen); 
  1866.     DXUTSetupCursor();
  1867. }
  1868. void DXUTSetWindowSettings( bool bCallDefWindowProc )
  1869. {
  1870.     GetDXUTState().SetCallDefWindowProc( bCallDefWindowProc );
  1871. }
  1872. void DXUTSetConstantFrameTime( bool bEnabled, float fTimePerFrame ) 
  1873.     if( GetDXUTState().GetOverrideConstantFrameTime() ) 
  1874.     { 
  1875.         bEnabled = GetDXUTState().GetOverrideConstantFrameTime(); 
  1876.         fTimePerFrame = GetDXUTState().GetOverrideConstantTimePerFrame(); 
  1877.     } 
  1878.     GetDXUTState().SetConstantFrameTime(bEnabled); 
  1879.     GetDXUTState().SetTimePerFrame(fTimePerFrame); 
  1880. }
  1881. //--------------------------------------------------------------------------------------
  1882. // Return if windowed in the current device.  If no device exists yet, then returns false
  1883. //--------------------------------------------------------------------------------------
  1884. bool DXUTIsWindowed()                               
  1885.     DXUTDeviceSettings* pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); 
  1886.     if(pDeviceSettings) 
  1887.         return (pDeviceSettings->pp.Windowed != 0); 
  1888.     else 
  1889.         return false; 
  1890. }
  1891. //--------------------------------------------------------------------------------------
  1892. // Return the present params of the current device.  If no device exists yet, then
  1893. // return blank present params
  1894. //--------------------------------------------------------------------------------------
  1895. D3DPRESENT_PARAMETERS DXUTGetPresentParameters()    
  1896.     DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings(); 
  1897.     if( pDS ) 
  1898.     {
  1899.         return pDS->pp; 
  1900.     }
  1901.     else 
  1902.     {
  1903.         D3DPRESENT_PARAMETERS pp;
  1904.         ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS) );
  1905.         return pp; 
  1906.     }
  1907. }
  1908. //--------------------------------------------------------------------------------------
  1909. // Return the device settings of the current device.  If no device exists yet, then
  1910. // return blank device settings 
  1911. //--------------------------------------------------------------------------------------
  1912. DXUTDeviceSettings DXUTGetDeviceSettings()   
  1913.     DXUTDeviceSettings* pDS = GetDXUTState().GetCurrentDeviceSettings();
  1914.     if( pDS )
  1915.     {
  1916.         return *pDS;
  1917.     }
  1918.     else
  1919.     {
  1920.         DXUTDeviceSettings ds;
  1921.         ZeroMemory( &ds, sizeof(DXUTDeviceSettings) );
  1922.         return ds;
  1923.     }
  1924. #ifndef SM_REMOTESESSION  // needs WINVER >= 0x0500
  1925. #define SM_REMOTESESSION  0x1000
  1926. #endif
  1927. //--------------------------------------------------------------------------------------
  1928. // Display an custom error msg box 
  1929. //--------------------------------------------------------------------------------------
  1930. void DXUTDisplayErrorMessage( HRESULT hr )
  1931. {
  1932.     WCHAR strBuffer[512];
  1933.     int nExitCode;
  1934.     bool bFound = true; 
  1935.     switch( hr )
  1936.     {
  1937.         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;
  1938.         case DXUTERR_INCORRECTVERSION:       nExitCode = 10; StringCchCopy( strBuffer, 512, L"Incorrect version of Direct3D and/or D3DX." ); break;
  1939.         case DXUTERR_MEDIANOTFOUND:          nExitCode = 4; StringCchCopy( strBuffer, 512, L"Could not find required media. Ensure that the DirectX SDK is correctly installed." ); break;
  1940.         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;
  1941.         case DXUTERR_CREATINGDEVICE:         nExitCode = 6; StringCchCopy( strBuffer, 512, L"Failed creating the Direct3D device." ); break;
  1942.         case DXUTERR_RESETTINGDEVICE:        nExitCode = 7; StringCchCopy( strBuffer, 512, L"Failed resetting the Direct3D device." ); break;
  1943.         case DXUTERR_CREATINGDEVICEOBJECTS:  nExitCode = 8; StringCchCopy( strBuffer, 512, L"Failed creating Direct3D device objects." ); break;
  1944.         case DXUTERR_RESETTINGDEVICEOBJECTS: nExitCode = 9; StringCchCopy( strBuffer, 512, L"Failed resetting Direct3D device objects." ); break;
  1945.         case DXUTERR_NOCOMPATIBLEDEVICES:    
  1946.             nExitCode = 3; 
  1947.             if( GetSystemMetrics(SM_REMOTESESSION) != 0 )
  1948.                 StringCchCopy( strBuffer, 512, L"Direct3D does not work over a remote session." ); 
  1949.             else
  1950.                 StringCchCopy( strBuffer, 512, L"Could not find any compatible Direct3D devices." ); 
  1951.             break;
  1952.         default: bFound = false; nExitCode = 1;break;
  1953.     }   
  1954.     GetDXUTState().SetExitCode(nExitCode);
  1955.     bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
  1956.     if( bFound && bShowMsgBoxOnError )
  1957.     {
  1958.         if( DXUTGetWindowTitle()[0] == 0 )
  1959.             MessageBox( DXUTGetHWND(), strBuffer, L"DirectX Application", MB_ICONERROR|MB_OK );
  1960.         else
  1961.             MessageBox( DXUTGetHWND(), strBuffer, DXUTGetWindowTitle(), MB_ICONERROR|MB_OK );
  1962.     }
  1963. }
  1964. //--------------------------------------------------------------------------------------
  1965. // Display error msg box to help debug 
  1966. //--------------------------------------------------------------------------------------
  1967. HRESULT WINAPI DXUTTrace( const CHAR* strFile, DWORD dwLine, HRESULT hr,
  1968.                           const WCHAR* strMsg, bool bPopMsgBox )
  1969. {
  1970.     bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError();
  1971.     if( bPopMsgBox && bShowMsgBoxOnError == false )
  1972.         bPopMsgBox = false;
  1973.     return DXTrace( strFile, dwLine, hr, strMsg, bPopMsgBox );
  1974. }
  1975. //--------------------------------------------------------------------------------------
  1976. // Checks to see if the HWND changed monitors, and if it did it creates a device 
  1977. // from the monitor's adapter and recreates the scene.
  1978. //--------------------------------------------------------------------------------------
  1979. void DXUTCheckForWindowChangingMonitors()
  1980. {
  1981.     // Skip this check for various reasons
  1982.     if( !GetDXUTState().GetAutoChangeAdapter() || 
  1983.          GetDXUTState().GetIgnoreSizeChange() ||
  1984.         !GetDXUTState().GetDeviceCreated() ||
  1985.         !GetDXUTState().GetCurrentDeviceSettings()->pp.Windowed )
  1986.     {
  1987.         return;
  1988.     }
  1989.     HRESULT hr;
  1990.     HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY );
  1991.     HMONITOR hAdapterMonitor = GetDXUTState().GetAdapterMonitor();
  1992.     if( hWindowMonitor != hAdapterMonitor )
  1993.     {
  1994.         UINT newOrdinal;
  1995.         if( SUCCEEDED( DXUTGetAdapterOrdinalFromMonitor( hWindowMonitor, &newOrdinal ) ) )
  1996.         {
  1997.             // Find the closest valid device settings with the new ordinal
  1998.             DXUTDeviceSettings deviceSettings = DXUTGetDeviceSettings();
  1999.             deviceSettings.AdapterOrdinal = newOrdinal;
  2000.             
  2001.             DXUTMatchOptions matchOptions;
  2002.             matchOptions.eAdapterOrdinal     = DXUTMT_PRESERVE_INPUT;
  2003.             matchOptions.eDeviceType         = DXUTMT_CLOSEST_TO_INPUT;
  2004.             matchOptions.eWindowed           = DXUTMT_CLOSEST_TO_INPUT;
  2005.             matchOptions.eAdapterFormat      = DXUTMT_CLOSEST_TO_INPUT;
  2006.             matchOptions.eVertexProcessing   = DXUTMT_CLOSEST_TO_INPUT;
  2007.             matchOptions.eResolution         = DXUTMT_CLOSEST_TO_INPUT;
  2008.             matchOptions.eBackBufferFormat   = DXUTMT_CLOSEST_TO_INPUT;
  2009.             matchOptions.eBackBufferCount    = DXUTMT_CLOSEST_TO_INPUT;
  2010.             matchOptions.eMultiSample        = DXUTMT_CLOSEST_TO_INPUT;
  2011.             matchOptions.eSwapEffect         = DXUTMT_CLOSEST_TO_INPUT;
  2012.             matchOptions.eDepthFormat        = DXUTMT_CLOSEST_TO_INPUT;
  2013.             matchOptions.eStencilFormat      = DXUTMT_CLOSEST_TO_INPUT;
  2014.             matchOptions.ePresentFlags       = DXUTMT_CLOSEST_TO_INPUT;
  2015.             matchOptions.eRefreshRate        = DXUTMT_CLOSEST_TO_INPUT;
  2016.             matchOptions.ePresentInterval    = DXUTMT_CLOSEST_TO_INPUT;
  2017.             hr = DXUTFindValidDeviceSettings( &deviceSettings, &deviceSettings, &matchOptions );
  2018.             if( SUCCEEDED(hr) ) 
  2019.             {
  2020.                 // Create a Direct3D device using the new device settings.  
  2021.                 // If there is an existing device, then it will either reset or recreate the scene.
  2022.                 hr = DXUTChangeDevice( &deviceSettings, NULL, false, false );
  2023.                 // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback
  2024.                 if( hr == E_ABORT )
  2025.                 {
  2026.                     // so nothing changed and keep from attempting to switch adapters next time
  2027.                     GetDXUTState().SetAutoChangeAdapter( false );
  2028.                 }
  2029.                 else if( FAILED(hr) )
  2030.                 {
  2031.                     DXUTShutdown();
  2032.                     DXUTPause( false, false );
  2033.                     return;
  2034.                 }
  2035.             }
  2036.         }
  2037.     }    
  2038. }
  2039. //--------------------------------------------------------------------------------------
  2040. // Look for an adapter ordinal that is tied to a HMONITOR
  2041. //--------------------------------------------------------------------------------------
  2042. HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal )
  2043. {
  2044.     *pAdapterOrdinal = 0;
  2045.     CD3DEnumeration* pd3dEnum = DXUTPrepareEnumerationObject();
  2046.     IDirect3D9*      pD3D     = DXUTGetD3DObject();
  2047.     CGrowableArray<CD3DEnumAdapterInfo*>* pAdapterList = pd3dEnum->GetAdapterInfoList();
  2048.     for( int iAdapter=0; iAdapter<pAdapterList->GetSize(); iAdapter++ )
  2049.     {
  2050.         CD3DEnumAdapterInfo* pAdapterInfo = pAdapterList->GetAt(iAdapter);
  2051.         HMONITOR hAdapterMonitor = pD3D->GetAdapterMonitor( pAdapterInfo->AdapterOrdinal );
  2052.         if( hAdapterMonitor == hMonitor )
  2053.         {
  2054.             *pAdapterOrdinal = pAdapterInfo->AdapterOrdinal;
  2055.             return S_OK;
  2056.         }
  2057.     }
  2058.     return E_FAIL;
  2059. }
  2060. //--------------------------------------------------------------------------------------
  2061. // Internal function to map MK_* to an array index
  2062. //--------------------------------------------------------------------------------------
  2063. int DXUTMapButtonToArrayIndex( BYTE vButton )
  2064. {
  2065.     switch( vButton )
  2066.     {
  2067.         case MK_LBUTTON: return 0;
  2068.         case VK_MBUTTON: 
  2069.         case MK_MBUTTON: return 1;
  2070.         case MK_RBUTTON: return 2;
  2071.         case VK_XBUTTON1:
  2072.         case MK_XBUTTON1: return 3;
  2073.         case VK_XBUTTON2:
  2074.         case MK_XBUTTON2: return 4;
  2075.     }
  2076.     return 0;
  2077. }
  2078. //--------------------------------------------------------------------------------------
  2079. // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state)
  2080. //--------------------------------------------------------------------------------------
  2081. void DXUTSetupCursor()
  2082. {
  2083.     // Show the cursor again if returning to fullscreen 
  2084.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  2085.     if( !DXUTIsWindowed() && pd3dDevice )
  2086.     {
  2087.         if( GetDXUTState().GetShowCursorWhenFullScreen() )
  2088.         {
  2089.             SetCursor( NULL ); // Turn off Windows cursor in full screen mode
  2090.             HCURSOR hCursor = (HCURSOR)(ULONG_PTR)GetClassLongPtr( DXUTGetHWNDDeviceFullScreen(), GCLP_HCURSOR );
  2091.             DXUTSetDeviceCursor( pd3dDevice, hCursor, false );
  2092.             DXUTGetD3DDevice()->ShowCursor( true );
  2093.         }
  2094.         else
  2095.         {
  2096.             SetCursor( NULL ); // Turn off Windows cursor in full screen mode
  2097.             DXUTGetD3DDevice()->ShowCursor( false );
  2098.         }
  2099.     }
  2100.     // Clip cursor if requested
  2101.     if( !DXUTIsWindowed() && GetDXUTState().GetClipCursorWhenFullScreen() )
  2102.     {
  2103.         // Confine cursor to full screen window
  2104.         RECT rcWindow;
  2105.         GetWindowRect( DXUTGetHWNDDeviceFullScreen(), &rcWindow );
  2106.         ClipCursor( &rcWindow );
  2107.     }
  2108.     else
  2109.     {
  2110.         ClipCursor( NULL );
  2111.     }
  2112. }
  2113. //--------------------------------------------------------------------------------------
  2114. // Gives the D3D device a cursor with image and hotspot from hCursor.
  2115. //--------------------------------------------------------------------------------------
  2116. HRESULT DXUTSetDeviceCursor( IDirect3DDevice9* pd3dDevice, HCURSOR hCursor, bool bAddWatermark )
  2117. {
  2118.     HRESULT hr = E_FAIL;
  2119.     ICONINFO iconinfo;
  2120.     bool bBWCursor;
  2121.     LPDIRECT3DSURFACE9 pCursorSurface = NULL;
  2122.     HDC hdcColor = NULL;
  2123.     HDC hdcMask = NULL;
  2124.     HDC hdcScreen = NULL;
  2125.     BITMAP bm;
  2126.     DWORD dwWidth;
  2127.     DWORD dwHeightSrc;
  2128.     DWORD dwHeightDest;
  2129.     COLORREF crColor;
  2130.     COLORREF crMask;
  2131.     UINT x;
  2132.     UINT y;
  2133.     BITMAPINFO bmi;
  2134.     COLORREF* pcrArrayColor = NULL;
  2135.     COLORREF* pcrArrayMask = NULL;
  2136.     DWORD* pBitmap;
  2137.     HGDIOBJ hgdiobjOld;
  2138.     ZeroMemory( &iconinfo, sizeof(iconinfo) );
  2139.     if( !GetIconInfo( hCursor, &iconinfo ) )
  2140.         goto End;
  2141.     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
  2142.         goto End;
  2143.     dwWidth = bm.bmWidth;
  2144.     dwHeightSrc = bm.bmHeight;
  2145.     if( iconinfo.hbmColor == NULL )
  2146.     {
  2147.         bBWCursor = TRUE;
  2148.         dwHeightDest = dwHeightSrc / 2;
  2149.     }
  2150.     else 
  2151.     {
  2152.         bBWCursor = FALSE;
  2153.         dwHeightDest = dwHeightSrc;
  2154.     }
  2155.     // Create a surface for the fullscreen cursor
  2156.     if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest, 
  2157.         D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCursorSurface, NULL ) ) )
  2158.     {
  2159.         goto End;
  2160.     }
  2161.     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
  2162.     ZeroMemory(&bmi, sizeof(bmi));
  2163.     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  2164.     bmi.bmiHeader.biWidth = dwWidth;
  2165.     bmi.bmiHeader.biHeight = dwHeightSrc;
  2166.     bmi.bmiHeader.biPlanes = 1;
  2167.     bmi.bmiHeader.biBitCount = 32;
  2168.     bmi.bmiHeader.biCompression = BI_RGB;
  2169.     hdcScreen = GetDC( NULL );
  2170.     hdcMask = CreateCompatibleDC( hdcScreen );
  2171.     if( hdcMask == NULL )
  2172.     {
  2173.         hr = E_FAIL;
  2174.         goto End;
  2175.     }
  2176.     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
  2177.     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, 
  2178.         pcrArrayMask, &bmi, DIB_RGB_COLORS);
  2179.     SelectObject(hdcMask, hgdiobjOld);
  2180.     if (!bBWCursor)
  2181.     {
  2182.         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
  2183.         hdcColor = CreateCompatibleDC( hdcScreen );
  2184.         if( hdcColor == NULL )
  2185.         {
  2186.             hr = E_FAIL;
  2187.             goto End;
  2188.         }
  2189.         SelectObject(hdcColor, iconinfo.hbmColor);
  2190.         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, 
  2191.             pcrArrayColor, &bmi, DIB_RGB_COLORS);
  2192.     }
  2193.     // Transfer cursor image into the surface
  2194.     D3DLOCKED_RECT lr;
  2195.     pCursorSurface->LockRect( &lr, NULL, 0 );
  2196.     pBitmap = (DWORD*)lr.pBits;
  2197.     for( y = 0; y < dwHeightDest; y++ )
  2198.     {
  2199.         for( x = 0; x < dwWidth; x++ )
  2200.         {
  2201.             if (bBWCursor)
  2202.             {
  2203.                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  2204.                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
  2205.             }
  2206.             else
  2207.             {
  2208.                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
  2209.                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  2210.             }
  2211.             if (crMask == 0)
  2212.                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
  2213.             else
  2214.                 pBitmap[dwWidth*y + x] = 0x00000000;
  2215.             // It may be helpful to make the D3D cursor look slightly 
  2216.             // different from the Windows cursor so you can distinguish 
  2217.             // between the two when developing/testing code.  When
  2218.             // bAddWatermark is TRUE, the following code adds some
  2219.             // small grey "D3D" characters to the upper-left corner of
  2220.             // the D3D cursor image.
  2221.             if( bAddWatermark && x < 12 && y < 5 )
  2222.             {
  2223.                 // 11.. 11.. 11.. .... CCC0
  2224.                 // 1.1. ..1. 1.1. .... A2A0
  2225.                 // 1.1. .1.. 1.1. .... A4A0
  2226.                 // 1.1. ..1. 1.1. .... A2A0
  2227.                 // 11.. 11.. 11.. .... CCC0
  2228.                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
  2229.                 if( wMask[y] & (1 << (15 - x)) )
  2230.                 {
  2231.                     pBitmap[dwWidth*y + x] |= 0xff808080;
  2232.                 }
  2233.             }
  2234.         }
  2235.     }
  2236.     pCursorSurface->UnlockRect();
  2237.     // Set the device cursor
  2238.     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, 
  2239.         iconinfo.yHotspot, pCursorSurface ) ) )
  2240.     {
  2241.         goto End;
  2242.     }
  2243.     hr = S_OK;
  2244. End:
  2245.     if( iconinfo.hbmMask != NULL )
  2246.         DeleteObject( iconinfo.hbmMask );
  2247.     if( iconinfo.hbmColor != NULL )
  2248.         DeleteObject( iconinfo.hbmColor );
  2249.     if( hdcScreen != NULL )
  2250.         ReleaseDC( NULL, hdcScreen );
  2251.     if( hdcColor != NULL )
  2252.         DeleteDC( hdcColor );
  2253.     if( hdcMask != NULL )
  2254.         DeleteDC( hdcMask );
  2255.     SAFE_DELETE_ARRAY( pcrArrayColor );
  2256.     SAFE_DELETE_ARRAY( pcrArrayMask );
  2257.     SAFE_RELEASE( pCursorSurface );
  2258.     return hr;
  2259. }