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 <mmsystem.h>
0010: #include <stdio.h>
0011: #include <tchar.h>
0012: #include <D3D9.h>
0013: #include "DXUtil.h"
0014: #include "D3DUtil.h"
0015: #include "D3DEnumeration.h"
0016: #include "D3DSettings.h"
0017: #include "D3DApp.h"
0018: #include "resource.h"
0019: 
0020: 
0021: 
0022: 
0023: //-----------------------------------------------------------------------------
0024: // Global access to the app (needed for the global WndProc())
0025: //-----------------------------------------------------------------------------
0026: static CD3DApplication* g_pD3DApp = NULL;
0027: 
0028: 
0029: 
0030: 
0031: //-----------------------------------------------------------------------------
0032: // Name: CD3DApplication()
0033: // Desc: Constructor
0034: //-----------------------------------------------------------------------------
0035: CD3DApplication::CD3DApplication()
0036: {
0037:     g_pD3DApp           = this;
0038: 
0039:     m_pD3D              = NULL;
0040:     m_pd3dDevice        = NULL;
0041:     m_hWnd              = NULL;
0042:     m_hWndFocus         = NULL;
0043:     m_hMenu             = NULL;
0044:     m_bWindowed         = true;
0045:     m_bActive           = false;
0046:     m_bDeviceLost       = false;
0047:     m_bMinimized        = false;
0048:     m_bMaximized        = false;
0049:     m_bIgnoreSizeChange = false;
0050:     m_bDeviceObjectsInited = false;
0051:     m_bDeviceObjectsRestored = false;
0052:     m_dwCreateFlags     = 0;
0053: 
0054:     m_bFrameMoving      = true;
0055:     m_bSingleStep       = false;
0056:     m_fTime             = 0.0f;
0057:     m_fElapsedTime      = 0.0f;
0058:     m_fFPS              = 0.0f;
0059:     m_strDeviceStats[0] = _T('\0');
0060:     m_strFrameStats[0]  = _T('\0');
0061: 
0062:     m_strWindowTitle    = _T("D3D9 Application");
0063:     m_dwCreationWidth   = 400;
0064:     m_dwCreationHeight  = 300;
0065:     m_bShowCursorWhenFullscreen = false;
0066:     m_bStartFullscreen  = false;
0067: 
0068:     Pause( true ); // Pause until we're ready to render
0069: 
0070:     // When m_bClipCursorWhenFullscreen is true, the cursor is limited to
0071:     // the device window when the app goes fullscreen.  This prevents users
0072:     // from accidentally clicking outside the app window on a multimon system.
0073:     // This flag is turned off by default for debug builds, since it makes 
0074:     // multimon debugging difficult.
0075: #if defined(_DEBUG) || defined(DEBUG)
0076:     m_bClipCursorWhenFullscreen = false;
0077: #else
0078:     m_bClipCursorWhenFullscreen = true;
0079: #endif
0080: }
0081: 
0082: 
0083: 
0084: 
0085: //-----------------------------------------------------------------------------
0086: // Name: WndProc()
0087: // Desc: Static msg handler which passes messages to the application class.
0088: //-----------------------------------------------------------------------------
0089: LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
0090: {
0091:     return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
0092: }
0093: 
0094: 
0095: 
0096: //-----------------------------------------------------------------------------
0097: // Name: ConfirmDeviceHelper()
0098: // Desc: Static function used by D3DEnumeration
0099: //-----------------------------------------------------------------------------
0100: bool CD3DApplication::ConfirmDeviceHelper( D3DCAPS9* pCaps, VertexProcessingType vertexProcessingType, 
0101:                          D3DFORMAT backBufferFormat )
0102: {
0103:     DWORD dwBehavior;
0104: 
0105:     if (vertexProcessingType == SOFTWARE_VP)
0106:         dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
0107:     else if (vertexProcessingType == MIXED_VP)
0108:         dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
0109:     else if (vertexProcessingType == HARDWARE_VP)
0110:         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
0111:     else if (vertexProcessingType == PURE_HARDWARE_VP)
0112:         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
0113:     else
0114:         dwBehavior = 0; // TODO: throw exception
0115:     
0116:     return SUCCEEDED( g_pD3DApp->ConfirmDevice( pCaps, dwBehavior, backBufferFormat ) );
0117: }
0118: 
0119: 
0120: 
0121: 
0122: //-----------------------------------------------------------------------------
0123: // Name: Create()
0124: // Desc:
0125: //-----------------------------------------------------------------------------
0126: HRESULT CD3DApplication::Create( HINSTANCE hInstance )
0127: {
0128:     HRESULT hr;
0129: 
0130:     // Create the Direct3D object
0131:     m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
0132:     if( m_pD3D == NULL )
0133:         return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
0134: 
0135:     // Build a list of Direct3D adapters, modes and devices. The
0136:     // ConfirmDevice() callback is used to confirm that only devices that
0137:     // meet the app's requirements are considered.
0138:     m_d3dEnumeration.SetD3D( m_pD3D );
0139:     m_d3dEnumeration.ConfirmDeviceCallback = ConfirmDeviceHelper;
0140:     if( FAILED( hr = m_d3dEnumeration.Enumerate() ) )
0141:     {
0142:         SAFE_RELEASE( m_pD3D );
0143:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0144:     }
0145: 
0146:     // Unless a substitute hWnd has been specified, create a window to
0147:     // render into
0148:     if( m_hWnd == NULL)
0149:     {
0150:         // Register the windows class
0151:         WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
0152:                               LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
0153:                               LoadCursor( NULL, IDC_ARROW ),
0154:                               (HBRUSH)GetStockObject(WHITE_BRUSH),
0155:                               NULL, _T("D3D Window") };
0156:         RegisterClass( &wndClass );
0157: 
0158:         // Set the window's initial style
0159:         m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
0160:                           WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
0161: 
0162:         // Set the window's initial width
0163:         RECT rc;
0164:         SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
0165:         AdjustWindowRect( &rc, m_dwWindowStyle, true );
0166: 
0167:         // Create the render window
0168:         m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle,
0169:                                CW_USEDEFAULT, CW_USEDEFAULT,
0170:                                (rc.right-rc.left), (rc.bottom-rc.top), 0,
0171:                                LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ),
0172:                                hInstance, 0 );
0173:     }
0174: 
0175:     // The focus window can be a specified to be a different window than the
0176:     // device window.  If not, use the device window as the focus window.
0177:     if( m_hWndFocus == NULL )
0178:         m_hWndFocus = m_hWnd;
0179: 
0180:     // Save window properties
0181:     m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
0182:     GetWindowRect( m_hWnd, &m_rcWindowBounds );
0183:     GetClientRect( m_hWnd, &m_rcWindowClient );
0184: 
0185:     if( FAILED( hr = ChooseInitialD3DSettings() ) )
0186:     {
0187:         SAFE_RELEASE( m_pD3D );
0188:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0189:     }
0190: 
0191:     // Initialize the application timer
0192:     DXUtil_Timer( TIMER_START );
0193: 
0194:     // Initialize the app's custom scene stuff
0195:     if( FAILED( hr = OneTimeSceneInit() ) )
0196:     {
0197:         SAFE_RELEASE( m_pD3D );
0198:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0199:     }
0200: 
0201:     // Initialize the 3D environment for the app
0202:     if( FAILED( hr = Initialize3DEnvironment() ) )
0203:     {
0204:         SAFE_RELEASE( m_pD3D );
0205:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0206:     }
0207: 
0208:     // The app is ready to go
0209:     Pause( false );
0210: 
0211:     return S_OK;
0212: }
0213: 
0214: 
0215: 
0216: 
0217: //-----------------------------------------------------------------------------
0218: // Name: FindBestWindowedMode()
0219: // Desc: Sets up m_d3dSettings with best available windowed mode, subject to 
0220: //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
0221: //       mode can be found.
0222: //-----------------------------------------------------------------------------
0223: bool CD3DApplication::FindBestWindowedMode( bool bRequireHAL, bool bRequireREF )
0224: {
0225:     // Get display mode of primary adapter (which is assumed to be where the window 
0226:     // will appear)
0227:     D3DDISPLAYMODE primaryDesktopDisplayMode;
0228:     m_pD3D->GetAdapterDisplayMode(0, &primaryDesktopDisplayMode);
0229: 
0230:     D3DAdapterInfo* pBestAdapterInfo = NULL;
0231:     D3DDeviceInfo* pBestDeviceInfo = NULL;
0232:     D3DDeviceCombo* pBestDeviceCombo = NULL;
0233: 
0234:     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
0235:     {
0236:         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
0237:         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
0238:         {
0239:             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
0240:             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
0241:                 continue;
0242:             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
0243:                 continue;
0244:             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
0245:             {
0246:                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
0247:                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
0248:                 if (!pDeviceCombo->IsWindowed)
0249:                     continue;
0250:                 if (pDeviceCombo->AdapterFormat != primaryDesktopDisplayMode.Format)
0251:                     continue;
0252:                 // If we haven't found a compatible DeviceCombo yet, or if this set
0253:                 // is better (because it's a HAL, and/or because formats match better),
0254:                 // save it
0255:                 if( pBestDeviceCombo == NULL || 
0256:                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceCombo->DevType == D3DDEVTYPE_HAL ||
0257:                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
0258:                 {
0259:                     pBestAdapterInfo = pAdapterInfo;
0260:                     pBestDeviceInfo = pDeviceInfo;
0261:                     pBestDeviceCombo = pDeviceCombo;
0262:                     if( pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
0263:                     {
0264:                         // This windowed device combo looks great -- take it
0265:                         goto EndWindowedDeviceComboSearch;
0266:                     }
0267:                     // Otherwise keep looking for a better windowed device combo
0268:                 }
0269:             }
0270:         }
0271:     }
0272: EndWindowedDeviceComboSearch:
0273:     if (pBestDeviceCombo == NULL )
0274:         return false;
0275: 
0276:     m_d3dSettings.pWindowed_AdapterInfo = pBestAdapterInfo;
0277:     m_d3dSettings.pWindowed_DeviceInfo = pBestDeviceInfo;
0278:     m_d3dSettings.pWindowed_DeviceCombo = pBestDeviceCombo;
0279:     m_d3dSettings.IsWindowed = true;
0280:     m_d3dSettings.Windowed_DisplayMode = primaryDesktopDisplayMode;
0281:     m_d3dSettings.Windowed_Width = m_rcWindowClient.right - m_rcWindowClient.left;
0282:     m_d3dSettings.Windowed_Height = m_rcWindowClient.bottom - m_rcWindowClient.top;
0283:     if (m_d3dEnumeration.AppUsesDepthBuffer)
0284:         m_d3dSettings.Windowed_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
0285:     m_d3dSettings.Windowed_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
0286:     m_d3dSettings.Windowed_MultisampleQuality = 0;
0287:     m_d3dSettings.Windowed_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
0288:     m_d3dSettings.Windowed_PresentInterval = *(UINT*)pBestDeviceCombo->pPresentIntervalList->GetPtr(0);
0289:     return true;
0290: }
0291: 
0292: 
0293: 
0294: 
0295: //-----------------------------------------------------------------------------
0296: // Name: FindBestFullscreenMode()
0297: // Desc: Sets up m_d3dSettings with best available fullscreen mode, subject to 
0298: //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
0299: //       mode can be found.
0300: //-----------------------------------------------------------------------------
0301: bool CD3DApplication::FindBestFullscreenMode( bool bRequireHAL, bool bRequireREF )
0302: {
0303:     // For fullscreen, default to first HAL DeviceCombo that supports the current desktop 
0304:     // display mode, or any display mode if HAL is not compatible with the desktop mode, or 
0305:     // non-HAL if no HAL is available
0306:     D3DDISPLAYMODE adapterDesktopDisplayMode;
0307:     D3DDISPLAYMODE bestAdapterDesktopDisplayMode;
0308:     D3DDISPLAYMODE bestDisplayMode;
0309:     bestAdapterDesktopDisplayMode.Width = 0;
0310:     bestAdapterDesktopDisplayMode.Height = 0;
0311:     bestAdapterDesktopDisplayMode.Format = D3DFMT_UNKNOWN;
0312:     bestAdapterDesktopDisplayMode.RefreshRate = 0;
0313: 
0314:     D3DAdapterInfo* pBestAdapterInfo = NULL;
0315:     D3DDeviceInfo* pBestDeviceInfo = NULL;
0316:     D3DDeviceCombo* pBestDeviceCombo = NULL;
0317: 
0318:     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
0319:     {
0320:         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
0321:         m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
0322:         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
0323:         {
0324:             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
0325:             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
0326:                 continue;
0327:             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
0328:                 continue;
0329:             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
0330:             {
0331:                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
0332:                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
0333:                 bool bAdapterMatchesDesktop = (pDeviceCombo->AdapterFormat == adapterDesktopDisplayMode.Format);
0334:                 if (pDeviceCombo->IsWindowed)
0335:                     continue;
0336:                 // If we haven't found a compatible set yet, or if this set
0337:                 // is better (because it's a HAL, and/or because formats match better),
0338:                 // save it
0339:                 if (pBestDeviceCombo == NULL ||
0340:                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceInfo->DevType == D3DDEVTYPE_HAL ||
0341:                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && pBestDeviceCombo->AdapterFormat != adapterDesktopDisplayMode.Format && bAdapterMatchesDesktop ||
0342:                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB )
0343:                 {
0344:                     bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
0345:                     pBestAdapterInfo = pAdapterInfo;
0346:                     pBestDeviceInfo = pDeviceInfo;
0347:                     pBestDeviceCombo = pDeviceCombo;
0348:                     if (pDeviceInfo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB)
0349:                     {
0350:                         // This fullscreen device combo looks great -- take it
0351:                         goto EndFullscreenDeviceComboSearch;
0352:                     }
0353:                     // Otherwise keep looking for a better fullscreen device combo
0354:                 }
0355:             }
0356:         }
0357:     }
0358: EndFullscreenDeviceComboSearch:
0359:     if (pBestDeviceCombo == NULL)
0360:         return false;
0361: 
0362:     // Need to find a display mode on the best adapter that uses pBestDeviceCombo->AdapterFormat
0363:     // and is as close to bestAdapterDesktopDisplayMode's res as possible
0364:     bestDisplayMode.Width = 0;
0365:     bestDisplayMode.Height = 0;
0366:     bestDisplayMode.Format = D3DFMT_UNKNOWN;
0367:     bestDisplayMode.RefreshRate = 0;
0368:     for( UINT idm = 0; idm < pBestAdapterInfo->pDisplayModeList->Count(); idm++ )
0369:     {
0370:         D3DDISPLAYMODE* pdm = (D3DDISPLAYMODE*)pBestAdapterInfo->pDisplayModeList->GetPtr(idm);
0371:         if( pdm->Format != pBestDeviceCombo->AdapterFormat )
0372:             continue;
0373:         if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
0374:             pdm->Height == bestAdapterDesktopDisplayMode.Height && 
0375:             pdm->RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate )
0376:         {
0377:             // found a perfect match, so stop
0378:             bestDisplayMode = *pdm;
0379:             break;
0380:         }
0381:         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
0382:                  pdm->Height == bestAdapterDesktopDisplayMode.Height && 
0383:                  pdm->RefreshRate > bestDisplayMode.RefreshRate )
0384:         {
0385:             // refresh rate doesn't match, but width/height match, so keep this
0386:             // and keep looking
0387:             bestDisplayMode = *pdm;
0388:         }
0389:         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width )
0390:         {
0391:             // width matches, so keep this and keep looking
0392:             bestDisplayMode = *pdm;
0393:         }
0394:         else if( bestDisplayMode.Width == 0 )
0395:         {
0396:             // we don't have anything better yet, so keep this and keep looking
0397:             bestDisplayMode = *pdm;
0398:         }
0399:     }
0400: 
0401:     m_d3dSettings.pFullscreen_AdapterInfo = pBestAdapterInfo;
0402:     m_d3dSettings.pFullscreen_DeviceInfo = pBestDeviceInfo;
0403:     m_d3dSettings.pFullscreen_DeviceCombo = pBestDeviceCombo;
0404:     m_d3dSettings.IsWindowed = false;
0405:     m_d3dSettings.Fullscreen_DisplayMode = bestDisplayMode;
0406:     if (m_d3dEnumeration.AppUsesDepthBuffer)
0407:         m_d3dSettings.Fullscreen_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
0408:     m_d3dSettings.Fullscreen_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
0409:     m_d3dSettings.Fullscreen_MultisampleQuality = 0;
0410:     m_d3dSettings.Fullscreen_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
0411:     m_d3dSettings.Fullscreen_PresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
0412:     return true;
0413: }
0414: 
0415: 
0416: 
0417: 
0418: //-----------------------------------------------------------------------------
0419: // Name: ChooseInitialD3DSettings()
0420: // Desc: 
0421: //-----------------------------------------------------------------------------
0422: HRESULT CD3DApplication::ChooseInitialD3DSettings()
0423: {
0424:     bool bFoundFullscreen = FindBestFullscreenMode( false, false );
0425:     bool bFoundWindowed = FindBestWindowedMode( false, false );
0426: 
0427:     if( m_bStartFullscreen && bFoundFullscreen )
0428:         m_d3dSettings.IsWindowed = false;
0429:     if( !bFoundWindowed && bFoundFullscreen )
0430:         m_d3dSettings.IsWindowed = false;
0431: 
0432:     if( !bFoundFullscreen && !bFoundWindowed )
0433:         return D3DAPPERR_NOCOMPATIBLEDEVICES;
0434: 
0435:     return S_OK;
0436: }
0437: 
0438: 
0439: 
0440: 
0441: //-----------------------------------------------------------------------------
0442: // Name: MsgProc()
0443: // Desc: Message handling function.
0444: //-----------------------------------------------------------------------------
0445: LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
0446:                                   LPARAM lParam )
0447: {
0448:     switch( uMsg )
0449:     {
0450:         case WM_PAINT:
0451:             // Handle paint messages when the app is paused
0452:             if( m_pd3dDevice && !m_bActive && m_bWindowed &&
0453:                 m_bDeviceObjectsInited && m_bDeviceObjectsRestored )
0454:             {
0455:                 Render();
0456:                 m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
0457:             }
0458:             break;
0459: 
0460:         case WM_GETMINMAXINFO:
0461:             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
0462:             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
0463:             break;
0464: 
0465:         case WM_ENTERSIZEMOVE:
0466:             // Halt frame movement while the app is sizing or moving
0467:             Pause( true );
0468:             break;
0469: 
0470:         case WM_SIZE:
0471:             // Pick up possible changes to window style due to maximize, etc.
0472:             if( m_bWindowed && m_hWnd != NULL )
0473:                 m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
0474: 
0475:             if( SIZE_MINIMIZED == wParam )
0476:             {
0477:                 if( m_bClipCursorWhenFullscreen && !m_bWindowed )
0478:                     ClipCursor( NULL );
0479:                 Pause( true ); // Pause while we're minimized
0480:                 m_bMinimized = true;
0481:                 m_bMaximized = false;
0482:             }
0483:             else if( SIZE_MAXIMIZED == wParam )
0484:             {
0485:                 if( m_bMinimized )
0486:                     Pause( false ); // Unpause since we're no longer minimized
0487:                 m_bMinimized = false;
0488:                 m_bMaximized = true;
0489:                 HandlePossibleSizeChange();
0490:             }
0491:             else if( SIZE_RESTORED == wParam )
0492:             {
0493:                 if( m_bMaximized )
0494:                 {
0495:                     m_bMaximized = false;
0496:                     HandlePossibleSizeChange();
0497:                 }
0498:                 else if( m_bMinimized)
0499:                 {
0500:                     Pause( false ); // Unpause since we're no longer minimized
0501:                     m_bMinimized = false;
0502:                     HandlePossibleSizeChange();
0503:                 }
0504:                 else
0505:                 {
0506:                     // If we're neither maximized nor minimized, the window size 
0507:                     // is changing by the user dragging the window edges.  In this 
0508:                     // case, we don't reset the device yet -- we wait until the 
0509:                     // user stops dragging, and a WM_EXITSIZEMOVE message comes.
0510:                 }
0511:             }
0512:             break;
0513: 
0514:         case WM_EXITSIZEMOVE:
0515:             Pause( false );
0516:             HandlePossibleSizeChange();
0517:             break;
0518: 
0519:         case WM_SETCURSOR:
0520:             // Turn off Windows cursor in fullscreen mode
0521:             if( m_bActive && !m_bWindowed )
0522:             {
0523:                 SetCursor( NULL );
0524:                 if( m_bShowCursorWhenFullscreen )
0525:                     m_pd3dDevice->ShowCursor( true );
0526:                 return true; // prevent Windows from setting cursor to window class cursor
0527:             }
0528:             break;
0529: 
0530:          case WM_MOUSEMOVE:
0531:             if( m_bActive && m_pd3dDevice != NULL )
0532:             {
0533:                 POINT ptCursor;
0534:                 GetCursorPos( &ptCursor );
0535:                 if( !m_bWindowed )
0536:                     ScreenToClient( m_hWnd, &ptCursor );
0537:                 m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
0538:             }
0539:             break;
0540: 
0541:        case WM_ENTERMENULOOP:
0542:             // Pause the app when menus are displayed
0543:             Pause(true);
0544:             break;
0545: 
0546:         case WM_EXITMENULOOP:
0547:             Pause(false);
0548:             break;
0549: 
0550:         case WM_NCHITTEST:
0551:             // Prevent the user from selecting the menu in fullscreen mode
0552:             if( !m_bWindowed )
0553:                 return HTCLIENT;
0554:             break;
0555: 
0556:         case WM_POWERBROADCAST:
0557:             switch( wParam )
0558:             {
0559:                 #ifndef PBT_APMQUERYSUSPEND
0560:                     #define PBT_APMQUERYSUSPEND 0x0000
0561:                 #endif
0562:                 case PBT_APMQUERYSUSPEND:
0563:                     // At this point, the app should save any data for open
0564:                     // network connections, files, etc., and prepare to go into
0565:                     // a suspended mode.
0566:                     return true;
0567: 
0568:                 #ifndef PBT_APMRESUMESUSPEND
0569:                     #define PBT_APMRESUMESUSPEND 0x0007
0570:                 #endif
0571:                 case PBT_APMRESUMESUSPEND:
0572:                     // At this point, the app should recover any data, network
0573:                     // connections, files, etc., and resume running from when
0574:                     // the app was suspended.
0575:                     return true;
0576:             }
0577:             break;
0578: 
0579:         case WM_SYSCOMMAND:
0580:             // Prevent moving/sizing and power loss in fullscreen mode
0581:             switch( wParam )
0582:             {
0583:                 case SC_MOVE:
0584:                 case SC_SIZE:
0585:                 case SC_MAXIMIZE:
0586:                 case SC_KEYMENU:
0587:                 case SC_MONITORPOWER:
0588:                     if( false == m_bWindowed )
0589:                         return 1;
0590:                     break;
0591:             }
0592:             break;
0593: 
0594:         case WM_COMMAND:
0595:             switch( LOWORD(wParam) )
0596:             {
0597:                 case IDM_CHANGEDEVICE:
0598:                     // Prompt the user to select a new device or mode
0599:                     Pause(true);
0600:                     UserSelectNewDevice();
0601:                     Pause(false);
0602:                     return 0;
0603: 
0604:                 case IDM_TOGGLEFULLSCREEN:
0605:                     // Toggle the fullscreen/window mode
0606:                     Pause( true );
0607:                     if( FAILED( ToggleFullscreen() ) )
0608:                         DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
0609:                     Pause( false );                        
0610:                     return 0;
0611: 
0612:                 case IDM_EXIT:
0613:                     // Recieved key/menu command to exit app
0614:                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
0615:                     return 0;
0616:             }
0617:             break;
0618: 
0619:         case WM_CLOSE:
0620:             Cleanup3DEnvironment();
0621:             SAFE_RELEASE( m_pD3D );
0622:             FinalCleanup();
0623:             HMENU hMenu;
0624:             hMenu = GetMenu(hWnd);
0625:             if( hMenu != NULL )
0626:                 DestroyMenu( hMenu );
0627:             DestroyWindow( hWnd );
0628:             PostQuitMessage(0);
0629:             m_hWnd = NULL;
0630:             return 0;
0631:     }
0632: 
0633:     return DefWindowProc( hWnd, uMsg, wParam, lParam );
0634: }
0635: 
0636: 
0637: 
0638: 
0639: //-----------------------------------------------------------------------------
0640: // Name: HandlePossibleSizeChange()
0641: // Desc: Reset the device if the client area size has changed.
0642: //-----------------------------------------------------------------------------
0643: HRESULT CD3DApplication::HandlePossibleSizeChange()
0644: {
0645:     HRESULT hr = S_OK;
0646:     RECT rcClientOld;
0647:     rcClientOld = m_rcWindowClient;
0648: 
0649:     if( m_bIgnoreSizeChange )
0650:         return S_OK;
0651: 
0652:     // Update window properties
0653:     GetWindowRect( m_hWnd, &m_rcWindowBounds );
0654:     GetClientRect( m_hWnd, &m_rcWindowClient );
0655: 
0656:     if( rcClientOld.right - rcClientOld.left !=
0657:         m_rcWindowClient.right - m_rcWindowClient.left ||
0658:         rcClientOld.bottom - rcClientOld.top !=
0659:         m_rcWindowClient.bottom - m_rcWindowClient.top)
0660:     {
0661:         // A new window size will require a new backbuffer
0662:         // size, so the 3D structures must be changed accordingly.
0663:         Pause( true );
0664: 
0665:         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
0666:         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
0667:     
0668:         if( m_pd3dDevice != NULL )
0669:         {
0670:             // Reset the 3D environment
0671:             if( FAILED( hr = Reset3DEnvironment() ) )
0672:             {
0673:                 if( hr != D3DERR_OUTOFVIDEOMEMORY )
0674:                     hr = D3DAPPERR_RESETFAILED;
0675:                 DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
0676:             }
0677:         }
0678:         Pause( false );
0679:     }
0680:     return hr;
0681: }
0682: 
0683: 
0684: 
0685: 
0686: //-----------------------------------------------------------------------------
0687: // Name: Initialize3DEnvironment()
0688: // Desc:
0689: //-----------------------------------------------------------------------------
0690: HRESULT CD3DApplication::Initialize3DEnvironment()
0691: {
0692:     HRESULT hr;
0693: 
0694:     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
0695:     D3DDeviceInfo* pDeviceInfo = m_d3dSettings.PDeviceInfo();
0696: 
0697:     m_bWindowed = m_d3dSettings.IsWindowed;
0698: 
0699:     // Prepare window for possible windowed/fullscreen change
0700:     AdjustWindowForChange();
0701: 
0702:     // Set up the presentation parameters
0703:     BuildPresentParamsFromSettings();
0704: 
0705:     if( pDeviceInfo->Caps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
0706:     {
0707:         // Warn user about null ref device that can't render anything
0708:         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
0709:     }
0710: 
0711:     DWORD behaviorFlags;
0712:     if (m_d3dSettings.GetVertexProcessingType() == SOFTWARE_VP)
0713:         behaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
0714:     else if (m_d3dSettings.GetVertexProcessingType() == MIXED_VP)
0715:         behaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
0716:     else if (m_d3dSettings.GetVertexProcessingType() == HARDWARE_VP)
0717:         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
0718:     else if (m_d3dSettings.GetVertexProcessingType() == PURE_HARDWARE_VP)
0719:         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
0720:     else
0721:         behaviorFlags = 0; // TODO: throw exception
0722: 
0723:     // Create the device
0724:     hr = m_pD3D->CreateDevice( m_d3dSettings.AdapterOrdinal(), pDeviceInfo->DevType,
0725:                                m_hWndFocus, behaviorFlags, &m_d3dpp,
0726:                                &m_pd3dDevice );
0727: 
0728:     if( SUCCEEDED(hr) )
0729:     {
0730:         // When moving from fullscreen to windowed mode, it is important to
0731:         // adjust the window size after recreating the device rather than
0732:         // beforehand to ensure that you get the window size you want.  For
0733:         // example, when switching from 640x480 fullscreen to windowed with
0734:         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
0735:         // the window size to 1000x600 until after the display mode has
0736:         // changed to 1024x768, because windows cannot be larger than the
0737:         // desktop.
0738:         if( m_bWindowed )
0739:         {
0740:             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
0741:                           m_rcWindowBounds.left, m_rcWindowBounds.top,
0742:                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
0743:                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
0744:                           SWP_SHOWWINDOW );
0745:         }
0746: 
0747:         // Store device Caps
0748:         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
0749:         m_dwCreateFlags = behaviorFlags;
0750: 
0751:         // Store device description
0752:         if( pDeviceInfo->DevType == D3DDEVTYPE_REF )
0753:             lstrcpy( m_strDeviceStats, TEXT("REF") );
0754:         else if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0755:             lstrcpy( m_strDeviceStats, TEXT("HAL") );
0756:         else if( pDeviceInfo->DevType == D3DDEVTYPE_SW )
0757:             lstrcpy( m_strDeviceStats, TEXT("SW") );
0758: 
0759:         if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
0760:             behaviorFlags & D3DCREATE_PUREDEVICE )
0761:         {
0762:             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0763:                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
0764:             else
0765:                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
0766:         }
0767:         else if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
0768:         {
0769:             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0770:                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
0771:             else
0772:                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
0773:         }
0774:         else if( behaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
0775:         {
0776:             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0777:                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
0778:             else
0779:                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
0780:         }
0781:         else if( behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
0782:         {
0783:             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
0784:         }
0785: 
0786:         if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0787:         {
0788:             // Be sure not to overflow m_strDeviceStats when appending the adapter 
0789:             // description, since it can be long.  Note that the adapter description
0790:             // is initially CHAR and must be converted to TCHAR.
0791:             lstrcat( m_strDeviceStats, TEXT(": ") );
0792:             const int cchDesc = sizeof(pAdapterInfo->AdapterIdentifier.Description);
0793:             TCHAR szDescription[cchDesc];
0794:             DXUtil_ConvertAnsiStringToGenericCch( szDescription, 
0795:                 pAdapterInfo->AdapterIdentifier.Description, cchDesc );
0796:             int maxAppend = sizeof(m_strDeviceStats) / sizeof(TCHAR) -
0797:                 lstrlen( m_strDeviceStats ) - 1;
0798:             _tcsncat( m_strDeviceStats, szDescription, maxAppend );
0799:         }
0800: 
0801:         // Store render target surface desc
0802:         LPDIRECT3DSURFACE9 pBackBuffer = NULL;
0803:         m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
0804:         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
0805:         pBackBuffer->Release();
0806: 
0807:         // Set up the fullscreen cursor
0808:         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
0809:         {
0810:             HCURSOR hCursor;
0811: #ifdef _WIN64
0812:             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
0813: #else
0814:             hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
0815: #endif
0816:             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
0817:             m_pd3dDevice->ShowCursor( true );
0818:         }
0819: 
0820:         // Confine cursor to fullscreen window
0821:         if( m_bClipCursorWhenFullscreen )
0822:         {
0823:             if (!m_bWindowed )
0824:             {
0825:                 RECT rcWindow;
0826:                 GetWindowRect( m_hWnd, &rcWindow );
0827:                 ClipCursor( &rcWindow );
0828:             }
0829:             else
0830:             {
0831:                 ClipCursor( NULL );
0832:             }
0833:         }
0834: 
0835:         // Initialize the app's device-dependent objects
0836:         hr = InitDeviceObjects();
0837:         if( FAILED(hr) )
0838:         {
0839:             DeleteDeviceObjects();
0840:         }
0841:         else
0842:         {
0843:             m_bDeviceObjectsInited = true;
0844:             hr = RestoreDeviceObjects();
0845:             if( FAILED(hr) )
0846:             {
0847:                 InvalidateDeviceObjects();
0848:             }
0849:             else
0850:             {
0851:                 m_bDeviceObjectsRestored = true;
0852:                 return S_OK;
0853:             }
0854:         }
0855: 
0856:         // Cleanup before we try again
0857:         Cleanup3DEnvironment();
0858:     }
0859: 
0860:     // If that failed, fall back to the reference rasterizer
0861:     if( hr != D3DAPPERR_MEDIANOTFOUND && 
0862:         hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) && 
0863:         pDeviceInfo->DevType == D3DDEVTYPE_HAL )
0864:     {
0865:         if (FindBestWindowedMode(false, true))
0866:         {
0867:             m_bWindowed = true;
0868:             AdjustWindowForChange();
0869:             // Make sure main window isn't topmost, so error message is visible
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:             // Let the user know we are switching from HAL to the reference rasterizer
0877:             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
0878: 
0879:             hr = Initialize3DEnvironment();
0880:         }
0881:     }
0882:     return hr;
0883: }
0884: 
0885: 
0886: 
0887: 
0888: //-----------------------------------------------------------------------------
0889: // Name: BuildPresentParamsFromSettings()
0890: // Desc:
0891: //-----------------------------------------------------------------------------
0892: void CD3DApplication::BuildPresentParamsFromSettings()
0893: {
0894:     m_d3dpp.Windowed               = m_d3dSettings.IsWindowed;
0895:     m_d3dpp.BackBufferCount        = 1;
0896:     m_d3dpp.MultiSampleType        = m_d3dSettings.MultisampleType();
0897:     m_d3dpp.MultiSampleQuality     = m_d3dSettings.MultisampleQuality();
0898:     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
0899:     m_d3dpp.EnableAutoDepthStencil = m_d3dEnumeration.AppUsesDepthBuffer;
0900:     m_d3dpp.hDeviceWindow          = m_hWnd;
0901:     if( m_d3dEnumeration.AppUsesDepthBuffer )
0902:     {
0903:         m_d3dpp.Flags              = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
0904:         m_d3dpp.AutoDepthStencilFormat = m_d3dSettings.DepthStencilBufferFormat();
0905:     }
0906:     else
0907:     {
0908:         m_d3dpp.Flags              = 0;
0909:     }
0910: 
0911:     if( m_bWindowed )
0912:     {
0913:         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
0914:         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
0915:         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
0916:         m_d3dpp.FullScreen_RefreshRateInHz = 0;
0917:         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
0918:     }
0919:     else
0920:     {
0921:         m_d3dpp.BackBufferWidth  = m_d3dSettings.DisplayMode().Width;
0922:         m_d3dpp.BackBufferHeight = m_d3dSettings.DisplayMode().Height;
0923:         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
0924:         m_d3dpp.FullScreen_RefreshRateInHz = m_d3dSettings.Fullscreen_DisplayMode.RefreshRate;
0925:         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
0926:     }
0927: }
0928: 
0929: 
0930: 
0931: 
0932: //-----------------------------------------------------------------------------
0933: // Name: Reset3DEnvironment()
0934: // Desc:
0935: //-----------------------------------------------------------------------------
0936: HRESULT CD3DApplication::Reset3DEnvironment()
0937: {
0938:     HRESULT hr;
0939: 
0940:     // Release all vidmem objects
0941:     if( m_bDeviceObjectsRestored )
0942:     {
0943:         m_bDeviceObjectsRestored = false;
0944:         InvalidateDeviceObjects();
0945:     }
0946:     // Reset the device
0947:     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
0948:         return hr;
0949: 
0950:     // Store render target surface desc
0951:     LPDIRECT3DSURFACE9 pBackBuffer;
0952:     m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
0953:     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
0954:     pBackBuffer->Release();
0955: 
0956:     // Set up the fullscreen cursor
0957:     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
0958:     {
0959:         HCURSOR hCursor;
0960: #ifdef _WIN64
0961:         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
0962: #else
0963:         hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
0964: #endif
0965:         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
0966:         m_pd3dDevice->ShowCursor( true );
0967:     }
0968: 
0969:     // Confine cursor to fullscreen window
0970:     if( m_bClipCursorWhenFullscreen )
0971:     {
0972:         if (!m_bWindowed )
0973:         {
0974:             RECT rcWindow;
0975:             GetWindowRect( m_hWnd, &rcWindow );
0976:             ClipCursor( &rcWindow );
0977:         }
0978:         else
0979:         {
0980:             ClipCursor( NULL );
0981:         }
0982:     }
0983: 
0984:     // Initialize the app's device-dependent objects
0985:     hr = RestoreDeviceObjects();
0986:     if( FAILED(hr) )
0987:     {
0988:         InvalidateDeviceObjects();
0989:         return hr;
0990:     }
0991:     m_bDeviceObjectsRestored = true;
0992: 
0993:     // If the app is paused, trigger the rendering of the current frame
0994:     if( false == m_bFrameMoving )
0995:     {
0996:         m_bSingleStep = true;
0997:         DXUtil_Timer( TIMER_START );
0998:         DXUtil_Timer( TIMER_STOP );
0999:     }
1000: 
1001:     return S_OK;
1002: }
1003: 
1004: 
1005: 
1006: 
1007: //-----------------------------------------------------------------------------
1008: // Name: ToggleFullScreen()
1009: // Desc: Called when user toggles between fullscreen mode and windowed mode
1010: //-----------------------------------------------------------------------------
1011: HRESULT CD3DApplication::ToggleFullscreen()
1012: {
1013:     HRESULT hr;
1014:     int AdapterOrdinalOld = m_d3dSettings.AdapterOrdinal();
1015:     D3DDEVTYPE DevTypeOld = m_d3dSettings.DevType();
1016: 
1017:     Pause( true );
1018:     m_bIgnoreSizeChange = true;
1019: 
1020:     // Toggle the windowed state
1021:     m_bWindowed = !m_bWindowed;
1022:     m_d3dSettings.IsWindowed = m_bWindowed;
1023: 
1024:     // Prepare window for windowed/fullscreen change
1025:     AdjustWindowForChange();
1026: 
1027:     // If AdapterOrdinal and DevType are the same, we can just do a Reset().
1028:     // If they've changed, we need to do a complete device teardown/rebuild.
1029:     if (m_d3dSettings.AdapterOrdinal() == AdapterOrdinalOld &&
1030:         m_d3dSettings.DevType() == DevTypeOld)
1031:     {
1032:         // Reset the 3D device
1033:         BuildPresentParamsFromSettings();
1034:         hr = Reset3DEnvironment();
1035:     }
1036:     else
1037:     {
1038:         Cleanup3DEnvironment();
1039:         hr = Initialize3DEnvironment();
1040:     }
1041:     if( FAILED( hr ) )
1042:     {
1043:         if( hr != D3DERR_OUTOFVIDEOMEMORY )
1044:             hr = D3DAPPERR_RESETFAILED;
1045:         m_bIgnoreSizeChange = false;
1046:         if( !m_bWindowed )
1047:         {
1048:             // Restore window type to windowed mode
1049:             m_bWindowed = !m_bWindowed;
1050:             m_d3dSettings.IsWindowed = m_bWindowed;
1051:             AdjustWindowForChange();
1052:             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
1053:                         m_rcWindowBounds.left, m_rcWindowBounds.top,
1054:                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
1055:                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
1056:                         SWP_SHOWWINDOW );
1057:         }
1058:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
1059:     }
1060: 
1061:     m_bIgnoreSizeChange = false;
1062: 
1063:     // When moving from fullscreen to windowed mode, it is important to
1064:     // adjust the window size after resetting the device rather than
1065:     // beforehand to ensure that you get the window size you want.  For
1066:     // example, when switching from 640x480 fullscreen to windowed with
1067:     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
1068:     // the window size to 1000x600 until after the display mode has
1069:     // changed to 1024x768, because windows cannot be larger than the
1070:     // desktop.
1071:     if( m_bWindowed )
1072:     {
1073:         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
1074:                       m_rcWindowBounds.left, m_rcWindowBounds.top,
1075:                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
1076:                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
1077:                       SWP_SHOWWINDOW );
1078:     }
1079: 
1080:     Pause( false );
1081:     return S_OK;
1082: }
1083: 
1084: 
1085: 
1086: 
1087: //-----------------------------------------------------------------------------
1088: // Name: ForceWindowed()
1089: // Desc: Switch to a windowed mode, even if that means picking a new device
1090: //       and/or adapter
1091: //-----------------------------------------------------------------------------
1092: HRESULT CD3DApplication::ForceWindowed()
1093: {
1094:     HRESULT hr;
1095: 
1096:     if( m_bWindowed )
1097:         return S_OK;
1098: 
1099:     if( !FindBestWindowedMode(false, false) )
1100:     {
1101:         return E_FAIL;
1102:     }
1103:     m_bWindowed = true;
1104: 
1105:     // Now destroy the current 3D device objects, then reinitialize
1106: 
1107:     Pause( true );
1108: 
1109:     // Release all scene objects that will be re-created for the new device
1110:     Cleanup3DEnvironment();
1111: 
1112:     // Create the new device
1113:     if( FAILED(hr = Initialize3DEnvironment() ) )
1114:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
1115: 
1116:     Pause( false );
1117:     return S_OK;
1118: }
1119: 
1120: 
1121: 
1122: 
1123: //-----------------------------------------------------------------------------
1124: // Name: AdjustWindowForChange()
1125: // Desc: Prepare the window for a possible change between windowed mode and
1126: //       fullscreen mode.  This function is virtual and thus can be overridden
1127: //       to provide different behavior, such as switching to an entirely
1128: //       different window for fullscreen mode (as in the MFC sample apps).
1129: //-----------------------------------------------------------------------------
1130: HRESULT CD3DApplication::AdjustWindowForChange()
1131: {
1132:     if( m_bWindowed )
1133:     {
1134:         // Set windowed-mode style
1135:         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
1136:         if( m_hMenu != NULL )
1137:         {
1138:             SetMenu( m_hWnd, m_hMenu );
1139:             m_hMenu = NULL;
1140:         }
1141:     }
1142:     else
1143:     {
1144:         // Set fullscreen-mode style
1145:         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
1146:         if( m_hMenu == NULL )
1147:         {
1148:             m_hMenu = GetMenu( m_hWnd );
1149:             SetMenu( m_hWnd, NULL );
1150:         }
1151:     }
1152:     return S_OK;
1153: }
1154: 
1155: 
1156: 
1157: 
1158: //-----------------------------------------------------------------------------
1159: // Name: UserSelectNewDevice()
1160: // Desc: Displays a dialog so the user can select a new adapter, device, or
1161: //       display mode, and then recreates the 3D environment if needed
1162: //-----------------------------------------------------------------------------
1163: HRESULT CD3DApplication::UserSelectNewDevice()
1164: {
1165:     HRESULT hr;
1166: 
1167:     // Can't display dialogs in fullscreen mode
1168:     if( m_bWindowed == false )
1169:     {
1170:         if( FAILED( ToggleFullscreen() ) )
1171:         {
1172:             DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
1173:             return E_FAIL;
1174:         }
1175:     }
1176: 
1177:     CD3DSettingsDialog settingsDialog( &m_d3dEnumeration, &m_d3dSettings);
1178:     if( settingsDialog.ShowDialog( m_hWnd ) != IDOK )
1179:         return S_OK;
1180:     settingsDialog.GetFinalSettings( &m_d3dSettings );
1181: 
1182:     m_bWindowed = m_d3dSettings.IsWindowed;
1183: 
1184:     // Release all scene objects that will be re-created for the new device
1185:     Cleanup3DEnvironment();
1186: 
1187:     // Inform the display class of the change. It will internally
1188:     // re-create valid surfaces, a d3ddevice, etc.
1189:     if( FAILED( hr = Initialize3DEnvironment() ) )
1190:     {
1191:         if( hr != D3DERR_OUTOFVIDEOMEMORY )
1192:             hr = D3DAPPERR_RESETFAILED;
1193:         if( !m_bWindowed )
1194:         {
1195:             // Restore window type to windowed mode
1196:             m_bWindowed = !m_bWindowed;
1197:             m_d3dSettings.IsWindowed = m_bWindowed;
1198:             AdjustWindowForChange();
1199:             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
1200:                         m_rcWindowBounds.left, m_rcWindowBounds.top,
1201:                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
1202:                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
1203:                         SWP_SHOWWINDOW );
1204:         }
1205:         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
1206:     }
1207: 
1208:     // If the app is paused, trigger the rendering of the current frame
1209:     if( false == m_bFrameMoving )
1210:     {
1211:         m_bSingleStep = true;
1212:         DXUtil_Timer( TIMER_START );
1213:         DXUtil_Timer( TIMER_STOP );
1214:     }
1215:     return S_OK;
1216: }
1217: 
1218: 
1219: 
1220: 
1221: //-----------------------------------------------------------------------------
1222: // Name: Run()
1223: // Desc:
1224: //-----------------------------------------------------------------------------
1225: INT CD3DApplication::Run()
1226: {
1227:     // Load keyboard accelerators
1228:     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
1229: 
1230:     // Now we're ready to recieve and process Windows messages.
1231:     bool bGotMsg;
1232:     MSG  msg;
1233:     msg.message = WM_NULL;
1234:     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
1235: 
1236:     while( WM_QUIT != msg.message  )
1237:     {
1238:         // Use PeekMessage() if the app is active, so we can use idle time to
1239:         // render the scene. Else, use GetMessage() to avoid eating CPU time.
1240:         if( m_bActive )
1241:             bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
1242:         else
1243:             bGotMsg = ( GetMessage( &msg, NULL, 0U, 0U ) != 0 );
1244: 
1245:         if( bGotMsg )
1246:         {
1247:             // Translate and dispatch the message
1248:             if( hAccel == NULL || m_hWnd == NULL || 
1249:                 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
1250:             {
1251:                 TranslateMessage( &msg );
1252:                 DispatchMessage( &msg );
1253:             }
1254:         }
1255:         else
1256:         {
1257:             if( m_bDeviceLost )
1258:             {
1259:                 // Yield some CPU time to other processes
1260:                 Sleep( 100 ); // 100 milliseconds
1261:             }
1262:             // Render a frame during idle time (no messages are waiting)
1263:             if( m_bActive )
1264:             {
1265:                 if( FAILED( Render3DEnvironment() ) )
1266:                     SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
1267:             }
1268:         }
1269:     }
1270:     if( hAccel != NULL )
1271:         DestroyAcceleratorTable( hAccel );
1272: 
1273:     return (INT)msg.wParam;
1274: }
1275: 
1276: 
1277: 
1278: 
1279: //-----------------------------------------------------------------------------
1280: // Name: Render3DEnvironment()
1281: // Desc: Draws the scene.
1282: //-----------------------------------------------------------------------------
1283: HRESULT CD3DApplication::Render3DEnvironment()
1284: {
1285:     HRESULT hr;
1286: 
1287:     if( m_bDeviceLost )
1288:     {
1289:         // Test the cooperative level to see if it's okay to render
1290:         if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
1291:         {
1292:             // If the device was lost, do not render until we get it back
1293:             if( D3DERR_DEVICELOST == hr )
1294:                 return S_OK;
1295: 
1296:             // Check if the device needs to be reset.
1297:             if( D3DERR_DEVICENOTRESET == hr )
1298:             {
1299:                 // If we are windowed, read the desktop mode and use the same format for
1300:                 // the back buffer
1301:                 if( m_bWindowed )
1302:                 {
1303:                     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
1304:                     m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &m_d3dSettings.Windowed_DisplayMode );
1305:                     m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
1306:                 }
1307: 
1308:                 if( FAILED( hr = Reset3DEnvironment() ) )
1309:                     return hr;
1310:             }
1311:             return hr;
1312:         }
1313:         m_bDeviceLost = false;
1314:     }
1315: 
1316:     // Get the app's time, in seconds. Skip rendering if no time elapsed
1317:     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
1318:     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
1319:     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
1320:         return S_OK;
1321: 
1322:     // FrameMove (animate) the scene
1323:     if( m_bFrameMoving || m_bSingleStep )
1324:     {
1325:         // Store the time for the app
1326:         m_fTime        = fAppTime;
1327:         m_fElapsedTime = fElapsedAppTime;
1328: 
1329:         // Frame move the scene
1330:         if( FAILED( hr = FrameMove() ) )
1331:             return hr;
1332: 
1333:         m_bSingleStep = false;
1334:     }
1335: 
1336:     // Render the scene as normal
1337:     if( FAILED( hr = Render() ) )
1338:         return hr;
1339: 
1340:     UpdateStats();
1341: 
1342:     // Show the frame on the primary surface.
1343:     hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
1344:     if( D3DERR_DEVICELOST == hr )
1345:         m_bDeviceLost = true;
1346: 
1347:     return S_OK;
1348: }
1349: 
1350: 
1351: 
1352: 
1353: //-----------------------------------------------------------------------------
1354: // Name: UpdateStats()
1355: // Desc: 
1356: //-----------------------------------------------------------------------------
1357: void CD3DApplication::UpdateStats()
1358: {
1359:     // Keep track of the frame count
1360:     static FLOAT fLastTime = 0.0f;
1361:     static DWORD dwFrames  = 0;
1362:     FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
1363:     ++dwFrames;
1364: 
1365:     // Update the scene stats once per second
1366:     if( fTime - fLastTime > 1.0f )
1367:     {
1368:         m_fFPS    = dwFrames / (fTime - fLastTime);
1369:         fLastTime = fTime;
1370:         dwFrames  = 0;
1371: 
1372:         TCHAR strFmt[100];
1373:         D3DFORMAT fmtAdapter = m_d3dSettings.DisplayMode().Format;
1374:         if( fmtAdapter == m_d3dsdBackBuffer.Format )
1375:         {
1376:             lstrcpyn( strFmt, D3DUtil_D3DFormatToString( fmtAdapter, false ), 100 );
1377:         }
1378:         else
1379:         {
1380:             _sntprintf( strFmt, 100, TEXT("backbuf %s, adapter %s"), 
1381:                 D3DUtil_D3DFormatToString( m_d3dsdBackBuffer.Format, false ), 
1382:                 D3DUtil_D3DFormatToString( fmtAdapter, false ) );
1383:         }
1384:         strFmt[99] = TEXT('\0');
1385: 
1386:         TCHAR strDepthFmt[100];
1387:         if( m_d3dEnumeration.AppUsesDepthBuffer )
1388:         {
1389:             _sntprintf( strDepthFmt, 100, TEXT(" (%s)"), 
1390:                 D3DUtil_D3DFormatToString( m_d3dSettings.DepthStencilBufferFormat(), false ) );
1391:             strDepthFmt[99] = TEXT('\0');
1392:         }
1393:         else
1394:         {
1395:             // No depth buffer
1396:             strDepthFmt[0] = TEXT('\0');
1397:         }
1398: 
1399:         TCHAR* pstrMultiSample;
1400:         switch( m_d3dSettings.MultisampleType() )
1401:         {
1402:         case D3DMULTISAMPLE_NONMASKABLE:  pstrMultiSample = TEXT(" (Nonmaskable Multisample)"); break;
1403:         case D3DMULTISAMPLE_2_SAMPLES:  pstrMultiSample = TEXT(" (2x Multisample)"); break;
1404:         case D3DMULTISAMPLE_3_SAMPLES:  pstrMultiSample = TEXT(" (3x Multisample)"); break;
1405:         case D3DMULTISAMPLE_4_SAMPLES:  pstrMultiSample = TEXT(" (4x Multisample)"); break;
1406:         case D3DMULTISAMPLE_5_SAMPLES:  pstrMultiSample = TEXT(" (5x Multisample)"); break;
1407:         case D3DMULTISAMPLE_6_SAMPLES:  pstrMultiSample = TEXT(" (6x Multisample)"); break;
1408:         case D3DMULTISAMPLE_7_SAMPLES:  pstrMultiSample = TEXT(" (7x Multisample)"); break;
1409:         case D3DMULTISAMPLE_8_SAMPLES:  pstrMultiSample = TEXT(" (8x Multisample)"); break;
1410:         case D3DMULTISAMPLE_9_SAMPLES:  pstrMultiSample = TEXT(" (9x Multisample)"); break;
1411:         case D3DMULTISAMPLE_10_SAMPLES: pstrMultiSample = TEXT(" (10x Multisample)"); break;
1412:         case D3DMULTISAMPLE_11_SAMPLES: pstrMultiSample = TEXT(" (11x Multisample)"); break;
1413:         case D3DMULTISAMPLE_12_SAMPLES: pstrMultiSample = TEXT(" (12x Multisample)"); break;
1414:         case D3DMULTISAMPLE_13_SAMPLES: pstrMultiSample = TEXT(" (13x Multisample)"); break;
1415:         case D3DMULTISAMPLE_14_SAMPLES: pstrMultiSample = TEXT(" (14x Multisample)"); break;
1416:         case D3DMULTISAMPLE_15_SAMPLES: pstrMultiSample = TEXT(" (15x Multisample)"); break;
1417:         case D3DMULTISAMPLE_16_SAMPLES: pstrMultiSample = TEXT(" (16x Multisample)"); break;
1418:         default:                        pstrMultiSample = TEXT(""); break;
1419:         }
1420: 
1421:         const int cchMaxFrameStats = sizeof(m_strFrameStats) / sizeof(TCHAR);
1422:         _sntprintf( m_strFrameStats, cchMaxFrameStats, _T("%.02f fps (%dx%d), %s%s%s"), m_fFPS,
1423:                     m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
1424:                     strFmt, strDepthFmt, pstrMultiSample );
1425:         m_strFrameStats[cchMaxFrameStats - 1] = TEXT('\0');
1426:     }
1427: }
1428: 
1429: 
1430: 
1431: 
1432: //-----------------------------------------------------------------------------
1433: // Name: Pause()
1434: // Desc: Called in to toggle the pause state of the app.
1435: //-----------------------------------------------------------------------------
1436: void CD3DApplication::Pause( bool bPause )
1437: {
1438:     static DWORD dwAppPausedCount = 0;
1439: 
1440:     dwAppPausedCount += ( bPause ? +1 : -1 );
1441:     m_bActive         = ( dwAppPausedCount ? false : true );
1442: 
1443:     // Handle the first pause request (of many, nestable pause requests)
1444:     if( bPause && ( 1 == dwAppPausedCount ) )
1445:     {
1446:         // Stop the scene from animating
1447:         if( m_bFrameMoving )
1448:             DXUtil_Timer( TIMER_STOP );
1449:     }
1450: 
1451:     if( 0 == dwAppPausedCount )
1452:     {
1453:         // Restart the timers
1454:         if( m_bFrameMoving )
1455:             DXUtil_Timer( TIMER_START );
1456:     }
1457: }
1458: 
1459: 
1460: 
1461: 
1462: //-----------------------------------------------------------------------------
1463: // Name: Cleanup3DEnvironment()
1464: // Desc: Cleanup scene objects
1465: //-----------------------------------------------------------------------------
1466: void CD3DApplication::Cleanup3DEnvironment()
1467: {
1468:     if( m_pd3dDevice != NULL )
1469:     {
1470:         if( m_bDeviceObjectsRestored )
1471:         {
1472:             m_bDeviceObjectsRestored = false;
1473:             InvalidateDeviceObjects();
1474:         }
1475:         if( m_bDeviceObjectsInited )
1476:         {
1477:             m_bDeviceObjectsInited = false;
1478:             DeleteDeviceObjects();
1479:         }
1480: 
1481:         if( m_pd3dDevice->Release() > 0 )
1482:             DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
1483:         m_pd3dDevice = NULL;
1484:     }
1485: }
1486: 
1487: 
1488: 
1489: 
1490: //-----------------------------------------------------------------------------
1491: // Name: DisplayErrorMsg()
1492: // Desc: Displays error messages in a message box
1493: //-----------------------------------------------------------------------------
1494: HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
1495: {
1496:     static bool s_bFatalErrorReported = false;
1497:     TCHAR strMsg[512];
1498: 
1499:     // If a fatal error message has already been reported, the app
1500:     // is already shutting down, so don't show more error messages.
1501:     if( s_bFatalErrorReported )
1502:         return hr;
1503: 
1504:     switch( hr )
1505:     {
1506:         case D3DAPPERR_NODIRECT3D:
1507:             _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n")
1508:                              _T("want to check that the latest version of\n")
1509:                              _T("DirectX is correctly installed on your\n")
1510:                              _T("system.  Also make sure that this program\n")
1511:                              _T("was compiled with header files that match\n")
1512:                              _T("the installed DirectX DLLs.") );
1513:             break;
1514: 
1515:         case D3DAPPERR_NOCOMPATIBLEDEVICES:
1516:             _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
1517:                              _T("devices.") );
1518:             break;
1519: 
1520:         case D3DAPPERR_NOWINDOWABLEDEVICES:
1521:             _tcscpy( strMsg, _T("This sample cannot run in a desktop\n")
1522:                              _T("window with the current display settings.\n")
1523:                              _T("Please change your desktop settings to a\n")
1524:                              _T("16- or 32-bit display mode and re-run this\n")
1525:                              _T("sample.") );
1526:             break;
1527: 
1528:         case D3DAPPERR_NOHARDWAREDEVICE:
1529:             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n")
1530:                              _T("were found.") );
1531:             break;
1532: 
1533:         case D3DAPPERR_HALNOTCOMPATIBLE:
1534:             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
1535:                              _T("not available on your Direct3D hardware\n")
1536:                              _T("accelerator.") );
1537:             break;
1538: 
1539:         case D3DAPPERR_NOWINDOWEDHAL:
1540:             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
1541:                              _T("render into a window.\n")
1542:                              _T("Press F2 while the app is running to see a\n")
1543:                              _T("list of available devices and modes.") );
1544:             break;
1545: 
1546:         case D3DAPPERR_NODESKTOPHAL:
1547:             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
1548:                              _T("render into a window with the current\n")
1549:                              _T("desktop display settings.\n")
1550:                              _T("Press F2 while the app is running to see a\n")
1551:                              _T("list of available devices and modes.") );
1552:             break;
1553: 
1554:         case D3DAPPERR_NOHALTHISMODE:
1555:             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
1556:                              _T("not available on your Direct3D hardware\n")
1557:                              _T("accelerator with the current desktop display\n")
1558:                              _T("settings.\n")
1559:                              _T("Press F2 while the app is running to see a\n")
1560:                              _T("list of available devices and modes.") );
1561:             break;
1562: 
1563:         case D3DAPPERR_MEDIANOTFOUND:
1564:         case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
1565:             _tcscpy( strMsg, _T("Could not load required media." ) );
1566:             break;
1567: 
1568:         case D3DAPPERR_RESETFAILED:
1569:             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
1570:             break;
1571: 
1572:         case D3DAPPERR_NONZEROREFCOUNT:
1573:             _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n")
1574:                              _T("count (meaning things were not properly\n")
1575:                              _T("cleaned up).") );
1576:             break;
1577: 
1578:         case D3DAPPERR_NULLREFDEVICE:
1579:             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n")
1580:                              _T("The reference rendering device was selected, but your\n")
1581:                              _T("computer only has a reduced-functionality reference device\n")
1582:                              _T("installed.  Install the DirectX SDK to get the full\n")
1583:                              _T("reference device.\n") );
1584:             break;
1585: 
1586:         case E_OUTOFMEMORY:
1587:             _tcscpy( strMsg, _T("Not enough memory.") );
1588:             break;
1589: 
1590:         case D3DERR_OUTOFVIDEOMEMORY:
1591:             _tcscpy( strMsg, _T("Not enough video memory.") );
1592:             break;
1593: 
1594:         default:
1595:             _tcscpy( strMsg, _T("Generic application error. Enable\n")
1596:                              _T("debug output for detailed information.") );
1597:     }
1598: 
1599:     if( MSGERR_APPMUSTEXIT == dwType )
1600:     {
1601:         s_bFatalErrorReported = true;
1602:         _tcscat( strMsg, _T("\n\nThis sample will now exit.") );
1603:         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
1604: 
1605:         // Close the window, which shuts down the app
1606:         if( m_hWnd )
1607:             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
1608:     }
1609:     else
1610:     {
1611:         if( MSGWARN_SWITCHEDTOREF == dwType )
1612:             _tcscat( strMsg, _T("\n\nSwitching to the reference rasterizer,\n")
1613:                              _T("a software device that implements the entire\n")
1614:                              _T("Direct3D feature set, but runs very slowly.") );
1615:         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
1616:     }
1617: 
1618:     return hr;
1619: }
1620: