home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / d3dapp.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  73.6 KB  |  2,017 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DApp.cpp
  3. //
  4. // Desc: Application class for the Direct3D samples framework library.
  5. //
  6. // Copyright (c) 1998-2001 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_hMenu             = 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_TOGGLESTART:
  762.                     // Toggle frame movement
  763.                     m_bFrameMoving = !m_bFrameMoving;
  764.                     DXUtil_Timer( m_bFrameMoving ? TIMER_START : TIMER_STOP );
  765.                     break;
  766.  
  767.                 case IDM_SINGLESTEP:
  768.                     // Single-step frame movement
  769.                     if( FALSE == m_bFrameMoving )
  770.                         DXUtil_Timer( TIMER_ADVANCE );
  771.                     else
  772.                         DXUtil_Timer( TIMER_STOP );
  773.                     m_bFrameMoving = FALSE;
  774.                     m_bSingleStep  = TRUE;
  775.                     break;
  776.  
  777.                 case IDM_CHANGEDEVICE:
  778.                     // Prompt the user to select a new device or mode
  779.                     if( m_bActive && m_bReady )
  780.                     {
  781.                         Pause(TRUE);
  782.  
  783.                         if( FAILED( hr = UserSelectNewDevice() ) )
  784.                             return 0;
  785.  
  786.                         Pause(FALSE);
  787.                     }
  788.                     return 0;
  789.  
  790.                 case IDM_TOGGLEFULLSCREEN:
  791.                     // Toggle the fullscreen/window mode
  792.                     if( m_bActive && m_bReady )
  793.                     {
  794.                         Pause( TRUE );
  795.                         
  796.                         if( FAILED( ToggleFullscreen() ) )
  797.                         {
  798.                             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  799.                             return 0;
  800.                         }
  801.  
  802.                         Pause( FALSE );                        
  803.                     }
  804.                     return 0;
  805.  
  806.                 case IDM_EXIT:
  807.                     // Recieved key/menu command to exit app
  808.                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
  809.                     return 0;
  810.             }
  811.             break;
  812.  
  813.         case WM_CLOSE:
  814.             Cleanup3DEnvironment();
  815.             DestroyMenu( GetMenu(hWnd) );
  816.             DestroyWindow( hWnd );
  817.             PostQuitMessage(0);
  818.             return 0;
  819.     }
  820.  
  821.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  822. }
  823.  
  824.  
  825.  
  826.  
  827. //-----------------------------------------------------------------------------
  828. // Name: Initialize3DEnvironment()
  829. // Desc:
  830. //-----------------------------------------------------------------------------
  831. HRESULT CD3DApplication::Initialize3DEnvironment()
  832. {
  833.     HRESULT hr;
  834.  
  835.     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  836.     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  837.     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  838.  
  839.     // Prepare window for possible windowed/fullscreen change
  840.     AdjustWindowForChange();
  841.  
  842.     // Set up the presentation parameters
  843.     ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
  844.     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
  845.     m_d3dpp.BackBufferCount        = 1;
  846.     if( pDeviceInfo->bWindowed )
  847.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
  848.     else
  849.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
  850.     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
  851.     m_d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  852.     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
  853.     m_d3dpp.hDeviceWindow          = m_hWnd;
  854.     if( m_bWindowed )
  855.     {
  856.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  857.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  858.         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  859.     }
  860.     else
  861.     {
  862.         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
  863.         m_d3dpp.BackBufferHeight = pModeInfo->Height;
  864.         m_d3dpp.BackBufferFormat = pModeInfo->Format;
  865.     }
  866.  
  867.     if( pDeviceInfo->d3dCaps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
  868.     {
  869.         // Warn user about null ref device that can't render anything
  870.         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
  871.     }
  872.  
  873.     // Create the device
  874.     hr = m_pD3D->CreateDevice( m_dwAdapter, pDeviceInfo->DeviceType,
  875.                                m_hWndFocus, pModeInfo->dwBehavior, &m_d3dpp,
  876.                                &m_pd3dDevice );
  877.     if( SUCCEEDED(hr) )
  878.     {
  879.         // When moving from fullscreen to windowed mode, it is important to
  880.         // adjust the window size after recreating the device rather than
  881.         // beforehand to ensure that you get the window size you want.  For
  882.         // example, when switching from 640x480 fullscreen to windowed with
  883.         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  884.         // the window size to 1000x600 until after the display mode has
  885.         // changed to 1024x768, because windows cannot be larger than the
  886.         // desktop.
  887.         if( m_bWindowed )
  888.         {
  889.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  890.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  891.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  892.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  893.                           SWP_SHOWWINDOW );
  894.         }
  895.  
  896.         // Store device Caps
  897.         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
  898.         m_dwCreateFlags = pModeInfo->dwBehavior;
  899.  
  900.         // Store device description
  901.         if( pDeviceInfo->DeviceType == D3DDEVTYPE_REF )
  902.             lstrcpy( m_strDeviceStats, TEXT("REF") );
  903.         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  904.             lstrcpy( m_strDeviceStats, TEXT("HAL") );
  905.         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  906.             lstrcpy( m_strDeviceStats, TEXT("SW") );
  907.  
  908.         if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  909.             pModeInfo->dwBehavior & D3DCREATE_PUREDEVICE )
  910.         {
  911.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  912.                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
  913.             else
  914.                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
  915.         }
  916.         else if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  917.         {
  918.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  919.                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
  920.             else
  921.                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
  922.         }
  923.         else if( pModeInfo->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
  924.         {
  925.             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  926.                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
  927.             else
  928.                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
  929.         }
  930.         else if( pModeInfo->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  931.         {
  932.             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
  933.         }
  934.  
  935.         if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  936.         {
  937.             lstrcat( m_strDeviceStats, TEXT(": ") );
  938.             lstrcat( m_strDeviceStats, pAdapterInfo->d3dAdapterIdentifier.Description );
  939.         }
  940.  
  941.         // Store render target surface desc
  942.         LPDIRECT3DSURFACE8 pBackBuffer;
  943.         m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  944.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  945.         pBackBuffer->Release();
  946.  
  947.         // Set up the fullscreen cursor
  948.         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  949.         {
  950.             HCURSOR hCursor;
  951. #ifdef _WIN64
  952.             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  953. #else
  954.             hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
  955. #endif
  956.             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
  957.             m_pd3dDevice->ShowCursor( TRUE );
  958.         }
  959.  
  960.         // Confine cursor to fullscreen window
  961.         if( m_bClipCursorWhenFullscreen )
  962.         {
  963.             if (!m_bWindowed )
  964.             {
  965.                 RECT rcWindow;
  966.                 GetWindowRect( m_hWnd, &rcWindow );
  967.                 ClipCursor( &rcWindow );
  968.             }
  969.             else
  970.             {
  971.                 ClipCursor( NULL );
  972.             }
  973.         }
  974.  
  975.         // Initialize the app's device-dependent objects
  976.         hr = InitDeviceObjects();
  977.         if( SUCCEEDED(hr) )
  978.         {
  979.             hr = RestoreDeviceObjects();
  980.             if( SUCCEEDED(hr) )
  981.             {
  982.                 m_bActive = TRUE;
  983.                 return S_OK;
  984.             }
  985.         }
  986.  
  987.         // Cleanup before we try again
  988.         InvalidateDeviceObjects();
  989.         DeleteDeviceObjects();
  990.         SAFE_RELEASE( m_pd3dDevice );
  991.     }
  992.  
  993.     // If that failed, fall back to the reference rasterizer
  994.     if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
  995.     {
  996.         // Select the default adapter
  997.         m_dwAdapter = 0L;
  998.         pAdapterInfo = &m_Adapters[m_dwAdapter];
  999.  
  1000.         // Look for a software device
  1001.         for( UINT i=0L; i<pAdapterInfo->dwNumDevices; i++ )
  1002.         {
  1003.             if( pAdapterInfo->devices[i].DeviceType == D3DDEVTYPE_REF )
  1004.             {
  1005.                 pAdapterInfo->dwCurrentDevice = i;
  1006.                 pDeviceInfo = &pAdapterInfo->devices[i];
  1007.                 m_bWindowed = pDeviceInfo->bWindowed;
  1008.                 break;
  1009.             }
  1010.         }
  1011.  
  1012.         // Try again, this time with the reference rasterizer
  1013.         if( pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice].DeviceType ==
  1014.             D3DDEVTYPE_REF )
  1015.         {
  1016.             // Make sure main window isn't topmost, so error message is visible
  1017.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1018.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  1019.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1020.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1021.                           SWP_SHOWWINDOW );
  1022.             AdjustWindowForChange();
  1023.  
  1024.             // Let the user know we are switching from HAL to the reference rasterizer
  1025.             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
  1026.  
  1027.             hr = Initialize3DEnvironment();
  1028.         }
  1029.     }
  1030.  
  1031.     return hr;
  1032. }
  1033.  
  1034.  
  1035.  
  1036.  
  1037. //-----------------------------------------------------------------------------
  1038. // Name:
  1039. // Desc:
  1040. //-----------------------------------------------------------------------------
  1041. HRESULT CD3DApplication::Resize3DEnvironment()
  1042. {
  1043.     HRESULT hr;
  1044.  
  1045.     // Release all vidmem objects
  1046.     if( FAILED( hr = InvalidateDeviceObjects() ) )
  1047.         return hr;
  1048.  
  1049.     // Reset the device
  1050.     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
  1051.         return hr;
  1052.  
  1053.     // Store render target surface desc
  1054.     LPDIRECT3DSURFACE8 pBackBuffer;
  1055.     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1056.     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  1057.     pBackBuffer->Release();
  1058.  
  1059.     // Set up the fullscreen cursor
  1060.     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  1061.     {
  1062.         HCURSOR hCursor;
  1063. #ifdef _WIN64
  1064.         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  1065. #else
  1066.         hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
  1067. #endif
  1068.         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
  1069.         m_pd3dDevice->ShowCursor( TRUE );
  1070.     }
  1071.  
  1072.     // Confine cursor to fullscreen window
  1073.     if( m_bClipCursorWhenFullscreen )
  1074.     {
  1075.         if (!m_bWindowed )
  1076.         {
  1077.             RECT rcWindow;
  1078.             GetWindowRect( m_hWnd, &rcWindow );
  1079.             ClipCursor( &rcWindow );
  1080.         }
  1081.         else
  1082.         {
  1083.             ClipCursor( NULL );
  1084.         }
  1085.     }
  1086.  
  1087.     // Initialize the app's device-dependent objects
  1088.     hr = RestoreDeviceObjects();
  1089.     if( FAILED(hr) )
  1090.         return hr;
  1091.  
  1092.     // If the app is paused, trigger the rendering of the current frame
  1093.     if( FALSE == m_bFrameMoving )
  1094.     {
  1095.         m_bSingleStep = TRUE;
  1096.         DXUtil_Timer( TIMER_START );
  1097.         DXUtil_Timer( TIMER_STOP );
  1098.     }
  1099.  
  1100.     return S_OK;
  1101. }
  1102.  
  1103.  
  1104.  
  1105.  
  1106. //-----------------------------------------------------------------------------
  1107. // Name: ToggleFullScreen()
  1108. // Desc: Called when user toggles between fullscreen mode and windowed mode
  1109. //-----------------------------------------------------------------------------
  1110. HRESULT CD3DApplication::ToggleFullscreen()
  1111. {
  1112.     // Get access to current adapter, device, and mode
  1113.     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1114.     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  1115.     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  1116.  
  1117.     // Need device change if going windowed and the current device
  1118.     // can only be fullscreen
  1119.     if( !m_bWindowed && !pDeviceInfo->bCanDoWindowed )
  1120.         return ForceWindowed();
  1121.  
  1122.     m_bReady = FALSE;
  1123.  
  1124.     // Toggle the windowed state
  1125.     m_bWindowed = !m_bWindowed;
  1126.     pDeviceInfo->bWindowed = m_bWindowed;
  1127.  
  1128.     // Prepare window for windowed/fullscreen change
  1129.     AdjustWindowForChange();
  1130.  
  1131.     // Set up the presentation parameters
  1132.     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
  1133.     if( m_bWindowed )
  1134.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
  1135.     else
  1136.         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
  1137.     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
  1138.     m_d3dpp.hDeviceWindow          = m_hWnd;
  1139.     if( m_bWindowed )
  1140.     {
  1141.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  1142.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  1143.         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  1144.     }
  1145.     else
  1146.     {
  1147.         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
  1148.         m_d3dpp.BackBufferHeight = pModeInfo->Height;
  1149.         m_d3dpp.BackBufferFormat = pModeInfo->Format;
  1150.     }
  1151.  
  1152.     // Resize the 3D device
  1153.     if( FAILED( Resize3DEnvironment() ) )
  1154.     {
  1155.         if( m_bWindowed )
  1156.             return ForceWindowed();
  1157.         else
  1158.             return E_FAIL;
  1159.     }
  1160.  
  1161.     // When moving from fullscreen to windowed mode, it is important to
  1162.     // adjust the window size after resetting the device rather than
  1163.     // beforehand to ensure that you get the window size you want.  For
  1164.     // example, when switching from 640x480 fullscreen to windowed with
  1165.     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  1166.     // the window size to 1000x600 until after the display mode has
  1167.     // changed to 1024x768, because windows cannot be larger than the
  1168.     // desktop.
  1169.     if( m_bWindowed )
  1170.     {
  1171.         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1172.                       m_rcWindowBounds.left, m_rcWindowBounds.top,
  1173.                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1174.                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1175.                       SWP_SHOWWINDOW );
  1176.     }
  1177.  
  1178.     m_bReady = TRUE;
  1179.  
  1180.     return S_OK;
  1181. }
  1182.  
  1183.  
  1184.  
  1185.  
  1186. //-----------------------------------------------------------------------------
  1187. // Name: ForceWindowed()
  1188. // Desc: Switch to a windowed mode, even if that means picking a new device
  1189. //       and/or adapter
  1190. //-----------------------------------------------------------------------------
  1191. HRESULT CD3DApplication::ForceWindowed()
  1192. {
  1193.     HRESULT hr;
  1194.     D3DAdapterInfo* pAdapterInfoCur = &m_Adapters[m_dwAdapter];
  1195.     D3DDeviceInfo*  pDeviceInfoCur  = &pAdapterInfoCur->devices[pAdapterInfoCur->dwCurrentDevice];
  1196.     BOOL bFoundDevice = FALSE;
  1197.  
  1198.     if( pDeviceInfoCur->bCanDoWindowed )
  1199.     {
  1200.         bFoundDevice = TRUE;
  1201.     }
  1202.     else
  1203.     {
  1204.         // Look for a windowable device on any adapter
  1205.         D3DAdapterInfo* pAdapterInfo;
  1206.         DWORD dwAdapter;
  1207.         D3DDeviceInfo* pDeviceInfo;
  1208.         DWORD dwDevice;
  1209.         for( dwAdapter = 0; dwAdapter < m_dwNumAdapters; dwAdapter++ )
  1210.         {
  1211.             pAdapterInfo = &m_Adapters[dwAdapter];
  1212.             for( dwDevice = 0; dwDevice < pAdapterInfo->dwNumDevices; dwDevice++ )
  1213.             {
  1214.                 pDeviceInfo = &pAdapterInfo->devices[dwDevice];
  1215.                 if( pDeviceInfo->bCanDoWindowed )
  1216.                 {
  1217.                     m_dwAdapter = dwAdapter;
  1218.                     pDeviceInfoCur = pDeviceInfo;
  1219.                     pAdapterInfo->dwCurrentDevice = dwDevice;
  1220.                     bFoundDevice = TRUE;
  1221.                     break;
  1222.                 }
  1223.             }
  1224.             if( bFoundDevice )
  1225.                 break;
  1226.         }
  1227.     }
  1228.  
  1229.     if( !bFoundDevice )
  1230.         return E_FAIL;
  1231.  
  1232.     pDeviceInfoCur->bWindowed = TRUE;
  1233.     m_bWindowed = TRUE;
  1234.  
  1235.     // Now destroy the current 3D device objects, then reinitialize
  1236.  
  1237.     m_bReady = FALSE;
  1238.  
  1239.     // Release all scene objects that will be re-created for the new device
  1240.     InvalidateDeviceObjects();
  1241.     DeleteDeviceObjects();
  1242.  
  1243.     // Release display objects, so a new device can be created
  1244.     if( m_pd3dDevice->Release() > 0L )
  1245.         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1246.  
  1247.     // Create the new device
  1248.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1249.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1250.     m_bReady = TRUE;
  1251.  
  1252.     return S_OK;
  1253. }
  1254.  
  1255.  
  1256.  
  1257.  
  1258. //-----------------------------------------------------------------------------
  1259. // Name: AdjustWindowForChange()
  1260. // Desc: Prepare the window for a possible change between windowed mode and
  1261. //       fullscreen mode.  This function is virtual and thus can be overridden
  1262. //       to provide different behavior, such as switching to an entirely
  1263. //       different window for fullscreen mode (as in the MFC sample apps).
  1264. //-----------------------------------------------------------------------------
  1265. HRESULT CD3DApplication::AdjustWindowForChange()
  1266. {
  1267.     if( m_bWindowed )
  1268.     {
  1269.         // Set windowed-mode style
  1270.         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
  1271.         if( m_hMenu != NULL )
  1272.             SetMenu( m_hWnd, m_hMenu );
  1273.     }
  1274.     else
  1275.     {
  1276.         // Set fullscreen-mode style
  1277.         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
  1278.         m_hMenu = (HMENU)SetMenu( m_hWnd, NULL );
  1279.     }
  1280.     return S_OK;
  1281. }
  1282.  
  1283.  
  1284.  
  1285.  
  1286. //-----------------------------------------------------------------------------
  1287. // Name: UserSelectNewDevice()
  1288. // Desc: Displays a dialog so the user can select a new adapter, device, or
  1289. //       display mode, and then recreates the 3D environment if needed
  1290. //-----------------------------------------------------------------------------
  1291. HRESULT CD3DApplication::UserSelectNewDevice()
  1292. {
  1293.     HRESULT hr;
  1294.  
  1295.     // Can't display dialogs in fullscreen mode
  1296.     if( m_bWindowed == FALSE )
  1297.     {
  1298.         if( FAILED( ToggleFullscreen() ) )
  1299.         {
  1300.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  1301.             return E_FAIL;
  1302.         }
  1303.     }
  1304.  
  1305.     // Prompt the user to change the mode
  1306.     if( IDOK != DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL),
  1307.                                 MAKEINTRESOURCE(IDD_SELECTDEVICE), m_hWnd,
  1308.                                 SelectDeviceProc, (LPARAM)this ) )
  1309.         return S_OK;
  1310.  
  1311.     // Get access to the newly selected adapter, device, and mode
  1312.     DWORD dwDevice;
  1313.     dwDevice  = m_Adapters[m_dwAdapter].dwCurrentDevice;
  1314.     m_bWindowed = m_Adapters[m_dwAdapter].devices[dwDevice].bWindowed;
  1315.  
  1316.     // Release all scene objects that will be re-created for the new device
  1317.     InvalidateDeviceObjects();
  1318.     DeleteDeviceObjects();
  1319.  
  1320.     // Release display objects, so a new device can be created
  1321.     if( m_pd3dDevice->Release() > 0L )
  1322.         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1323.  
  1324.     // Inform the display class of the change. It will internally
  1325.     // re-create valid surfaces, a d3ddevice, etc.
  1326.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1327.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1328.  
  1329.     // If the app is paused, trigger the rendering of the current frame
  1330.     if( FALSE == m_bFrameMoving )
  1331.     {
  1332.         m_bSingleStep = TRUE;
  1333.         DXUtil_Timer( TIMER_START );
  1334.         DXUtil_Timer( TIMER_STOP );
  1335.     }
  1336.  
  1337.     return S_OK;
  1338. }
  1339.  
  1340.  
  1341.  
  1342.  
  1343. //-----------------------------------------------------------------------------
  1344. // Name: SelectDeviceProc()
  1345. // Desc: Windows message handling function for the device select dialog
  1346. //-----------------------------------------------------------------------------
  1347. INT_PTR CALLBACK CD3DApplication::SelectDeviceProc( HWND hDlg, UINT msg,
  1348.                                                     WPARAM wParam, LPARAM lParam )
  1349. {
  1350.     // Get access to the UI controls
  1351.     HWND hwndAdapterList        = GetDlgItem( hDlg, IDC_ADAPTER_COMBO );
  1352.     HWND hwndDeviceList         = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
  1353.     HWND hwndFullscreenModeList = GetDlgItem( hDlg, IDC_FULLSCREENMODES_COMBO );
  1354.     HWND hwndWindowedRadio      = GetDlgItem( hDlg, IDC_WINDOW );
  1355.     HWND hwndFullscreenRadio    = GetDlgItem( hDlg, IDC_FULLSCREEN );
  1356.     HWND hwndMultiSampleList    = GetDlgItem( hDlg, IDC_MULTISAMPLE_COMBO );
  1357.     BOOL bUpdateDlgControls     = FALSE;
  1358.  
  1359.     // Static state for adapter/device/mode selection
  1360.     static CD3DApplication* pd3dApp;
  1361.     static DWORD  dwOldAdapter, dwNewAdapter;
  1362.     static DWORD  dwOldDevice,  dwNewDevice;
  1363.     static DWORD  dwOldMode,    dwNewMode;
  1364.     static BOOL   bOldWindowed, bNewWindowed;
  1365.     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeWindowed, NewMultiSampleTypeWindowed;
  1366.     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeFullscreen, NewMultiSampleTypeFullscreen;
  1367.  
  1368.     // Working variables
  1369.     D3DAdapterInfo* pAdapter;
  1370.     D3DDeviceInfo*  pDevice;
  1371.  
  1372.     // Handle the initialization message
  1373.     if( WM_INITDIALOG == msg )
  1374.     {
  1375.         // Old state
  1376.         pd3dApp      = (CD3DApplication*)lParam;
  1377.         dwOldAdapter = pd3dApp->m_dwAdapter;
  1378.         pAdapter     = &pd3dApp->m_Adapters[dwOldAdapter];
  1379.  
  1380.         dwOldDevice  = pAdapter->dwCurrentDevice;
  1381.         pDevice      = &pAdapter->devices[dwOldDevice];
  1382.  
  1383.         dwOldMode    = pDevice->dwCurrentMode;
  1384.         bOldWindowed = pDevice->bWindowed;
  1385.         OldMultiSampleTypeWindowed = pDevice->MultiSampleTypeWindowed;
  1386.         OldMultiSampleTypeFullscreen = pDevice->MultiSampleTypeFullscreen;
  1387.  
  1388.         // New state is initially the same as the old state
  1389.         dwNewAdapter = dwOldAdapter;
  1390.         dwNewDevice  = dwOldDevice;
  1391.         dwNewMode    = dwOldMode;
  1392.         bNewWindowed = bOldWindowed;
  1393.         NewMultiSampleTypeWindowed = OldMultiSampleTypeWindowed;
  1394.         NewMultiSampleTypeFullscreen = OldMultiSampleTypeFullscreen;
  1395.  
  1396.         // Set flag to update dialog controls below
  1397.         bUpdateDlgControls = TRUE;
  1398.     }
  1399.  
  1400.     if( WM_COMMAND == msg )
  1401.     {
  1402.         // Get current UI state
  1403.         bNewWindowed  = Button_GetCheck( hwndWindowedRadio );
  1404.  
  1405.         if( IDOK == LOWORD(wParam) )
  1406.         {
  1407.             // Handle the case when the user hits the OK button. Check if any
  1408.             // of the options were changed
  1409.             if( dwNewAdapter != dwOldAdapter || dwNewDevice  != dwOldDevice  ||
  1410.                 dwNewMode    != dwOldMode    || bNewWindowed != bOldWindowed ||
  1411.                 NewMultiSampleTypeWindowed != OldMultiSampleTypeWindowed ||
  1412.                 NewMultiSampleTypeFullscreen != OldMultiSampleTypeFullscreen )
  1413.             {
  1414.                 pd3dApp->m_dwAdapter = dwNewAdapter;
  1415.  
  1416.                 pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
  1417.                 pAdapter->dwCurrentDevice = dwNewDevice;
  1418.  
  1419.                 pAdapter->devices[dwNewDevice].dwCurrentMode = dwNewMode;
  1420.                 pAdapter->devices[dwNewDevice].bWindowed     = bNewWindowed;
  1421.                 pAdapter->devices[dwNewDevice].MultiSampleTypeWindowed = NewMultiSampleTypeWindowed;
  1422.                 pAdapter->devices[dwNewDevice].MultiSampleTypeFullscreen = NewMultiSampleTypeFullscreen;
  1423.  
  1424.                 EndDialog( hDlg, IDOK );
  1425.             }
  1426.             else
  1427.                 EndDialog( hDlg, IDCANCEL );
  1428.  
  1429.             return TRUE;
  1430.         }
  1431.         else if( IDCANCEL == LOWORD(wParam) )
  1432.         {
  1433.             // Handle the case when the user hits the Cancel button
  1434.             EndDialog( hDlg, IDCANCEL );
  1435.             return TRUE;
  1436.         }
  1437.         else if( CBN_SELENDOK == HIWORD(wParam) )
  1438.         {
  1439.             if( LOWORD(wParam) == IDC_ADAPTER_COMBO )
  1440.             {
  1441.                 dwNewAdapter = ComboBox_GetCurSel( hwndAdapterList );
  1442.                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
  1443.  
  1444.                 dwNewDevice  = pAdapter->dwCurrentDevice;
  1445.                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
  1446.                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
  1447.             }
  1448.             else if( LOWORD(wParam) == IDC_DEVICE_COMBO )
  1449.             {
  1450.                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
  1451.  
  1452.                 dwNewDevice  = ComboBox_GetCurSel( hwndDeviceList );
  1453.                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
  1454.                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
  1455.             }
  1456.             else if( LOWORD(wParam) == IDC_FULLSCREENMODES_COMBO )
  1457.             {
  1458.                 dwNewMode = ComboBox_GetCurSel( hwndFullscreenModeList );
  1459.             }
  1460.             else if( LOWORD(wParam) == IDC_MULTISAMPLE_COMBO )
  1461.             {
  1462.                 DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
  1463.                 if( bNewWindowed )
  1464.                     NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1465.                 else
  1466.                     NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1467.             }
  1468.         }
  1469.         // Keep the UI current
  1470.         bUpdateDlgControls = TRUE;
  1471.     }
  1472.  
  1473.     // Update the dialog controls
  1474.     if( bUpdateDlgControls )
  1475.     {
  1476.         // Reset the content in each of the combo boxes
  1477.         ComboBox_ResetContent( hwndAdapterList );
  1478.         ComboBox_ResetContent( hwndDeviceList );
  1479.         ComboBox_ResetContent( hwndFullscreenModeList );
  1480.         ComboBox_ResetContent( hwndMultiSampleList );
  1481.  
  1482.         pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
  1483.         pDevice  = &pAdapter->devices[dwNewDevice];
  1484.  
  1485.         // Add a list of adapters to the adapter combo box
  1486.         for( DWORD a=0; a < pd3dApp->m_dwNumAdapters; a++ )
  1487.         {
  1488.             // Add device name to the combo box
  1489.             DWORD dwItem = ComboBox_AddString( hwndAdapterList,
  1490.                              pd3dApp->m_Adapters[a].d3dAdapterIdentifier.Description );
  1491.  
  1492.             // Set the item data to identify this adapter
  1493.             ComboBox_SetItemData( hwndAdapterList, dwItem, a );
  1494.  
  1495.             // Set the combobox selection on the current adapater
  1496.             if( a == dwNewAdapter )
  1497.                 ComboBox_SetCurSel( hwndAdapterList, dwItem );
  1498.         }
  1499.  
  1500.         // Add a list of devices to the device combo box
  1501.         for( DWORD d=0; d < pAdapter->dwNumDevices; d++ )
  1502.         {
  1503.             // Add device name to the combo box
  1504.             DWORD dwItem = ComboBox_AddString( hwndDeviceList,
  1505.                                                pAdapter->devices[d].strDesc );
  1506.  
  1507.             // Set the item data to identify this device
  1508.             ComboBox_SetItemData( hwndDeviceList, dwItem, d );
  1509.  
  1510.             // Set the combobox selection on the current device
  1511.             if( d == dwNewDevice )
  1512.                 ComboBox_SetCurSel( hwndDeviceList, dwItem );
  1513.         }
  1514.  
  1515.         // Add a list of modes to the mode combo box
  1516.         for( DWORD m=0; m < pDevice->dwNumModes; m++ )
  1517.         {
  1518.             DWORD BitDepth = 16;
  1519.             if( pDevice->modes[m].Format == D3DFMT_X8R8G8B8 ||
  1520.                 pDevice->modes[m].Format == D3DFMT_A8R8G8B8 ||
  1521.                 pDevice->modes[m].Format == D3DFMT_R8G8B8 )
  1522.             {
  1523.                 BitDepth = 32;
  1524.             }
  1525.  
  1526.             // Add mode desc to the combo box
  1527.             TCHAR strMode[80];
  1528.             _stprintf( strMode, _T("%ld x %ld x %ld"), pDevice->modes[m].Width,
  1529.                                                        pDevice->modes[m].Height,
  1530.                                                        BitDepth );
  1531.             DWORD dwItem = ComboBox_AddString( hwndFullscreenModeList, strMode );
  1532.  
  1533.             // Set the item data to identify this mode
  1534.             ComboBox_SetItemData( hwndFullscreenModeList, dwItem, m );
  1535.  
  1536.             // Set the combobox selection on the current mode
  1537.             if( m == dwNewMode )
  1538.                 ComboBox_SetCurSel( hwndFullscreenModeList, dwItem );
  1539.         }
  1540.  
  1541.         // Add a list of multisample modes to the multisample combo box
  1542.         for( m=0; m <= 16; m++ )
  1543.         {
  1544.             TCHAR strDesc[50];
  1545.  
  1546.             D3DFORMAT fmt;
  1547.             if( bNewWindowed )
  1548.                 fmt = pd3dApp->m_Adapters[dwNewAdapter].d3ddmDesktop.Format;
  1549.             else
  1550.                 fmt = pDevice->modes[dwNewMode].Format;
  1551.  
  1552.             if ( m == 1 ) // 1 is not a valid multisample type
  1553.                 continue;
  1554.  
  1555.             if( SUCCEEDED( pd3dApp->m_pD3D->CheckDeviceMultiSampleType( dwNewAdapter,
  1556.                 pDevice->DeviceType, fmt, bNewWindowed, (D3DMULTISAMPLE_TYPE)m ) ) )
  1557.             {
  1558.                 if( m == 0 )
  1559.                     lstrcpy( strDesc, _T("none") );
  1560.                 else
  1561.                     wsprintf( strDesc, _T("%d samples"), m );
  1562.  
  1563.                 // Add device name to the combo box
  1564.                 DWORD dwItem = ComboBox_AddString( hwndMultiSampleList, strDesc );
  1565.  
  1566.                 // Set the item data to identify this multisample type
  1567.                 ComboBox_SetItemData( hwndMultiSampleList, dwItem, m );
  1568.  
  1569.                 // Set the combobox selection on the current multisample type
  1570.                 if( bNewWindowed )
  1571.                 {
  1572.                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeWindowed || m == 0 )
  1573.                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
  1574.                 }
  1575.                 else
  1576.                 {
  1577.                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeFullscreen || m == 0 )
  1578.                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
  1579.                 }
  1580.             }
  1581.         }
  1582.         DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
  1583.         if( bNewWindowed )
  1584.             NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1585.         else
  1586.             NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
  1587.         EnableWindow( hwndMultiSampleList, ComboBox_GetCount( hwndMultiSampleList ) > 1);
  1588.         EnableWindow( hwndWindowedRadio, pDevice->bCanDoWindowed );
  1589.  
  1590.         if( bNewWindowed )
  1591.         {
  1592.             Button_SetCheck( hwndWindowedRadio,   TRUE );
  1593.             Button_SetCheck( hwndFullscreenRadio, FALSE );
  1594.             EnableWindow( hwndFullscreenModeList, FALSE );
  1595.         }
  1596.         else
  1597.         {
  1598.             Button_SetCheck( hwndWindowedRadio,   FALSE );
  1599.             Button_SetCheck( hwndFullscreenRadio, TRUE );
  1600.             EnableWindow( hwndFullscreenModeList, TRUE );
  1601.         }
  1602.         return TRUE;
  1603.     }
  1604.  
  1605.     return FALSE;
  1606. }
  1607.  
  1608.  
  1609.  
  1610.  
  1611. //-----------------------------------------------------------------------------
  1612. // Name: Run()
  1613. // Desc:
  1614. //-----------------------------------------------------------------------------
  1615. INT CD3DApplication::Run()
  1616. {
  1617.     // Load keyboard accelerators
  1618.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  1619.  
  1620.     // Now we're ready to recieve and process Windows messages.
  1621.     BOOL bGotMsg;
  1622.     MSG  msg;
  1623.     msg.message = WM_NULL;
  1624.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  1625.  
  1626.     while( WM_QUIT != msg.message  )
  1627.     {
  1628.         // Use PeekMessage() if the app is active, so we can use idle time to
  1629.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  1630.         if( m_bActive )
  1631.             bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  1632.         else
  1633.             bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
  1634.  
  1635.         if( bGotMsg )
  1636.         {
  1637.             // Translate and dispatch the message
  1638.             if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
  1639.             {
  1640.                 TranslateMessage( &msg );
  1641.                 DispatchMessage( &msg );
  1642.             }
  1643.         }
  1644.         else
  1645.         {
  1646.             // Render a frame during idle time (no messages are waiting)
  1647.             if( m_bActive && m_bReady )
  1648.             {
  1649.                 if( FAILED( Render3DEnvironment() ) )
  1650.                     SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1651.             }
  1652.         }
  1653.     }
  1654.  
  1655.     return (INT)msg.wParam;
  1656. }
  1657.  
  1658.  
  1659.  
  1660.  
  1661. //-----------------------------------------------------------------------------
  1662. // Name: Render3DEnvironment()
  1663. // Desc: Draws the scene.
  1664. //-----------------------------------------------------------------------------
  1665. HRESULT CD3DApplication::Render3DEnvironment()
  1666. {
  1667.     HRESULT hr;
  1668.  
  1669.     // Test the cooperative level to see if it's okay to render
  1670.     if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  1671.     {
  1672.         // If the device was lost, do not render until we get it back
  1673.         if( D3DERR_DEVICELOST == hr )
  1674.             return S_OK;
  1675.  
  1676.         // Check if the device needs to be resized.
  1677.         if( D3DERR_DEVICENOTRESET == hr )
  1678.         {
  1679.             // If we are windowed, read the desktop mode and use the same format for
  1680.             // the back buffer
  1681.             if( m_bWindowed )
  1682.             {
  1683.                 D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1684.                 m_pD3D->GetAdapterDisplayMode( m_dwAdapter, &pAdapterInfo->d3ddmDesktop );
  1685.                 m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  1686.             }
  1687.  
  1688.             if( FAILED( hr = Resize3DEnvironment() ) )
  1689.                 return hr;
  1690.         }
  1691.         return hr;
  1692.     }
  1693.  
  1694.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  1695.     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  1696.     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  1697.     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
  1698.         return S_OK;
  1699.  
  1700.     // FrameMove (animate) the scene
  1701.     if( m_bFrameMoving || m_bSingleStep )
  1702.     {
  1703.         // Store the time for the app
  1704.         m_fTime        = fAppTime;
  1705.         m_fElapsedTime = fElapsedAppTime;
  1706.  
  1707.         // Frame move the scene
  1708.         if( FAILED( hr = FrameMove() ) )
  1709.             return hr;
  1710.  
  1711.         m_bSingleStep = FALSE;
  1712.     }
  1713.  
  1714.     // Render the scene as normal
  1715.     if( FAILED( hr = Render() ) )
  1716.         return hr;
  1717.  
  1718.     // Keep track of the frame count
  1719.     {
  1720.         static FLOAT fLastTime = 0.0f;
  1721.         static DWORD dwFrames  = 0L;
  1722.         FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  1723.         ++dwFrames;
  1724.  
  1725.         // Update the scene stats once per second
  1726.         if( fTime - fLastTime > 1.0f )
  1727.         {
  1728.             m_fFPS    = dwFrames / (fTime - fLastTime);
  1729.             fLastTime = fTime;
  1730.             dwFrames  = 0L;
  1731.  
  1732.             // Get adapter's current mode so we can report
  1733.             // bit depth (back buffer depth may be unknown)
  1734.             D3DDISPLAYMODE mode;
  1735.             m_pD3D->GetAdapterDisplayMode(m_dwAdapter, &mode);
  1736.  
  1737.             _stprintf( m_strFrameStats, _T("%.02f fps (%dx%dx%d)"), m_fFPS,
  1738.                        m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
  1739.                        mode.Format==D3DFMT_X8R8G8B8?32:16 );
  1740.             D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
  1741.             D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  1742.             D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  1743.             if( m_bUseDepthBuffer )
  1744.             {
  1745.  
  1746.                 switch( pModeInfo->DepthStencilFormat )
  1747.                 {
  1748.                 case D3DFMT_D16:
  1749.                     lstrcat( m_strFrameStats, _T(" (D16)") );
  1750.                     break;
  1751.                 case D3DFMT_D15S1:
  1752.                     lstrcat( m_strFrameStats, _T(" (D15S1)") );
  1753.                     break;
  1754.                 case D3DFMT_D24X8:
  1755.                     lstrcat( m_strFrameStats, _T(" (D24X8)") );
  1756.                     break;
  1757.                 case D3DFMT_D24S8:
  1758.                     lstrcat( m_strFrameStats, _T(" (D24S8)") );
  1759.                     break;
  1760.                 case D3DFMT_D24X4S4:
  1761.                     lstrcat( m_strFrameStats, _T(" (D24X4S4)") );
  1762.                     break;
  1763.                 case D3DFMT_D32:
  1764.                     lstrcat( m_strFrameStats, _T(" (D32)") );
  1765.                     break;
  1766.                 }
  1767.             }
  1768.  
  1769.             D3DMULTISAMPLE_TYPE MultiSampleType;
  1770.             if( m_bWindowed )
  1771.                 MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed;
  1772.             else
  1773.                 MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen;
  1774.             switch( MultiSampleType )
  1775.             {
  1776.             case D3DMULTISAMPLE_2_SAMPLES:
  1777.                 lstrcat( m_strFrameStats, _T(" (2x Multisample)") );
  1778.                 break;
  1779.             case D3DMULTISAMPLE_3_SAMPLES:
  1780.                 lstrcat( m_strFrameStats, _T(" (3x Multisample)") );
  1781.                 break;
  1782.             case D3DMULTISAMPLE_4_SAMPLES:
  1783.                 lstrcat( m_strFrameStats, _T(" (4x Multisample)") );
  1784.                 break;
  1785.             case D3DMULTISAMPLE_5_SAMPLES:
  1786.                 lstrcat( m_strFrameStats, _T(" (5x Multisample)") );
  1787.                 break;
  1788.             case D3DMULTISAMPLE_6_SAMPLES:
  1789.                 lstrcat( m_strFrameStats, _T(" (6x Multisample)") );
  1790.                 break;
  1791.             case D3DMULTISAMPLE_7_SAMPLES:
  1792.                 lstrcat( m_strFrameStats, _T(" (7x Multisample)") );
  1793.                 break;
  1794.             case D3DMULTISAMPLE_8_SAMPLES:
  1795.                 lstrcat( m_strFrameStats, _T(" (8x Multisample)") );
  1796.                 break;
  1797.             case D3DMULTISAMPLE_9_SAMPLES:
  1798.                 lstrcat( m_strFrameStats, _T(" (9x Multisample)") );
  1799.                 break;
  1800.             case D3DMULTISAMPLE_10_SAMPLES:
  1801.                 lstrcat( m_strFrameStats, _T(" (10x Multisample)") );
  1802.                 break;
  1803.             case D3DMULTISAMPLE_11_SAMPLES:
  1804.                 lstrcat( m_strFrameStats, _T(" (11x Multisample)") );
  1805.                 break;
  1806.             case D3DMULTISAMPLE_12_SAMPLES:
  1807.                 lstrcat( m_strFrameStats, _T(" (12x Multisample)") );
  1808.                 break;
  1809.             case D3DMULTISAMPLE_13_SAMPLES:
  1810.                 lstrcat( m_strFrameStats, _T(" (13x Multisample)") );
  1811.                 break;
  1812.             case D3DMULTISAMPLE_14_SAMPLES:
  1813.                 lstrcat( m_strFrameStats, _T(" (14x Multisample)") );
  1814.                 break;
  1815.             case D3DMULTISAMPLE_15_SAMPLES:
  1816.                 lstrcat( m_strFrameStats, _T(" (15x Multisample)") );
  1817.                 break;
  1818.             case D3DMULTISAMPLE_16_SAMPLES:
  1819.                 lstrcat( m_strFrameStats, _T(" (16x Multisample)") );
  1820.                 break;
  1821.             }
  1822.         }
  1823.     }
  1824.  
  1825.     // Show the frame on the primary surface.
  1826.     m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1827.  
  1828.     return S_OK;
  1829. }
  1830.  
  1831.  
  1832.  
  1833.  
  1834. //-----------------------------------------------------------------------------
  1835. // Name: Pause()
  1836. // Desc: Called in to toggle the pause state of the app.
  1837. //-----------------------------------------------------------------------------
  1838. VOID CD3DApplication::Pause( BOOL bPause )
  1839. {
  1840.     static DWORD dwAppPausedCount = 0L;
  1841.  
  1842.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1843.     m_bReady          = ( dwAppPausedCount ? FALSE : TRUE );
  1844.  
  1845.     // Handle the first pause request (of many, nestable pause requests)
  1846.     if( bPause && ( 1 == dwAppPausedCount ) )
  1847.     {
  1848.         // Stop the scene from animating
  1849.         if( m_bFrameMoving )
  1850.             DXUtil_Timer( TIMER_STOP );
  1851.     }
  1852.  
  1853.     if( 0 == dwAppPausedCount )
  1854.     {
  1855.         // Restart the timers
  1856.         if( m_bFrameMoving )
  1857.             DXUtil_Timer( TIMER_START );
  1858.     }
  1859. }
  1860.  
  1861.  
  1862.  
  1863.  
  1864. //-----------------------------------------------------------------------------
  1865. // Name: Cleanup3DEnvironment()
  1866. // Desc: Cleanup scene objects
  1867. //-----------------------------------------------------------------------------
  1868. VOID CD3DApplication::Cleanup3DEnvironment()
  1869. {
  1870.     m_bActive = FALSE;
  1871.     m_bReady  = FALSE;
  1872.  
  1873.     if( m_pd3dDevice )
  1874.     {
  1875.         InvalidateDeviceObjects();
  1876.         DeleteDeviceObjects();
  1877.  
  1878.         m_pd3dDevice->Release();
  1879.         m_pD3D->Release();
  1880.  
  1881.         m_pd3dDevice = NULL;
  1882.         m_pD3D       = NULL;
  1883.     }
  1884.  
  1885.     FinalCleanup();
  1886. }
  1887.  
  1888.  
  1889.  
  1890.  
  1891. //-----------------------------------------------------------------------------
  1892. // Name: DisplayErrorMsg()
  1893. // Desc: Displays error messages in a message box
  1894. //-----------------------------------------------------------------------------
  1895. HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  1896. {
  1897.     TCHAR strMsg[512];
  1898.  
  1899.     switch( hr )
  1900.     {
  1901.         case D3DAPPERR_NODIRECT3D:
  1902.             _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n")
  1903.                              _T("want to check that the latest version of\n")
  1904.                              _T("DirectX is correctly installed on your\n")
  1905.                              _T("system.  Also make sure that this program\n")
  1906.                              _T("was compiled with header files that match\n")
  1907.                              _T("the installed DirectX DLLs.") );
  1908.             break;
  1909.  
  1910.         case D3DAPPERR_NOCOMPATIBLEDEVICES:
  1911.             _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
  1912.                              _T("devices.") );
  1913.             break;
  1914.  
  1915.         case D3DAPPERR_NOWINDOWABLEDEVICES:
  1916.             _tcscpy( strMsg, _T("This sample cannot run in a desktop\n")
  1917.                              _T("window with the current display settings.\n")
  1918.                              _T("Please change your desktop settings to a\n")
  1919.                              _T("16- or 32-bit display mode and re-run this\n")
  1920.                              _T("sample.") );
  1921.             break;
  1922.  
  1923.         case D3DAPPERR_NOHARDWAREDEVICE:
  1924.             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n")
  1925.                              _T("were found.") );
  1926.             break;
  1927.  
  1928.         case D3DAPPERR_HALNOTCOMPATIBLE:
  1929.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1930.                              _T("not available on your Direct3D hardware\n")
  1931.                              _T("accelerator.") );
  1932.             break;
  1933.  
  1934.         case D3DAPPERR_NOWINDOWEDHAL:
  1935.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1936.                              _T("render into a window.\n")
  1937.                              _T("Press F2 while the app is running to see a\n")
  1938.                              _T("list of available devices and modes.") );
  1939.             break;
  1940.  
  1941.         case D3DAPPERR_NODESKTOPHAL:
  1942.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1943.                              _T("render into a window with the current\n")
  1944.                              _T("desktop display settings.\n")
  1945.                              _T("Press F2 while the app is running to see a\n")
  1946.                              _T("list of available devices and modes.") );
  1947.             break;
  1948.  
  1949.         case D3DAPPERR_NOHALTHISMODE:
  1950.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1951.                              _T("not available on your Direct3D hardware\n")
  1952.                              _T("accelerator with the current desktop display\n")
  1953.                              _T("settings.\n")
  1954.                              _T("Press F2 while the app is running to see a\n")
  1955.                              _T("list of available devices and modes.") );
  1956.             break;
  1957.  
  1958.         case D3DAPPERR_MEDIANOTFOUND:
  1959.             _tcscpy( strMsg, _T("Could not load required media." ) );
  1960.             break;
  1961.  
  1962.         case D3DAPPERR_RESIZEFAILED:
  1963.             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
  1964.             break;
  1965.  
  1966.         case D3DAPPERR_NONZEROREFCOUNT:
  1967.             _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n")
  1968.                              _T("count (meaning things were not properly\n")
  1969.                              _T("cleaned up).") );
  1970.             break;
  1971.  
  1972.         case D3DAPPERR_NULLREFDEVICE:
  1973.             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n")
  1974.                              _T("The reference rendering device was selected, but your\n")
  1975.                              _T("computer only has a reduced-functionality reference device\n")
  1976.                              _T("installed.  Install the DirectX SDK to get the full\n")
  1977.                              _T("reference device.\n") );
  1978.             break;
  1979.  
  1980.         case E_OUTOFMEMORY:
  1981.             _tcscpy( strMsg, _T("Not enough memory.") );
  1982.             break;
  1983.  
  1984.         case D3DERR_OUTOFVIDEOMEMORY:
  1985.             _tcscpy( strMsg, _T("Not enough video memory.") );
  1986.             break;
  1987.  
  1988.         default:
  1989.             _tcscpy( strMsg, _T("Generic application error. Enable\n")
  1990.                              _T("debug output for detailed information.") );
  1991.     }
  1992.  
  1993.     if( MSGERR_APPMUSTEXIT == dwType )
  1994.     {
  1995.         _tcscat( strMsg, _T("\n\nThis sample will now exit.") );
  1996.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
  1997.  
  1998.         // Close the window, which shuts down the app
  1999.         if( m_hWnd )
  2000.             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  2001.     }
  2002.     else
  2003.     {
  2004.         if( MSGWARN_SWITCHEDTOREF == dwType )
  2005.             _tcscat( strMsg, _T("\n\nSwitching to the reference rasterizer,\n")
  2006.                              _T("a software device that implements the entire\n")
  2007.                              _T("Direct3D feature set, but runs very slowly.") );
  2008.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
  2009.     }
  2010.  
  2011.     return hr;
  2012. }
  2013.  
  2014.  
  2015.  
  2016.  
  2017.