home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / common / src / d3dapp.cpp next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  66.8 KB  |  1,852 lines

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