home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / D3DAPP.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  72.7 KB  |  1,998 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DApp.cpp
  3. //
  4. // Desc: Application class for the Direct3D samples framework library.
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DLG)
  8. #include "stdafx.h"
  9. $$ENDIF
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include <basetsd.h>
  13. #include <mmsystem.h>
  14. #include <stdio.h>
  15. #include <tchar.h>
  16. #include <D3D8.h>
  17. #include "D3DApp.h"
  18. #include "D3DUtil.h"
  19. #include "DXUtil.h"
  20. #include "D3DRes.h"
  21.  
  22.  
  23.  
  24.  
  25. //-----------------------------------------------------------------------------
  26. // Global access to the app (needed for the global WndProc())
  27. //-----------------------------------------------------------------------------
  28. static CD3DApplication* g_pD3DApp = NULL;
  29.  
  30.  
  31.  
  32.  
  33. //-----------------------------------------------------------------------------
  34. // Name: CD3DApplication()
  35. // Desc: Constructor
  36. //-----------------------------------------------------------------------------
  37. CD3DApplication::CD3DApplication()
  38. {
  39.     g_pD3DApp           = this;
  40.  
  41.     m_dwNumAdapters     = 0;
  42.     m_dwAdapter         = 0L;
  43.     m_pD3D              = NULL;
  44.     m_pd3dDevice        = NULL;
  45.     m_hWnd              = NULL;
  46.     m_hWndFocus         = NULL;
  47.     m_bActive           = FALSE;
  48.     m_bReady            = FALSE;
  49.     m_bHasFocus        = FALSE;
  50.     m_dwCreateFlags     = 0L;
  51.  
  52.     m_bFrameMoving      = TRUE;
  53.     m_bSingleStep       = FALSE;
  54.     m_fFPS              = 0.0f;
  55.     m_strDeviceStats[0] = _T('\0');
  56.     m_strFrameStats[0]  = _T('\0');
  57.  
  58.     m_strWindowTitle    = _T("D3D8 Application");
  59.     m_dwCreationWidth   = 400;
  60.     m_dwCreationHeight  = 300;
  61.     m_bUseDepthBuffer   = FALSE;
  62.     m_dwMinDepthBits    = 16;
  63.     m_dwMinStencilBits  = 0;
  64.     m_bShowCursorWhenFullscreen = FALSE;
  65.  
  66.     // When m_bClipCursorWhenFullscreen is TRUE, the cursor is limited to
  67.     // the device window when the app goes fullscreen.  This prevents users
  68.     // from accidentally clicking outside the app window on a multimon system.
  69.     // This flag is turned off by default for debug builds, since it makes 
  70.     // multimon debugging difficult.
  71. #if defined(_DEBUG) || defined(DEBUG)
  72.     m_bClipCursorWhenFullscreen = FALSE;
  73. #else
  74.     m_bClipCursorWhenFullscreen = TRUE;
  75. #endif
  76. }
  77.  
  78.  
  79.  
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Name: WndProc()
  83. // Desc: Static msg handler which passes messages to the application class.
  84. //-----------------------------------------------------------------------------
  85. LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  86. {
  87.     return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
  88. }
  89.  
  90.  
  91.  
  92.  
  93. //-----------------------------------------------------------------------------
  94. // Name: Create()
  95. // Desc:
  96. //-----------------------------------------------------------------------------
  97. HRESULT CD3DApplication::Create( HINSTANCE hInstance )
  98. {
  99.     HRESULT hr;
  100.  
  101.     // Create the Direct3D object
  102.     m_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
  103.     if( m_pD3D == NULL )
  104.         return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
  105.  
  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.     if( FAILED( hr = BuildDeviceList() ) )
  110.     {
  111.         SAFE_RELEASE( m_pD3D );
  112.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  113.     }
  114.  
  115.     // Unless a substitute hWnd has been specified, create a window to
  116.     // render into
  117.     if( m_hWnd == NULL)
  118.     {
  119.         // Register the windows class
  120.         WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
  121.                               LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
  122.                               LoadCursor( NULL, IDC_ARROW ),
  123.                               (HBRUSH)GetStockObject(WHITE_BRUSH),
  124.                               NULL, _T("D3D Window") };
  125.         RegisterClass( &wndClass );
  126.  
  127.         // Set the window's initial style
  128.         m_dwWindowStyle = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|
  129.                           WS_MINIMIZEBOX|WS_VISIBLE;
  130.  
  131.         // Set the window's initial width
  132.         RECT rc;
  133.         SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
  134.         AdjustWindowRect( &rc, m_dwWindowStyle, TRUE );
  135.  
  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), 0L,
  140.                                LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ),
  141.                                hInstance, 0L );
  142.     }
  143.  
  144.     // The focus window can be a specified to be a different window than the
  145.     // device window.  If not, use the device window as the focus window.
  146.     if( m_hWndFocus == NULL )
  147.         m_hWndFocus = m_hWnd;
  148.  
  149.     // Save window properties
  150.     m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  151.     GetWindowRect( m_hWnd, &m_rcWindowBounds );
  152.     GetClientRect( m_hWnd, &m_rcWindowClient );
  153.  
  154.     // Initialize the application timer
  155.     DXUtil_Timer( TIMER_START );
  156.  
  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.  
  164.     // Initialize the 3D environment for the app
  165.     if( FAILED( hr = Initialize3DEnvironment() ) )
  166.     {
  167.         SAFE_RELEASE( m_pD3D );
  168.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  169.     }
  170.  
  171.     // The app is ready to go
  172.     m_bReady = TRUE;
  173.  
  174.     return S_OK;
  175. }
  176.  
  177.  
  178.  
  179.  
  180. //-----------------------------------------------------------------------------
  181. // Name: SortModesCallback()
  182. // Desc: Callback function for sorting display modes (used by BuildDeviceList).
  183. //-----------------------------------------------------------------------------
  184. static int SortModesCallback( const VOID* arg1, const VOID* arg2 )
  185. {
  186.     D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
  187.     D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
  188.  
  189.     if( p1->Format > p2->Format )   return -1;
  190.     if( p1->Format < p2->Format )   return +1;
  191.     if( p1->Width  < p2->Width )    return -1;
  192.     if( p1->Width  > p2->Width )    return +1;
  193.     if( p1->Height < p2->Height )   return -1;
  194.     if( p1->Height > p2->Height )   return +1;
  195.  
  196.     return 0;
  197. }
  198.  
  199.  
  200.  
  201.  
  202. //-----------------------------------------------------------------------------
  203. // Name: BuildDeviceList()
  204. // Desc:
  205. //-----------------------------------------------------------------------------
  206. HRESULT CD3DApplication::BuildDeviceList()
  207. {
  208.     const DWORD dwNumDeviceTypes = 2;
  209.     const TCHAR* strDeviceDescs[] = { _T("HAL"), _T("REF") };
  210.     const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF };
  211.  
  212.     BOOL bHALExists = FALSE;
  213.     BOOL bHALIsWindowedCompatible = FALSE;
  214.     BOOL bHALIsDesktopCompatible = FALSE;
  215.     BOOL bHALIsSampleCompatible = FALSE;
  216.  
  217.     // Loop through all the adapters on the system (usually, there's just one
  218.     // unless more than one graphics card is present).
  219.     for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
  220.     {
  221.         // Fill in adapter info
  222.         D3DAdapterInfo* pAdapter  = &m_Adapters[m_dwNumAdapters];
  223.         m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier );
  224.         m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
  225.         pAdapter->dwNumDevices    = 0;
  226.         pAdapter->dwCurrentDevice = 0;
  227.  
  228.         // Enumerate all display modes on this adapter
  229.         D3DDISPLAYMODE modes[100];
  230.         D3DFORMAT      formats[20];
  231.         DWORD dwNumFormats      = 0;
  232.         DWORD dwNumModes        = 0;
  233.         DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter );
  234.  
  235.         // Add the adapter's current desktop format to the list of formats
  236.         formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
  237.  
  238.         for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
  239.         {
  240.             // Get the display mode attributes
  241.             D3DDISPLAYMODE DisplayMode;
  242.             m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode );
  243.  
  244.             // Filter out low-resolution modes
  245.             if( DisplayMode.Width  < 640 || DisplayMode.Height < 400 )
  246.                 continue;
  247.  
  248.             // Check if the mode already exists (to filter out refresh rates)
  249.             for( DWORD m=0L; m<dwNumModes; m++ )
  250.             {
  251.                 if( ( modes[m].Width  == DisplayMode.Width  ) &&
  252.                     ( modes[m].Height == DisplayMode.Height ) &&
  253.                     ( modes[m].Format == DisplayMode.Format ) )
  254.                     break;
  255.             }
  256.  
  257.             // If we found a new mode, add it to the list of modes
  258.             if( m == dwNumModes )
  259.             {
  260.                 modes[dwNumModes].Width       = DisplayMode.Width;
  261.                 modes[dwNumModes].Height      = DisplayMode.Height;
  262.                 modes[dwNumModes].Format      = DisplayMode.Format;
  263.                 modes[dwNumModes].RefreshRate = 0;
  264.                 dwNumModes++;
  265.  
  266.                 // Check if the mode's format already exists
  267.                 for( DWORD f=0; f<dwNumFormats; f++ )
  268.                 {
  269.                     if( DisplayMode.Format == formats[f] )
  270.                         break;
  271.                 }
  272.  
  273.                 // If the format is new, add it to the list
  274.                 if( f== dwNumFormats )
  275.                     formats[dwNumFormats++] = DisplayMode.Format;
  276.             }
  277.         }
  278.  
  279.         // Sort the list of display modes (by format, then width, then height)
  280.         qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
  281.  
  282.         // Add devices to adapter
  283.         for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
  284.         {
  285.             // Fill in device info
  286.             D3DDeviceInfo* pDevice;
  287.             pDevice                 = &pAdapter->devices[pAdapter->dwNumDevices];
  288.             pDevice->DeviceType     = DeviceTypes[iDevice];
  289.             m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
  290.             pDevice->strDesc        = strDeviceDescs[iDevice];
  291.             pDevice->dwNumModes     = 0;
  292.             pDevice->dwCurrentMode  = 0;
  293.             pDevice->bCanDoWindowed = FALSE;
  294.             pDevice->bWindowed      = FALSE;
  295.             pDevice->MultiSampleTypeFullscreen = D3DMULTISAMPLE_NONE;
  296.             pDevice->MultiSampleTypeWindowed = D3DMULTISAMPLE_NONE;
  297.  
  298.             // Examine each format supported by the adapter to see if it will
  299.             // work with this device and meets the needs of the application.
  300.             BOOL  bFormatConfirmed[20];
  301.             DWORD dwBehavior[20];
  302.             D3DFORMAT fmtDepthStencil[20];
  303.  
  304.             for( DWORD f=0; f<dwNumFormats; f++ )
  305.             {
  306.                 bFormatConfirmed[f] = FALSE;
  307.                 fmtDepthStencil[f] = D3DFMT_UNKNOWN;
  308.  
  309.                 // Skip formats that cannot be used as render targets on this device
  310.                 if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
  311.                                                      formats[f], formats[f], FALSE ) ) )
  312.                     continue;
  313.  
  314.                 if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  315.                 {
  316.                     // This system has a HAL device
  317.                     bHALExists = TRUE;
  318.  
  319.                     if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED )
  320.                     {
  321.                         // HAL can run in a window for some mode
  322.                         bHALIsWindowedCompatible = TRUE;
  323.  
  324.                         if( f == 0 )
  325.                         {
  326.                             // HAL can run in a window for the current desktop mode
  327.                             bHALIsDesktopCompatible = TRUE;
  328.                         }
  329.                     }
  330.                 }
  331.  
  332.                 // Confirm the device/format for HW vertex processing
  333.                 if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  334.                 {
  335.                     if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  336.                     {
  337.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  338.                                         D3DCREATE_PUREDEVICE;
  339.  
  340.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  341.                                                       formats[f] ) ) )
  342.                             bFormatConfirmed[f] = TRUE;
  343.                     }
  344.  
  345.                     if ( FALSE == bFormatConfirmed[f] )
  346.                     {
  347.                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  348.  
  349.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  350.                                                       formats[f] ) ) )
  351.                             bFormatConfirmed[f] = TRUE;
  352.                     }
  353.  
  354.                     if ( FALSE == bFormatConfirmed[f] )
  355.                     {
  356.                         dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
  357.  
  358.                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  359.                                                       formats[f] ) ) )
  360.                             bFormatConfirmed[f] = TRUE;
  361.                     }
  362.                 }
  363.  
  364.                 // Confirm the device/format for SW vertex processing
  365.                 if( FALSE == bFormatConfirmed[f] )
  366.                 {
  367.                     dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  368.  
  369.                     if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  370.                                                   formats[f] ) ) )
  371.                         bFormatConfirmed[f] = TRUE;
  372.                 }
  373.  
  374.                 // Find a suitable depth/stencil buffer format for this device/format
  375.                 if( bFormatConfirmed[f] && m_bUseDepthBuffer )
  376.                 {
  377.                     if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
  378.                         formats[f], &fmtDepthStencil[f] ) )
  379.                     {
  380.                         bFormatConfirmed[f] = FALSE;
  381.                     }
  382.                 }
  383.             }
  384.  
  385.             // Add all enumerated display modes with confirmed formats to the
  386.             // device's list of valid modes
  387.             for( DWORD m=0L; m<dwNumModes; m++ )
  388.             {
  389.                 for( DWORD f=0; f<dwNumFormats; f++ )
  390.                 {
  391.                     if( modes[m].Format == formats[f] )
  392.                     {
  393.                         if( bFormatConfirmed[f] == TRUE )
  394.                         {
  395.                             // Add this mode to the device's list of valid modes
  396.                             pDevice->modes[pDevice->dwNumModes].Width      = modes[m].Width;
  397.                             pDevice->modes[pDevice->dwNumModes].Height     = modes[m].Height;
  398.                             pDevice->modes[pDevice->dwNumModes].Format     = modes[m].Format;
  399.                             pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
  400.                             pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
  401.                             pDevice->dwNumModes++;
  402.  
  403.                             if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  404.                                 bHALIsSampleCompatible = TRUE;
  405.                         }
  406.                     }
  407.                 }
  408.             }
  409.  
  410.             // Select any 640x480 mode for default (but prefer a 16-bit mode)
  411.             for( m=0; m<pDevice->dwNumModes; m++ )
  412.             {
  413.                 if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
  414.                 {
  415.                     pDevice->dwCurrentMode = m;
  416.                     if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
  417.                         pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
  418.                         pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
  419.                     {
  420.                         break;
  421.                     }
  422.                 }
  423.             }
  424.  
  425.             // Check if the device is compatible with the desktop display mode
  426.             // (which was added initially as formats[0])
  427.             if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) )
  428.             {
  429.                 pDevice->bCanDoWindowed = TRUE;
  430.                 pDevice->bWindowed      = TRUE;
  431.             }
  432.  
  433.             // If valid modes were found, keep this device
  434.             if( pDevice->dwNumModes > 0 )
  435.                 pAdapter->dwNumDevices++;
  436.         }
  437.  
  438.         // If valid devices were found, keep this adapter
  439.         if( pAdapter->dwNumDevices > 0 )
  440.             m_dwNumAdapters++;
  441.     }
  442.  
  443.     // Return an error if no compatible devices were found
  444.     if( 0L == m_dwNumAdapters )
  445.         return D3DAPPERR_NOCOMPATIBLEDEVICES;
  446.  
  447.     // Pick a default device that can render into a window
  448.     // (This code assumes that the HAL device comes before the REF
  449.     // device in the device array).
  450.     for( DWORD a=0; a<m_dwNumAdapters; a++ )
  451.     {
  452.         for( DWORD d=0; d < m_Adapters[a].dwNumDevices; d++ )
  453.         {
  454.             if( m_Adapters[a].devices[d].bWindowed )
  455.             {
  456.                 m_Adapters[a].dwCurrentDevice = d;
  457.                 m_dwAdapter = a;
  458.                 m_bWindowed = TRUE;
  459.  
  460.                 // Display a warning message
  461.                 if( m_Adapters[a].devices[d].DeviceType == D3DDEVTYPE_REF )
  462.                 {
  463.                     if( !bHALExists )
  464.                         DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
  465.                     else if( !bHALIsSampleCompatible )
  466.                         DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
  467.                     else if( !bHALIsWindowedCompatible )
  468.                         DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
  469.                     else if( !bHALIsDesktopCompatible )
  470.                         DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
  471.                     else // HAL is desktop compatible, but not sample compatible
  472.                         DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
  473.                 }
  474.  
  475.                 return S_OK;
  476.             }
  477.         }
  478.     }
  479.  
  480.     return D3DAPPERR_NOWINDOWABLEDEVICES;
  481. }
  482.  
  483.  
  484.  
  485.  
  486. //-----------------------------------------------------------------------------
  487. // Name: FindDepthStencilFormat()
  488. // Desc: Finds a depth/stencil format for the given device that is compatible
  489. //       with the render target format and meets the needs of the app.
  490. //-----------------------------------------------------------------------------
  491. BOOL CD3DApplication::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
  492.     D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
  493. {
  494.     if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
  495.     {
  496.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  497.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
  498.         {
  499.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  500.                 TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
  501.             {
  502.                 *pDepthStencilFormat = D3DFMT_D16;
  503.                 return TRUE;
  504.             }
  505.         }
  506.     }
  507.  
  508.     if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
  509.     {
  510.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  511.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
  512.         {
  513.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  514.                 TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
  515.             {
  516.                 *pDepthStencilFormat = D3DFMT_D15S1;
  517.                 return TRUE;
  518.             }
  519.         }
  520.     }
  521.  
  522.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
  523.     {
  524.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  525.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
  526.         {
  527.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  528.                 TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
  529.             {
  530.                 *pDepthStencilFormat = D3DFMT_D24X8;
  531.                 return TRUE;
  532.             }
  533.         }
  534.     }
  535.  
  536.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
  537.     {
  538.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  539.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
  540.         {
  541.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  542.                 TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
  543.             {
  544.                 *pDepthStencilFormat = D3DFMT_D24S8;
  545.                 return TRUE;
  546.             }
  547.         }
  548.     }
  549.  
  550.     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
  551.     {
  552.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  553.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
  554.         {
  555.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  556.                 TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
  557.             {
  558.                 *pDepthStencilFormat = D3DFMT_D24X4S4;
  559.                 return TRUE;
  560.             }
  561.         }
  562.     }
  563.  
  564.     if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
  565.     {
  566.         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  567.             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
  568.         {
  569.             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  570.                 TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
  571.             {
  572.                 *pDepthStencilFormat = D3DFMT_D32;
  573.                 return TRUE;
  574.             }
  575.         }
  576.     }
  577.  
  578.     return FALSE;
  579. }
  580.  
  581.  
  582.  
  583.  
  584. //-----------------------------------------------------------------------------
  585. // Name: MsgProc()
  586. // Desc: Message handling function.
  587. //-----------------------------------------------------------------------------
  588. LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  589.                                   LPARAM lParam )
  590. {
  591.     HRESULT hr;
  592.  
  593.     switch( uMsg )
  594.     {
  595.         case WM_PAINT:
  596.             // Handle paint messages when the app is not ready
  597.             if( m_pd3dDevice && !m_bReady )
  598.             {
  599.                 if( m_bWindowed )
  600.                 {
  601.                     Render();
  602.                     m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  603.                 }
  604.             }
  605.             break;
  606.  
  607.         case WM_ACTIVATEAPP:
  608.             m_bHasFocus = (BOOL) wParam;
  609.             break;
  610.  
  611.         case WM_GETMINMAXINFO:
  612.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
  613.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
  614.             break;
  615.  
  616.         case WM_ENTERSIZEMOVE:
  617.             // Halt frame movement while the app is sizing or moving
  618.             Pause( TRUE );
  619.             break;
  620.  
  621.         case WM_SIZE:
  622.             // Check to see if we are losing our window...
  623.             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
  624.             {
  625.                 if( m_bClipCursorWhenFullscreen && !m_bWindowed )
  626.                     ClipCursor( NULL );
  627.                 m_bActive = FALSE;
  628.             }
  629.             else
  630.             {
  631.                 m_bActive = TRUE;
  632.             }
  633.             break;
  634.  
  635.         case WM_EXITSIZEMOVE:
  636.             Pause( FALSE );
  637.  
  638.             if( m_bActive && m_bWindowed )
  639.             {
  640.                 RECT rcClientOld;
  641.                 rcClientOld = m_rcWindowClient;
  642.  
  643.                 // Update window properties
  644.                 GetWindowRect( m_hWnd, &m_rcWindowBounds );
  645.                 GetClientRect( m_hWnd, &m_rcWindowClient );
  646.  
  647.                 if( rcClientOld.right - rcClientOld.left !=
  648.                     m_rcWindowClient.right - m_rcWindowClient.left ||
  649.                     rcClientOld.bottom - rcClientOld.top !=
  650.                     m_rcWindowClient.bottom - m_rcWindowClient.top)
  651.                 {
  652.                     // A new window size will require a new backbuffer
  653.                     // size, so the 3D structures must be changed accordingly.
  654.                     m_bReady = FALSE;
  655.  
  656.                     m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  657.                     m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  658.  
  659.                     // Resize the 3D environment
  660.                     if( FAILED( hr = Resize3DEnvironment() ) )
  661.                     {
  662.                         DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  663.                         return 0;
  664.                     }
  665.  
  666.                     m_bReady = TRUE;
  667.                 }
  668.             }
  669.  
  670.             break;
  671.  
  672.         case WM_SETCURSOR:
  673.             // Turn off Windows cursor in fullscreen mode
  674.             if( m_bActive && m_bReady && !m_bWindowed )
  675.             {
  676.                 SetCursor( NULL );
  677.                 if( m_bShowCursorWhenFullscreen )
  678.                     m_pd3dDevice->ShowCursor( TRUE );
  679.                 return TRUE; // prevent Windows from setting cursor to window class cursor
  680.             }
  681.             break;
  682.  
  683.          case WM_MOUSEMOVE:
  684.             if( m_bActive && m_bReady && m_pd3dDevice != NULL )
  685.             {
  686.                 POINT ptCursor;
  687.                 GetCursorPos( &ptCursor );
  688.                 if( !m_bWindowed )
  689.                     ScreenToClient( m_hWnd, &ptCursor );
  690.                 m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0L );
  691.             }
  692.             break;
  693.  
  694.        case WM_ENTERMENULOOP:
  695.             // Pause the app when menus are displayed
  696.             Pause(TRUE);
  697.             break;
  698.  
  699.         case WM_EXITMENULOOP:
  700.             Pause(FALSE);
  701.             break;
  702.  
  703.         case WM_CONTEXTMENU:
  704.             // No context menus allowed in fullscreen mode
  705.             if( m_bWindowed == FALSE )
  706.                 break;
  707.  
  708.             // Handle the app's context menu (via right mouse click)
  709.             TrackPopupMenuEx( GetSubMenu( LoadMenu( 0, MAKEINTRESOURCE(IDR_POPUP) ), 0 ),
  710.                               TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL );
  711.             break;
  712.  
  713.         case WM_NCHITTEST:
  714.             // Prevent the user from selecting the menu in fullscreen mode
  715.             if( !m_bWindowed )
  716.                 return HTCLIENT;
  717.  
  718.             break;
  719.  
  720.         case WM_POWERBROADCAST:
  721.             switch( wParam )
  722.             {
  723.                 #ifndef PBT_APMQUERYSUSPEND
  724.                     #define PBT_APMQUERYSUSPEND 0x0000
  725.                 #endif
  726.                 case PBT_APMQUERYSUSPEND:
  727.                     // At this point, the app should save any data for open
  728.                     // network connections, files, etc., and prepare to go into
  729.                     // a suspended mode.
  730.                     return TRUE;
  731.  
  732.                 #ifndef PBT_APMRESUMESUSPEND
  733.                     #define PBT_APMRESUMESUSPEND 0x0007
  734.                 #endif
  735.                 case PBT_APMRESUMESUSPEND:
  736.                     // At this point, the app should recover any data, network
  737.                     // connections, files, etc., and resume running from when
  738.                     // the app was suspended.
  739.                     return TRUE;
  740.             }
  741.             break;
  742.  
  743.         case WM_SYSCOMMAND:
  744.             // Prevent moving/sizing and power loss in fullscreen mode
  745.             switch( wParam )
  746.             {
  747.                 case SC_MOVE:
  748.                 case SC_SIZE:
  749.                 case SC_MAXIMIZE:
  750.                 case SC_KEYMENU:
  751.                 case SC_MONITORPOWER:
  752.                     if( FALSE == m_bWindowed )
  753.                         return 1;
  754.                     break;
  755.             }
  756.             break;
  757.  
  758.         case WM_COMMAND:
  759.             switch( LOWORD(wParam) )
  760.             {
  761.                 case IDM_CHANGEDEVICE:
  762.                     // Prompt the user to select a new device or mode
  763.                     if( m_bActive && m_bReady )
  764.                     {
  765.                         Pause(TRUE);
  766.  
  767.                         if( FAILED( hr = UserSelectNewDevice() ) )
  768.                             return 0;
  769.  
  770.                         Pause(FALSE);
  771.                     }
  772.                     return 0;
  773.  
  774.                 case IDM_TOGGLEFULLSCREEN:
  775.                     // Toggle the fullscreen/window mode
  776.                     if( m_bActive && m_bReady )
  777.                     {
  778.                         Pause( TRUE );
  779.                         
  780.                         if( FAILED( ToggleFullscreen() ) )
  781.                         {
  782.                             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  783.                             return 0;
  784.                         }
  785.  
  786.                         Pause( FALSE );                        
  787.                     }
  788.                     return 0;
  789.  
  790.                 case IDM_EXIT:
  791.                     // Recieved key/menu command to exit app
  792.                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
  793.                     return 0;
  794.             }
  795.             break;
  796.  
  797.         case WM_CLOSE:
  798.             Cleanup3DEnvironment();
  799.             DestroyMenu( GetMenu(hWnd) );
  800.             DestroyWindow( hWnd );
  801.             PostQuitMessage(0);
  802.             return 0;
  803.     }
  804.  
  805.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  806. }
  807.  
  808.  
  809.  
  810.  
  811. //-----------------------------------------------------------------------------
  812. // Name: Initialize3DEnvironment()
  813. // Desc:
  814. //-----------------------------------------------------------------------------
  815. HRESULT CD3DApplication::Initialize3DEnvironment()
  816. {
  817.     HRESULT hr;
  818.  
  819.     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  820.     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  821.     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  822.  
  823.     // Prepare window for possible windowed/fullscreen change
  824.     AdjustWindowForChange();
  825.  
  826.     // Set up the presentation parameters
  827.     ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
  828.     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
  829.     m_d3dpp.BackBufferCount        = 1;
  830.     if( pDeviceInfo->bWindowed )
  831.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
  832.     else
  833.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
  834.     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
  835.     m_d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  836.     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
  837.     m_d3dpp.hDeviceWindow          = m_hWnd;
  838.     if( m_bWindowed )
  839.     {
  840.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  841.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  842.         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  843.     }
  844.     else
  845.     {
  846.         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
  847.         m_d3dpp.BackBufferHeight = pModeInfo->Height;
  848.         m_d3dpp.BackBufferFormat = pModeInfo->Format;
  849.     }
  850.  
  851.     if( pDeviceInfo->d3dCaps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
  852.     {
  853.         // Warn user about null ref device that can't render anything
  854.         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
  855.     }
  856.  
  857.     // Create the device
  858.     hr = m_pD3D->CreateDevice( m_dwAdapter, pDeviceInfo->DeviceType,
  859.                                m_hWndFocus, pModeInfo->dwBehavior, &m_d3dpp,
  860.                                &m_pd3dDevice );
  861.     if( SUCCEEDED(hr) )
  862.     {
  863.         // When moving from fullscreen to windowed mode, it is important to
  864.         // adjust the window size after recreating the device rather than
  865.         // beforehand to ensure that you get the window size you want.  For
  866.         // example, when switching from 640x480 fullscreen to windowed with
  867.         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  868.         // the window size to 1000x600 until after the display mode has
  869.         // changed to 1024x768, because windows cannot be larger than the
  870.         // desktop.
  871.         if( m_bWindowed )
  872.         {
  873.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  874.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  875.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  876.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  877.                           SWP_SHOWWINDOW );
  878.         }
  879.  
  880.         // Store device Caps
  881.         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
  882.         m_dwCreateFlags = pModeInfo->dwBehavior;
  883.  
  884.         // Store device description
  885.         if( pDeviceInfo->DeviceType == D3DDEVTYPE_REF )
  886.             lstrcpy( m_strDeviceStats, TEXT("REF") );
  887.         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  888.             lstrcpy( m_strDeviceStats, TEXT("HAL") );
  889.         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  890.             lstrcpy( m_strDeviceStats, TEXT("SW") );
  891.  
  892.         if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  893.             pModeInfo->dwBehavior & D3DCREATE_PUREDEVICE )
  894.         {
  895.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  896.                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
  897.             else
  898.                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
  899.         }
  900.         else if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  901.         {
  902.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  903.                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
  904.             else
  905.                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
  906.         }
  907.         else if( pModeInfo->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
  908.         {
  909.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  910.                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
  911.             else
  912.                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
  913.         }
  914.         else if( pModeInfo->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  915.         {
  916.             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
  917.         }
  918.  
  919.         if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  920.         {
  921.             lstrcat( m_strDeviceStats, TEXT(": ") );
  922.             lstrcat( m_strDeviceStats, pAdapterInfo->d3dAdapterIdentifier.Description );
  923.         }
  924.  
  925.         // Store render target surface desc
  926.         LPDIRECT3DSURFACE8 pBackBuffer;
  927.         m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  928.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  929.         pBackBuffer->Release();
  930.  
  931.         // Set up the fullscreen cursor
  932.         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  933.         {
  934.             HCURSOR hCursor;
  935. #ifdef _WIN64
  936.             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  937. #else
  938.             hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
  939. #endif
  940.             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
  941.             m_pd3dDevice->ShowCursor( TRUE );
  942.         }
  943.  
  944.         // Confine cursor to fullscreen window
  945.         if( m_bClipCursorWhenFullscreen )
  946.         {
  947.             if (!m_bWindowed )
  948.             {
  949.                 RECT rcWindow;
  950.                 GetWindowRect( m_hWnd, &rcWindow );
  951.                 ClipCursor( &rcWindow );
  952.             }
  953.             else
  954.             {
  955.                 ClipCursor( NULL );
  956.             }
  957.         }
  958.  
  959.         // Initialize the app's device-dependent objects
  960.         hr = InitDeviceObjects();
  961.         if( SUCCEEDED(hr) )
  962.         {
  963.             hr = RestoreDeviceObjects();
  964.             if( SUCCEEDED(hr) )
  965.             {
  966.                 m_bActive = TRUE;
  967.                 return S_OK;
  968.             }
  969.         }
  970.  
  971.         // Cleanup before we try again
  972.         InvalidateDeviceObjects();
  973.         DeleteDeviceObjects();
  974.         SAFE_RELEASE( m_pd3dDevice );
  975.     }
  976.  
  977.     // If that failed, fall back to the reference rasterizer
  978.     if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  979.     {
  980.         // Select the default adapter
  981.         m_dwAdapter = 0L;
  982.         pAdapterInfo = &m_Adapters[m_dwAdapter];
  983.  
  984.         // Look for a software device
  985.         for( UINT i=0L; i<pAdapterInfo->dwNumDevices; i++ )
  986.         {
  987.             if( pAdapterInfo->devices[i].DeviceType == D3DDEVTYPE_REF )
  988.             {
  989.                 pAdapterInfo->dwCurrentDevice = i;
  990.                 pDeviceInfo = &pAdapterInfo->devices[i];
  991.                 m_bWindowed = pDeviceInfo->bWindowed;
  992.                 break;
  993.             }
  994.         }
  995.  
  996.         // Try again, this time with the reference rasterizer
  997.         if( pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice].DeviceType ==
  998.             D3DDEVTYPE_REF )
  999.         {
  1000.             // Make sure main window isn't topmost, so error message is visible
  1001.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1002.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  1003.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1004.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1005.                           SWP_SHOWWINDOW );
  1006.             AdjustWindowForChange();
  1007.  
  1008.             // Let the user know we are switching from HAL to the reference rasterizer
  1009.             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
  1010.  
  1011.             hr = Initialize3DEnvironment();
  1012.         }
  1013.     }
  1014.  
  1015.     return hr;
  1016. }
  1017.  
  1018.  
  1019.  
  1020.  
  1021. //-----------------------------------------------------------------------------
  1022. // Name:
  1023. // Desc:
  1024. //-----------------------------------------------------------------------------
  1025. HRESULT CD3DApplication::Resize3DEnvironment()
  1026. {
  1027.     HRESULT hr;
  1028.  
  1029.     // Release all vidmem objects
  1030.     if( FAILED( hr = InvalidateDeviceObjects() ) )
  1031.         return hr;
  1032.  
  1033.     // Reset the device
  1034.     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
  1035.         return hr;
  1036.  
  1037.     // Store render target surface desc
  1038.     LPDIRECT3DSURFACE8 pBackBuffer;
  1039.     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1040.     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  1041.     pBackBuffer->Release();
  1042.  
  1043.     // Set up the fullscreen cursor
  1044.     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  1045.     {
  1046.         HCURSOR hCursor;
  1047. #ifdef _WIN64
  1048.         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  1049. #else
  1050.         hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
  1051. #endif
  1052.         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
  1053.         m_pd3dDevice->ShowCursor( TRUE );
  1054.     }
  1055.  
  1056.     // Confine cursor to fullscreen window
  1057.     if( m_bClipCursorWhenFullscreen )
  1058.     {
  1059.         if (!m_bWindowed )
  1060.         {
  1061.             RECT rcWindow;
  1062.             GetWindowRect( m_hWnd, &rcWindow );
  1063.             ClipCursor( &rcWindow );
  1064.         }
  1065.         else
  1066.         {
  1067.             ClipCursor( NULL );
  1068.         }
  1069.     }
  1070.  
  1071.     // Initialize the app's device-dependent objects
  1072.     hr = RestoreDeviceObjects();
  1073.     if( FAILED(hr) )
  1074.         return hr;
  1075.  
  1076.     // If the app is paused, trigger the rendering of the current frame
  1077.     if( FALSE == m_bFrameMoving )
  1078.     {
  1079.         m_bSingleStep = TRUE;
  1080.         DXUtil_Timer( TIMER_START );
  1081.         DXUtil_Timer( TIMER_STOP );
  1082.     }
  1083.  
  1084.     return S_OK;
  1085. }
  1086.  
  1087.  
  1088.  
  1089.  
  1090. //-----------------------------------------------------------------------------
  1091. // Name: ToggleFullScreen()
  1092. // Desc: Called when user toggles between fullscreen mode and windowed mode
  1093. //-----------------------------------------------------------------------------
  1094. HRESULT CD3DApplication::ToggleFullscreen()
  1095. {
  1096.     // Get access to current adapter, device, and mode
  1097.     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1098.     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  1099.     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  1100.  
  1101.     // Need device change if going windowed and the current device
  1102.     // can only be fullscreen
  1103.     if( !m_bWindowed && !pDeviceInfo->bCanDoWindowed )
  1104.         return ForceWindowed();
  1105.  
  1106.     m_bReady = FALSE;
  1107.  
  1108.     // Toggle the windowed state
  1109.     m_bWindowed = !m_bWindowed;
  1110.     pDeviceInfo->bWindowed = m_bWindowed;
  1111.  
  1112.     // Prepare window for windowed/fullscreen change
  1113.     AdjustWindowForChange();
  1114.  
  1115.     // Set up the presentation parameters
  1116.     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
  1117.     if( m_bWindowed )
  1118.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
  1119.     else
  1120.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
  1121.     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
  1122.     m_d3dpp.hDeviceWindow          = m_hWnd;
  1123.     if( m_bWindowed )
  1124.     {
  1125.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  1126.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  1127.         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  1128.     }
  1129.     else
  1130.     {
  1131.         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
  1132.         m_d3dpp.BackBufferHeight = pModeInfo->Height;
  1133.         m_d3dpp.BackBufferFormat = pModeInfo->Format;
  1134.     }
  1135.  
  1136.     // Resize the 3D device
  1137.     if( FAILED( Resize3DEnvironment() ) )
  1138.     {
  1139.         if( m_bWindowed )
  1140.             return ForceWindowed();
  1141.         else
  1142.             return E_FAIL;
  1143.     }
  1144.  
  1145.     // When moving from fullscreen to windowed mode, it is important to
  1146.     // adjust the window size after resetting the device rather than
  1147.     // beforehand to ensure that you get the window size you want.  For
  1148.     // example, when switching from 640x480 fullscreen to windowed with
  1149.     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  1150.     // the window size to 1000x600 until after the display mode has
  1151.     // changed to 1024x768, because windows cannot be larger than the
  1152.     // desktop.
  1153.     if( m_bWindowed )
  1154.     {
  1155.         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1156.                       m_rcWindowBounds.left, m_rcWindowBounds.top,
  1157.                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1158.                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1159.                       SWP_SHOWWINDOW );
  1160.     }
  1161.  
  1162.     m_bReady = TRUE;
  1163.  
  1164.     return S_OK;
  1165. }
  1166.  
  1167.  
  1168.  
  1169.  
  1170. //-----------------------------------------------------------------------------
  1171. // Name: ForceWindowed()
  1172. // Desc: Switch to a windowed mode, even if that means picking a new device
  1173. //       and/or adapter
  1174. //-----------------------------------------------------------------------------
  1175. HRESULT CD3DApplication::ForceWindowed()
  1176. {
  1177.     HRESULT hr;
  1178.     D3DAdapterInfo* pAdapterInfoCur = &m_Adapters[m_dwAdapter];
  1179.     D3DDeviceInfo*  pDeviceInfoCur  = &pAdapterInfoCur->devices[pAdapterInfoCur->dwCurrentDevice];
  1180.     BOOL bFoundDevice = FALSE;
  1181.  
  1182.     if( pDeviceInfoCur->bCanDoWindowed )
  1183.     {
  1184.         bFoundDevice = TRUE;
  1185.     }
  1186.     else
  1187.     {
  1188.         // Look for a windowable device on any adapter
  1189.         D3DAdapterInfo* pAdapterInfo;
  1190.         DWORD dwAdapter;
  1191.         D3DDeviceInfo* pDeviceInfo;
  1192.         DWORD dwDevice;
  1193.         for( dwAdapter = 0; dwAdapter < m_dwNumAdapters; dwAdapter++ )
  1194.         {
  1195.             pAdapterInfo = &m_Adapters[dwAdapter];
  1196.             for( dwDevice = 0; dwDevice < pAdapterInfo->dwNumDevices; dwDevice++ )
  1197.             {
  1198.                 pDeviceInfo = &pAdapterInfo->devices[dwDevice];
  1199.                 if( pDeviceInfo->bCanDoWindowed )
  1200.                 {
  1201.                     m_dwAdapter = dwAdapter;
  1202.                     pDeviceInfoCur = pDeviceInfo;
  1203.                     pAdapterInfo->dwCurrentDevice = dwDevice;
  1204.                     bFoundDevice = TRUE;
  1205.                     break;
  1206.                 }
  1207.             }
  1208.             if( bFoundDevice )
  1209.                 break;
  1210.         }
  1211.     }
  1212.  
  1213.     if( !bFoundDevice )
  1214.         return E_FAIL;
  1215.  
  1216.     pDeviceInfoCur->bWindowed = TRUE;
  1217.     m_bWindowed = TRUE;
  1218.  
  1219.     // Now destroy the current 3D device objects, then reinitialize
  1220.  
  1221.     m_bReady = FALSE;
  1222.  
  1223.     // Release all scene objects that will be re-created for the new device
  1224.     InvalidateDeviceObjects();
  1225.     DeleteDeviceObjects();
  1226.  
  1227.     // Release display objects, so a new device can be created
  1228.     if( m_pd3dDevice->Release() > 0L )
  1229.         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1230.  
  1231.     // Create the new device
  1232.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1233.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1234.     m_bReady = TRUE;
  1235.  
  1236.     return S_OK;
  1237. }
  1238.  
  1239.  
  1240.  
  1241.  
  1242. //-----------------------------------------------------------------------------
  1243. // Name: AdjustWindowForChange()
  1244. // Desc: Prepare the window for a possible change between windowed mode and
  1245. //       fullscreen mode.  This function is virtual and thus can be overridden
  1246. //       to provide different behavior, such as switching to an entirely
  1247. //       different window for fullscreen mode (as in the MFC sample apps).
  1248. //-----------------------------------------------------------------------------
  1249. HRESULT CD3DApplication::AdjustWindowForChange()
  1250. {
  1251.     if( m_bWindowed )
  1252.     {
  1253.         // Set windowed-mode style
  1254.         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
  1255.     }
  1256.     else
  1257.     {
  1258.         // Set fullscreen-mode style
  1259.         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
  1260.     }
  1261.     return S_OK;
  1262. }
  1263.  
  1264.  
  1265.  
  1266.  
  1267. //-----------------------------------------------------------------------------
  1268. // Name: UserSelectNewDevice()
  1269. // Desc: Displays a dialog so the user can select a new adapter, device, or
  1270. //       display mode, and then recreates the 3D environment if needed
  1271. //-----------------------------------------------------------------------------
  1272. HRESULT CD3DApplication::UserSelectNewDevice()
  1273. {
  1274.     HRESULT hr;
  1275.  
  1276.     // Can't display dialogs in fullscreen mode
  1277.     if( m_bWindowed == FALSE )
  1278.     {
  1279.         if( FAILED( ToggleFullscreen() ) )
  1280.         {
  1281.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  1282.             return E_FAIL;
  1283.         }
  1284.     }
  1285.  
  1286.     // Prompt the user to change the mode
  1287.     if( IDOK != DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL),
  1288.                                 MAKEINTRESOURCE(IDD_SELECTDEVICE), m_hWnd,
  1289.                                 SelectDeviceProc, (LPARAM)this ) )
  1290.         return S_OK;
  1291.  
  1292.     // Get access to the newly selected adapter, device, and mode
  1293.     DWORD dwDevice;
  1294.     dwDevice  = m_Adapters[m_dwAdapter].dwCurrentDevice;
  1295.     m_bWindowed = m_Adapters[m_dwAdapter].devices[dwDevice].bWindowed;
  1296.  
  1297.     // Release all scene objects that will be re-created for the new device
  1298.     InvalidateDeviceObjects();
  1299.     DeleteDeviceObjects();
  1300.  
  1301.     // Release display objects, so a new device can be created
  1302.     if( m_pd3dDevice->Release() > 0L )
  1303.         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1304.  
  1305.     // Inform the display class of the change. It will internally
  1306.     // re-create valid surfaces, a d3ddevice, etc.
  1307.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1308.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1309.  
  1310.     // If the app is paused, trigger the rendering of the current frame
  1311.     if( FALSE == m_bFrameMoving )
  1312.     {
  1313.         m_bSingleStep = TRUE;
  1314.         DXUtil_Timer( TIMER_START );
  1315.         DXUtil_Timer( TIMER_STOP );
  1316.     }
  1317.  
  1318.     return S_OK;
  1319. }
  1320.  
  1321.  
  1322.  
  1323.  
  1324. //-----------------------------------------------------------------------------
  1325. // Name: SelectDeviceProc()
  1326. // Desc: Windows message handling function for the device select dialog
  1327. //-----------------------------------------------------------------------------
  1328. INT_PTR CALLBACK CD3DApplication::SelectDeviceProc( HWND hDlg, UINT msg,
  1329.                                                     WPARAM wParam, LPARAM lParam )
  1330. {
  1331.     // Get access to the UI controls
  1332.     HWND hwndAdapterList        = GetDlgItem( hDlg, IDC_ADAPTER_COMBO );
  1333.     HWND hwndDeviceList         = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
  1334.     HWND hwndFullscreenModeList = GetDlgItem( hDlg, IDC_FULLSCREENMODES_COMBO );
  1335.     HWND hwndWindowedRadio      = GetDlgItem( hDlg, IDC_WINDOW );
  1336.     HWND hwndFullscreenRadio    = GetDlgItem( hDlg, IDC_FULLSCREEN );
  1337.     HWND hwndMultiSampleList    = GetDlgItem( hDlg, IDC_MULTISAMPLE_COMBO );
  1338.     BOOL bUpdateDlgControls     = FALSE;
  1339.  
  1340.     // Static state for adapter/device/mode selection
  1341.     static CD3DApplication* pd3dApp;
  1342.     static DWORD  dwOldAdapter, dwNewAdapter;
  1343.     static DWORD  dwOldDevice,  dwNewDevice;
  1344.     static DWORD  dwOldMode,    dwNewMode;
  1345.     static BOOL   bOldWindowed, bNewWindowed;
  1346.     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeWindowed, NewMultiSampleTypeWindowed;
  1347.     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeFullscreen, NewMultiSampleTypeFullscreen;
  1348.  
  1349.     // Working variables
  1350.     D3DAdapterInfo* pAdapter;
  1351.     D3DDeviceInfo*  pDevice;
  1352.  
  1353.     // Handle the initialization message
  1354.     if( WM_INITDIALOG == msg )
  1355.     {
  1356.         // Old state
  1357.         pd3dApp      = (CD3DApplication*)lParam;
  1358.         dwOldAdapter = pd3dApp->m_dwAdapter;
  1359.         pAdapter     = &pd3dApp->m_Adapters[dwOldAdapter];
  1360.  
  1361.         dwOldDevice  = pAdapter->dwCurrentDevice;
  1362.         pDevice      = &pAdapter->devices[dwOldDevice];
  1363.  
  1364.         dwOldMode    = pDevice->dwCurrentMode;
  1365.         bOldWindowed = pDevice->bWindowed;
  1366.         OldMultiSampleTypeWindowed = pDevice->MultiSampleTypeWindowed;
  1367.         OldMultiSampleTypeFullscreen = pDevice->MultiSampleTypeFullscreen;
  1368.  
  1369.         // New state is initially the same as the old state
  1370.         dwNewAdapter = dwOldAdapter;
  1371.         dwNewDevice  = dwOldDevice;
  1372.         dwNewMode    = dwOldMode;
  1373.         bNewWindowed = bOldWindowed;
  1374.         NewMultiSampleTypeWindowed = OldMultiSampleTypeWindowed;
  1375.         NewMultiSampleTypeFullscreen = OldMultiSampleTypeFullscreen;
  1376.  
  1377.         // Set flag to update dialog controls below
  1378.         bUpdateDlgControls = TRUE;
  1379.     }
  1380.  
  1381.     if( WM_COMMAND == msg )
  1382.     {
  1383.         // Get current UI state
  1384.         bNewWindowed  = Button_GetCheck( hwndWindowedRadio );
  1385.  
  1386.         if( IDOK == LOWORD(wParam) )
  1387.         {
  1388.             // Handle the case when the user hits the OK button. Check if any
  1389.             // of the options were changed
  1390.             if( dwNewAdapter != dwOldAdapter || dwNewDevice  != dwOldDevice  ||
  1391.                 dwNewMode    != dwOldMode    || bNewWindowed != bOldWindowed ||
  1392.                 NewMultiSampleTypeWindowed != OldMultiSampleTypeWindowed ||
  1393.                 NewMultiSampleTypeFullscreen != OldMultiSampleTypeFullscreen )
  1394.             {
  1395.                 pd3dApp->m_dwAdapter = dwNewAdapter;
  1396.  
  1397.                 pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
  1398.                 pAdapter->dwCurrentDevice = dwNewDevice;
  1399.  
  1400.                 pAdapter->devices[dwNewDevice].dwCurrentMode = dwNewMode;
  1401.                 pAdapter->devices[dwNewDevice].bWindowed     = bNewWindowed;
  1402.                 pAdapter->devices[dwNewDevice].MultiSampleTypeWindowed = NewMultiSampleTypeWindowed;
  1403.                 pAdapter->devices[dwNewDevice].MultiSampleTypeFullscreen = NewMultiSampleTypeFullscreen;
  1404.  
  1405.                 EndDialog( hDlg, IDOK );
  1406.             }
  1407.             else
  1408.                 EndDialog( hDlg, IDCANCEL );
  1409.  
  1410.             return TRUE;
  1411.         }
  1412.         else if( IDCANCEL == LOWORD(wParam) )
  1413.         {
  1414.             // Handle the case when the user hits the Cancel button
  1415.             EndDialog( hDlg, IDCANCEL );
  1416.             return TRUE;
  1417.         }
  1418.         else if( CBN_SELENDOK == HIWORD(wParam) )
  1419.         {
  1420.             if( LOWORD(wParam) == IDC_ADAPTER_COMBO )
  1421.             {
  1422.                 dwNewAdapter = ComboBox_GetCurSel( hwndAdapterList );
  1423.                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
  1424.  
  1425.                 dwNewDevice  = pAdapter->dwCurrentDevice;
  1426.                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
  1427.                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
  1428.             }
  1429.             else if( LOWORD(wParam) == IDC_DEVICE_COMBO )
  1430.             {
  1431.                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
  1432.  
  1433.                 dwNewDevice  = ComboBox_GetCurSel( hwndDeviceList );
  1434.                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
  1435.                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
  1436.             }
  1437.             else if( LOWORD(wParam) == IDC_FULLSCREENMODES_COMBO )
  1438.             {
  1439.                 dwNewMode = ComboBox_GetCurSel( hwndFullscreenModeList );
  1440.             }
  1441.             else if( LOWORD(wParam) == IDC_MULTISAMPLE_COMBO )
  1442.             {
  1443.                 DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
  1444.                 if( bNewWindowed )
  1445.                     NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1446.                 else
  1447.                     NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1448.             }
  1449.         }
  1450.         // Keep the UI current
  1451.         bUpdateDlgControls = TRUE;
  1452.     }
  1453.  
  1454.     // Update the dialog controls
  1455.     if( bUpdateDlgControls )
  1456.     {
  1457.         // Reset the content in each of the combo boxes
  1458.         ComboBox_ResetContent( hwndAdapterList );
  1459.         ComboBox_ResetContent( hwndDeviceList );
  1460.         ComboBox_ResetContent( hwndFullscreenModeList );
  1461.         ComboBox_ResetContent( hwndMultiSampleList );
  1462.  
  1463.         pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
  1464.         pDevice  = &pAdapter->devices[dwNewDevice];
  1465.  
  1466.         // Add a list of adapters to the adapter combo box
  1467.         for( DWORD a=0; a < pd3dApp->m_dwNumAdapters; a++ )
  1468.         {
  1469.             // Add device name to the combo box
  1470.             DWORD dwItem = ComboBox_AddString( hwndAdapterList,
  1471.                              pd3dApp->m_Adapters[a].d3dAdapterIdentifier.Description );
  1472.  
  1473.             // Set the item data to identify this adapter
  1474.             ComboBox_SetItemData( hwndAdapterList, dwItem, a );
  1475.  
  1476.             // Set the combobox selection on the current adapater
  1477.             if( a == dwNewAdapter )
  1478.                 ComboBox_SetCurSel( hwndAdapterList, dwItem );
  1479.         }
  1480.  
  1481.         // Add a list of devices to the device combo box
  1482.         for( DWORD d=0; d < pAdapter->dwNumDevices; d++ )
  1483.         {
  1484.             // Add device name to the combo box
  1485.             DWORD dwItem = ComboBox_AddString( hwndDeviceList,
  1486.                                                pAdapter->devices[d].strDesc );
  1487.  
  1488.             // Set the item data to identify this device
  1489.             ComboBox_SetItemData( hwndDeviceList, dwItem, d );
  1490.  
  1491.             // Set the combobox selection on the current device
  1492.             if( d == dwNewDevice )
  1493.                 ComboBox_SetCurSel( hwndDeviceList, dwItem );
  1494.         }
  1495.  
  1496.         // Add a list of modes to the mode combo box
  1497.         for( DWORD m=0; m < pDevice->dwNumModes; m++ )
  1498.         {
  1499.             DWORD BitDepth = 16;
  1500.             if( pDevice->modes[m].Format == D3DFMT_X8R8G8B8 ||
  1501.                 pDevice->modes[m].Format == D3DFMT_A8R8G8B8 ||
  1502.                 pDevice->modes[m].Format == D3DFMT_R8G8B8 )
  1503.             {
  1504.                 BitDepth = 32;
  1505.             }
  1506.  
  1507.             // Add mode desc to the combo box
  1508.             TCHAR strMode[80];
  1509.             _stprintf( strMode, _T("%ld x %ld x %ld"), pDevice->modes[m].Width,
  1510.                                                        pDevice->modes[m].Height,
  1511.                                                        BitDepth );
  1512.             DWORD dwItem = ComboBox_AddString( hwndFullscreenModeList, strMode );
  1513.  
  1514.             // Set the item data to identify this mode
  1515.             ComboBox_SetItemData( hwndFullscreenModeList, dwItem, m );
  1516.  
  1517.             // Set the combobox selection on the current mode
  1518.             if( m == dwNewMode )
  1519.                 ComboBox_SetCurSel( hwndFullscreenModeList, dwItem );
  1520.         }
  1521.  
  1522.         // Add a list of multisample modes to the multisample combo box
  1523.         for( m=0; m <= 16; m++ )
  1524.         {
  1525.             TCHAR strDesc[50];
  1526.  
  1527.             D3DFORMAT fmt;
  1528.             if( bNewWindowed )
  1529.                 fmt = pd3dApp->m_Adapters[dwNewAdapter].d3ddmDesktop.Format;
  1530.             else
  1531.                 fmt = pDevice->modes[dwNewMode].Format;
  1532.  
  1533.             if ( m == 1 ) // 1 is not a valid multisample type
  1534.                 continue;
  1535.  
  1536.             if( SUCCEEDED( pd3dApp->m_pD3D->CheckDeviceMultiSampleType( dwNewAdapter,
  1537.                 pDevice->DeviceType, fmt, bNewWindowed, (D3DMULTISAMPLE_TYPE)m ) ) )
  1538.             {
  1539.                 if( m == 0 )
  1540.                     lstrcpy( strDesc, _T("none") );
  1541.                 else
  1542.                     wsprintf( strDesc, _T("%d samples"), m );
  1543.  
  1544.                 // Add device name to the combo box
  1545.                 DWORD dwItem = ComboBox_AddString( hwndMultiSampleList, strDesc );
  1546.  
  1547.                 // Set the item data to identify this multisample type
  1548.                 ComboBox_SetItemData( hwndMultiSampleList, dwItem, m );
  1549.  
  1550.                 // Set the combobox selection on the current multisample type
  1551.                 if( bNewWindowed )
  1552.                 {
  1553.                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeWindowed || m == 0 )
  1554.                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
  1555.                 }
  1556.                 else
  1557.                 {
  1558.                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeFullscreen || m == 0 )
  1559.                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
  1560.                 }
  1561.             }
  1562.         }
  1563.         DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
  1564.         if( bNewWindowed )
  1565.             NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1566.         else
  1567.             NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1568.         EnableWindow( hwndMultiSampleList, ComboBox_GetCount( hwndMultiSampleList ) > 1);
  1569.         EnableWindow( hwndWindowedRadio, pDevice->bCanDoWindowed );
  1570.  
  1571.         if( bNewWindowed )
  1572.         {
  1573.             Button_SetCheck( hwndWindowedRadio,   TRUE );
  1574.             Button_SetCheck( hwndFullscreenRadio, FALSE );
  1575.             EnableWindow( hwndFullscreenModeList, FALSE );
  1576.         }
  1577.         else
  1578.         {
  1579.             Button_SetCheck( hwndWindowedRadio,   FALSE );
  1580.             Button_SetCheck( hwndFullscreenRadio, TRUE );
  1581.             EnableWindow( hwndFullscreenModeList, TRUE );
  1582.         }
  1583.         return TRUE;
  1584.     }
  1585.  
  1586.     return FALSE;
  1587. }
  1588.  
  1589.  
  1590.  
  1591.  
  1592. //-----------------------------------------------------------------------------
  1593. // Name: Run()
  1594. // Desc:
  1595. //-----------------------------------------------------------------------------
  1596. INT CD3DApplication::Run()
  1597. {
  1598.     // Load keyboard accelerators
  1599.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  1600.  
  1601.     // Now we're ready to recieve and process Windows messages.
  1602.     BOOL bGotMsg;
  1603.     MSG  msg;
  1604.     msg.message = WM_NULL;
  1605.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  1606.  
  1607.     while( WM_QUIT != msg.message  )
  1608.     {
  1609.         // Use PeekMessage() if the app is active, so we can use idle time to
  1610.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  1611.         if( m_bActive )
  1612.             bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  1613.         else
  1614.             bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
  1615.  
  1616.         if( bGotMsg )
  1617.         {
  1618.             // Translate and dispatch the message
  1619.             if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
  1620.             {
  1621.                 TranslateMessage( &msg );
  1622.                 DispatchMessage( &msg );
  1623.             }
  1624.         }
  1625.         else
  1626.         {
  1627.             // Render a frame during idle time (no messages are waiting)
  1628.             if( m_bActive && m_bReady )
  1629.             {
  1630.                 if( FAILED( Render3DEnvironment() ) )
  1631.                     SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1632.             }
  1633.         }
  1634.     }
  1635.  
  1636.     return (INT)msg.wParam;
  1637. }
  1638.  
  1639.  
  1640.  
  1641.  
  1642. //-----------------------------------------------------------------------------
  1643. // Name: Render3DEnvironment()
  1644. // Desc: Draws the scene.
  1645. //-----------------------------------------------------------------------------
  1646. HRESULT CD3DApplication::Render3DEnvironment()
  1647. {
  1648.     HRESULT hr;
  1649.  
  1650.     // Test the cooperative level to see if it's okay to render
  1651.     if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  1652.     {
  1653.         // If the device was lost, do not render until we get it back
  1654.         if( D3DERR_DEVICELOST == hr )
  1655.             return S_OK;
  1656.  
  1657.         // Check if the device needs to be resized.
  1658.         if( D3DERR_DEVICENOTRESET == hr )
  1659.         {
  1660.             // If we are windowed, read the desktop mode and use the same format for
  1661.             // the back buffer
  1662.             if( m_bWindowed )
  1663.             {
  1664.                 D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1665.                 m_pD3D->GetAdapterDisplayMode( m_dwAdapter, &pAdapterInfo->d3ddmDesktop );
  1666.                 m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  1667.             }
  1668.  
  1669.             if( FAILED( hr = Resize3DEnvironment() ) )
  1670.                 return hr;
  1671.         }
  1672.         return hr;
  1673.     }
  1674.  
  1675.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  1676.     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  1677.     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  1678.     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
  1679.         return S_OK;
  1680.  
  1681.     // FrameMove (animate) the scene
  1682.     if( m_bFrameMoving || m_bSingleStep )
  1683.     {
  1684.         // Store the time for the app
  1685.         m_fTime        = fAppTime;
  1686.         m_fElapsedTime = fElapsedAppTime;
  1687.  
  1688.         // Frame move the scene
  1689.         if( FAILED( hr = FrameMove() ) )
  1690.             return hr;
  1691.  
  1692.         m_bSingleStep = FALSE;
  1693.     }
  1694.  
  1695.     // Render the scene as normal
  1696.     if( FAILED( hr = Render() ) )
  1697.         return hr;
  1698.  
  1699.     // Keep track of the frame count
  1700.     {
  1701.         static FLOAT fLastTime = 0.0f;
  1702.         static DWORD dwFrames  = 0L;
  1703.         FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  1704.         ++dwFrames;
  1705.  
  1706.         // Update the scene stats once per second
  1707.         if( fTime - fLastTime > 1.0f )
  1708.         {
  1709.             m_fFPS    = dwFrames / (fTime - fLastTime);
  1710.             fLastTime = fTime;
  1711.             dwFrames  = 0L;
  1712.  
  1713.             // Get adapter's current mode so we can report
  1714.             // bit depth (back buffer depth may be unknown)
  1715.             D3DDISPLAYMODE mode;
  1716.             m_pD3D->GetAdapterDisplayMode(m_dwAdapter, &mode);
  1717.  
  1718.             _stprintf( m_strFrameStats, _T("%.02f fps (%dx%dx%d)"), m_fFPS,
  1719.                        m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
  1720.                        mode.Format==D3DFMT_X8R8G8B8?32:16 );
  1721.             D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1722.             D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  1723.             D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  1724.             if( m_bUseDepthBuffer )
  1725.             {
  1726.  
  1727.                 switch( pModeInfo->DepthStencilFormat )
  1728.                 {
  1729.                 case D3DFMT_D16:
  1730.                     lstrcat( m_strFrameStats, _T(" (D16)") );
  1731.                     break;
  1732.                 case D3DFMT_D15S1:
  1733.                     lstrcat( m_strFrameStats, _T(" (D15S1)") );
  1734.                     break;
  1735.                 case D3DFMT_D24X8:
  1736.                     lstrcat( m_strFrameStats, _T(" (D24X8)") );
  1737.                     break;
  1738.                 case D3DFMT_D24S8:
  1739.                     lstrcat( m_strFrameStats, _T(" (D24S8)") );
  1740.                     break;
  1741.                 case D3DFMT_D24X4S4:
  1742.                     lstrcat( m_strFrameStats, _T(" (D24X4S4)") );
  1743.                     break;
  1744.                 case D3DFMT_D32:
  1745.                     lstrcat( m_strFrameStats, _T(" (D32)") );
  1746.                     break;
  1747.                 }
  1748.             }
  1749.  
  1750.             D3DMULTISAMPLE_TYPE MultiSampleType;
  1751.             if( m_bWindowed )
  1752.                 MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed;
  1753.             else
  1754.                 MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen;
  1755.             switch( MultiSampleType )
  1756.             {
  1757.             case D3DMULTISAMPLE_2_SAMPLES:
  1758.                 lstrcat( m_strFrameStats, _T(" (2x Multisample)") );
  1759.                 break;
  1760.             case D3DMULTISAMPLE_3_SAMPLES:
  1761.                 lstrcat( m_strFrameStats, _T(" (3x Multisample)") );
  1762.                 break;
  1763.             case D3DMULTISAMPLE_4_SAMPLES:
  1764.                 lstrcat( m_strFrameStats, _T(" (4x Multisample)") );
  1765.                 break;
  1766.             case D3DMULTISAMPLE_5_SAMPLES:
  1767.                 lstrcat( m_strFrameStats, _T(" (5x Multisample)") );
  1768.                 break;
  1769.             case D3DMULTISAMPLE_6_SAMPLES:
  1770.                 lstrcat( m_strFrameStats, _T(" (6x Multisample)") );
  1771.                 break;
  1772.             case D3DMULTISAMPLE_7_SAMPLES:
  1773.                 lstrcat( m_strFrameStats, _T(" (7x Multisample)") );
  1774.                 break;
  1775.             case D3DMULTISAMPLE_8_SAMPLES:
  1776.                 lstrcat( m_strFrameStats, _T(" (8x Multisample)") );
  1777.                 break;
  1778.             case D3DMULTISAMPLE_9_SAMPLES:
  1779.                 lstrcat( m_strFrameStats, _T(" (9x Multisample)") );
  1780.                 break;
  1781.             case D3DMULTISAMPLE_10_SAMPLES:
  1782.                 lstrcat( m_strFrameStats, _T(" (10x Multisample)") );
  1783.                 break;
  1784.             case D3DMULTISAMPLE_11_SAMPLES:
  1785.                 lstrcat( m_strFrameStats, _T(" (11x Multisample)") );
  1786.                 break;
  1787.             case D3DMULTISAMPLE_12_SAMPLES:
  1788.                 lstrcat( m_strFrameStats, _T(" (12x Multisample)") );
  1789.                 break;
  1790.             case D3DMULTISAMPLE_13_SAMPLES:
  1791.                 lstrcat( m_strFrameStats, _T(" (13x Multisample)") );
  1792.                 break;
  1793.             case D3DMULTISAMPLE_14_SAMPLES:
  1794.                 lstrcat( m_strFrameStats, _T(" (14x Multisample)") );
  1795.                 break;
  1796.             case D3DMULTISAMPLE_15_SAMPLES:
  1797.                 lstrcat( m_strFrameStats, _T(" (15x Multisample)") );
  1798.                 break;
  1799.             case D3DMULTISAMPLE_16_SAMPLES:
  1800.                 lstrcat( m_strFrameStats, _T(" (16x Multisample)") );
  1801.                 break;
  1802.             }
  1803.         }
  1804.     }
  1805.  
  1806.     // Show the frame on the primary surface.
  1807.     m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1808.  
  1809.     return S_OK;
  1810. }
  1811.  
  1812.  
  1813.  
  1814.  
  1815. //-----------------------------------------------------------------------------
  1816. // Name: Pause()
  1817. // Desc: Called in to toggle the pause state of the app.
  1818. //-----------------------------------------------------------------------------
  1819. VOID CD3DApplication::Pause( BOOL bPause )
  1820. {
  1821.     static DWORD dwAppPausedCount = 0L;
  1822.  
  1823.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1824.     m_bReady          = ( dwAppPausedCount ? FALSE : TRUE );
  1825.  
  1826.     // Handle the first pause request (of many, nestable pause requests)
  1827.     if( bPause && ( 1 == dwAppPausedCount ) )
  1828.     {
  1829.         // Stop the scene from animating
  1830.         if( m_bFrameMoving )
  1831.             DXUtil_Timer( TIMER_STOP );
  1832.     }
  1833.  
  1834.     if( 0 == dwAppPausedCount )
  1835.     {
  1836.         // Restart the timers
  1837.         if( m_bFrameMoving )
  1838.             DXUtil_Timer( TIMER_START );
  1839.     }
  1840. }
  1841.  
  1842.  
  1843.  
  1844.  
  1845. //-----------------------------------------------------------------------------
  1846. // Name: Cleanup3DEnvironment()
  1847. // Desc: Cleanup scene objects
  1848. //-----------------------------------------------------------------------------
  1849. VOID CD3DApplication::Cleanup3DEnvironment()
  1850. {
  1851.     m_bActive = FALSE;
  1852.     m_bReady  = FALSE;
  1853.  
  1854.     if( m_pd3dDevice )
  1855.     {
  1856.         InvalidateDeviceObjects();
  1857.         DeleteDeviceObjects();
  1858.  
  1859.         m_pd3dDevice->Release();
  1860.         m_pD3D->Release();
  1861.  
  1862.         m_pd3dDevice = NULL;
  1863.         m_pD3D       = NULL;
  1864.     }
  1865.  
  1866.     FinalCleanup();
  1867. }
  1868.  
  1869.  
  1870.  
  1871.  
  1872. //-----------------------------------------------------------------------------
  1873. // Name: DisplayErrorMsg()
  1874. // Desc: Displays error messages in a message box
  1875. //-----------------------------------------------------------------------------
  1876. HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  1877. {
  1878.     TCHAR strMsg[512];
  1879.  
  1880.     switch( hr )
  1881.     {
  1882.         case D3DAPPERR_NODIRECT3D:
  1883.             _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n")
  1884.                              _T("want to check that the latest version of\n")
  1885.                              _T("DirectX is correctly installed on your\n")
  1886.                              _T("system.  Also make sure that this program\n")
  1887.                              _T("was compiled with header files that match\n")
  1888.                              _T("the installed DirectX DLLs.") );
  1889.             break;
  1890.  
  1891.         case D3DAPPERR_NOCOMPATIBLEDEVICES:
  1892.             _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
  1893.                              _T("devices.") );
  1894.             break;
  1895.  
  1896.         case D3DAPPERR_NOWINDOWABLEDEVICES:
  1897.             _tcscpy( strMsg, _T("This sample cannot run in a desktop\n")
  1898.                              _T("window with the current display settings.\n")
  1899.                              _T("Please change your desktop settings to a\n")
  1900.                              _T("16- or 32-bit display mode and re-run this\n")
  1901.                              _T("sample.") );
  1902.             break;
  1903.  
  1904.         case D3DAPPERR_NOHARDWAREDEVICE:
  1905.             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n")
  1906.                              _T("were found.") );
  1907.             break;
  1908.  
  1909.         case D3DAPPERR_HALNOTCOMPATIBLE:
  1910.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1911.                              _T("not available on your Direct3D hardware\n")
  1912.                              _T("accelerator.") );
  1913.             break;
  1914.  
  1915.         case D3DAPPERR_NOWINDOWEDHAL:
  1916.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1917.                              _T("render into a window.\n")
  1918.                              _T("Press F2 while the app is running to see a\n")
  1919.                              _T("list of available devices and modes.") );
  1920.             break;
  1921.  
  1922.         case D3DAPPERR_NODESKTOPHAL:
  1923.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1924.                              _T("render into a window with the current\n")
  1925.                              _T("desktop display settings.\n")
  1926.                              _T("Press F2 while the app is running to see a\n")
  1927.                              _T("list of available devices and modes.") );
  1928.             break;
  1929.  
  1930.         case D3DAPPERR_NOHALTHISMODE:
  1931.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1932.                              _T("not available on your Direct3D hardware\n")
  1933.                              _T("accelerator with the current desktop display\n")
  1934.                              _T("settings.\n")
  1935.                              _T("Press F2 while the app is running to see a\n")
  1936.                              _T("list of available devices and modes.") );
  1937.             break;
  1938.  
  1939.         case D3DAPPERR_MEDIANOTFOUND:
  1940.             _tcscpy( strMsg, _T("Could not load required media." ) );
  1941.             break;
  1942.  
  1943.         case D3DAPPERR_RESIZEFAILED:
  1944.             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
  1945.             break;
  1946.  
  1947.         case D3DAPPERR_NONZEROREFCOUNT:
  1948.             _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n")
  1949.                              _T("count (meaning things were not properly\n")
  1950.                              _T("cleaned up).") );
  1951.             break;
  1952.  
  1953.         case D3DAPPERR_NULLREFDEVICE:
  1954.             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n")
  1955.                              _T("The reference rendering device was selected, but your\n")
  1956.                              _T("computer only has a reduced-functionality reference device\n")
  1957.                              _T("installed.  Install the DirectX SDK to get the full\n")
  1958.                              _T("reference device.\n") );
  1959.             break;
  1960.  
  1961.         case E_OUTOFMEMORY:
  1962.             _tcscpy( strMsg, _T("Not enough memory.") );
  1963.             break;
  1964.  
  1965.         case D3DERR_OUTOFVIDEOMEMORY:
  1966.             _tcscpy( strMsg, _T("Not enough video memory.") );
  1967.             break;
  1968.  
  1969.         default:
  1970.             _tcscpy( strMsg, _T("Generic application error. Enable\n")
  1971.                              _T("debug output for detailed information.") );
  1972.     }
  1973.  
  1974.     if( MSGERR_APPMUSTEXIT == dwType )
  1975.     {
  1976.         _tcscat( strMsg, _T("\n\nThis sample will now exit.") );
  1977.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
  1978.  
  1979.         // Close the window, which shuts down the app
  1980.         if( m_hWnd )
  1981.             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1982.     }
  1983.     else
  1984.     {
  1985.         if( MSGWARN_SWITCHEDTOREF == dwType )
  1986.             _tcscat( strMsg, _T("\n\nSwitching to the reference rasterizer,\n")
  1987.                              _T("a software device that implements the entire\n")
  1988.                              _T("Direct3D feature set, but runs very slowly.") );
  1989.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
  1990.     }
  1991.  
  1992.     return hr;
  1993. }
  1994.  
  1995.  
  1996.  
  1997.  
  1998.