0001: //-----------------------------------------------------------------------------
0002: // File: D3DApp.cpp
0003: //
0004: // Desc: Application class for the Direct3D samples framework library.
0005: //-----------------------------------------------------------------------------
0006: #define STRICT
0007: #include <windows.h>
0008: #include <windowsx.h>
0009: #include <basetsd.h>
0010: #include <mmsystem.h>
0011: #include <stdio.h>
0012: #include <tchar.h>
0013: #include <D3D8.h>
0014: #include "D3DApp.h"
0015: #include "D3DUtil.h"
0016: #include "DXUtil.h"
0017: #include "D3DRes.h"
0018: 
0019: 
0020: 
0021: 
0022: //-----------------------------------------------------------------------------
0023: // Global access to the app (needed for the global WndProc())
0024: //-----------------------------------------------------------------------------
0025: static CD3DApplication* g_pD3DApp = NULL;
0026: 
0027: 
0028: 
0029: 
0030: //-----------------------------------------------------------------------------
0031: // Name: CD3DApplication()
0032: // Desc: Constructor
0033: //-----------------------------------------------------------------------------
0034: CD3DApplication::CD3DApplication()
0035: {
0036:     g_pD3DApp           = this;
0037: 
0038:     m_dwNumAdapters     = 0;
0039:     m_dwAdapter         = 0L;
0040:     m_pD3D              = NULL;
0041:     m_pd3dDevice        = NULL;
0042:     m_hWnd              = NULL;
0043:     m_hWndFocus         = NULL;
0044:     m_bActive           = FALSE;
0045:     m_bReady            = FALSE;
0046:     m_bHasFocus     = FALSE;
0047:     m_dwCreateFlags     = 0L;
0048: 
0049:     m_bFrameMoving      = TRUE;
0050:     m_bSingleStep       = FALSE;
0051:     m_fFPS              = 0.0f;
0052:     m_strDeviceStats[0] = _T('\0');
0053:     m_strFrameStats[0]  = _T('\0');
0054: 
0055:     m_strWindowTitle    = _T("D3D8 Application");
0056:     m_dwCreationWidth   = 400;
0057:     m_dwCreationHeight  = 300;
0058:     m_bUseDepthBuffer   = FALSE;
0059:     m_dwMinDepthBits    = 16;
0060:     m_dwMinStencilBits  = 0;
0061:     m_bShowCursorWhenFullscreen = FALSE;
0062: 
0063:     // When m_bClipCursorWhenFullscreen is TRUE, the cursor is limited to
0064:     // the device window when the app goes fullscreen.  This prevents users
0065:     // from accidentally clicking outside the app window on a multimon system.
0066:     // This flag is turned off by default for debug builds, since it makes 
0067:     // multimon debugging difficult.
0068: #if defined(_DEBUG) || defined(DEBUG)
0069:     m_bClipCursorWhenFullscreen = FALSE;
0070: #else
0071:     m_bClipCursorWhenFullscreen = TRUE;
0072: #endif
0073: }
0074: 
0075: 
0076: 
0077: 
0078: //-----------------------------------------------------------------------------
0079: // Name: WndProc()
0080: // Desc: Static msg handler which passes messages to the application class.
0081: //-----------------------------------------------------------------------------
0082: LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
0083: {
0084:     return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
0085: }
0086: 
0087: 
0088: 
0089: 
0090: //-----------------------------------------------------------------------------
0091: // Name: Create()
0092: // Desc:
0093: //-----------------------------------------------------------------------------
0094: HRESULT CD3DApplication::Create( HINSTANCE hInstance )
0095: {
0096:     HRESULT hr;
0097: 
0098:     // Create the Direct3D object
0099:     m_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
0100:     if( m_pD3D == NULL )
0101:         return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
0102: 
0103:     // Build a list of Direct3D adapters, modes and devices. The
0104:     // ConfirmDevice() callback is used to confirm that only devices that
0105:     // meet the app's requirements are considered.
0106:     if( FAILED( hr = BuildDeviceList() ) )
0107:     {
0108:         SAFE_RELEASE( m_pD3D );
0109:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0110:     }
0111: 
0112:     // Unless a substitute hWnd has been specified, create a window to
0113:     // render into
0114:     if( m_hWnd == NULL)
0115:     {
0116:         // Register the windows class
0117:         WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
0118:                               LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
0119:                               LoadCursor( NULL, IDC_ARROW ),
0120:                               (HBRUSH)GetStockObject(WHITE_BRUSH),
0121:                               NULL, _T("D3D Window") };
0122:         RegisterClass( &wndClass );
0123: 
0124:         // Set the window's initial style
0125:         m_dwWindowStyle = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|
0126:                           WS_MINIMIZEBOX|WS_VISIBLE;
0127: 
0128:         // Set the window's initial width
0129:         RECT rc;
0130:         SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
0131:         AdjustWindowRect( &rc, m_dwWindowStyle, TRUE );
0132: 
0133:         // Create the render window
0134:         m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle,
0135:                                CW_USEDEFAULT, CW_USEDEFAULT,
0136:                                (rc.right-rc.left), (rc.bottom-rc.top), 0L,
0137:                                LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ),
0138:                                hInstance, 0L );
0139:     }
0140: 
0141:     // The focus window can be a specified to be a different window than the
0142:     // device window.  If not, use the device window as the focus window.
0143:     if( m_hWndFocus == NULL )
0144:         m_hWndFocus = m_hWnd;
0145: 
0146:     // Save window properties
0147:     m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
0148:     GetWindowRect( m_hWnd, &m_rcWindowBounds );
0149:     GetClientRect( m_hWnd, &m_rcWindowClient );
0150: 
0151:     // Initialize the application timer
0152:     DXUtil_Timer( TIMER_START );
0153: 
0154:     // Initialize the app's custom scene stuff
0155:     if( FAILED( hr = OneTimeSceneInit() ) )
0156:     {
0157:         SAFE_RELEASE( m_pD3D );
0158:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0159:     }
0160: 
0161:     // Initialize the 3D environment for the app
0162:     if( FAILED( hr = Initialize3DEnvironment() ) )
0163:     {
0164:         SAFE_RELEASE( m_pD3D );
0165:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0166:     }
0167: 
0168:     // The app is ready to go
0169:     m_bReady = TRUE;
0170: 
0171:     return S_OK;
0172: }
0173: 
0174: 
0175: 
0176: 
0177: //-----------------------------------------------------------------------------
0178: // Name: SortModesCallback()
0179: // Desc: Callback function for sorting display modes (used by BuildDeviceList).
0180: //-----------------------------------------------------------------------------
0181: static int SortModesCallback( const VOID* arg1, const VOID* arg2 )
0182: {
0183:     D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
0184:     D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
0185: 
0186:     if( p1->Format > p2->Format )   return -1;
0187:     if( p1->Format < p2->Format )   return +1;
0188:     if( p1->Width  < p2->Width )    return -1;
0189:     if( p1->Width  > p2->Width )    return +1;
0190:     if( p1->Height < p2->Height )   return -1;
0191:     if( p1->Height > p2->Height )   return +1;
0192: 
0193:     return 0;
0194: }
0195: 
0196: 
0197: 
0198: 
0199: //-----------------------------------------------------------------------------
0200: // Name: BuildDeviceList()
0201: // Desc:
0202: //-----------------------------------------------------------------------------
0203: HRESULT CD3DApplication::BuildDeviceList()
0204: {
0205:     const DWORD dwNumDeviceTypes = 2;
0206:     const TCHAR* strDeviceDescs[] = { _T("HAL"), _T("REF") };
0207:     const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF };
0208: 
0209:     BOOL bHALExists = FALSE;
0210:     BOOL bHALIsWindowedCompatible = FALSE;
0211:     BOOL bHALIsDesktopCompatible = FALSE;
0212:     BOOL bHALIsSampleCompatible = FALSE;
0213: 
0214:     // Loop through all the adapters on the system (usually, there's just one
0215:     // unless more than one graphics card is present).
0216:     for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
0217:     {
0218:         // Fill in adapter info
0219:         D3DAdapterInfo* pAdapter  = &m_Adapters[m_dwNumAdapters];
0220:         m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier );
0221:         m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
0222:         pAdapter->dwNumDevices    = 0;
0223:         pAdapter->dwCurrentDevice = 0;
0224: 
0225:         // Enumerate all display modes on this adapter
0226:         D3DDISPLAYMODE modes[100];
0227:         D3DFORMAT      formats[20];
0228:         DWORD dwNumFormats      = 0;
0229:         DWORD dwNumModes        = 0;
0230:         DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter );
0231: 
0232:         // Add the adapter's current desktop format to the list of formats
0233:         formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
0234: 
0235:         for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
0236:         {
0237:             // Get the display mode attributes
0238:             D3DDISPLAYMODE DisplayMode;
0239:             m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode );
0240: 
0241:             // Filter out low-resolution modes
0242:             if( DisplayMode.Width  < 640 || DisplayMode.Height < 400 )
0243:                 continue;
0244: 
0245:             // Check if the mode already exists (to filter out refresh rates)
0246:             for( DWORD m=0L; m<dwNumModes; m++ )
0247:             {
0248:                 if( ( modes[m].Width  == DisplayMode.Width  ) &&
0249:                     ( modes[m].Height == DisplayMode.Height ) &&
0250:                     ( modes[m].Format == DisplayMode.Format ) )
0251:                     break;
0252:             }
0253: 
0254:             // If we found a new mode, add it to the list of modes
0255:             if( m == dwNumModes )
0256:             {
0257:                 modes[dwNumModes].Width       = DisplayMode.Width;
0258:                 modes[dwNumModes].Height      = DisplayMode.Height;
0259:                 modes[dwNumModes].Format      = DisplayMode.Format;
0260:                 modes[dwNumModes].RefreshRate = 0;
0261:                 dwNumModes++;
0262: 
0263:                 // Check if the mode's format already exists
0264:                 for( DWORD f=0; f<dwNumFormats; f++ )
0265:                 {
0266:                     if( DisplayMode.Format == formats[f] )
0267:                         break;
0268:                 }
0269: 
0270:                 // If the format is new, add it to the list
0271:                 if( f== dwNumFormats )
0272:                     formats[dwNumFormats++] = DisplayMode.Format;
0273:             }
0274:         }
0275: 
0276:         // Sort the list of display modes (by format, then width, then height)
0277:         qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
0278: 
0279:         // Add devices to adapter
0280:         for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
0281:         {
0282:             // Fill in device info
0283:             D3DDeviceInfo* pDevice;
0284:             pDevice                 = &pAdapter->devices[pAdapter->dwNumDevices];
0285:             pDevice->DeviceType     = DeviceTypes[iDevice];
0286:             m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
0287:             pDevice->strDesc        = strDeviceDescs[iDevice];
0288:             pDevice->dwNumModes     = 0;
0289:             pDevice->dwCurrentMode  = 0;
0290:             pDevice->bCanDoWindowed = FALSE;
0291:             pDevice->bWindowed      = FALSE;
0292:             pDevice->MultiSampleTypeFullscreen = D3DMULTISAMPLE_NONE;
0293:             pDevice->MultiSampleTypeWindowed = D3DMULTISAMPLE_NONE;
0294: 
0295:             // Examine each format supported by the adapter to see if it will
0296:             // work with this device and meets the needs of the application.
0297:             BOOL  bFormatConfirmed[20];
0298:             DWORD dwBehavior[20];
0299:             D3DFORMAT fmtDepthStencil[20];
0300: 
0301:             for( DWORD f=0; f<dwNumFormats; f++ )
0302:             {
0303:                 bFormatConfirmed[f] = FALSE;
0304:                 fmtDepthStencil[f] = D3DFMT_UNKNOWN;
0305: 
0306:                 // Skip formats that cannot be used as render targets on this device
0307:                 if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
0308:                                                      formats[f], formats[f], FALSE ) ) )
0309:                     continue;
0310: 
0311:                 if( pDevice->DeviceType == D3DDEVTYPE_HAL )
0312:                 {
0313:                     // This system has a HAL device
0314:                     bHALExists = TRUE;
0315: 
0316:                     if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED )
0317:                     {
0318:                         // HAL can run in a window for some mode
0319:                         bHALIsWindowedCompatible = TRUE;
0320: 
0321:                         if( f == 0 )
0322:                         {
0323:                             // HAL can run in a window for the current desktop mode
0324:                             bHALIsDesktopCompatible = TRUE;
0325:                         }
0326:                     }
0327:                 }
0328: 
0329:                 // Confirm the device/format for HW vertex processing
0330:                 if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
0331:                 {
0332:                     if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
0333:                     {
0334:                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
0335:                                         D3DCREATE_PUREDEVICE;
0336: 
0337:                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
0338:                                                       formats[f] ) ) )
0339:                             bFormatConfirmed[f] = TRUE;
0340:                     }
0341: 
0342:                     if ( FALSE == bFormatConfirmed[f] )
0343:                     {
0344:                         dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
0345: 
0346:                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
0347:                                                       formats[f] ) ) )
0348:                             bFormatConfirmed[f] = TRUE;
0349:                     }
0350: 
0351:                     if ( FALSE == bFormatConfirmed[f] )
0352:                     {
0353:                         dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
0354: 
0355:                         if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
0356:                                                       formats[f] ) ) )
0357:                             bFormatConfirmed[f] = TRUE;
0358:                     }
0359:                 }
0360: 
0361:                 // Confirm the device/format for SW vertex processing
0362:                 if( FALSE == bFormatConfirmed[f] )
0363:                 {
0364:                     dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
0365: 
0366:                     if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
0367:                                                   formats[f] ) ) )
0368:                         bFormatConfirmed[f] = TRUE;
0369:                 }
0370: 
0371:                 // Find a suitable depth/stencil buffer format for this device/format
0372:                 if( bFormatConfirmed[f] && m_bUseDepthBuffer )
0373:                 {
0374:                     if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
0375:                         formats[f], &fmtDepthStencil[f] ) )
0376:                     {
0377:                         bFormatConfirmed[f] = FALSE;
0378:                     }
0379:                 }
0380:             }
0381: 
0382:             // Add all enumerated display modes with confirmed formats to the
0383:             // device's list of valid modes
0384:             for( DWORD m=0L; m<dwNumModes; m++ )
0385:             {
0386:                 for( DWORD f=0; f<dwNumFormats; f++ )
0387:                 {
0388:                     if( modes[m].Format == formats[f] )
0389:                     {
0390:                         if( bFormatConfirmed[f] == TRUE )
0391:                         {
0392:                             // Add this mode to the device's list of valid modes
0393:                             pDevice->modes[pDevice->dwNumModes].Width      = modes[m].Width;
0394:                             pDevice->modes[pDevice->dwNumModes].Height     = modes[m].Height;
0395:                             pDevice->modes[pDevice->dwNumModes].Format     = modes[m].Format;
0396:                             pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
0397:                             pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
0398:                             pDevice->dwNumModes++;
0399: 
0400:                             if( pDevice->DeviceType == D3DDEVTYPE_HAL )
0401:                                 bHALIsSampleCompatible = TRUE;
0402:                         }
0403:                     }
0404:                 }
0405:             }
0406: 
0407:             // Select any 640x480 mode for default (but prefer a 16-bit mode)
0408:             for( m=0; m<pDevice->dwNumModes; m++ )
0409:             {
0410:                 if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
0411:                 {
0412:                     pDevice->dwCurrentMode = m;
0413:                     if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
0414:                         pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
0415:                         pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
0416:                     {
0417:                         break;
0418:                     }
0419:                 }
0420:             }
0421: 
0422:             // Check if the device is compatible with the desktop display mode
0423:             // (which was added initially as formats[0])
0424:             if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) )
0425:             {
0426:                 pDevice->bCanDoWindowed = TRUE;
0427:                 pDevice->bWindowed      = TRUE;
0428:             }
0429: 
0430:             // If valid modes were found, keep this device
0431:             if( pDevice->dwNumModes > 0 )
0432:                 pAdapter->dwNumDevices++;
0433:         }
0434: 
0435:         // If valid devices were found, keep this adapter
0436:         if( pAdapter->dwNumDevices > 0 )
0437:             m_dwNumAdapters++;
0438:     }
0439: 
0440:     // Return an error if no compatible devices were found
0441:     if( 0L == m_dwNumAdapters )
0442:         return D3DAPPERR_NOCOMPATIBLEDEVICES;
0443: 
0444:     // Pick a default device that can render into a window
0445:     // (This code assumes that the HAL device comes before the REF
0446:     // device in the device array).
0447:     for( DWORD a=0; a<m_dwNumAdapters; a++ )
0448:     {
0449:         for( DWORD d=0; d < m_Adapters[a].dwNumDevices; d++ )
0450:         {
0451:             if( m_Adapters[a].devices[d].bWindowed )
0452:             {
0453:                 m_Adapters[a].dwCurrentDevice = d;
0454:                 m_dwAdapter = a;
0455:                 m_bWindowed = TRUE;
0456: 
0457:                 // Display a warning message
0458:                 if( m_Adapters[a].devices[d].DeviceType == D3DDEVTYPE_REF )
0459:                 {
0460:                     if( !bHALExists )
0461:                         DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
0462:                     else if( !bHALIsSampleCompatible )
0463:                         DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
0464:                     else if( !bHALIsWindowedCompatible )
0465:                         DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
0466:                     else if( !bHALIsDesktopCompatible )
0467:                         DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
0468:                     else // HAL is desktop compatible, but not sample compatible
0469:                         DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
0470:                 }
0471: 
0472:                 return S_OK;
0473:             }
0474:         }
0475:     }
0476: 
0477:     return D3DAPPERR_NOWINDOWABLEDEVICES;
0478: }
0479: 
0480: 
0481: 
0482: 
0483: //-----------------------------------------------------------------------------
0484: // Name: FindDepthStencilFormat()
0485: // Desc: Finds a depth/stencil format for the given device that is compatible
0486: //       with the render target format and meets the needs of the app.
0487: //-----------------------------------------------------------------------------
0488: BOOL CD3DApplication::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
0489:     D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
0490: {
0491:     if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
0492:     {
0493:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0494:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
0495:         {
0496:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0497:                 TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
0498:             {
0499:                 *pDepthStencilFormat = D3DFMT_D16;
0500:                 return TRUE;
0501:             }
0502:         }
0503:     }
0504: 
0505:     if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
0506:     {
0507:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0508:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
0509:         {
0510:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0511:                 TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
0512:             {
0513:                 *pDepthStencilFormat = D3DFMT_D15S1;
0514:                 return TRUE;
0515:             }
0516:         }
0517:     }
0518: 
0519:     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
0520:     {
0521:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0522:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
0523:         {
0524:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0525:                 TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
0526:             {
0527:                 *pDepthStencilFormat = D3DFMT_D24X8;
0528:                 return TRUE;
0529:             }
0530:         }
0531:     }
0532: 
0533:     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
0534:     {
0535:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0536:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
0537:         {
0538:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0539:                 TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
0540:             {
0541:                 *pDepthStencilFormat = D3DFMT_D24S8;
0542:                 return TRUE;
0543:             }
0544:         }
0545:     }
0546: 
0547:     if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
0548:     {
0549:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0550:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
0551:         {
0552:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0553:                 TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
0554:             {
0555:                 *pDepthStencilFormat = D3DFMT_D24X4S4;
0556:                 return TRUE;
0557:             }
0558:         }
0559:     }
0560: 
0561:     if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
0562:     {
0563:         if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
0564:             TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
0565:         {
0566:             if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
0567:                 TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
0568:             {
0569:                 *pDepthStencilFormat = D3DFMT_D32;
0570:                 return TRUE;
0571:             }
0572:         }
0573:     }
0574: 
0575:     return FALSE;
0576: }
0577: 
0578: 
0579: 
0580: 
0581: //-----------------------------------------------------------------------------
0582: // Name: MsgProc()
0583: // Desc: Message handling function.
0584: //-----------------------------------------------------------------------------
0585: LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
0586:                                   LPARAM lParam )
0587: {
0588:     HRESULT hr;
0589: 
0590:     switch( uMsg )
0591:     {
0592:         case WM_PAINT:
0593:             // Handle paint messages when the app is not ready
0594:             if( m_pd3dDevice && !m_bReady )
0595:             {
0596:                 if( m_bWindowed )
0597:                 {
0598:                     Render();
0599:                     m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
0600:                 }
0601:             }
0602:             break;
0603: 
0604:         case WM_ACTIVATEAPP:
0605:             m_bHasFocus = (BOOL) wParam;
0606:             break;
0607: 
0608:         case WM_GETMINMAXINFO:
0609:             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
0610:             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
0611:             break;
0612: 
0613:         case WM_ENTERSIZEMOVE:
0614:             // Halt frame movement while the app is sizing or moving
0615:             Pause( TRUE );
0616:             break;
0617: 
0618:         case WM_SIZE:
0619:             // Check to see if we are losing our window...
0620:             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
0621:             {
0622:                 if( m_bClipCursorWhenFullscreen && !m_bWindowed )
0623:                     ClipCursor( NULL );
0624:                 m_bActive = FALSE;
0625:             }
0626:             else
0627:             {
0628:                 m_bActive = TRUE;
0629:             }
0630:             break;
0631: 
0632:         case WM_EXITSIZEMOVE:
0633:             Pause( FALSE );
0634: 
0635:             if( m_bActive && m_bWindowed )
0636:             {
0637:                 RECT rcClientOld;
0638:                 rcClientOld = m_rcWindowClient;
0639: 
0640:                 // Update window properties
0641:                 GetWindowRect( m_hWnd, &m_rcWindowBounds );
0642:                 GetClientRect( m_hWnd, &m_rcWindowClient );
0643: 
0644:                 if( rcClientOld.right - rcClientOld.left !=
0645:                     m_rcWindowClient.right - m_rcWindowClient.left ||
0646:                     rcClientOld.bottom - rcClientOld.top !=
0647:                     m_rcWindowClient.bottom - m_rcWindowClient.top)
0648:                 {
0649:                     // A new window size will require a new backbuffer
0650:                     // size, so the 3D structures must be changed accordingly.
0651:                     m_bReady = FALSE;
0652: 
0653:                     m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
0654:                     m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
0655: 
0656:                     // Resize the 3D environment
0657:                     if( FAILED( hr = Resize3DEnvironment() ) )
0658:                     {
0659:                         DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
0660:                         return 0;
0661:                     }
0662: 
0663:                     m_bReady = TRUE;
0664:                 }
0665:             }
0666: 
0667:             break;
0668: 
0669:         case WM_SETCURSOR:
0670:             // Turn off Windows cursor in fullscreen mode
0671:             if( m_bActive && m_bReady && !m_bWindowed )
0672:             {
0673:                 SetCursor( NULL );
0674:                 if( m_bShowCursorWhenFullscreen )
0675:                     m_pd3dDevice->ShowCursor( TRUE );
0676:                 return TRUE; // prevent Windows from setting cursor to window class cursor
0677:             }
0678:             break;
0679: 
0680:          case WM_MOUSEMOVE:
0681:             if( m_bActive && m_bReady && m_pd3dDevice != NULL )
0682:             {
0683:                 POINT ptCursor;
0684:                 GetCursorPos( &ptCursor );
0685:                 if( !m_bWindowed )
0686:                     ScreenToClient( m_hWnd, &ptCursor );
0687:                 m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0L );
0688:             }
0689:             break;
0690: 
0691:        case WM_ENTERMENULOOP:
0692:             // Pause the app when menus are displayed
0693:             Pause(TRUE);
0694:             break;
0695: 
0696:         case WM_EXITMENULOOP:
0697:             Pause(FALSE);
0698:             break;
0699: 
0700:         case WM_CONTEXTMENU:
0701:             // No context menus allowed in fullscreen mode
0702:             if( m_bWindowed == FALSE )
0703:                 break;
0704: 
0705:             // Handle the app's context menu (via right mouse click)
0706:             TrackPopupMenuEx( GetSubMenu( LoadMenu( 0, MAKEINTRESOURCE(IDR_POPUP) ), 0 ),
0707:                               TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL );
0708:             break;
0709: 
0710:         case WM_NCHITTEST:
0711:             // Prevent the user from selecting the menu in fullscreen mode
0712:             if( !m_bWindowed )
0713:                 return HTCLIENT;
0714: 
0715:             break;
0716: 
0717:         case WM_POWERBROADCAST:
0718:             switch( wParam )
0719:             {
0720:                 #ifndef PBT_APMQUERYSUSPEND
0721:                     #define PBT_APMQUERYSUSPEND 0x0000
0722:                 #endif
0723:                 case PBT_APMQUERYSUSPEND:
0724:                     // At this point, the app should save any data for open
0725:                     // network connections, files, etc., and prepare to go into
0726:                     // a suspended mode.
0727:                     return TRUE;
0728: 
0729:                 #ifndef PBT_APMRESUMESUSPEND
0730:                     #define PBT_APMRESUMESUSPEND 0x0007
0731:                 #endif
0732:                 case PBT_APMRESUMESUSPEND:
0733:                     // At this point, the app should recover any data, network
0734:                     // connections, files, etc., and resume running from when
0735:                     // the app was suspended.
0736:                     return TRUE;
0737:             }
0738:             break;
0739: 
0740:         case WM_SYSCOMMAND:
0741:             // Prevent moving/sizing and power loss in fullscreen mode
0742:             switch( wParam )
0743:             {
0744:                 case SC_MOVE:
0745:                 case SC_SIZE:
0746:                 case SC_MAXIMIZE:
0747:                 case SC_KEYMENU:
0748:                 case SC_MONITORPOWER:
0749:                     if( FALSE == m_bWindowed )
0750:                         return 1;
0751:                     break;
0752:             }
0753:             break;
0754: 
0755:         case WM_COMMAND:
0756:             switch( LOWORD(wParam) )
0757:             {
0758:                 case IDM_CHANGEDEVICE:
0759:                     // Prompt the user to select a new device or mode
0760:                     if( m_bActive && m_bReady )
0761:                     {
0762:                         Pause(TRUE);
0763: 
0764:                         if( FAILED( hr = UserSelectNewDevice() ) )
0765:                             return 0;
0766: 
0767:                         Pause(FALSE);
0768:                     }
0769:                     return 0;
0770: 
0771:                 case IDM_TOGGLEFULLSCREEN:
0772:                     // Toggle the fullscreen/window mode
0773:                     if( m_bActive && m_bReady )
0774:                     {
0775:                         Pause( TRUE );
0776:                         
0777:                         if( FAILED( ToggleFullscreen() ) )
0778:                         {
0779:                             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
0780:                             return 0;
0781:                         }
0782: 
0783:                         Pause( FALSE );                        
0784:                     }
0785:                     return 0;
0786: 
0787:                 case IDM_EXIT:
0788:                     // Recieved key/menu command to exit app
0789:                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
0790:                     return 0;
0791:             }
0792:             break;
0793: 
0794:         case WM_CLOSE:
0795:             Cleanup3DEnvironment();
0796:             DestroyMenu( GetMenu(hWnd) );
0797:             DestroyWindow( hWnd );
0798:             PostQuitMessage(0);
0799:             return 0;
0800:     }
0801: 
0802:     return DefWindowProc( hWnd, uMsg, wParam, lParam );
0803: }
0804: 
0805: 
0806: 
0807: 
0808: //-----------------------------------------------------------------------------
0809: // Name: Initialize3DEnvironment()
0810: // Desc:
0811: //-----------------------------------------------------------------------------
0812: HRESULT CD3DApplication::Initialize3DEnvironment()
0813: {
0814:     HRESULT hr;
0815: 
0816:     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
0817:     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
0818:     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
0819: 
0820:     // Prepare window for possible windowed/fullscreen change
0821:     AdjustWindowForChange();
0822: 
0823:     // Set up the presentation parameters
0824:     ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
0825:     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
0826:     m_d3dpp.BackBufferCount        = 1;
0827:     if( pDeviceInfo->bWindowed )
0828:         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
0829:     else
0830:         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
0831:     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
0832:     m_d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
0833:     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
0834:     m_d3dpp.hDeviceWindow          = m_hWnd;
0835:     if( m_bWindowed )
0836:     {
0837:         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
0838:         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
0839:         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
0840:     }
0841:     else
0842:     {
0843:         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
0844:         m_d3dpp.BackBufferHeight = pModeInfo->Height;
0845:         m_d3dpp.BackBufferFormat = pModeInfo->Format;
0846:     }
0847: 
0848:     if( pDeviceInfo->d3dCaps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
0849:     {
0850:         // Warn user about null ref device that can't render anything
0851:         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
0852:     }
0853: 
0854:     // Create the device
0855:     hr = m_pD3D->CreateDevice( m_dwAdapter, pDeviceInfo->DeviceType,
0856:                                m_hWndFocus, pModeInfo->dwBehavior, &m_d3dpp,
0857:                                &m_pd3dDevice );
0858:     if( SUCCEEDED(hr) )
0859:     {
0860:         // When moving from fullscreen to windowed mode, it is important to
0861:         // adjust the window size after recreating the device rather than
0862:         // beforehand to ensure that you get the window size you want.  For
0863:         // example, when switching from 640x480 fullscreen to windowed with
0864:         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
0865:         // the window size to 1000x600 until after the display mode has
0866:         // changed to 1024x768, because windows cannot be larger than the
0867:         // desktop.
0868:         if( m_bWindowed )
0869:         {
0870:             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
0871:                           m_rcWindowBounds.left, m_rcWindowBounds.top,
0872:                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
0873:                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
0874:                           SWP_SHOWWINDOW );
0875:         }
0876: 
0877:         // Store device Caps
0878:         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
0879:         m_dwCreateFlags = pModeInfo->dwBehavior;
0880: 
0881:         // Store device description
0882:         if( pDeviceInfo->DeviceType == D3DDEVTYPE_REF )
0883:             lstrcpy( m_strDeviceStats, TEXT("REF") );
0884:         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0885:             lstrcpy( m_strDeviceStats, TEXT("HAL") );
0886:         else if( pDeviceInfo->DeviceType == D3DDEVTYPE_SW )
0887:             lstrcpy( m_strDeviceStats, TEXT("SW") );
0888: 
0889:         if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
0890:             pModeInfo->dwBehavior & D3DCREATE_PUREDEVICE )
0891:         {
0892:             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0893:                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
0894:             else
0895:                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
0896:         }
0897:         else if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
0898:         {
0899:             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0900:                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
0901:             else
0902:                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
0903:         }
0904:         else if( pModeInfo->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
0905:         {
0906:             if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0907:                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
0908:             else
0909:                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
0910:         }
0911:         else if( pModeInfo->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
0912:         {
0913:             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
0914:         }
0915: 
0916:         if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0917:         {
0918:             lstrcat( m_strDeviceStats, TEXT(": ") );
0919:             lstrcat( m_strDeviceStats, pAdapterInfo->d3dAdapterIdentifier.Description );
0920:         }
0921: 
0922:         // Store render target surface desc
0923:         LPDIRECT3DSURFACE8 pBackBuffer;
0924:         m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
0925:         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
0926:         pBackBuffer->Release();
0927: 
0928:         // Set up the fullscreen cursor
0929:         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
0930:         {
0931:             HCURSOR hCursor;
0932: #ifdef _WIN64
0933:             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
0934: #else
0935:             hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
0936: #endif
0937:             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
0938:             m_pd3dDevice->ShowCursor( TRUE );
0939:         }
0940: 
0941:         // Confine cursor to fullscreen window
0942:         if( m_bClipCursorWhenFullscreen )
0943:         {
0944:             if (!m_bWindowed )
0945:             {
0946:                 RECT rcWindow;
0947:                 GetWindowRect( m_hWnd, &rcWindow );
0948:                 ClipCursor( &rcWindow );
0949:             }
0950:             else
0951:             {
0952:                 ClipCursor( NULL );
0953:             }
0954:         }
0955: 
0956:         // Initialize the app's device-dependent objects
0957:         hr = InitDeviceObjects();
0958:         if( SUCCEEDED(hr) )
0959:         {
0960:             hr = RestoreDeviceObjects();
0961:             if( SUCCEEDED(hr) )
0962:             {
0963:                 m_bActive = TRUE;
0964:                 return S_OK;
0965:             }
0966:         }
0967: 
0968:         // Cleanup before we try again
0969:         InvalidateDeviceObjects();
0970:         DeleteDeviceObjects();
0971:         SAFE_RELEASE( m_pd3dDevice );
0972:     }
0973: 
0974:     // If that failed, fall back to the reference rasterizer
0975:     if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
0976:     {
0977:         // Select the default adapter
0978:         m_dwAdapter = 0L;
0979:         pAdapterInfo = &m_Adapters[m_dwAdapter];
0980: 
0981:         // Look for a software device
0982:         for( UINT i=0L; i<pAdapterInfo->dwNumDevices; i++ )
0983:         {
0984:             if( pAdapterInfo->devices[i].DeviceType == D3DDEVTYPE_REF )
0985:             {
0986:                 pAdapterInfo->dwCurrentDevice = i;
0987:                 pDeviceInfo = &pAdapterInfo->devices[i];
0988:                 m_bWindowed = pDeviceInfo->bWindowed;
0989:                 break;
0990:             }
0991:         }
0992: 
0993:         // Try again, this time with the reference rasterizer
0994:         if( pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice].DeviceType ==
0995:             D3DDEVTYPE_REF )
0996:         {
0997:             // Make sure main window isn't topmost, so error message is visible
0998:             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
0999:                           m_rcWindowBounds.left, m_rcWindowBounds.top,
1000:                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
1001:                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
1002:                           SWP_SHOWWINDOW );
1003:             AdjustWindowForChange();
1004: 
1005:             // Let the user know we are switching from HAL to the reference rasterizer
1006:             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
1007: 
1008:             hr = Initialize3DEnvironment();
1009:         }
1010:     }
1011: 
1012:     return hr;
1013: }
1014: 
1015: 
1016: 
1017: 
1018: //-----------------------------------------------------------------------------
1019: // Name:
1020: // Desc:
1021: //-----------------------------------------------------------------------------
1022: HRESULT CD3DApplication::Resize3DEnvironment()
1023: {
1024:     HRESULT hr;
1025: 
1026:     // Release all vidmem objects
1027:     if( FAILED( hr = InvalidateDeviceObjects() ) )
1028:         return hr;
1029: 
1030:     // Reset the device
1031:     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
1032:         return hr;
1033: 
1034:     // Store render target surface desc
1035:     LPDIRECT3DSURFACE8 pBackBuffer;
1036:     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
1037:     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
1038:     pBackBuffer->Release();
1039: 
1040:     // Set up the fullscreen cursor
1041:     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
1042:     {
1043:         HCURSOR hCursor;
1044: #ifdef _WIN64
1045:         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
1046: #else
1047:         hCursor = (HCURSOR)GetClassLong( m_hWnd, GCL_HCURSOR );
1048: #endif
1049:         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, TRUE );
1050:         m_pd3dDevice->ShowCursor( TRUE );
1051:     }
1052: 
1053:     // Confine cursor to fullscreen window
1054:     if( m_bClipCursorWhenFullscreen )
1055:     {
1056:         if (!m_bWindowed )
1057:         {
1058:             RECT rcWindow;
1059:             GetWindowRect( m_hWnd, &rcWindow );
1060:             ClipCursor( &rcWindow );
1061:         }
1062:         else
1063:         {
1064:             ClipCursor( NULL );
1065:         }
1066:     }
1067: 
1068:     // Initialize the app's device-dependent objects
1069:     hr = RestoreDeviceObjects();
1070:     if( FAILED(hr) )
1071:         return hr;
1072: 
1073:     // If the app is paused, trigger the rendering of the current frame
1074:     if( FALSE == m_bFrameMoving )
1075:     {
1076:         m_bSingleStep = TRUE;
1077:         DXUtil_Timer( TIMER_START );
1078:         DXUtil_Timer( TIMER_STOP );
1079:     }
1080: 
1081:     return S_OK;
1082: }
1083: 
1084: 
1085: 
1086: 
1087: //-----------------------------------------------------------------------------
1088: // Name: ToggleFullScreen()
1089: // Desc: Called when user toggles between fullscreen mode and windowed mode
1090: //-----------------------------------------------------------------------------
1091: HRESULT CD3DApplication::ToggleFullscreen()
1092: {
1093:     // Get access to current adapter, device, and mode
1094:     D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
1095:     D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
1096:     D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
1097: 
1098:     // Need device change if going windowed and the current device
1099:     // can only be fullscreen
1100:     if( !m_bWindowed && !pDeviceInfo->bCanDoWindowed )
1101:         return ForceWindowed();
1102: 
1103:     m_bReady = FALSE;
1104: 
1105:     // Toggle the windowed state
1106:     m_bWindowed = !m_bWindowed;
1107:     pDeviceInfo->bWindowed = m_bWindowed;
1108: 
1109:     // Prepare window for windowed/fullscreen change
1110:     AdjustWindowForChange();
1111: 
1112:     // Set up the presentation parameters
1113:     m_d3dpp.Windowed               = pDeviceInfo->bWindowed;
1114:     if( m_bWindowed )
1115:         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeWindowed;
1116:     else
1117:         m_d3dpp.MultiSampleType    = pDeviceInfo->MultiSampleTypeFullscreen;
1118:     m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
1119:     m_d3dpp.hDeviceWindow          = m_hWnd;
1120:     if( m_bWindowed )
1121:     {
1122:         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
1123:         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
1124:         m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
1125:     }
1126:     else
1127:     {
1128:         m_d3dpp.BackBufferWidth  = pModeInfo->Width;
1129:         m_d3dpp.BackBufferHeight = pModeInfo->Height;
1130:         m_d3dpp.BackBufferFormat = pModeInfo->Format;
1131:     }
1132: 
1133:     // Resize the 3D device
1134:     if( FAILED( Resize3DEnvironment() ) )
1135:     {
1136:         if( m_bWindowed )
1137:             return ForceWindowed();
1138:         else
1139:             return E_FAIL;
1140:     }
1141: 
1142:     // When moving from fullscreen to windowed mode, it is important to
1143:     // adjust the window size after resetting the device rather than
1144:     // beforehand to ensure that you get the window size you want.  For
1145:     // example, when switching from 640x480 fullscreen to windowed with
1146:     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
1147:     // the window size to 1000x600 until after the display mode has
1148:     // changed to 1024x768, because windows cannot be larger than the
1149:     // desktop.
1150:     if( m_bWindowed )
1151:     {
1152:         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
1153:                       m_rcWindowBounds.left, m_rcWindowBounds.top,
1154:                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
1155:                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
1156:                       SWP_SHOWWINDOW );
1157:     }
1158: 
1159:     m_bReady = TRUE;
1160: 
1161:     return S_OK;
1162: }
1163: 
1164: 
1165: 
1166: 
1167: //-----------------------------------------------------------------------------
1168: // Name: ForceWindowed()
1169: // Desc: Switch to a windowed mode, even if that means picking a new device
1170: //       and/or adapter
1171: //-----------------------------------------------------------------------------
1172: HRESULT CD3DApplication::ForceWindowed()
1173: {
1174:     HRESULT hr;
1175:     D3DAdapterInfo* pAdapterInfoCur = &m_Adapters[m_dwAdapter];
1176:     D3DDeviceInfo*  pDeviceInfoCur  = &pAdapterInfoCur->devices[pAdapterInfoCur->dwCurrentDevice];
1177:     BOOL bFoundDevice = FALSE;
1178: 
1179:     if( pDeviceInfoCur->bCanDoWindowed )
1180:     {
1181:         bFoundDevice = TRUE;
1182:     }
1183:     else
1184:     {
1185:         // Look for a windowable device on any adapter
1186:         D3DAdapterInfo* pAdapterInfo;
1187:         DWORD dwAdapter;
1188:         D3DDeviceInfo* pDeviceInfo;
1189:         DWORD dwDevice;
1190:         for( dwAdapter = 0; dwAdapter < m_dwNumAdapters; dwAdapter++ )
1191:         {
1192:             pAdapterInfo = &m_Adapters[dwAdapter];
1193:             for( dwDevice = 0; dwDevice < pAdapterInfo->dwNumDevices; dwDevice++ )
1194:             {
1195:                 pDeviceInfo = &pAdapterInfo->devices[dwDevice];
1196:                 if( pDeviceInfo->bCanDoWindowed )
1197:                 {
1198:                     m_dwAdapter = dwAdapter;
1199:                     pDeviceInfoCur = pDeviceInfo;
1200:                     pAdapterInfo->dwCurrentDevice = dwDevice;
1201:                     bFoundDevice = TRUE;
1202:                     break;
1203:                 }
1204:             }
1205:             if( bFoundDevice )
1206:                 break;
1207:         }
1208:     }
1209: 
1210:     if( !bFoundDevice )
1211:         return E_FAIL;
1212: 
1213:     pDeviceInfoCur->bWindowed = TRUE;
1214:     m_bWindowed = TRUE;
1215: 
1216:     // Now destroy the current 3D device objects, then reinitialize
1217: 
1218:     m_bReady = FALSE;
1219: 
1220:     // Release all scene objects that will be re-created for the new device
1221:     InvalidateDeviceObjects();
1222:     DeleteDeviceObjects();
1223: 
1224:     // Release display objects, so a new device can be created
1225:     if( m_pd3dDevice->Release() > 0L )
1226:         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
1227: 
1228:     // Create the new device
1229:     if( FAILED( hr = Initialize3DEnvironment() ) )
1230:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
1231:     m_bReady = TRUE;
1232: 
1233:     return S_OK;
1234: }
1235: 
1236: 
1237: 
1238: 
1239: //-----------------------------------------------------------------------------
1240: // Name: AdjustWindowForChange()
1241: // Desc: Prepare the window for a possible change between windowed mode and
1242: //       fullscreen mode.  This function is virtual and thus can be overridden
1243: //       to provide different behavior, such as switching to an entirely
1244: //       different window for fullscreen mode (as in the MFC sample apps).
1245: //-----------------------------------------------------------------------------
1246: HRESULT CD3DApplication::AdjustWindowForChange()
1247: {
1248:     if( m_bWindowed )
1249:     {
1250:         // Set windowed-mode style
1251:         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
1252:     }
1253:     else
1254:     {
1255:         // Set fullscreen-mode style
1256:         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
1257:     }
1258:     return S_OK;
1259: }
1260: 
1261: 
1262: 
1263: 
1264: //-----------------------------------------------------------------------------
1265: // Name: UserSelectNewDevice()
1266: // Desc: Displays a dialog so the user can select a new adapter, device, or
1267: //       display mode, and then recreates the 3D environment if needed
1268: //-----------------------------------------------------------------------------
1269: HRESULT CD3DApplication::UserSelectNewDevice()
1270: {
1271:     HRESULT hr;
1272: 
1273:     // Can't display dialogs in fullscreen mode
1274:     if( m_bWindowed == FALSE )
1275:     {
1276:         if( FAILED( ToggleFullscreen() ) )
1277:         {
1278:             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
1279:             return E_FAIL;
1280:         }
1281:     }
1282: 
1283:     // Prompt the user to change the mode
1284:     if( IDOK != DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL),
1285:                                 MAKEINTRESOURCE(IDD_SELECTDEVICE), m_hWnd,
1286:                                 SelectDeviceProc, (LPARAM)this ) )
1287:         return S_OK;
1288: 
1289:     // Get access to the newly selected adapter, device, and mode
1290:     DWORD dwDevice;
1291:     dwDevice  = m_Adapters[m_dwAdapter].dwCurrentDevice;
1292:     m_bWindowed = m_Adapters[m_dwAdapter].devices[dwDevice].bWindowed;
1293: 
1294:     // Release all scene objects that will be re-created for the new device
1295:     InvalidateDeviceObjects();
1296:     DeleteDeviceObjects();
1297: 
1298:     // Release display objects, so a new device can be created
1299:     if( m_pd3dDevice->Release() > 0L )
1300:         return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
1301: 
1302:     // Inform the display class of the change. It will internally
1303:     // re-create valid surfaces, a d3ddevice, etc.
1304:     if( FAILED( hr = Initialize3DEnvironment() ) )
1305:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
1306: 
1307:     // If the app is paused, trigger the rendering of the current frame
1308:     if( FALSE == m_bFrameMoving )
1309:     {
1310:         m_bSingleStep = TRUE;
1311:         DXUtil_Timer( TIMER_START );
1312:         DXUtil_Timer( TIMER_STOP );
1313:     }
1314: 
1315:     return S_OK;
1316: }
1317: 
1318: 
1319: 
1320: 
1321: //-----------------------------------------------------------------------------
1322: // Name: SelectDeviceProc()
1323: // Desc: Windows message handling function for the device select dialog
1324: //-----------------------------------------------------------------------------
1325: INT_PTR CALLBACK CD3DApplication::SelectDeviceProc( HWND hDlg, UINT msg,
1326:                                                     WPARAM wParam, LPARAM lParam )
1327: {
1328:     // Get access to the UI controls
1329:     HWND hwndAdapterList        = GetDlgItem( hDlg, IDC_ADAPTER_COMBO );
1330:     HWND hwndDeviceList         = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
1331:     HWND hwndFullscreenModeList = GetDlgItem( hDlg, IDC_FULLSCREENMODES_COMBO );
1332:     HWND hwndWindowedRadio      = GetDlgItem( hDlg, IDC_WINDOW );
1333:     HWND hwndFullscreenRadio    = GetDlgItem( hDlg, IDC_FULLSCREEN );
1334:     HWND hwndMultiSampleList    = GetDlgItem( hDlg, IDC_MULTISAMPLE_COMBO );
1335:     BOOL bUpdateDlgControls     = FALSE;
1336: 
1337:     // Static state for adapter/device/mode selection
1338:     static CD3DApplication* pd3dApp;
1339:     static DWORD  dwOldAdapter, dwNewAdapter;
1340:     static DWORD  dwOldDevice,  dwNewDevice;
1341:     static DWORD  dwOldMode,    dwNewMode;
1342:     static BOOL   bOldWindowed, bNewWindowed;
1343:     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeWindowed, NewMultiSampleTypeWindowed;
1344:     static D3DMULTISAMPLE_TYPE OldMultiSampleTypeFullscreen, NewMultiSampleTypeFullscreen;
1345: 
1346:     // Working variables
1347:     D3DAdapterInfo* pAdapter;
1348:     D3DDeviceInfo*  pDevice;
1349: 
1350:     // Handle the initialization message
1351:     if( WM_INITDIALOG == msg )
1352:     {
1353:         // Old state
1354:         pd3dApp      = (CD3DApplication*)lParam;
1355:         dwOldAdapter = pd3dApp->m_dwAdapter;
1356:         pAdapter     = &pd3dApp->m_Adapters[dwOldAdapter];
1357: 
1358:         dwOldDevice  = pAdapter->dwCurrentDevice;
1359:         pDevice      = &pAdapter->devices[dwOldDevice];
1360: 
1361:         dwOldMode    = pDevice->dwCurrentMode;
1362:         bOldWindowed = pDevice->bWindowed;
1363:         OldMultiSampleTypeWindowed = pDevice->MultiSampleTypeWindowed;
1364:         OldMultiSampleTypeFullscreen = pDevice->MultiSampleTypeFullscreen;
1365: 
1366:         // New state is initially the same as the old state
1367:         dwNewAdapter = dwOldAdapter;
1368:         dwNewDevice  = dwOldDevice;
1369:         dwNewMode    = dwOldMode;
1370:         bNewWindowed = bOldWindowed;
1371:         NewMultiSampleTypeWindowed = OldMultiSampleTypeWindowed;
1372:         NewMultiSampleTypeFullscreen = OldMultiSampleTypeFullscreen;
1373: 
1374:         // Set flag to update dialog controls below
1375:         bUpdateDlgControls = TRUE;
1376:     }
1377: 
1378:     if( WM_COMMAND == msg )
1379:     {
1380:         // Get current UI state
1381:         bNewWindowed  = Button_GetCheck( hwndWindowedRadio );
1382: 
1383:         if( IDOK == LOWORD(wParam) )
1384:         {
1385:             // Handle the case when the user hits the OK button. Check if any
1386:             // of the options were changed
1387:             if( dwNewAdapter != dwOldAdapter || dwNewDevice  != dwOldDevice  ||
1388:                 dwNewMode    != dwOldMode    || bNewWindowed != bOldWindowed ||
1389:                 NewMultiSampleTypeWindowed != OldMultiSampleTypeWindowed ||
1390:                 NewMultiSampleTypeFullscreen != OldMultiSampleTypeFullscreen )
1391:             {
1392:                 pd3dApp->m_dwAdapter = dwNewAdapter;
1393: 
1394:                 pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
1395:                 pAdapter->dwCurrentDevice = dwNewDevice;
1396: 
1397:                 pAdapter->devices[dwNewDevice].dwCurrentMode = dwNewMode;
1398:                 pAdapter->devices[dwNewDevice].bWindowed     = bNewWindowed;
1399:                 pAdapter->devices[dwNewDevice].MultiSampleTypeWindowed = NewMultiSampleTypeWindowed;
1400:                 pAdapter->devices[dwNewDevice].MultiSampleTypeFullscreen = NewMultiSampleTypeFullscreen;
1401: 
1402:                 EndDialog( hDlg, IDOK );
1403:             }
1404:             else
1405:                 EndDialog( hDlg, IDCANCEL );
1406: 
1407:             return TRUE;
1408:         }
1409:         else if( IDCANCEL == LOWORD(wParam) )
1410:         {
1411:             // Handle the case when the user hits the Cancel button
1412:             EndDialog( hDlg, IDCANCEL );
1413:             return TRUE;
1414:         }
1415:         else if( CBN_SELENDOK == HIWORD(wParam) )
1416:         {
1417:             if( LOWORD(wParam) == IDC_ADAPTER_COMBO )
1418:             {
1419:                 dwNewAdapter = ComboBox_GetCurSel( hwndAdapterList );
1420:                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
1421: 
1422:                 dwNewDevice  = pAdapter->dwCurrentDevice;
1423:                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
1424:                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
1425:             }
1426:             else if( LOWORD(wParam) == IDC_DEVICE_COMBO )
1427:             {
1428:                 pAdapter     = &pd3dApp->m_Adapters[dwNewAdapter];
1429: 
1430:                 dwNewDevice  = ComboBox_GetCurSel( hwndDeviceList );
1431:                 dwNewMode    = pAdapter->devices[dwNewDevice].dwCurrentMode;
1432:                 bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed;
1433:             }
1434:             else if( LOWORD(wParam) == IDC_FULLSCREENMODES_COMBO )
1435:             {
1436:                 dwNewMode = ComboBox_GetCurSel( hwndFullscreenModeList );
1437:             }
1438:             else if( LOWORD(wParam) == IDC_MULTISAMPLE_COMBO )
1439:             {
1440:                 DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
1441:                 if( bNewWindowed )
1442:                     NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
1443:                 else
1444:                     NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
1445:             }
1446:         }
1447:         // Keep the UI current
1448:         bUpdateDlgControls = TRUE;
1449:     }
1450: 
1451:     // Update the dialog controls
1452:     if( bUpdateDlgControls )
1453:     {
1454:         // Reset the content in each of the combo boxes
1455:         ComboBox_ResetContent( hwndAdapterList );
1456:         ComboBox_ResetContent( hwndDeviceList );
1457:         ComboBox_ResetContent( hwndFullscreenModeList );
1458:         ComboBox_ResetContent( hwndMultiSampleList );
1459: 
1460:         pAdapter = &pd3dApp->m_Adapters[dwNewAdapter];
1461:         pDevice  = &pAdapter->devices[dwNewDevice];
1462: 
1463:         // Add a list of adapters to the adapter combo box
1464:         for( DWORD a=0; a < pd3dApp->m_dwNumAdapters; a++ )
1465:         {
1466:             // Add device name to the combo box
1467:             DWORD dwItem = ComboBox_AddString( hwndAdapterList,
1468:                              pd3dApp->m_Adapters[a].d3dAdapterIdentifier.Description );
1469: 
1470:             // Set the item data to identify this adapter
1471:             ComboBox_SetItemData( hwndAdapterList, dwItem, a );
1472: 
1473:             // Set the combobox selection on the current adapater
1474:             if( a == dwNewAdapter )
1475:                 ComboBox_SetCurSel( hwndAdapterList, dwItem );
1476:         }
1477: 
1478:         // Add a list of devices to the device combo box
1479:         for( DWORD d=0; d < pAdapter->dwNumDevices; d++ )
1480:         {
1481:             // Add device name to the combo box
1482:             DWORD dwItem = ComboBox_AddString( hwndDeviceList,
1483:                                                pAdapter->devices[d].strDesc );
1484: 
1485:             // Set the item data to identify this device
1486:             ComboBox_SetItemData( hwndDeviceList, dwItem, d );
1487: 
1488:             // Set the combobox selection on the current device
1489:             if( d == dwNewDevice )
1490:                 ComboBox_SetCurSel( hwndDeviceList, dwItem );
1491:         }
1492: 
1493:         // Add a list of modes to the mode combo box
1494:         for( DWORD m=0; m < pDevice->dwNumModes; m++ )
1495:         {
1496:             DWORD BitDepth = 16;
1497:             if( pDevice->modes[m].Format == D3DFMT_X8R8G8B8 ||
1498:                 pDevice->modes[m].Format == D3DFMT_A8R8G8B8 ||
1499:                 pDevice->modes[m].Format == D3DFMT_R8G8B8 )
1500:             {
1501:                 BitDepth = 32;
1502:             }
1503: 
1504:             // Add mode desc to the combo box
1505:             TCHAR strMode[80];
1506:             _stprintf( strMode, _T("%ld x %ld x %ld"), pDevice->modes[m].Width,
1507:                                                        pDevice->modes[m].Height,
1508:                                                        BitDepth );
1509:             DWORD dwItem = ComboBox_AddString( hwndFullscreenModeList, strMode );
1510: 
1511:             // Set the item data to identify this mode
1512:             ComboBox_SetItemData( hwndFullscreenModeList, dwItem, m );
1513: 
1514:             // Set the combobox selection on the current mode
1515:             if( m == dwNewMode )
1516:                 ComboBox_SetCurSel( hwndFullscreenModeList, dwItem );
1517:         }
1518: 
1519:         // Add a list of multisample modes to the multisample combo box
1520:         for( m=0; m <= 16; m++ )
1521:         {
1522:             TCHAR strDesc[50];
1523: 
1524:             D3DFORMAT fmt;
1525:             if( bNewWindowed )
1526:                 fmt = pd3dApp->m_Adapters[dwNewAdapter].d3ddmDesktop.Format;
1527:             else
1528:                 fmt = pDevice->modes[dwNewMode].Format;
1529: 
1530:             if ( m == 1 ) // 1 is not a valid multisample type
1531:                 continue;
1532: 
1533:             if( SUCCEEDED( pd3dApp->m_pD3D->CheckDeviceMultiSampleType( dwNewAdapter,
1534:                 pDevice->DeviceType, fmt, bNewWindowed, (D3DMULTISAMPLE_TYPE)m ) ) )
1535:             {
1536:                 if( m == 0 )
1537:                     lstrcpy( strDesc, _T("none") );
1538:                 else
1539:                     wsprintf( strDesc, _T("%d samples"), m );
1540: 
1541:                 // Add device name to the combo box
1542:                 DWORD dwItem = ComboBox_AddString( hwndMultiSampleList, strDesc );
1543: 
1544:                 // Set the item data to identify this multisample type
1545:                 ComboBox_SetItemData( hwndMultiSampleList, dwItem, m );
1546: 
1547:                 // Set the combobox selection on the current multisample type
1548:                 if( bNewWindowed )
1549:                 {
1550:                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeWindowed || m == 0 )
1551:                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
1552:                 }
1553:                 else
1554:                 {
1555:                     if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeFullscreen || m == 0 )
1556:                         ComboBox_SetCurSel( hwndMultiSampleList, dwItem );
1557:                 }
1558:             }
1559:         }
1560:         DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList );
1561:         if( bNewWindowed )
1562:             NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
1563:         else
1564:             NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem );
1565:         EnableWindow( hwndMultiSampleList, ComboBox_GetCount( hwndMultiSampleList ) > 1);
1566:         EnableWindow( hwndWindowedRadio, pDevice->bCanDoWindowed );
1567: 
1568:         if( bNewWindowed )
1569:         {
1570:             Button_SetCheck( hwndWindowedRadio,   TRUE );
1571:             Button_SetCheck( hwndFullscreenRadio, FALSE );
1572:             EnableWindow( hwndFullscreenModeList, FALSE );
1573:         }
1574:         else
1575:         {
1576:             Button_SetCheck( hwndWindowedRadio,   FALSE );
1577:             Button_SetCheck( hwndFullscreenRadio, TRUE );
1578:             EnableWindow( hwndFullscreenModeList, TRUE );
1579:         }
1580:         return TRUE;
1581:     }
1582: 
1583:     return FALSE;
1584: }
1585: 
1586: 
1587: 
1588: 
1589: //-----------------------------------------------------------------------------
1590: // Name: Run()
1591: // Desc:
1592: //-----------------------------------------------------------------------------
1593: INT CD3DApplication::Run()
1594: {
1595:     // Load keyboard accelerators
1596:     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
1597: 
1598:     // Now we're ready to recieve and process Windows messages.
1599:     BOOL bGotMsg;
1600:     MSG  msg;
1601:     msg.message = WM_NULL;
1602:     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
1603: 
1604:     while( WM_QUIT != msg.message  )
1605:     {
1606:         // Use PeekMessage() if the app is active, so we can use idle time to
1607:         // render the scene. Else, use GetMessage() to avoid eating CPU time.
1608:         if( m_bActive )
1609:             bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
1610:         else
1611:             bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
1612: 
1613:         if( bGotMsg )
1614:         {
1615:             // Translate and dispatch the message
1616:             if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
1617:             {
1618:                 TranslateMessage( &msg );
1619:                 DispatchMessage( &msg );
1620:             }
1621:         }
1622:         else
1623:         {
1624:             // Render a frame during idle time (no messages are waiting)
1625:             if( m_bActive && m_bReady )
1626:             {
1627:                 if( FAILED( Render3DEnvironment() ) )
1628:                     SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
1629:             }
1630:         }
1631:     }
1632: 
1633:     return (INT)msg.wParam;
1634: }
1635: 
1636: 
1637: 
1638: 
1639: //-----------------------------------------------------------------------------
1640: // Name: Render3DEnvironment()
1641: // Desc: Draws the scene.
1642: //-----------------------------------------------------------------------------
1643: HRESULT CD3DApplication::Render3DEnvironment()
1644: {
1645:     HRESULT hr;
1646: 
1647:     // Test the cooperative level to see if it's okay to render
1648:     if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
1649:     {
1650:         // If the device was lost, do not render until we get it back
1651:         if( D3DERR_DEVICELOST == hr )
1652:             return S_OK;
1653: 
1654:         // Check if the device needs to be resized.
1655:         if( D3DERR_DEVICENOTRESET == hr )
1656:         {
1657:             // If we are windowed, read the desktop mode and use the same format for
1658:             // the back buffer
1659:             if( m_bWindowed )
1660:             {
1661:                 D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
1662:                 m_pD3D->GetAdapterDisplayMode( m_dwAdapter, &pAdapterInfo->d3ddmDesktop );
1663:                 m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
1664:             }
1665: 
1666:             if( FAILED( hr = Resize3DEnvironment() ) )
1667:                 return hr;
1668:         }
1669:         return hr;
1670:     }
1671: 
1672:     // Get the app's time, in seconds. Skip rendering if no time elapsed
1673:     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
1674:     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
1675:     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
1676:         return S_OK;
1677: 
1678:     // FrameMove (animate) the scene
1679:     if( m_bFrameMoving || m_bSingleStep )
1680:     {
1681:         // Store the time for the app
1682:         m_fTime        = fAppTime;
1683:         m_fElapsedTime = fElapsedAppTime;
1684: 
1685:         // Frame move the scene
1686:         if( FAILED( hr = FrameMove() ) )
1687:             return hr;
1688: 
1689:         m_bSingleStep = FALSE;
1690:     }
1691: 
1692:     // Render the scene as normal
1693:     if( FAILED( hr = Render() ) )
1694:         return hr;
1695: 
1696:     // Keep track of the frame count
1697:     {
1698:         static FLOAT fLastTime = 0.0f;
1699:         static DWORD dwFrames  = 0L;
1700:         FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
1701:         ++dwFrames;
1702: 
1703:         // Update the scene stats once per second
1704:         if( fTime - fLastTime > 1.0f )
1705:         {
1706:             m_fFPS    = dwFrames / (fTime - fLastTime);
1707:             fLastTime = fTime;
1708:             dwFrames  = 0L;
1709: 
1710:             // Get adapter's current mode so we can report
1711:             // bit depth (back buffer depth may be unknown)
1712:             D3DDISPLAYMODE mode;
1713:             m_pD3D->GetAdapterDisplayMode(m_dwAdapter, &mode);
1714: 
1715:             _stprintf( m_strFrameStats, _T("%.02f fps (%dx%dx%d)"), m_fFPS,
1716:                        m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
1717:                        mode.Format==D3DFMT_X8R8G8B8?32:16 );
1718:             D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter];
1719:             D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
1720:             D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
1721:             if( m_bUseDepthBuffer )
1722:             {
1723: 
1724:                 switch( pModeInfo->DepthStencilFormat )
1725:                 {
1726:                 case D3DFMT_D16:
1727:                     lstrcat( m_strFrameStats, _T(" (D16)") );
1728:                     break;
1729:                 case D3DFMT_D15S1:
1730:                     lstrcat( m_strFrameStats, _T(" (D15S1)") );
1731:                     break;
1732:                 case D3DFMT_D24X8:
1733:                     lstrcat( m_strFrameStats, _T(" (D24X8)") );
1734:                     break;
1735:                 case D3DFMT_D24S8:
1736:                     lstrcat( m_strFrameStats, _T(" (D24S8)") );
1737:                     break;
1738:                 case D3DFMT_D24X4S4:
1739:                     lstrcat( m_strFrameStats, _T(" (D24X4S4)") );
1740:                     break;
1741:                 case D3DFMT_D32:
1742:                     lstrcat( m_strFrameStats, _T(" (D32)") );
1743:                     break;
1744:                 }
1745:             }
1746: 
1747:             D3DMULTISAMPLE_TYPE MultiSampleType;
1748:             if( m_bWindowed )
1749:                 MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed;
1750:             else
1751:                 MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen;
1752:             switch( MultiSampleType )
1753:             {
1754:             case D3DMULTISAMPLE_2_SAMPLES:
1755:                 lstrcat( m_strFrameStats, _T(" (2x Multisample)") );
1756:                 break;
1757:             case D3DMULTISAMPLE_3_SAMPLES:
1758:                 lstrcat( m_strFrameStats, _T(" (3x Multisample)") );
1759:                 break;
1760:             case D3DMULTISAMPLE_4_SAMPLES:
1761:                 lstrcat( m_strFrameStats, _T(" (4x Multisample)") );
1762:                 break;
1763:             case D3DMULTISAMPLE_5_SAMPLES:
1764:                 lstrcat( m_strFrameStats, _T(" (5x Multisample)") );
1765:                 break;
1766:             case D3DMULTISAMPLE_6_SAMPLES:
1767:                 lstrcat( m_strFrameStats, _T(" (6x Multisample)") );
1768:                 break;
1769:             case D3DMULTISAMPLE_7_SAMPLES:
1770:                 lstrcat( m_strFrameStats, _T(" (7x Multisample)") );
1771:                 break;
1772:             case D3DMULTISAMPLE_8_SAMPLES:
1773:                 lstrcat( m_strFrameStats, _T(" (8x Multisample)") );
1774:                 break;
1775:             case D3DMULTISAMPLE_9_SAMPLES:
1776:                 lstrcat( m_strFrameStats, _T(" (9x Multisample)") );
1777:                 break;
1778:             case D3DMULTISAMPLE_10_SAMPLES:
1779:                 lstrcat( m_strFrameStats, _T(" (10x Multisample)") );
1780:                 break;
1781:             case D3DMULTISAMPLE_11_SAMPLES:
1782:                 lstrcat( m_strFrameStats, _T(" (11x Multisample)") );
1783:                 break;
1784:             case D3DMULTISAMPLE_12_SAMPLES:
1785:                 lstrcat( m_strFrameStats, _T(" (12x Multisample)") );
1786:                 break;
1787:             case D3DMULTISAMPLE_13_SAMPLES:
1788:                 lstrcat( m_strFrameStats, _T(" (13x Multisample)") );
1789:                 break;
1790:             case D3DMULTISAMPLE_14_SAMPLES:
1791:                 lstrcat( m_strFrameStats, _T(" (14x Multisample)") );
1792:                 break;
1793:             case D3DMULTISAMPLE_15_SAMPLES:
1794:                 lstrcat( m_strFrameStats, _T(" (15x Multisample)") );
1795:                 break;
1796:             case D3DMULTISAMPLE_16_SAMPLES:
1797:                 lstrcat( m_strFrameStats, _T(" (16x Multisample)") );
1798:                 break;
1799:             }
1800:         }
1801:     }
1802: 
1803:     // Show the frame on the primary surface.
1804:     m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
1805: 
1806:     return S_OK;
1807: }
1808: 
1809: 
1810: 
1811: 
1812: //-----------------------------------------------------------------------------
1813: // Name: Pause()
1814: // Desc: Called in to toggle the pause state of the app.
1815: //-----------------------------------------------------------------------------
1816: VOID CD3DApplication::Pause( BOOL bPause )
1817: {
1818:     static DWORD dwAppPausedCount = 0L;
1819: 
1820:     dwAppPausedCount += ( bPause ? +1 : -1 );
1821:     m_bReady          = ( dwAppPausedCount ? FALSE : TRUE );
1822: 
1823:     // Handle the first pause request (of many, nestable pause requests)
1824:     if( bPause && ( 1 == dwAppPausedCount ) )
1825:     {
1826:         // Stop the scene from animating
1827:         if( m_bFrameMoving )
1828:             DXUtil_Timer( TIMER_STOP );
1829:     }
1830: 
1831:     if( 0 == dwAppPausedCount )
1832:     {
1833:         // Restart the timers
1834:         if( m_bFrameMoving )
1835:             DXUtil_Timer( TIMER_START );
1836:     }
1837: }
1838: 
1839: 
1840: 
1841: 
1842: //-----------------------------------------------------------------------------
1843: // Name: Cleanup3DEnvironment()
1844: // Desc: Cleanup scene objects
1845: //-----------------------------------------------------------------------------
1846: VOID CD3DApplication::Cleanup3DEnvironment()
1847: {
1848:     m_bActive = FALSE;
1849:     m_bReady  = FALSE;
1850: 
1851:     if( m_pd3dDevice )
1852:     {
1853:         InvalidateDeviceObjects();
1854:         DeleteDeviceObjects();
1855: 
1856:         m_pd3dDevice->Release();
1857:         m_pD3D->Release();
1858: 
1859:         m_pd3dDevice = NULL;
1860:         m_pD3D       = NULL;
1861:     }
1862: 
1863:     FinalCleanup();
1864: }
1865: 
1866: 
1867: 
1868: 
1869: //-----------------------------------------------------------------------------
1870: // Name: DisplayErrorMsg()
1871: // Desc: Displays error messages in a message box
1872: //-----------------------------------------------------------------------------
1873: HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
1874: {
1875:     TCHAR strMsg[512];
1876: 
1877:     switch( hr )
1878:     {
1879:         case D3DAPPERR_NODIRECT3D:
1880:             _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n")
1881:                              _T("want to check that the latest version of\n")
1882:                              _T("DirectX is correctly installed on your\n")
1883:                              _T("system.  Also make sure that this program\n")
1884:                              _T("was compiled with header files that match\n")
1885:                              _T("the installed DirectX DLLs.") );
1886:             break;
1887: 
1888:         case D3DAPPERR_NOCOMPATIBLEDEVICES:
1889:             _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
1890:                              _T("devices.") );
1891:             break;
1892: 
1893:         case D3DAPPERR_NOWINDOWABLEDEVICES:
1894:             _tcscpy( strMsg, _T("This sample cannot run in a desktop\n")
1895:                              _T("window with the current display settings.\n")
1896:                              _T("Please change your desktop settings to a\n")
1897:                              _T("16- or 32-bit display mode and re-run this\n")
1898:                              _T("sample.") );
1899:             break;
1900: 
1901:         case D3DAPPERR_NOHARDWAREDEVICE:
1902:             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n")
1903:                              _T("were found.") );
1904:             break;
1905: 
1906:         case D3DAPPERR_HALNOTCOMPATIBLE:
1907:             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
1908:                              _T("not available on your Direct3D hardware\n")
1909:                              _T("accelerator.") );
1910:             break;
1911: 
1912:         case D3DAPPERR_NOWINDOWEDHAL:
1913:             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
1914:                              _T("render into a window.\n")
1915:                              _T("Press F2 while the app is running to see a\n")
1916:                              _T("list of available devices and modes.") );
1917:             break;
1918: 
1919:         case D3DAPPERR_NODESKTOPHAL:
1920:             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
1921:                              _T("render into a window with the current\n")
1922:                              _T("desktop display settings.\n")
1923:                              _T("Press F2 while the app is running to see a\n")
1924:                              _T("list of available devices and modes.") );
1925:             break;
1926: 
1927:         case D3DAPPERR_NOHALTHISMODE:
1928:             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
1929:                              _T("not available on your Direct3D hardware\n")
1930:                              _T("accelerator with the current desktop display\n")
1931:                              _T("settings.\n")
1932:                              _T("Press F2 while the app is running to see a\n")
1933:                              _T("list of available devices and modes.") );
1934:             break;
1935: 
1936:         case D3DAPPERR_MEDIANOTFOUND:
1937:             _tcscpy( strMsg, _T("Could not load required media." ) );
1938:             break;
1939: 
1940:         case D3DAPPERR_RESIZEFAILED:
1941:             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
1942:             break;
1943: 
1944:         case D3DAPPERR_NONZEROREFCOUNT:
1945:             _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n")
1946:                              _T("count (meaning things were not properly\n")
1947:                              _T("cleaned up).") );
1948:             break;
1949: 
1950:         case D3DAPPERR_NULLREFDEVICE:
1951:             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n")
1952:                              _T("The reference rendering device was selected, but your\n")
1953:                              _T("computer only has a reduced-functionality reference device\n")
1954:                              _T("installed.  Install the DirectX SDK to get the full\n")
1955:                              _T("reference device.\n") );
1956:             break;
1957: 
1958:         case E_OUTOFMEMORY:
1959:             _tcscpy( strMsg, _T("Not enough memory.") );
1960:             break;
1961: 
1962:         case D3DERR_OUTOFVIDEOMEMORY:
1963:             _tcscpy( strMsg, _T("Not enough video memory.") );
1964:             break;
1965: 
1966:         default:
1967:             _tcscpy( strMsg, _T("Generic application error. Enable\n")
1968:                              _T("debug output for detailed information.") );
1969:     }
1970: 
1971:     if( MSGERR_APPMUSTEXIT == dwType )
1972:     {
1973:         _tcscat( strMsg, _T("\n\nThis sample will now exit.") );
1974:         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
1975: 
1976:         // Close the window, which shuts down the app
1977:         if( m_hWnd )
1978:             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
1979:     }
1980:     else
1981:     {
1982:         if( MSGWARN_SWITCHEDTOREF == dwType )
1983:             _tcscat( strMsg, _T("\n\nSwitching to the reference rasterizer,\n")
1984:                              _T("a software device that implements the entire\n")
1985:                              _T("Direct3D feature set, but runs very slowly.") );
1986:         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
1987:     }
1988: 
1989:     return hr;
1990: }
1991: 
1992: 
1993: 
1994: 
1995: