d3dapp.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:68k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DApp.cpp
  3. //
  4. // Desc: Application class for the Direct3D samples framework library.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. //-----------------------------------------------------------------------------
  10. // Global access to the app (needed for the global WndProc())
  11. //-----------------------------------------------------------------------------
  12. static CD3DApplication* g_pD3DApp = NULL;
  13. //-----------------------------------------------------------------------------
  14. // Name: CD3DApplication()
  15. // Desc: Constructor
  16. //-----------------------------------------------------------------------------
  17. CD3DApplication::CD3DApplication()
  18. {
  19.     g_pD3DApp           = this;
  20.     m_pD3D              = NULL;
  21.     m_pd3dDevice        = NULL;
  22.     m_hWnd              = NULL;
  23.     m_hWndFocus         = NULL;
  24.     m_hMenu             = NULL;
  25.     m_bWindowed         = true;
  26.     m_bActive           = false;
  27.     m_bDeviceLost       = false;
  28.     m_bMinimized        = false;
  29.     m_bMaximized        = false;
  30.     m_bIgnoreSizeChange = false;
  31.     m_bDeviceObjectsInited = false;
  32.     m_bDeviceObjectsRestored = false;
  33.     m_dwCreateFlags     = 0;
  34.     m_bFrameMoving      = true;
  35.     m_bSingleStep       = false;
  36.     m_fTime             = 0.0f;
  37.     m_fElapsedTime      = 0.0f;
  38.     m_fFPS              = 0.0f;
  39.     m_strDeviceStats[0] = _T('');
  40.     m_strFrameStats[0]  = _T('');
  41.     m_strWindowTitle    = _T("D3D9 Application");
  42.     m_dwCreationWidth   = 400;
  43.     m_dwCreationHeight  = 300;
  44.     m_bShowCursorWhenFullscreen = false;
  45.     m_bStartFullscreen  = false;
  46.     m_bCreateMultithreadDevice = false;
  47.     m_bAllowDialogBoxMode = false;
  48.     Pause( true ); // Pause until we're ready to render
  49.     // When m_bClipCursorWhenFullscreen is true, the cursor is limited to
  50.     // the device window when the app goes fullscreen.  This prevents users
  51.     // from accidentally clicking outside the app window on a multimon system.
  52.     // This flag is turned off by default for debug builds, since it makes 
  53.     // multimon debugging difficult.
  54. #if defined(_DEBUG) || defined(DEBUG)
  55.     m_bClipCursorWhenFullscreen = false;
  56. #else
  57.     m_bClipCursorWhenFullscreen = true;
  58. #endif
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Name: WndProc()
  62. // Desc: Static msg handler which passes messages to the application class.
  63. //-----------------------------------------------------------------------------
  64. LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  65. {
  66.     return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Name: ConfirmDeviceHelper()
  70. // Desc: Static function used by D3DEnumeration
  71. //-----------------------------------------------------------------------------
  72. bool CD3DApplication::ConfirmDeviceHelper( D3DCAPS9* pCaps, VertexProcessingType vertexProcessingType, 
  73.                          D3DFORMAT adapterFormat, D3DFORMAT backBufferFormat )
  74. {
  75.     DWORD dwBehavior;
  76.     if (vertexProcessingType == SOFTWARE_VP)
  77.         dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  78.     else if (vertexProcessingType == MIXED_VP)
  79.         dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  80.     else if (vertexProcessingType == HARDWARE_VP)
  81.         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  82.     else if (vertexProcessingType == PURE_HARDWARE_VP)
  83.         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  84.     else
  85.         dwBehavior = 0; // TODO: throw exception
  86.     
  87.     return SUCCEEDED( g_pD3DApp->ConfirmDevice( pCaps, dwBehavior, adapterFormat, backBufferFormat ) );
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Name: Create()
  91. // Desc: Here's what this function does:
  92. //       - Checks to make sure app is still active (if fullscreen, etc)
  93. //       - Checks to see if it is time to draw with DXUtil_Timer, if not, it just returns S_OK
  94. //       - Calls FrameMove() to recalculate new positions
  95. //       - Calls Render() to draw the new frame
  96. //       - Updates some frame count statistics
  97. //       - Calls m_pd3dDevice->Present() to display the rendered frame.
  98. //-----------------------------------------------------------------------------
  99. HRESULT CD3DApplication::Create( HINSTANCE hInstance )
  100. {
  101.     HRESULT hr;
  102.     // Create the Direct3D object
  103.     m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
  104.     if( m_pD3D == NULL )
  105.         return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
  106.     // Build a list of Direct3D adapters, modes and devices. The
  107.     // ConfirmDevice() callback is used to confirm that only devices that
  108.     // meet the app's requirements are considered.
  109.     m_d3dEnumeration.SetD3D( m_pD3D );
  110.     m_d3dEnumeration.ConfirmDeviceCallback = ConfirmDeviceHelper;
  111.     if( FAILED( hr = m_d3dEnumeration.Enumerate() ) )
  112.     {
  113.         SAFE_RELEASE( m_pD3D );
  114.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  115.     }
  116.     // Unless a substitute hWnd has been specified, create a window to
  117.     // render into
  118.     if( m_hWnd == NULL)
  119.     {
  120.         // Register the windows class
  121.         WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
  122.                               LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
  123.                               LoadCursor( NULL, IDC_ARROW ),
  124.                               (HBRUSH)GetStockObject(WHITE_BRUSH),
  125.                               NULL, _T("D3D Window") };
  126.         RegisterClass( &wndClass );
  127.         // Set the window's initial style
  128.         m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
  129.                           WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
  130.         
  131.         HMENU hMenu = LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) );
  132.         // Set the window's initial width
  133.         RECT rc;
  134.         SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );        
  135.         AdjustWindowRect( &rc, m_dwWindowStyle, ( hMenu != NULL ) ? true : false );
  136.         // Create the render window
  137.         m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle,
  138.                                CW_USEDEFAULT, CW_USEDEFAULT,
  139.                                (rc.right-rc.left), (rc.bottom-rc.top), 0,
  140.                                hMenu, hInstance, 0 );
  141.     }
  142.     // The focus window can be a specified to be a different window than the
  143.     // device window.  If not, use the device window as the focus window.
  144.     if( m_hWndFocus == NULL )
  145.         m_hWndFocus = m_hWnd;
  146.     // Save window properties
  147.     m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  148.     GetWindowRect( m_hWnd, &m_rcWindowBounds );
  149.     GetClientRect( m_hWnd, &m_rcWindowClient );
  150.     if( FAILED( hr = ChooseInitialD3DSettings() ) )
  151.     {
  152.         SAFE_RELEASE( m_pD3D );
  153.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  154.     }
  155.     // Initialize the application timer
  156.     DXUtil_Timer( TIMER_START );
  157.     // Initialize the app's custom scene stuff
  158.     if( FAILED( hr = OneTimeSceneInit() ) )
  159.     {
  160.         SAFE_RELEASE( m_pD3D );
  161.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  162.     }
  163.     // Initialize the 3D environment for the app
  164.     if( FAILED( hr = Initialize3DEnvironment() ) )
  165.     {
  166.         SAFE_RELEASE( m_pD3D );
  167.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  168.     }
  169.     // The app is ready to go
  170.     Pause( false );
  171.     return S_OK;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Name: FindBestWindowedMode()
  175. // Desc: Sets up m_d3dSettings with best available windowed mode, subject to 
  176. //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
  177. //       mode can be found.
  178. //-----------------------------------------------------------------------------
  179. bool CD3DApplication::FindBestWindowedMode( bool bRequireHAL, bool bRequireREF )
  180. {
  181.     // Get display mode of primary adapter (which is assumed to be where the window 
  182.     // will appear)
  183.     D3DDISPLAYMODE primaryDesktopDisplayMode;
  184.     m_pD3D->GetAdapterDisplayMode(0, &primaryDesktopDisplayMode);
  185.     D3DAdapterInfo* pBestAdapterInfo = NULL;
  186.     D3DDeviceInfo* pBestDeviceInfo = NULL;
  187.     D3DDeviceCombo* pBestDeviceCombo = NULL;
  188.     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
  189.     {
  190.         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
  191.         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
  192.         {
  193.             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
  194.             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
  195.                 continue;
  196.             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
  197.                 continue;
  198.             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
  199.             {
  200.                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
  201.                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
  202.                 if (!pDeviceCombo->IsWindowed)
  203.                     continue;
  204.                 if (pDeviceCombo->AdapterFormat != primaryDesktopDisplayMode.Format)
  205.                     continue;
  206.                 // If we haven't found a compatible DeviceCombo yet, or if this set
  207.                 // is better (because it's a HAL, and/or because formats match better),
  208.                 // save it
  209.                 if( pBestDeviceCombo == NULL || 
  210.                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceCombo->DevType == D3DDEVTYPE_HAL ||
  211.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
  212.                 {
  213.                     pBestAdapterInfo = pAdapterInfo;
  214.                     pBestDeviceInfo = pDeviceInfo;
  215.                     pBestDeviceCombo = pDeviceCombo;
  216.                     if( pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
  217.                     {
  218.                         // This windowed device combo looks great -- take it
  219.                         goto EndWindowedDeviceComboSearch;
  220.                     }
  221.                     // Otherwise keep looking for a better windowed device combo
  222.                 }
  223.             }
  224.         }
  225.     }
  226. EndWindowedDeviceComboSearch:
  227.     if (pBestDeviceCombo == NULL )
  228.         return false;
  229.     m_d3dSettings.pWindowed_AdapterInfo = pBestAdapterInfo;
  230.     m_d3dSettings.pWindowed_DeviceInfo = pBestDeviceInfo;
  231.     m_d3dSettings.pWindowed_DeviceCombo = pBestDeviceCombo;
  232.     m_d3dSettings.IsWindowed = true;
  233.     m_d3dSettings.Windowed_DisplayMode = primaryDesktopDisplayMode;
  234.     m_d3dSettings.Windowed_Width = m_rcWindowClient.right - m_rcWindowClient.left;
  235.     m_d3dSettings.Windowed_Height = m_rcWindowClient.bottom - m_rcWindowClient.top;
  236.     if (m_d3dEnumeration.AppUsesDepthBuffer)
  237.         m_d3dSettings.Windowed_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
  238.     m_d3dSettings.Windowed_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
  239.     m_d3dSettings.Windowed_MultisampleQuality = 0;
  240.     m_d3dSettings.Windowed_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
  241.     m_d3dSettings.Windowed_PresentInterval = *(UINT*)pBestDeviceCombo->pPresentIntervalList->GetPtr(0);
  242.     return true;
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Name: FindBestFullscreenMode()
  246. // Desc: Sets up m_d3dSettings with best available fullscreen mode, subject to 
  247. //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
  248. //       mode can be found.
  249. //-----------------------------------------------------------------------------
  250. bool CD3DApplication::FindBestFullscreenMode( bool bRequireHAL, bool bRequireREF )
  251. {
  252.     // For fullscreen, default to first HAL DeviceCombo that supports the current desktop 
  253.     // display mode, or any display mode if HAL is not compatible with the desktop mode, or 
  254.     // non-HAL if no HAL is available
  255.     D3DDISPLAYMODE adapterDesktopDisplayMode;
  256.     D3DDISPLAYMODE bestAdapterDesktopDisplayMode;
  257.     D3DDISPLAYMODE bestDisplayMode;
  258.     bestAdapterDesktopDisplayMode.Width = 0;
  259.     bestAdapterDesktopDisplayMode.Height = 0;
  260.     bestAdapterDesktopDisplayMode.Format = D3DFMT_UNKNOWN;
  261.     bestAdapterDesktopDisplayMode.RefreshRate = 0;
  262.     D3DAdapterInfo* pBestAdapterInfo = NULL;
  263.     D3DDeviceInfo* pBestDeviceInfo = NULL;
  264.     D3DDeviceCombo* pBestDeviceCombo = NULL;
  265.     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
  266.     {
  267.         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
  268.         m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
  269.         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
  270.         {
  271.             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
  272.             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
  273.                 continue;
  274.             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
  275.                 continue;
  276.             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
  277.             {
  278.                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
  279.                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
  280.                 bool bAdapterMatchesDesktop = (pDeviceCombo->AdapterFormat == adapterDesktopDisplayMode.Format);
  281.                 if (pDeviceCombo->IsWindowed)
  282.                     continue;
  283.                 // If we haven't found a compatible set yet, or if this set
  284.                 // is better (because it's a HAL, and/or because formats match better),
  285.                 // save it
  286.                 if (pBestDeviceCombo == NULL ||
  287.                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceInfo->DevType == D3DDEVTYPE_HAL ||
  288.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && pBestDeviceCombo->AdapterFormat != adapterDesktopDisplayMode.Format && bAdapterMatchesDesktop ||
  289.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB )
  290.                 {
  291.                     bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
  292.                     pBestAdapterInfo = pAdapterInfo;
  293.                     pBestDeviceInfo = pDeviceInfo;
  294.                     pBestDeviceCombo = pDeviceCombo;
  295.                     if (pDeviceInfo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB)
  296.                     {
  297.                         // This fullscreen device combo looks great -- take it
  298.                         goto EndFullscreenDeviceComboSearch;
  299.                     }
  300.                     // Otherwise keep looking for a better fullscreen device combo
  301.                 }
  302.             }
  303.         }
  304.     }
  305. EndFullscreenDeviceComboSearch:
  306.     if (pBestDeviceCombo == NULL)
  307.         return false;
  308.     // Need to find a display mode on the best adapter that uses pBestDeviceCombo->AdapterFormat
  309.     // and is as close to bestAdapterDesktopDisplayMode's res as possible
  310.     bestDisplayMode.Width = 0;
  311.     bestDisplayMode.Height = 0;
  312.     bestDisplayMode.Format = D3DFMT_UNKNOWN;
  313.     bestDisplayMode.RefreshRate = 0;
  314.     for( UINT idm = 0; idm < pBestAdapterInfo->pDisplayModeList->Count(); idm++ )
  315.     {
  316.         D3DDISPLAYMODE* pdm = (D3DDISPLAYMODE*)pBestAdapterInfo->pDisplayModeList->GetPtr(idm);
  317.         if( pdm->Format != pBestDeviceCombo->AdapterFormat )
  318.             continue;
  319.         if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
  320.             pdm->Height == bestAdapterDesktopDisplayMode.Height && 
  321.             pdm->RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate )
  322.         {
  323.             // found a perfect match, so stop
  324.             bestDisplayMode = *pdm;
  325.             break;
  326.         }
  327.         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
  328.                  pdm->Height == bestAdapterDesktopDisplayMode.Height && 
  329.                  pdm->RefreshRate > bestDisplayMode.RefreshRate )
  330.         {
  331.             // refresh rate doesn't match, but width/height match, so keep this
  332.             // and keep looking
  333.             bestDisplayMode = *pdm;
  334.         }
  335.         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width )
  336.         {
  337.             // width matches, so keep this and keep looking
  338.             bestDisplayMode = *pdm;
  339.         }
  340.         else if( bestDisplayMode.Width == 0 )
  341.         {
  342.             // we don't have anything better yet, so keep this and keep looking
  343.             bestDisplayMode = *pdm;
  344.         }
  345.     }
  346.     m_d3dSettings.pFullscreen_AdapterInfo = pBestAdapterInfo;
  347.     m_d3dSettings.pFullscreen_DeviceInfo = pBestDeviceInfo;
  348.     m_d3dSettings.pFullscreen_DeviceCombo = pBestDeviceCombo;
  349.     m_d3dSettings.IsWindowed = false;
  350.     m_d3dSettings.Fullscreen_DisplayMode = bestDisplayMode;
  351.     if (m_d3dEnumeration.AppUsesDepthBuffer)
  352.         m_d3dSettings.Fullscreen_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
  353.     m_d3dSettings.Fullscreen_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
  354.     m_d3dSettings.Fullscreen_MultisampleQuality = 0;
  355.     m_d3dSettings.Fullscreen_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
  356.     m_d3dSettings.Fullscreen_PresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
  357.     return true;
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Name: ChooseInitialD3DSettings()
  361. // Desc: 
  362. //-----------------------------------------------------------------------------
  363. HRESULT CD3DApplication::ChooseInitialD3DSettings()
  364. {
  365.     bool bFoundFullscreen = FindBestFullscreenMode( false, false );
  366.     bool bFoundWindowed = FindBestWindowedMode( false, false );
  367.     m_d3dSettings.SetDeviceClip( false );
  368.     if( m_bStartFullscreen && bFoundFullscreen )
  369.         m_d3dSettings.IsWindowed = false;
  370.     if( !bFoundWindowed && bFoundFullscreen )
  371.         m_d3dSettings.IsWindowed = false;
  372.     if( !bFoundFullscreen && !bFoundWindowed )
  373.         return D3DAPPERR_NOCOMPATIBLEDEVICES;
  374.     return S_OK;
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Name: MsgProc()
  378. // Desc: Message handling function.  Here's what this function does:
  379. //       - WM_PAINT: calls Render() and Present() is called if !m_bReady
  380. //       - WM_EXITSIZEMOVE: window size recalc'd and calls HandlePossibleSizeChange()
  381. //       - WM_CLOSE: calls Cleanup3dEnvironment(), DestroyMenu(), DestroyWindow(), PostQuitMessage()
  382. //       - WM_COMMAND: IDM_CHANGEDEVICE calls UserSelectNewDevice() to select a new device
  383. //       - WM_COMMAND: IDM_TOGGLEFULLSCREEN calls ToggleFullScreen() to toggle 
  384. //                  between fullscreen and windowed
  385. //       - WM_COMMAND: IDM_EXIT: shuts down the app with a WM_CLOSE 
  386. //       - anything not handled goes to DefWindowProc()     
  387. //-----------------------------------------------------------------------------
  388. LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  389.                                   LPARAM lParam )
  390. {
  391.     switch( uMsg )
  392.     {
  393.         case WM_PAINT:
  394.             // Handle paint messages when the app is paused
  395.             if( m_pd3dDevice && !m_bActive && 
  396.                 m_bDeviceObjectsInited && m_bDeviceObjectsRestored )
  397.             {
  398.                 HRESULT hr;
  399.                 Render();
  400.                 hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  401.                 if( D3DERR_DEVICELOST == hr )
  402.                     m_bDeviceLost = true;
  403.             }
  404.             break;
  405.         case WM_GETMINMAXINFO:
  406.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
  407.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
  408.             break;
  409.         case WM_ENTERSIZEMOVE:
  410.             // Halt frame movement while the app is sizing or moving
  411.             Pause( true );
  412.             break;
  413.         case WM_SIZE:
  414.             // Pick up possible changes to window style due to maximize, etc.
  415.             if( m_bWindowed && m_hWnd != NULL )
  416.                 m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  417.             if( SIZE_MINIMIZED == wParam )
  418.             {
  419.                 if( m_bClipCursorWhenFullscreen && !m_bWindowed )
  420.                     ClipCursor( NULL );
  421.                 Pause( true ); // Pause while we're minimized
  422.                 m_bMinimized = true;
  423.                 m_bMaximized = false;
  424.             }
  425.             else if( SIZE_MAXIMIZED == wParam )
  426.             {
  427.                 if( m_bMinimized )
  428.                     Pause( false ); // Unpause since we're no longer minimized
  429.                 m_bMinimized = false;
  430.                 m_bMaximized = true;
  431.                 HandlePossibleSizeChange();
  432.             }
  433.             else if( SIZE_RESTORED == wParam )
  434.             {
  435.                 if( m_bMaximized )
  436.                 {
  437.                     m_bMaximized = false;
  438.                     HandlePossibleSizeChange();
  439.                 }
  440.                 else if( m_bMinimized)
  441.                 {
  442.                     Pause( false ); // Unpause since we're no longer minimized
  443.                     m_bMinimized = false;
  444.                     HandlePossibleSizeChange();
  445.                 }
  446.                 else
  447.                 {
  448.                     // If we're neither maximized nor minimized, the window size 
  449.                     // is changing by the user dragging the window edges.  In this 
  450.                     // case, we don't reset the device yet -- we wait until the 
  451.                     // user stops dragging, and a WM_EXITSIZEMOVE message comes.
  452.                 }
  453.             }
  454.             break;
  455.         case WM_EXITSIZEMOVE:
  456.             Pause( false );
  457.             HandlePossibleSizeChange();
  458.             break;
  459.         case WM_SETCURSOR:
  460.             // Turn off Windows cursor in fullscreen mode
  461.             if( m_bActive && !m_bWindowed )
  462.             {
  463.                 SetCursor( NULL );
  464.                 if( m_bShowCursorWhenFullscreen )
  465.                     m_pd3dDevice->ShowCursor( true );
  466.                 return true; // prevent Windows from setting cursor to window class cursor
  467.             }
  468.             break;
  469.          case WM_MOUSEMOVE:
  470.             if( m_bActive && m_pd3dDevice != NULL )
  471.             {
  472.                 POINT ptCursor;
  473.                 GetCursorPos( &ptCursor );
  474.                 if( !m_bWindowed )
  475.                     ScreenToClient( m_hWnd, &ptCursor );
  476.                 m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
  477.             }
  478.             break;
  479.        case WM_ENTERMENULOOP:
  480.             // Pause the app when menus are displayed
  481.             Pause(true);
  482.             break;
  483.         case WM_EXITMENULOOP:
  484.             Pause(false);
  485.             break;
  486.         case WM_NCHITTEST:
  487.             // Prevent the user from selecting the menu in fullscreen mode
  488.             if( !m_bWindowed )
  489.                 return HTCLIENT;
  490.             break;
  491.         case WM_POWERBROADCAST:
  492.             switch( wParam )
  493.             {
  494.                 #ifndef PBT_APMQUERYSUSPEND
  495.                     #define PBT_APMQUERYSUSPEND 0x0000
  496.                 #endif
  497.                 case PBT_APMQUERYSUSPEND:
  498.                     // At this point, the app should save any data for open
  499.                     // network connections, files, etc., and prepare to go into
  500.                     // a suspended mode.
  501.                     return true;
  502.                 #ifndef PBT_APMRESUMESUSPEND
  503.                     #define PBT_APMRESUMESUSPEND 0x0007
  504.                 #endif
  505.                 case PBT_APMRESUMESUSPEND:
  506.                     // At this point, the app should recover any data, network
  507.                     // connections, files, etc., and resume running from when
  508.                     // the app was suspended.
  509.                     return true;
  510.             }
  511.             break;
  512.         case WM_SYSCOMMAND:
  513.             // Prevent moving/sizing and power loss in fullscreen mode
  514.             switch( wParam )
  515.             {
  516.                 case SC_MOVE:
  517.                 case SC_SIZE:
  518.                 case SC_MAXIMIZE:
  519.                 case SC_KEYMENU:
  520.                 case SC_MONITORPOWER:
  521.                     if( false == m_bWindowed )
  522.                         return 1;
  523.                     break;
  524.             }
  525.             break;
  526.         case WM_COMMAND:
  527.             switch( LOWORD(wParam) )
  528.             {
  529.                 case IDM_TOGGLESTART:
  530.                     // Toggle frame movement
  531.                     m_bFrameMoving = !m_bFrameMoving;
  532.                     DXUtil_Timer( m_bFrameMoving ? TIMER_START : TIMER_STOP );
  533.                     break;
  534.                 case IDM_SINGLESTEP:
  535.                     // Single-step frame movement
  536.                     if( false == m_bFrameMoving )
  537.                         DXUtil_Timer( TIMER_ADVANCE );
  538.                     else
  539.                         DXUtil_Timer( TIMER_STOP );
  540.                     m_bFrameMoving = false;
  541.                     m_bSingleStep  = true;
  542.                     break;
  543.                 case IDM_CHANGEDEVICE:
  544.                     // Prompt the user to select a new device or mode
  545.                     Pause(true);
  546.                     UserSelectNewDevice();
  547.                     Pause(false);
  548.                     return 0;
  549.                 case IDM_TOGGLEFULLSCREEN:
  550.                     // Toggle the fullscreen/window mode
  551.                     Pause( true );
  552.                     if( FAILED( ToggleFullscreen() ) )
  553.                         DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  554.                     Pause( false );                        
  555.                     return 0;
  556.                 case IDM_HELP:
  557.                     LaunchReadme();
  558.                     return 0;
  559.                 case IDM_EXIT:
  560.                     // Recieved key/menu command to exit app
  561.                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
  562.                     return 0;
  563.             }
  564.             break;
  565.         case WM_CLOSE:
  566.             Cleanup3DEnvironment();
  567.             SAFE_RELEASE( m_pD3D );
  568.             FinalCleanup();
  569.             HMENU hMenu;
  570.             hMenu = GetMenu(hWnd);
  571.             if( hMenu != NULL )
  572.                 DestroyMenu( hMenu );
  573.             DestroyWindow( hWnd );
  574.             PostQuitMessage(0);
  575.             m_hWnd = NULL;
  576.             return 0;
  577.     }
  578.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  579. }
  580. //-----------------------------------------------------------------------------
  581. // Name: HandlePossibleSizeChange()
  582. // Desc: Reset the device if the client area size has changed.
  583. //-----------------------------------------------------------------------------
  584. HRESULT CD3DApplication::HandlePossibleSizeChange()
  585. {
  586.     HRESULT hr = S_OK;
  587.     RECT rcClientOld;
  588.     rcClientOld = m_rcWindowClient;
  589.     if( m_bIgnoreSizeChange )
  590.         return S_OK;
  591.     // Update window properties
  592.     GetWindowRect( m_hWnd, &m_rcWindowBounds );
  593.     GetClientRect( m_hWnd, &m_rcWindowClient );
  594.     if( rcClientOld.right - rcClientOld.left !=
  595.         m_rcWindowClient.right - m_rcWindowClient.left ||
  596.         rcClientOld.bottom - rcClientOld.top !=
  597.         m_rcWindowClient.bottom - m_rcWindowClient.top)
  598.     {
  599.         // A new window size will require a new backbuffer
  600.         // size, so the 3D structures must be changed accordingly.
  601.         Pause( true );
  602.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  603.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  604.         m_d3dSettings.Windowed_Width = m_d3dpp.BackBufferWidth;
  605.         m_d3dSettings.Windowed_Height = m_d3dpp.BackBufferHeight;
  606.     
  607.         if( m_pd3dDevice != NULL )
  608.         {
  609.             // Reset the 3D environment
  610.             if( FAILED( hr = Reset3DEnvironment() ) )
  611.             {
  612.                 if( hr == D3DERR_DEVICELOST )
  613.                 {
  614.                     m_bDeviceLost = true;
  615.                     hr = S_OK;
  616.                 }
  617.                 else
  618.                 {
  619.                     if( hr != D3DERR_OUTOFVIDEOMEMORY )
  620.                         hr = D3DAPPERR_RESETFAILED;
  621.                     DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  622.                 }
  623.             }
  624.         }
  625.         Pause( false );
  626.     }
  627.     return hr;
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Name: Initialize3DEnvironment()
  631. // Desc: Usually this function is not overridden.  Here's what this function does:
  632. //       - Sets the windowed flag to be either windowed or fullscreen
  633. //       - Sets parameters for z-buffer depth and back buffer
  634. //       - Creates the D3D device
  635. //       - Sets the window position (if windowed, that is)
  636. //       - Makes some determinations as to the abilites of the driver (HAL, etc)
  637. //       - Sets up some cursor stuff
  638. //       - Calls InitDeviceObjects()
  639. //       - Calls RestoreDeviceObjects()
  640. //       - If all goes well, m_bActive is set to TRUE, and the function returns
  641. //       - Otherwise, initialization is reattempted using the reference device
  642. //-----------------------------------------------------------------------------
  643. HRESULT CD3DApplication::Initialize3DEnvironment()
  644. {
  645.     HRESULT hr;
  646.     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
  647.     D3DDeviceInfo* pDeviceInfo = m_d3dSettings.PDeviceInfo();
  648.     m_bWindowed = m_d3dSettings.IsWindowed;
  649.     // Prepare window for possible windowed/fullscreen change
  650.     AdjustWindowForChange();
  651.     // Set up the presentation parameters
  652.     BuildPresentParamsFromSettings();
  653.     if( pDeviceInfo->Caps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
  654.     {
  655.         // Warn user about null ref device that can't render anything
  656.         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
  657.     }
  658.     DWORD behaviorFlags;
  659.     if (m_d3dSettings.GetVertexProcessingType() == SOFTWARE_VP)
  660.         behaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  661.     else if (m_d3dSettings.GetVertexProcessingType() == MIXED_VP)
  662.         behaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
  663.     else if (m_d3dSettings.GetVertexProcessingType() == HARDWARE_VP)
  664.         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  665.     else if (m_d3dSettings.GetVertexProcessingType() == PURE_HARDWARE_VP)
  666.         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  667.     else
  668.         behaviorFlags = 0; // TODO: throw exception
  669.     // Add multithreaded flag if requested by app
  670.     if( m_bCreateMultithreadDevice )
  671.         behaviorFlags |= D3DCREATE_MULTITHREADED;
  672.     // Create the device
  673.     hr = m_pD3D->CreateDevice( m_d3dSettings.AdapterOrdinal(), pDeviceInfo->DevType,
  674.                                m_hWndFocus, behaviorFlags, &m_d3dpp,
  675.                                &m_pd3dDevice );
  676.     if( SUCCEEDED(hr) )
  677.     {
  678.         // When moving from fullscreen to windowed mode, it is important to
  679.         // adjust the window size after recreating the device rather than
  680.         // beforehand to ensure that you get the window size you want.  For
  681.         // example, when switching from 640x480 fullscreen to windowed with
  682.         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  683.         // the window size to 1000x600 until after the display mode has
  684.         // changed to 1024x768, because windows cannot be larger than the
  685.         // desktop.
  686.         if( m_bWindowed )
  687.         {
  688.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  689.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  690.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  691.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  692.                           SWP_SHOWWINDOW );
  693.         }
  694.         // Store device Caps
  695.         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
  696.         m_dwCreateFlags = behaviorFlags;
  697.         // Store device description
  698.         if( pDeviceInfo->DevType == D3DDEVTYPE_REF )
  699.             lstrcpy( m_strDeviceStats, TEXT("REF") );
  700.         else if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  701.             lstrcpy( m_strDeviceStats, TEXT("HAL") );
  702.         else if( pDeviceInfo->DevType == D3DDEVTYPE_SW )
  703.             lstrcpy( m_strDeviceStats, TEXT("SW") );
  704.         if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  705.             behaviorFlags & D3DCREATE_PUREDEVICE )
  706.         {
  707.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  708.                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
  709.             else
  710.                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
  711.         }
  712.         else if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  713.         {
  714.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  715.                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
  716.             else
  717.                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
  718.         }
  719.         else if( behaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
  720.         {
  721.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  722.                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
  723.             else
  724.                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
  725.         }
  726.         else if( behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  727.         {
  728.             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
  729.         }
  730.         if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  731.         {
  732.             // Be sure not to overflow m_strDeviceStats when appending the adapter 
  733.             // description, since it can be long.  Note that the adapter description
  734.             // is initially CHAR and must be converted to TCHAR.
  735.             lstrcat( m_strDeviceStats, TEXT(": ") );
  736.             const int cchDesc = sizeof(pAdapterInfo->AdapterIdentifier.Description);
  737.             TCHAR szDescription[cchDesc];
  738.             DXUtil_ConvertAnsiStringToGenericCch( szDescription, 
  739.                 pAdapterInfo->AdapterIdentifier.Description, cchDesc );
  740.             int maxAppend = sizeof(m_strDeviceStats) / sizeof(TCHAR) -
  741.                 lstrlen( m_strDeviceStats ) - 1;
  742.             _tcsncat( m_strDeviceStats, szDescription, maxAppend );
  743.         }
  744.         // Store render target surface desc
  745.         LPDIRECT3DSURFACE9 pBackBuffer = NULL;
  746.         m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  747.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  748.         pBackBuffer->Release();
  749.         // Set up the fullscreen cursor
  750.         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  751.         {
  752.             HCURSOR hCursor;
  753. #ifdef _WIN64
  754.             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  755. #else
  756.             hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
  757. #endif
  758.             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
  759.             m_pd3dDevice->ShowCursor( true );
  760.         }
  761.         // Confine cursor to fullscreen window
  762.         if( m_bClipCursorWhenFullscreen )
  763.         {
  764.             if (!m_bWindowed )
  765.             {
  766.                 RECT rcWindow;
  767.                 GetWindowRect( m_hWnd, &rcWindow );
  768.                 ClipCursor( &rcWindow );
  769.             }
  770.             else
  771.             {
  772.                 ClipCursor( NULL );
  773.             }
  774.         }
  775.         // Initialize the app's device-dependent objects
  776.         hr = InitDeviceObjects();
  777.         if( FAILED(hr) )
  778.         {
  779.             DeleteDeviceObjects();
  780.         }
  781.         else
  782.         {
  783.             m_bDeviceObjectsInited = true;
  784.             hr = RestoreDeviceObjects();
  785.             if( FAILED(hr) )
  786.             {
  787.                 InvalidateDeviceObjects();
  788.             }
  789.             else
  790.             {
  791.                 m_bDeviceObjectsRestored = true;
  792.                 return S_OK;
  793.             }
  794.         }
  795.         // Cleanup before we try again
  796.         Cleanup3DEnvironment();
  797.     }
  798.     // If that failed, fall back to the reference rasterizer
  799.     if( hr != D3DAPPERR_MEDIANOTFOUND && 
  800.         hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) && 
  801.         pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  802.     {
  803.         if (FindBestWindowedMode(false, true))
  804.         {
  805.             m_bWindowed = true;
  806.             AdjustWindowForChange();
  807.             // Make sure main window isn't topmost, so error message is visible
  808.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  809.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  810.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  811.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  812.                           SWP_SHOWWINDOW );
  813.             // Let the user know we are switching from HAL to the reference rasterizer
  814.             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
  815.             hr = Initialize3DEnvironment();
  816.         }
  817.     }
  818.     return hr;
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Name: BuildPresentParamsFromSettings()
  822. // Desc:
  823. //-----------------------------------------------------------------------------
  824. void CD3DApplication::BuildPresentParamsFromSettings()
  825. {
  826.     m_d3dpp.Windowed               = m_d3dSettings.IsWindowed;
  827.     m_d3dpp.BackBufferCount        = 1;
  828.     m_d3dpp.MultiSampleType        = m_d3dSettings.MultisampleType();
  829.     m_d3dpp.MultiSampleQuality     = m_d3dSettings.MultisampleQuality();
  830.     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
  831.     m_d3dpp.EnableAutoDepthStencil = m_d3dEnumeration.AppUsesDepthBuffer;
  832.     m_d3dpp.hDeviceWindow          = m_hWnd;
  833.     if( m_d3dEnumeration.AppUsesDepthBuffer )
  834.     {
  835.         m_d3dpp.Flags              = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  836.         m_d3dpp.AutoDepthStencilFormat = m_d3dSettings.DepthStencilBufferFormat();
  837.     }
  838.     else
  839.     {
  840.         m_d3dpp.Flags              = 0;
  841.     }
  842.     if ( m_d3dSettings.DeviceClip() )
  843.         m_d3dpp.Flags |= D3DPRESENTFLAG_DEVICECLIP;
  844.     if( m_bWindowed )
  845.     {
  846.         m_d3dpp.BackBufferWidth  = m_d3dSettings.Windowed_Width;
  847.         m_d3dpp.BackBufferHeight = m_d3dSettings.Windowed_Height;
  848.         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
  849.         m_d3dpp.FullScreen_RefreshRateInHz = 0;
  850.         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
  851.     }
  852.     else
  853.     {
  854.         m_d3dpp.BackBufferWidth  = m_d3dSettings.DisplayMode().Width;
  855.         m_d3dpp.BackBufferHeight = m_d3dSettings.DisplayMode().Height;
  856.         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
  857.         m_d3dpp.FullScreen_RefreshRateInHz = m_d3dSettings.Fullscreen_DisplayMode.RefreshRate;
  858.         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
  859.         if( m_bAllowDialogBoxMode )
  860.         {
  861.             // Make the back buffers lockable in fullscreen mode
  862.             // so we can show dialog boxes via SetDialogBoxMode() 
  863.             // but since lockable back buffers incur a performance cost on 
  864.             // some graphics hardware configurations we'll only 
  865.             // enable lockable backbuffers where SetDialogBoxMode() would work.
  866.             if ( (m_d3dpp.BackBufferFormat == D3DFMT_X1R5G5B5 || m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5 || m_d3dpp.BackBufferFormat == D3DFMT_X8R8G8B8 ) &&
  867.                 ( m_d3dpp.MultiSampleType == D3DMULTISAMPLE_NONE ) &&
  868.                 ( m_d3dpp.SwapEffect == D3DSWAPEFFECT_DISCARD ) )
  869.             {
  870.                 m_d3dpp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  871.             }
  872.         }
  873.     }
  874. }
  875. //-----------------------------------------------------------------------------
  876. // Name: Reset3DEnvironment()
  877. // Desc: Usually this function is not overridden.  Here's what this function does:
  878. //       - Sets the windowed flag to be either windowed or fullscreen
  879. //       - Sets parameters for z-buffer depth and back buffer
  880. //       - Creates the D3D device
  881. //       - Sets the window position (if windowed, that is)
  882. //       - Makes some determinations as to the abilites of the driver (HAL, etc)
  883. //       - Sets up some cursor stuff
  884. //       - Calls InitDeviceObjects()
  885. //       - Calls RestoreDeviceObjects()
  886. //       - If all goes well, m_bActive is set to TRUE, and the function returns
  887. //       - Otherwise, initialization is reattempted using the reference device
  888. //-----------------------------------------------------------------------------
  889. HRESULT CD3DApplication::Reset3DEnvironment()
  890. {
  891.     HRESULT hr;
  892.     // Release all vidmem objects
  893.     if( m_bDeviceObjectsRestored )
  894.     {
  895.         m_bDeviceObjectsRestored = false;
  896.         InvalidateDeviceObjects();
  897.     }
  898.     // Reset the device
  899.     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
  900.         return hr;
  901.     // Store render target surface desc
  902.     LPDIRECT3DSURFACE9 pBackBuffer;
  903.     m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  904.     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  905.     pBackBuffer->Release();
  906.     // Set up the fullscreen cursor
  907.     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  908.     {
  909.         HCURSOR hCursor;
  910. #ifdef _WIN64
  911.         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  912. #else
  913.         hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
  914. #endif
  915.         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
  916.         m_pd3dDevice->ShowCursor( true );
  917.     }
  918.     // Confine cursor to fullscreen window
  919.     if( m_bClipCursorWhenFullscreen )
  920.     {
  921.         if (!m_bWindowed )
  922.         {
  923.             RECT rcWindow;
  924.             GetWindowRect( m_hWnd, &rcWindow );
  925.             ClipCursor( &rcWindow );
  926.         }
  927.         else
  928.         {
  929.             ClipCursor( NULL );
  930.         }
  931.     }
  932.     // Initialize the app's device-dependent objects
  933.     hr = RestoreDeviceObjects();
  934.     if( FAILED(hr) )
  935.     {
  936.         InvalidateDeviceObjects();
  937.         return hr;
  938.     }
  939.     m_bDeviceObjectsRestored = true;
  940.     // If the app is paused, trigger the rendering of the current frame
  941.     if( false == m_bFrameMoving )
  942.     {
  943.         m_bSingleStep = true;
  944.         DXUtil_Timer( TIMER_START );
  945.         DXUtil_Timer( TIMER_STOP );
  946.     }
  947.     return S_OK;
  948. }
  949. //-----------------------------------------------------------------------------
  950. // Name: ToggleFullScreen()
  951. // Desc: Called when user toggles between fullscreen mode and windowed mode
  952. //-----------------------------------------------------------------------------
  953. HRESULT CD3DApplication::ToggleFullscreen()
  954. {
  955.     HRESULT hr;
  956.     int AdapterOrdinalOld = m_d3dSettings.AdapterOrdinal();
  957.     D3DDEVTYPE DevTypeOld = m_d3dSettings.DevType();
  958.     Pause( true );
  959.     m_bIgnoreSizeChange = true;
  960.     // Toggle the windowed state
  961.     m_bWindowed = !m_bWindowed;
  962.     m_d3dSettings.IsWindowed = m_bWindowed;
  963.     // Prepare window for windowed/fullscreen change
  964.     AdjustWindowForChange();
  965.     // If AdapterOrdinal and DevType are the same, we can just do a Reset().
  966.     // If they've changed, we need to do a complete device teardown/rebuild.
  967.     if (m_d3dSettings.AdapterOrdinal() == AdapterOrdinalOld &&
  968.         m_d3dSettings.DevType() == DevTypeOld)
  969.     {
  970.         // Reset the 3D device
  971.         BuildPresentParamsFromSettings();
  972.         hr = Reset3DEnvironment();
  973.     }
  974.     else
  975.     {
  976.         Cleanup3DEnvironment();
  977.         hr = Initialize3DEnvironment();
  978.     }
  979.     if( FAILED( hr ) )
  980.     {
  981.         if( hr != D3DERR_OUTOFVIDEOMEMORY )
  982.             hr = D3DAPPERR_RESETFAILED;
  983.         m_bIgnoreSizeChange = false;
  984.         if( !m_bWindowed )
  985.         {
  986.             // Restore window type to windowed mode
  987.             m_bWindowed = !m_bWindowed;
  988.             m_d3dSettings.IsWindowed = m_bWindowed;
  989.             AdjustWindowForChange();
  990.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  991.                         m_rcWindowBounds.left, m_rcWindowBounds.top,
  992.                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  993.                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  994.                         SWP_SHOWWINDOW );
  995.         }
  996.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  997.     }
  998.     m_bIgnoreSizeChange = false;
  999.     // When moving from fullscreen to windowed mode, it is important to
  1000.     // adjust the window size after resetting the device rather than
  1001.     // beforehand to ensure that you get the window size you want.  For
  1002.     // example, when switching from 640x480 fullscreen to windowed with
  1003.     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  1004.     // the window size to 1000x600 until after the display mode has
  1005.     // changed to 1024x768, because windows cannot be larger than the
  1006.     // desktop.
  1007.     if( m_bWindowed )
  1008.     {
  1009.         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1010.                       m_rcWindowBounds.left, m_rcWindowBounds.top,
  1011.                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1012.                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1013.                       SWP_SHOWWINDOW );
  1014.     }
  1015.     GetClientRect( m_hWnd, &m_rcWindowClient );  // Update our copy
  1016.     Pause( false );
  1017.     return S_OK;
  1018. }
  1019. //-----------------------------------------------------------------------------
  1020. // Name: ForceWindowed()
  1021. // Desc: Switch to a windowed mode, even if that means picking a new device
  1022. //       and/or adapter
  1023. //-----------------------------------------------------------------------------
  1024. HRESULT CD3DApplication::ForceWindowed()
  1025. {
  1026.     HRESULT hr;
  1027.     if( m_bWindowed )
  1028.         return S_OK;
  1029.     if( !FindBestWindowedMode(false, false) )
  1030.     {
  1031.         return E_FAIL;
  1032.     }
  1033.     m_bWindowed = true;
  1034.     // Now destroy the current 3D device objects, then reinitialize
  1035.     Pause( true );
  1036.     // Release all scene objects that will be re-created for the new device
  1037.     Cleanup3DEnvironment();
  1038.     // Create the new device
  1039.     if( FAILED(hr = Initialize3DEnvironment() ) )
  1040.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1041.     Pause( false );
  1042.     return S_OK;
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. // Name: AdjustWindowForChange()
  1046. // Desc: Prepare the window for a possible change between windowed mode and
  1047. //       fullscreen mode.  This function is virtual and thus can be overridden
  1048. //       to provide different behavior, such as switching to an entirely
  1049. //       different window for fullscreen mode (as in the MFC sample apps).
  1050. //-----------------------------------------------------------------------------
  1051. HRESULT CD3DApplication::AdjustWindowForChange()
  1052. {
  1053.     if( m_bWindowed )
  1054.     {
  1055.         // Set windowed-mode style
  1056.         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
  1057.         if( m_hMenu != NULL )
  1058.         {
  1059.             SetMenu( m_hWnd, m_hMenu );
  1060.             m_hMenu = NULL;
  1061.         }
  1062.     }
  1063.     else
  1064.     {
  1065.         // Set fullscreen-mode style
  1066.         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
  1067.         if( m_hMenu == NULL )
  1068.         {
  1069.             m_hMenu = GetMenu( m_hWnd );
  1070.             SetMenu( m_hWnd, NULL );
  1071.         }
  1072.     }
  1073.     return S_OK;
  1074. }
  1075. //-----------------------------------------------------------------------------
  1076. // Name: UserSelectNewDevice()
  1077. // Desc: Displays a dialog so the user can select a new adapter, device, or
  1078. //       display mode, and then recreates the 3D environment if needed
  1079. //-----------------------------------------------------------------------------
  1080. HRESULT CD3DApplication::UserSelectNewDevice()
  1081. {
  1082.     HRESULT hr;
  1083.     bool bDialogBoxMode = false;
  1084.     bool bOldWindowed = m_bWindowed;  // Preserve original windowed flag
  1085.     if( m_bWindowed == false )
  1086.     {
  1087.         // See if the current settings comply with the rules
  1088.         // for allowing SetDialogBoxMode().  
  1089.         if( (m_d3dpp.BackBufferFormat == D3DFMT_X1R5G5B5 || m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5 || m_d3dpp.BackBufferFormat == D3DFMT_X8R8G8B8 ) &&
  1090.             ( m_d3dpp.MultiSampleType == D3DMULTISAMPLE_NONE ) &&
  1091.             ( m_d3dpp.SwapEffect == D3DSWAPEFFECT_DISCARD ) &&
  1092.             ( (m_d3dpp.Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) == D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ) &&
  1093.             ( (m_dwCreateFlags & D3DCREATE_ADAPTERGROUP_DEVICE) != D3DCREATE_ADAPTERGROUP_DEVICE ) )
  1094.         {
  1095.             if( SUCCEEDED( m_pd3dDevice->SetDialogBoxMode( true ) ) )
  1096.                 bDialogBoxMode = true;
  1097.         }
  1098.         // If SetDialogBoxMode(true) didn't work then we can't display dialogs  
  1099.         // in fullscreen mode so we'll go back to windowed mode
  1100.         if( FALSE == bDialogBoxMode )
  1101.         {
  1102.             if( FAILED( ToggleFullscreen() ) )
  1103.             {
  1104.                 DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  1105.                 return E_FAIL;
  1106.             }
  1107.         }
  1108.     }
  1109.     // The dialog should use the mode the sample runs in, not
  1110.     // the mode that the dialog runs in.
  1111.     CD3DSettings tempSettings = m_d3dSettings;
  1112.     tempSettings.IsWindowed = bOldWindowed;
  1113.     CD3DSettingsDialog settingsDialog( &m_d3dEnumeration, &tempSettings);
  1114.     INT_PTR nResult = settingsDialog.ShowDialog( m_hWnd );
  1115.     // Before creating the device, switch back to SetDialogBoxMode(false) 
  1116.     // mode to allow the user to pick multisampling or backbuffer formats 
  1117.     // not supported by SetDialogBoxMode(true) but typical apps wouldn't 
  1118.     // need to switch back.
  1119.     if( bDialogBoxMode )
  1120.         m_pd3dDevice->SetDialogBoxMode( false );
  1121.     if( nResult != IDOK )
  1122.     {
  1123.         // If we had to switch mode to display the dialog, we
  1124.         // need to go back to the original mode the sample
  1125.         // was running in.
  1126.         if( bOldWindowed != m_bWindowed && FAILED( ToggleFullscreen() ) )
  1127.         {
  1128.             DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  1129.             return E_FAIL;
  1130.         }
  1131.         return S_OK;
  1132.     }
  1133.     settingsDialog.GetFinalSettings( &m_d3dSettings );
  1134.     m_bWindowed = m_d3dSettings.IsWindowed;
  1135.     // Release all scene objects that will be re-created for the new device
  1136.     Cleanup3DEnvironment();
  1137.     // Inform the display class of the change. It will internally
  1138.     // re-create valid surfaces, a d3ddevice, etc.
  1139.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1140.     {
  1141.         if( hr != D3DERR_OUTOFVIDEOMEMORY )
  1142.             hr = D3DAPPERR_RESETFAILED;
  1143.         if( !m_bWindowed )
  1144.         {
  1145.             // Restore window type to windowed mode
  1146.             m_bWindowed = !m_bWindowed;
  1147.             m_d3dSettings.IsWindowed = m_bWindowed;
  1148.             AdjustWindowForChange();
  1149.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1150.                         m_rcWindowBounds.left, m_rcWindowBounds.top,
  1151.                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1152.                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1153.                         SWP_SHOWWINDOW );
  1154.         }
  1155.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1156.     }
  1157.     // If the app is paused, trigger the rendering of the current frame
  1158.     if( false == m_bFrameMoving )
  1159.     {
  1160.         m_bSingleStep = true;
  1161.         DXUtil_Timer( TIMER_START );
  1162.         DXUtil_Timer( TIMER_STOP );
  1163.     }
  1164.     return S_OK;
  1165. }
  1166. //-----------------------------------------------------------------------------
  1167. // Name: Run()
  1168. // Desc: Here's what this function does:
  1169. //       - Runs through the message loop.  If no messages are waiting, then
  1170. //         it calls Render3DEnvironment().
  1171. //       - Messages are forwarded (through WndProc) to CD3DApplication::MsgProc()
  1172. //-----------------------------------------------------------------------------
  1173. INT CD3DApplication::Run()
  1174. {
  1175.     // Load keyboard accelerators
  1176.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  1177.     // Now we're ready to recieve and process Windows messages.
  1178.     HRESULT hr;
  1179.     bool bGotMsg;
  1180.     MSG  msg;
  1181.     msg.message = WM_NULL;
  1182.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  1183.     while( WM_QUIT != msg.message  )
  1184.     {
  1185.         // Use PeekMessage() if the app is active, so we can use idle time to
  1186.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  1187.         if( m_bActive )
  1188.             bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
  1189.         else
  1190.             bGotMsg = ( GetMessage( &msg, NULL, 0U, 0U ) != 0 );
  1191.         if( bGotMsg )
  1192.         {
  1193.             // Translate and dispatch the message
  1194.             if( hAccel == NULL || m_hWnd == NULL || 
  1195.                 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
  1196.             {
  1197.                 TranslateMessage( &msg );
  1198.                 DispatchMessage( &msg );
  1199.             }
  1200.         }
  1201.         else
  1202.         {
  1203.             if( m_bDeviceLost )
  1204.             {
  1205.                 // Yield some CPU time to other processes
  1206.                 Sleep( 100 ); // 100 milliseconds
  1207.             }
  1208.             // Render a frame during idle time (no messages are waiting)
  1209.             if( m_bActive )
  1210.             {
  1211.                 if( FAILED( hr = Render3DEnvironment() ) )
  1212.                     DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1213.             }
  1214.         }
  1215.     }
  1216.     if( hAccel != NULL )
  1217.         DestroyAcceleratorTable( hAccel );
  1218.     return (INT)msg.wParam;
  1219. }
  1220. //-----------------------------------------------------------------------------
  1221. // Name: Render3DEnvironment()
  1222. // Desc: Here's what this function does:
  1223. //       - Checks to make sure app is still active (if fullscreen, etc)
  1224. //       - Checks to see if it is time to draw with DXUtil_Timer, if not, it just returns S_OK
  1225. //       - Calls FrameMove() to recalculate new positions
  1226. //       - Calls Render() to draw the new frame
  1227. //       - Updates some frame count statistics
  1228. //       - Calls m_pd3dDevice->Present() to display the rendered frame.
  1229. //-----------------------------------------------------------------------------
  1230. HRESULT CD3DApplication::Render3DEnvironment()
  1231. {
  1232.     HRESULT hr;
  1233.     if( m_bDeviceLost )
  1234.     {
  1235.         // Test the cooperative level to see if it's okay to render
  1236.         if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  1237.         {
  1238.             // If the device was lost, do not render until we get it back
  1239.             if( D3DERR_DEVICELOST == hr )
  1240.                 return S_OK;
  1241.             // Check if the device needs to be reset.
  1242.             if( D3DERR_DEVICENOTRESET == hr )
  1243.             {
  1244.                 // If we are windowed, read the desktop mode and use the same format for
  1245.                 // the back buffer
  1246.                 if( m_bWindowed )
  1247.                 {
  1248.                     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
  1249.                     m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &m_d3dSettings.Windowed_DisplayMode );
  1250.                     m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
  1251.                 }
  1252.                 if( FAILED( hr = Reset3DEnvironment() ) )
  1253.                     return DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  1254.             }
  1255.             return hr;
  1256.         }
  1257.         m_bDeviceLost = false;
  1258.     }
  1259.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  1260.     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  1261.     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  1262.     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
  1263.         return S_OK;
  1264.     // FrameMove (animate) the scene
  1265.     if( m_bFrameMoving || m_bSingleStep )
  1266.     {
  1267.         // Store the time for the app
  1268.         m_fTime        = fAppTime;
  1269.         m_fElapsedTime = fElapsedAppTime;
  1270.         // Frame move the scene
  1271.         if( FAILED( hr = FrameMove() ) )
  1272.             return hr;
  1273.         m_bSingleStep = false;
  1274.     } else
  1275.         m_fElapsedTime = fElapsedAppTime;
  1276.     // Render the scene as normal
  1277.     if( FAILED( hr = Render() ) )
  1278.         return hr;
  1279.     UpdateStats();
  1280.     // Show the frame on the primary surface.
  1281.     hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1282.     if( D3DERR_DEVICELOST == hr )
  1283.         m_bDeviceLost = true;
  1284.     return S_OK;
  1285. }
  1286. //-----------------------------------------------------------------------------
  1287. // Name: UpdateStats()
  1288. // Desc: 
  1289. //-----------------------------------------------------------------------------
  1290. void CD3DApplication::UpdateStats()
  1291. {
  1292.     // Keep track of the frame count
  1293.     static FLOAT fLastTime = 0.0f;
  1294.     static DWORD dwFrames  = 0;
  1295.     FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  1296.     ++dwFrames;
  1297.     // Update the scene stats once per second
  1298.     if( fTime - fLastTime > 1.0f )
  1299.     {
  1300.         m_fFPS    = dwFrames / (fTime - fLastTime);
  1301.         fLastTime = fTime;
  1302.         dwFrames  = 0;
  1303.         TCHAR strFmt[100];
  1304.         D3DFORMAT fmtAdapter = m_d3dSettings.DisplayMode().Format;
  1305.         if( fmtAdapter == m_d3dsdBackBuffer.Format )
  1306.         {
  1307.             lstrcpyn( strFmt, D3DUtil_D3DFormatToString( fmtAdapter, false ), 100 );
  1308.         }
  1309.         else
  1310.         {
  1311.             _sntprintf( strFmt, 100, TEXT("backbuf %s, adapter %s"), 
  1312.                 D3DUtil_D3DFormatToString( m_d3dsdBackBuffer.Format, false ), 
  1313.                 D3DUtil_D3DFormatToString( fmtAdapter, false ) );
  1314.         }
  1315.         strFmt[99] = TEXT('');
  1316.         TCHAR strDepthFmt[100];
  1317.         if( m_d3dEnumeration.AppUsesDepthBuffer )
  1318.         {
  1319.             _sntprintf( strDepthFmt, 100, TEXT(" (%s)"), 
  1320.                 D3DUtil_D3DFormatToString( m_d3dSettings.DepthStencilBufferFormat(), false ) );
  1321.             strDepthFmt[99] = TEXT('');
  1322.         }
  1323.         else
  1324.         {
  1325.             // No depth buffer
  1326.             strDepthFmt[0] = TEXT('');
  1327.         }
  1328.         TCHAR* pstrMultiSample;
  1329.         switch( m_d3dSettings.MultisampleType() )
  1330.         {
  1331.         case D3DMULTISAMPLE_NONMASKABLE:  pstrMultiSample = TEXT(" (Nonmaskable Multisample)"); break;
  1332.         case D3DMULTISAMPLE_2_SAMPLES:  pstrMultiSample = TEXT(" (2x Multisample)"); break;
  1333.         case D3DMULTISAMPLE_3_SAMPLES:  pstrMultiSample = TEXT(" (3x Multisample)"); break;
  1334.         case D3DMULTISAMPLE_4_SAMPLES:  pstrMultiSample = TEXT(" (4x Multisample)"); break;
  1335.         case D3DMULTISAMPLE_5_SAMPLES:  pstrMultiSample = TEXT(" (5x Multisample)"); break;
  1336.         case D3DMULTISAMPLE_6_SAMPLES:  pstrMultiSample = TEXT(" (6x Multisample)"); break;
  1337.         case D3DMULTISAMPLE_7_SAMPLES:  pstrMultiSample = TEXT(" (7x Multisample)"); break;
  1338.         case D3DMULTISAMPLE_8_SAMPLES:  pstrMultiSample = TEXT(" (8x Multisample)"); break;
  1339.         case D3DMULTISAMPLE_9_SAMPLES:  pstrMultiSample = TEXT(" (9x Multisample)"); break;
  1340.         case D3DMULTISAMPLE_10_SAMPLES: pstrMultiSample = TEXT(" (10x Multisample)"); break;
  1341.         case D3DMULTISAMPLE_11_SAMPLES: pstrMultiSample = TEXT(" (11x Multisample)"); break;
  1342.         case D3DMULTISAMPLE_12_SAMPLES: pstrMultiSample = TEXT(" (12x Multisample)"); break;
  1343.         case D3DMULTISAMPLE_13_SAMPLES: pstrMultiSample = TEXT(" (13x Multisample)"); break;
  1344.         case D3DMULTISAMPLE_14_SAMPLES: pstrMultiSample = TEXT(" (14x Multisample)"); break;
  1345.         case D3DMULTISAMPLE_15_SAMPLES: pstrMultiSample = TEXT(" (15x Multisample)"); break;
  1346.         case D3DMULTISAMPLE_16_SAMPLES: pstrMultiSample = TEXT(" (16x Multisample)"); break;
  1347.         default:                        pstrMultiSample = TEXT(""); break;
  1348.         }
  1349.         const int cchMaxFrameStats = sizeof(m_strFrameStats) / sizeof(TCHAR);
  1350.         _sntprintf( m_strFrameStats, cchMaxFrameStats, _T("%.02f fps (%dx%d), %s%s%s"), m_fFPS,
  1351.                     m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
  1352.                     strFmt, strDepthFmt, pstrMultiSample );
  1353.         m_strFrameStats[cchMaxFrameStats - 1] = TEXT('');
  1354.     }
  1355. }
  1356. //-----------------------------------------------------------------------------
  1357. // Name: Pause()
  1358. // Desc: Called in to toggle the pause state of the app.
  1359. //-----------------------------------------------------------------------------
  1360. void CD3DApplication::Pause( bool bPause )
  1361. {
  1362.     static DWORD dwAppPausedCount = 0;
  1363.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1364.     m_bActive         = ( dwAppPausedCount ? false : true );
  1365.     // Handle the first pause request (of many, nestable pause requests)
  1366.     if( bPause && ( 1 == dwAppPausedCount ) )
  1367.     {
  1368.         // Stop the scene from animating
  1369.         if( m_bFrameMoving )
  1370.             DXUtil_Timer( TIMER_STOP );
  1371.     }
  1372.     if( 0 == dwAppPausedCount )
  1373.     {
  1374.         // Restart the timers
  1375.         if( m_bFrameMoving )
  1376.             DXUtil_Timer( TIMER_START );
  1377.     }
  1378. }
  1379. //-----------------------------------------------------------------------------
  1380. // Name: Cleanup3DEnvironment()
  1381. // Desc: Cleanup scene objects
  1382. //-----------------------------------------------------------------------------
  1383. void CD3DApplication::Cleanup3DEnvironment()
  1384. {
  1385.     if( m_pd3dDevice != NULL )
  1386.     {
  1387.         if( m_bDeviceObjectsRestored )
  1388.         {
  1389.             m_bDeviceObjectsRestored = false;
  1390.             InvalidateDeviceObjects();
  1391.         }
  1392.         if( m_bDeviceObjectsInited )
  1393.         {
  1394.             m_bDeviceObjectsInited = false;
  1395.             DeleteDeviceObjects();
  1396.         }
  1397.         if( m_pd3dDevice->Release() > 0 )
  1398.             DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1399.         m_pd3dDevice = NULL;
  1400.     }
  1401. }
  1402. //-----------------------------------------------------------------------------
  1403. // Name: DisplayErrorMsg()
  1404. // Desc: Displays error messages in a message box
  1405. //-----------------------------------------------------------------------------
  1406. HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  1407. {
  1408.     static bool s_bFatalErrorReported = false;
  1409.     TCHAR strMsg[512];
  1410.     // If a fatal error message has already been reported, the app
  1411.     // is already shutting down, so don't show more error messages.
  1412.     if( s_bFatalErrorReported )
  1413.         return hr;
  1414.     switch( hr )
  1415.     {
  1416.         case D3DAPPERR_NODIRECT3D:
  1417.             _tcscpy( strMsg, _T("Could not initialize Direct3D. You mayn")
  1418.                              _T("want to check that the latest version ofn")
  1419.                              _T("DirectX is correctly installed on yourn")
  1420.                              _T("system.  Also make sure that this programn")
  1421.                              _T("was compiled with header files that matchn")
  1422.                              _T("the installed DirectX DLLs.") );
  1423.             break;
  1424.         case D3DAPPERR_NOCOMPATIBLEDEVICES:
  1425.             _tcscpy( strMsg, _T("Could not find any compatible Direct3Dn")
  1426.                              _T("devices.") );
  1427.             break;
  1428.         case D3DAPPERR_NOWINDOWABLEDEVICES:
  1429.             _tcscpy( strMsg, _T("This sample cannot run in a desktopn")
  1430.                              _T("window with the current display settings.n")
  1431.                              _T("Please change your desktop settings to an")
  1432.                              _T("16- or 32-bit display mode and re-run thisn")
  1433.                              _T("sample.") );
  1434.             break;
  1435.         case D3DAPPERR_NOHARDWAREDEVICE:
  1436.             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devicesn")
  1437.                              _T("were found.") );
  1438.             break;
  1439.         case D3DAPPERR_HALNOTCOMPATIBLE:
  1440.             _tcscpy( strMsg, _T("This sample requires functionality that isn")
  1441.                              _T("not available on your Direct3D hardwaren")
  1442.                              _T("accelerator.") );
  1443.             break;
  1444.         case D3DAPPERR_NOWINDOWEDHAL:
  1445.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannotn")
  1446.                              _T("render into a window.n")
  1447.                              _T("Press F2 while the app is running to see an")
  1448.                              _T("list of available devices and modes.") );
  1449.             break;
  1450.         case D3DAPPERR_NODESKTOPHAL:
  1451.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannotn")
  1452.                              _T("render into a window with the currentn")
  1453.                              _T("desktop display settings.n")
  1454.                              _T("Press F2 while the app is running to see an")
  1455.                              _T("list of available devices and modes.") );
  1456.             break;
  1457.         case D3DAPPERR_NOHALTHISMODE:
  1458.             _tcscpy( strMsg, _T("This sample requires functionality that isn")
  1459.                              _T("not available on your Direct3D hardwaren")
  1460.                              _T("accelerator with the current desktop displayn")
  1461.                              _T("settings.n")
  1462.                              _T("Press F2 while the app is running to see an")
  1463.                              _T("list of available devices and modes.") );
  1464.             break;
  1465.         case D3DAPPERR_MEDIANOTFOUND:
  1466.         case 0x80070002: // HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
  1467.             _tcscpy( strMsg, _T("Could not load required media." ) );
  1468.             break;
  1469.         case D3DAPPERR_RESETFAILED:
  1470.             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
  1471.             break;
  1472.         case D3DAPPERR_NONZEROREFCOUNT:
  1473.             _tcscpy( strMsg, _T("A D3D object has a non-zero referencen")
  1474.                              _T("count (meaning things were not properlyn")
  1475.                              _T("cleaned up).") );
  1476.             break;
  1477.         case D3DAPPERR_NULLREFDEVICE:
  1478.             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.n")
  1479.                              _T("The reference rendering device was selected, but yourn")
  1480.                              _T("computer only has a reduced-functionality reference devicen")
  1481.                              _T("installed.  Install the DirectX SDK to get the fulln")
  1482.                              _T("reference device.n") );
  1483.             break;
  1484.         case E_OUTOFMEMORY:
  1485.             _tcscpy( strMsg, _T("Not enough memory.") );
  1486.             break;
  1487.         case D3DERR_OUTOFVIDEOMEMORY:
  1488.             _tcscpy( strMsg, _T("Not enough video memory.") );
  1489.             break;
  1490.         case D3DERR_DRIVERINTERNALERROR:
  1491.             _tcscpy( strMsg, _T("A serious problem occured inside the display driver.") );
  1492.             dwType = MSGERR_APPMUSTEXIT;
  1493.             break;
  1494.         default:
  1495.             _tcscpy( strMsg, _T("Generic application error. Enablen")
  1496.                              _T("debug output for detailed information.") );
  1497.     }
  1498.     if( MSGERR_APPMUSTEXIT == dwType )
  1499.     {
  1500.         s_bFatalErrorReported = true;
  1501.         _tcscat( strMsg, _T("nnThis sample will now exit.") );
  1502.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
  1503.         // Close the window, which shuts down the app
  1504.         if( m_hWnd )
  1505.             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1506.     }
  1507.     else
  1508.     {
  1509.         if( MSGWARN_SWITCHEDTOREF == dwType )
  1510.             _tcscat( strMsg, _T("nnSwitching to the reference rasterizer,n")
  1511.                              _T("a software device that implements the entiren")
  1512.                              _T("Direct3D feature set, but runs very slowly.") );
  1513.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
  1514.     }
  1515.     return hr;
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. // Name: LaunchReadme()
  1519. // Desc: Ensures the app is windowed, and launches the readme.txt 
  1520. //       in the default text editor
  1521. //-----------------------------------------------------------------------------
  1522. HRESULT CD3DApplication::LaunchReadme()
  1523. {
  1524.     // Switch to windowed if launching the readme.txt
  1525.     if( m_bWindowed == false )
  1526.     {
  1527.         if( FAILED( ToggleFullscreen() ) )
  1528.         {
  1529.             DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  1530.             return E_FAIL;
  1531.         }
  1532.     }
  1533.     DXUtil_LaunchReadme( m_hWnd );
  1534.     return S_OK;
  1535. }