d3dapp.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:68k
- //-----------------------------------------------------------------------------
- // File: D3DApp.cpp
- //
- // Desc: Application class for the Direct3D samples framework library.
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- #include "dxstdafx.h"
- //-----------------------------------------------------------------------------
- // Global access to the app (needed for the global WndProc())
- //-----------------------------------------------------------------------------
- static CD3DApplication* g_pD3DApp = NULL;
- //-----------------------------------------------------------------------------
- // Name: CD3DApplication()
- // Desc: Constructor
- //-----------------------------------------------------------------------------
- CD3DApplication::CD3DApplication()
- {
- g_pD3DApp = this;
- m_pD3D = NULL;
- m_pd3dDevice = NULL;
- m_hWnd = NULL;
- m_hWndFocus = NULL;
- m_hMenu = NULL;
- m_bWindowed = true;
- m_bActive = false;
- m_bDeviceLost = false;
- m_bMinimized = false;
- m_bMaximized = false;
- m_bIgnoreSizeChange = false;
- m_bDeviceObjectsInited = false;
- m_bDeviceObjectsRestored = false;
- m_dwCreateFlags = 0;
- m_bFrameMoving = true;
- m_bSingleStep = false;
- m_fTime = 0.0f;
- m_fElapsedTime = 0.0f;
- m_fFPS = 0.0f;
- m_strDeviceStats[0] = _T(' ');
- m_strFrameStats[0] = _T(' ');
- m_strWindowTitle = _T("D3D9 Application");
- m_dwCreationWidth = 400;
- m_dwCreationHeight = 300;
- m_bShowCursorWhenFullscreen = false;
- m_bStartFullscreen = false;
- m_bCreateMultithreadDevice = false;
- m_bAllowDialogBoxMode = false;
- Pause( true ); // Pause until we're ready to render
- // When m_bClipCursorWhenFullscreen is true, the cursor is limited to
- // the device window when the app goes fullscreen. This prevents users
- // from accidentally clicking outside the app window on a multimon system.
- // This flag is turned off by default for debug builds, since it makes
- // multimon debugging difficult.
- #if defined(_DEBUG) || defined(DEBUG)
- m_bClipCursorWhenFullscreen = false;
- #else
- m_bClipCursorWhenFullscreen = true;
- #endif
- }
- //-----------------------------------------------------------------------------
- // Name: WndProc()
- // Desc: Static msg handler which passes messages to the application class.
- //-----------------------------------------------------------------------------
- LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- {
- return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
- }
- //-----------------------------------------------------------------------------
- // Name: ConfirmDeviceHelper()
- // Desc: Static function used by D3DEnumeration
- //-----------------------------------------------------------------------------
- bool CD3DApplication::ConfirmDeviceHelper( D3DCAPS9* pCaps, VertexProcessingType vertexProcessingType,
- D3DFORMAT adapterFormat, D3DFORMAT backBufferFormat )
- {
- DWORD dwBehavior;
- if (vertexProcessingType == SOFTWARE_VP)
- dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
- else if (vertexProcessingType == MIXED_VP)
- dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
- else if (vertexProcessingType == HARDWARE_VP)
- dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
- else if (vertexProcessingType == PURE_HARDWARE_VP)
- dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
- else
- dwBehavior = 0; // TODO: throw exception
-
- return SUCCEEDED( g_pD3DApp->ConfirmDevice( pCaps, dwBehavior, adapterFormat, backBufferFormat ) );
- }
- //-----------------------------------------------------------------------------
- // Name: Create()
- // Desc: Here's what this function does:
- // - Checks to make sure app is still active (if fullscreen, etc)
- // - Checks to see if it is time to draw with DXUtil_Timer, if not, it just returns S_OK
- // - Calls FrameMove() to recalculate new positions
- // - Calls Render() to draw the new frame
- // - Updates some frame count statistics
- // - Calls m_pd3dDevice->Present() to display the rendered frame.
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::Create( HINSTANCE hInstance )
- {
- HRESULT hr;
- // Create the Direct3D object
- m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
- if( m_pD3D == NULL )
- return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
- // Build a list of Direct3D adapters, modes and devices. The
- // ConfirmDevice() callback is used to confirm that only devices that
- // meet the app's requirements are considered.
- m_d3dEnumeration.SetD3D( m_pD3D );
- m_d3dEnumeration.ConfirmDeviceCallback = ConfirmDeviceHelper;
- if( FAILED( hr = m_d3dEnumeration.Enumerate() ) )
- {
- SAFE_RELEASE( m_pD3D );
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- // Unless a substitute hWnd has been specified, create a window to
- // render into
- if( m_hWnd == NULL)
- {
- // Register the windows class
- WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
- LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
- LoadCursor( NULL, IDC_ARROW ),
- (HBRUSH)GetStockObject(WHITE_BRUSH),
- NULL, _T("D3D Window") };
- RegisterClass( &wndClass );
- // Set the window's initial style
- m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
- WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
-
- HMENU hMenu = LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) );
- // Set the window's initial width
- RECT rc;
- SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
- AdjustWindowRect( &rc, m_dwWindowStyle, ( hMenu != NULL ) ? true : false );
- // Create the render window
- m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle,
- CW_USEDEFAULT, CW_USEDEFAULT,
- (rc.right-rc.left), (rc.bottom-rc.top), 0,
- hMenu, hInstance, 0 );
- }
- // The focus window can be a specified to be a different window than the
- // device window. If not, use the device window as the focus window.
- if( m_hWndFocus == NULL )
- m_hWndFocus = m_hWnd;
- // Save window properties
- m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
- GetWindowRect( m_hWnd, &m_rcWindowBounds );
- GetClientRect( m_hWnd, &m_rcWindowClient );
- if( FAILED( hr = ChooseInitialD3DSettings() ) )
- {
- SAFE_RELEASE( m_pD3D );
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- // Initialize the application timer
- DXUtil_Timer( TIMER_START );
- // Initialize the app's custom scene stuff
- if( FAILED( hr = OneTimeSceneInit() ) )
- {
- SAFE_RELEASE( m_pD3D );
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- // Initialize the 3D environment for the app
- if( FAILED( hr = Initialize3DEnvironment() ) )
- {
- SAFE_RELEASE( m_pD3D );
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- // The app is ready to go
- Pause( false );
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: FindBestWindowedMode()
- // Desc: Sets up m_d3dSettings with best available windowed mode, subject to
- // the bRequireHAL and bRequireREF constraints. Returns false if no such
- // mode can be found.
- //-----------------------------------------------------------------------------
- bool CD3DApplication::FindBestWindowedMode( bool bRequireHAL, bool bRequireREF )
- {
- // Get display mode of primary adapter (which is assumed to be where the window
- // will appear)
- D3DDISPLAYMODE primaryDesktopDisplayMode;
- m_pD3D->GetAdapterDisplayMode(0, &primaryDesktopDisplayMode);
- D3DAdapterInfo* pBestAdapterInfo = NULL;
- D3DDeviceInfo* pBestDeviceInfo = NULL;
- D3DDeviceCombo* pBestDeviceCombo = NULL;
- for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
- {
- D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
- for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
- {
- D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
- if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
- continue;
- if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
- continue;
- for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
- {
- D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
- bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
- if (!pDeviceCombo->IsWindowed)
- continue;
- if (pDeviceCombo->AdapterFormat != primaryDesktopDisplayMode.Format)
- continue;
- // If we haven't found a compatible DeviceCombo yet, or if this set
- // is better (because it's a HAL, and/or because formats match better),
- // save it
- if( pBestDeviceCombo == NULL ||
- pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceCombo->DevType == D3DDEVTYPE_HAL ||
- pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
- {
- pBestAdapterInfo = pAdapterInfo;
- pBestDeviceInfo = pDeviceInfo;
- pBestDeviceCombo = pDeviceCombo;
- if( pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
- {
- // This windowed device combo looks great -- take it
- goto EndWindowedDeviceComboSearch;
- }
- // Otherwise keep looking for a better windowed device combo
- }
- }
- }
- }
- EndWindowedDeviceComboSearch:
- if (pBestDeviceCombo == NULL )
- return false;
- m_d3dSettings.pWindowed_AdapterInfo = pBestAdapterInfo;
- m_d3dSettings.pWindowed_DeviceInfo = pBestDeviceInfo;
- m_d3dSettings.pWindowed_DeviceCombo = pBestDeviceCombo;
- m_d3dSettings.IsWindowed = true;
- m_d3dSettings.Windowed_DisplayMode = primaryDesktopDisplayMode;
- m_d3dSettings.Windowed_Width = m_rcWindowClient.right - m_rcWindowClient.left;
- m_d3dSettings.Windowed_Height = m_rcWindowClient.bottom - m_rcWindowClient.top;
- if (m_d3dEnumeration.AppUsesDepthBuffer)
- m_d3dSettings.Windowed_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
- m_d3dSettings.Windowed_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
- m_d3dSettings.Windowed_MultisampleQuality = 0;
- m_d3dSettings.Windowed_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
- m_d3dSettings.Windowed_PresentInterval = *(UINT*)pBestDeviceCombo->pPresentIntervalList->GetPtr(0);
- return true;
- }
- //-----------------------------------------------------------------------------
- // Name: FindBestFullscreenMode()
- // Desc: Sets up m_d3dSettings with best available fullscreen mode, subject to
- // the bRequireHAL and bRequireREF constraints. Returns false if no such
- // mode can be found.
- //-----------------------------------------------------------------------------
- bool CD3DApplication::FindBestFullscreenMode( bool bRequireHAL, bool bRequireREF )
- {
- // For fullscreen, default to first HAL DeviceCombo that supports the current desktop
- // display mode, or any display mode if HAL is not compatible with the desktop mode, or
- // non-HAL if no HAL is available
- D3DDISPLAYMODE adapterDesktopDisplayMode;
- D3DDISPLAYMODE bestAdapterDesktopDisplayMode;
- D3DDISPLAYMODE bestDisplayMode;
- bestAdapterDesktopDisplayMode.Width = 0;
- bestAdapterDesktopDisplayMode.Height = 0;
- bestAdapterDesktopDisplayMode.Format = D3DFMT_UNKNOWN;
- bestAdapterDesktopDisplayMode.RefreshRate = 0;
- D3DAdapterInfo* pBestAdapterInfo = NULL;
- D3DDeviceInfo* pBestDeviceInfo = NULL;
- D3DDeviceCombo* pBestDeviceCombo = NULL;
- for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
- {
- D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
- m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
- for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
- {
- D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
- if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
- continue;
- if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
- continue;
- for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
- {
- D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
- bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
- bool bAdapterMatchesDesktop = (pDeviceCombo->AdapterFormat == adapterDesktopDisplayMode.Format);
- if (pDeviceCombo->IsWindowed)
- continue;
- // If we haven't found a compatible set yet, or if this set
- // is better (because it's a HAL, and/or because formats match better),
- // save it
- if (pBestDeviceCombo == NULL ||
- pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceInfo->DevType == D3DDEVTYPE_HAL ||
- pDeviceCombo->DevType == D3DDEVTYPE_HAL && pBestDeviceCombo->AdapterFormat != adapterDesktopDisplayMode.Format && bAdapterMatchesDesktop ||
- pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB )
- {
- bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
- pBestAdapterInfo = pAdapterInfo;
- pBestDeviceInfo = pDeviceInfo;
- pBestDeviceCombo = pDeviceCombo;
- if (pDeviceInfo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB)
- {
- // This fullscreen device combo looks great -- take it
- goto EndFullscreenDeviceComboSearch;
- }
- // Otherwise keep looking for a better fullscreen device combo
- }
- }
- }
- }
- EndFullscreenDeviceComboSearch:
- if (pBestDeviceCombo == NULL)
- return false;
- // Need to find a display mode on the best adapter that uses pBestDeviceCombo->AdapterFormat
- // and is as close to bestAdapterDesktopDisplayMode's res as possible
- bestDisplayMode.Width = 0;
- bestDisplayMode.Height = 0;
- bestDisplayMode.Format = D3DFMT_UNKNOWN;
- bestDisplayMode.RefreshRate = 0;
- for( UINT idm = 0; idm < pBestAdapterInfo->pDisplayModeList->Count(); idm++ )
- {
- D3DDISPLAYMODE* pdm = (D3DDISPLAYMODE*)pBestAdapterInfo->pDisplayModeList->GetPtr(idm);
- if( pdm->Format != pBestDeviceCombo->AdapterFormat )
- continue;
- if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
- pdm->Height == bestAdapterDesktopDisplayMode.Height &&
- pdm->RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate )
- {
- // found a perfect match, so stop
- bestDisplayMode = *pdm;
- break;
- }
- else if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
- pdm->Height == bestAdapterDesktopDisplayMode.Height &&
- pdm->RefreshRate > bestDisplayMode.RefreshRate )
- {
- // refresh rate doesn't match, but width/height match, so keep this
- // and keep looking
- bestDisplayMode = *pdm;
- }
- else if( pdm->Width == bestAdapterDesktopDisplayMode.Width )
- {
- // width matches, so keep this and keep looking
- bestDisplayMode = *pdm;
- }
- else if( bestDisplayMode.Width == 0 )
- {
- // we don't have anything better yet, so keep this and keep looking
- bestDisplayMode = *pdm;
- }
- }
- m_d3dSettings.pFullscreen_AdapterInfo = pBestAdapterInfo;
- m_d3dSettings.pFullscreen_DeviceInfo = pBestDeviceInfo;
- m_d3dSettings.pFullscreen_DeviceCombo = pBestDeviceCombo;
- m_d3dSettings.IsWindowed = false;
- m_d3dSettings.Fullscreen_DisplayMode = bestDisplayMode;
- if (m_d3dEnumeration.AppUsesDepthBuffer)
- m_d3dSettings.Fullscreen_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
- m_d3dSettings.Fullscreen_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
- m_d3dSettings.Fullscreen_MultisampleQuality = 0;
- m_d3dSettings.Fullscreen_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
- m_d3dSettings.Fullscreen_PresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
- return true;
- }
- //-----------------------------------------------------------------------------
- // Name: ChooseInitialD3DSettings()
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::ChooseInitialD3DSettings()
- {
- bool bFoundFullscreen = FindBestFullscreenMode( false, false );
- bool bFoundWindowed = FindBestWindowedMode( false, false );
- m_d3dSettings.SetDeviceClip( false );
- if( m_bStartFullscreen && bFoundFullscreen )
- m_d3dSettings.IsWindowed = false;
- if( !bFoundWindowed && bFoundFullscreen )
- m_d3dSettings.IsWindowed = false;
- if( !bFoundFullscreen && !bFoundWindowed )
- return D3DAPPERR_NOCOMPATIBLEDEVICES;
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: MsgProc()
- // Desc: Message handling function. Here's what this function does:
- // - WM_PAINT: calls Render() and Present() is called if !m_bReady
- // - WM_EXITSIZEMOVE: window size recalc'd and calls HandlePossibleSizeChange()
- // - WM_CLOSE: calls Cleanup3dEnvironment(), DestroyMenu(), DestroyWindow(), PostQuitMessage()
- // - WM_COMMAND: IDM_CHANGEDEVICE calls UserSelectNewDevice() to select a new device
- // - WM_COMMAND: IDM_TOGGLEFULLSCREEN calls ToggleFullScreen() to toggle
- // between fullscreen and windowed
- // - WM_COMMAND: IDM_EXIT: shuts down the app with a WM_CLOSE
- // - anything not handled goes to DefWindowProc()
- //-----------------------------------------------------------------------------
- LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
- LPARAM lParam )
- {
- switch( uMsg )
- {
- case WM_PAINT:
- // Handle paint messages when the app is paused
- if( m_pd3dDevice && !m_bActive &&
- m_bDeviceObjectsInited && m_bDeviceObjectsRestored )
- {
- HRESULT hr;
- Render();
- hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
- if( D3DERR_DEVICELOST == hr )
- m_bDeviceLost = true;
- }
- break;
- case WM_GETMINMAXINFO:
- ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
- ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
- break;
- case WM_ENTERSIZEMOVE:
- // Halt frame movement while the app is sizing or moving
- Pause( true );
- break;
- case WM_SIZE:
- // Pick up possible changes to window style due to maximize, etc.
- if( m_bWindowed && m_hWnd != NULL )
- m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
- if( SIZE_MINIMIZED == wParam )
- {
- if( m_bClipCursorWhenFullscreen && !m_bWindowed )
- ClipCursor( NULL );
- Pause( true ); // Pause while we're minimized
- m_bMinimized = true;
- m_bMaximized = false;
- }
- else if( SIZE_MAXIMIZED == wParam )
- {
- if( m_bMinimized )
- Pause( false ); // Unpause since we're no longer minimized
- m_bMinimized = false;
- m_bMaximized = true;
- HandlePossibleSizeChange();
- }
- else if( SIZE_RESTORED == wParam )
- {
- if( m_bMaximized )
- {
- m_bMaximized = false;
- HandlePossibleSizeChange();
- }
- else if( m_bMinimized)
- {
- Pause( false ); // Unpause since we're no longer minimized
- m_bMinimized = false;
- HandlePossibleSizeChange();
- }
- else
- {
- // If we're neither maximized nor minimized, the window size
- // is changing by the user dragging the window edges. In this
- // case, we don't reset the device yet -- we wait until the
- // user stops dragging, and a WM_EXITSIZEMOVE message comes.
- }
- }
- break;
- case WM_EXITSIZEMOVE:
- Pause( false );
- HandlePossibleSizeChange();
- break;
- case WM_SETCURSOR:
- // Turn off Windows cursor in fullscreen mode
- if( m_bActive && !m_bWindowed )
- {
- SetCursor( NULL );
- if( m_bShowCursorWhenFullscreen )
- m_pd3dDevice->ShowCursor( true );
- return true; // prevent Windows from setting cursor to window class cursor
- }
- break;
- case WM_MOUSEMOVE:
- if( m_bActive && m_pd3dDevice != NULL )
- {
- POINT ptCursor;
- GetCursorPos( &ptCursor );
- if( !m_bWindowed )
- ScreenToClient( m_hWnd, &ptCursor );
- m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
- }
- break;
- case WM_ENTERMENULOOP:
- // Pause the app when menus are displayed
- Pause(true);
- break;
- case WM_EXITMENULOOP:
- Pause(false);
- break;
- case WM_NCHITTEST:
- // Prevent the user from selecting the menu in fullscreen mode
- if( !m_bWindowed )
- return HTCLIENT;
- break;
- case WM_POWERBROADCAST:
- switch( wParam )
- {
- #ifndef PBT_APMQUERYSUSPEND
- #define PBT_APMQUERYSUSPEND 0x0000
- #endif
- case PBT_APMQUERYSUSPEND:
- // At this point, the app should save any data for open
- // network connections, files, etc., and prepare to go into
- // a suspended mode.
- return true;
- #ifndef PBT_APMRESUMESUSPEND
- #define PBT_APMRESUMESUSPEND 0x0007
- #endif
- case PBT_APMRESUMESUSPEND:
- // At this point, the app should recover any data, network
- // connections, files, etc., and resume running from when
- // the app was suspended.
- return true;
- }
- break;
- case WM_SYSCOMMAND:
- // Prevent moving/sizing and power loss in fullscreen mode
- switch( wParam )
- {
- case SC_MOVE:
- case SC_SIZE:
- case SC_MAXIMIZE:
- case SC_KEYMENU:
- case SC_MONITORPOWER:
- if( false == m_bWindowed )
- return 1;
- break;
- }
- break;
- case WM_COMMAND:
- switch( LOWORD(wParam) )
- {
- case IDM_TOGGLESTART:
- // Toggle frame movement
- m_bFrameMoving = !m_bFrameMoving;
- DXUtil_Timer( m_bFrameMoving ? TIMER_START : TIMER_STOP );
- break;
- case IDM_SINGLESTEP:
- // Single-step frame movement
- if( false == m_bFrameMoving )
- DXUtil_Timer( TIMER_ADVANCE );
- else
- DXUtil_Timer( TIMER_STOP );
- m_bFrameMoving = false;
- m_bSingleStep = true;
- break;
- case IDM_CHANGEDEVICE:
- // Prompt the user to select a new device or mode
- Pause(true);
- UserSelectNewDevice();
- Pause(false);
- return 0;
- case IDM_TOGGLEFULLSCREEN:
- // Toggle the fullscreen/window mode
- Pause( true );
- if( FAILED( ToggleFullscreen() ) )
- DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
- Pause( false );
- return 0;
- case IDM_HELP:
- LaunchReadme();
- return 0;
- case IDM_EXIT:
- // Recieved key/menu command to exit app
- SendMessage( hWnd, WM_CLOSE, 0, 0 );
- return 0;
- }
- break;
- case WM_CLOSE:
- Cleanup3DEnvironment();
- SAFE_RELEASE( m_pD3D );
- FinalCleanup();
- HMENU hMenu;
- hMenu = GetMenu(hWnd);
- if( hMenu != NULL )
- DestroyMenu( hMenu );
- DestroyWindow( hWnd );
- PostQuitMessage(0);
- m_hWnd = NULL;
- return 0;
- }
- return DefWindowProc( hWnd, uMsg, wParam, lParam );
- }
- //-----------------------------------------------------------------------------
- // Name: HandlePossibleSizeChange()
- // Desc: Reset the device if the client area size has changed.
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::HandlePossibleSizeChange()
- {
- HRESULT hr = S_OK;
- RECT rcClientOld;
- rcClientOld = m_rcWindowClient;
- if( m_bIgnoreSizeChange )
- return S_OK;
- // Update window properties
- GetWindowRect( m_hWnd, &m_rcWindowBounds );
- GetClientRect( m_hWnd, &m_rcWindowClient );
- if( rcClientOld.right - rcClientOld.left !=
- m_rcWindowClient.right - m_rcWindowClient.left ||
- rcClientOld.bottom - rcClientOld.top !=
- m_rcWindowClient.bottom - m_rcWindowClient.top)
- {
- // A new window size will require a new backbuffer
- // size, so the 3D structures must be changed accordingly.
- Pause( true );
- m_d3dpp.BackBufferWidth = m_rcWindowClient.right - m_rcWindowClient.left;
- m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
- m_d3dSettings.Windowed_Width = m_d3dpp.BackBufferWidth;
- m_d3dSettings.Windowed_Height = m_d3dpp.BackBufferHeight;
-
- if( m_pd3dDevice != NULL )
- {
- // Reset the 3D environment
- if( FAILED( hr = Reset3DEnvironment() ) )
- {
- if( hr == D3DERR_DEVICELOST )
- {
- m_bDeviceLost = true;
- hr = S_OK;
- }
- else
- {
- if( hr != D3DERR_OUTOFVIDEOMEMORY )
- hr = D3DAPPERR_RESETFAILED;
- DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- }
- }
- Pause( false );
- }
- return hr;
- }
- //-----------------------------------------------------------------------------
- // Name: Initialize3DEnvironment()
- // Desc: Usually this function is not overridden. Here's what this function does:
- // - Sets the windowed flag to be either windowed or fullscreen
- // - Sets parameters for z-buffer depth and back buffer
- // - Creates the D3D device
- // - Sets the window position (if windowed, that is)
- // - Makes some determinations as to the abilites of the driver (HAL, etc)
- // - Sets up some cursor stuff
- // - Calls InitDeviceObjects()
- // - Calls RestoreDeviceObjects()
- // - If all goes well, m_bActive is set to TRUE, and the function returns
- // - Otherwise, initialization is reattempted using the reference device
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::Initialize3DEnvironment()
- {
- HRESULT hr;
- D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
- D3DDeviceInfo* pDeviceInfo = m_d3dSettings.PDeviceInfo();
- m_bWindowed = m_d3dSettings.IsWindowed;
- // Prepare window for possible windowed/fullscreen change
- AdjustWindowForChange();
- // Set up the presentation parameters
- BuildPresentParamsFromSettings();
- if( pDeviceInfo->Caps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
- {
- // Warn user about null ref device that can't render anything
- DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
- }
- DWORD behaviorFlags;
- if (m_d3dSettings.GetVertexProcessingType() == SOFTWARE_VP)
- behaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
- else if (m_d3dSettings.GetVertexProcessingType() == MIXED_VP)
- behaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
- else if (m_d3dSettings.GetVertexProcessingType() == HARDWARE_VP)
- behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
- else if (m_d3dSettings.GetVertexProcessingType() == PURE_HARDWARE_VP)
- behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
- else
- behaviorFlags = 0; // TODO: throw exception
- // Add multithreaded flag if requested by app
- if( m_bCreateMultithreadDevice )
- behaviorFlags |= D3DCREATE_MULTITHREADED;
- // Create the device
- hr = m_pD3D->CreateDevice( m_d3dSettings.AdapterOrdinal(), pDeviceInfo->DevType,
- m_hWndFocus, behaviorFlags, &m_d3dpp,
- &m_pd3dDevice );
- if( SUCCEEDED(hr) )
- {
- // When moving from fullscreen to windowed mode, it is important to
- // adjust the window size after recreating the device rather than
- // beforehand to ensure that you get the window size you want. For
- // example, when switching from 640x480 fullscreen to windowed with
- // a 1000x600 window on a 1024x768 desktop, it is impossible to set
- // the window size to 1000x600 until after the display mode has
- // changed to 1024x768, because windows cannot be larger than the
- // desktop.
- if( m_bWindowed )
- {
- SetWindowPos( m_hWnd, HWND_NOTOPMOST,
- m_rcWindowBounds.left, m_rcWindowBounds.top,
- ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
- ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
- SWP_SHOWWINDOW );
- }
- // Store device Caps
- m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
- m_dwCreateFlags = behaviorFlags;
- // Store device description
- if( pDeviceInfo->DevType == D3DDEVTYPE_REF )
- lstrcpy( m_strDeviceStats, TEXT("REF") );
- else if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- lstrcpy( m_strDeviceStats, TEXT("HAL") );
- else if( pDeviceInfo->DevType == D3DDEVTYPE_SW )
- lstrcpy( m_strDeviceStats, TEXT("SW") );
- if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
- behaviorFlags & D3DCREATE_PUREDEVICE )
- {
- if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
- else
- lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
- }
- else if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
- {
- if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
- else
- lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
- }
- else if( behaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
- {
- if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
- else
- lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
- }
- else if( behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
- {
- lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
- }
- if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- {
- // Be sure not to overflow m_strDeviceStats when appending the adapter
- // description, since it can be long. Note that the adapter description
- // is initially CHAR and must be converted to TCHAR.
- lstrcat( m_strDeviceStats, TEXT(": ") );
- const int cchDesc = sizeof(pAdapterInfo->AdapterIdentifier.Description);
- TCHAR szDescription[cchDesc];
- DXUtil_ConvertAnsiStringToGenericCch( szDescription,
- pAdapterInfo->AdapterIdentifier.Description, cchDesc );
- int maxAppend = sizeof(m_strDeviceStats) / sizeof(TCHAR) -
- lstrlen( m_strDeviceStats ) - 1;
- _tcsncat( m_strDeviceStats, szDescription, maxAppend );
- }
- // Store render target surface desc
- LPDIRECT3DSURFACE9 pBackBuffer = NULL;
- m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
- pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
- pBackBuffer->Release();
- // Set up the fullscreen cursor
- if( m_bShowCursorWhenFullscreen && !m_bWindowed )
- {
- HCURSOR hCursor;
- #ifdef _WIN64
- hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
- #else
- hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
- #endif
- D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
- m_pd3dDevice->ShowCursor( true );
- }
- // Confine cursor to fullscreen window
- if( m_bClipCursorWhenFullscreen )
- {
- if (!m_bWindowed )
- {
- RECT rcWindow;
- GetWindowRect( m_hWnd, &rcWindow );
- ClipCursor( &rcWindow );
- }
- else
- {
- ClipCursor( NULL );
- }
- }
- // Initialize the app's device-dependent objects
- hr = InitDeviceObjects();
- if( FAILED(hr) )
- {
- DeleteDeviceObjects();
- }
- else
- {
- m_bDeviceObjectsInited = true;
- hr = RestoreDeviceObjects();
- if( FAILED(hr) )
- {
- InvalidateDeviceObjects();
- }
- else
- {
- m_bDeviceObjectsRestored = true;
- return S_OK;
- }
- }
- // Cleanup before we try again
- Cleanup3DEnvironment();
- }
- // If that failed, fall back to the reference rasterizer
- if( hr != D3DAPPERR_MEDIANOTFOUND &&
- hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) &&
- pDeviceInfo->DevType == D3DDEVTYPE_HAL )
- {
- if (FindBestWindowedMode(false, true))
- {
- m_bWindowed = true;
- AdjustWindowForChange();
- // Make sure main window isn't topmost, so error message is visible
- SetWindowPos( m_hWnd, HWND_NOTOPMOST,
- m_rcWindowBounds.left, m_rcWindowBounds.top,
- ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
- ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
- SWP_SHOWWINDOW );
- // Let the user know we are switching from HAL to the reference rasterizer
- DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
- hr = Initialize3DEnvironment();
- }
- }
- return hr;
- }
- //-----------------------------------------------------------------------------
- // Name: BuildPresentParamsFromSettings()
- // Desc:
- //-----------------------------------------------------------------------------
- void CD3DApplication::BuildPresentParamsFromSettings()
- {
- m_d3dpp.Windowed = m_d3dSettings.IsWindowed;
- m_d3dpp.BackBufferCount = 1;
- m_d3dpp.MultiSampleType = m_d3dSettings.MultisampleType();
- m_d3dpp.MultiSampleQuality = m_d3dSettings.MultisampleQuality();
- m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- m_d3dpp.EnableAutoDepthStencil = m_d3dEnumeration.AppUsesDepthBuffer;
- m_d3dpp.hDeviceWindow = m_hWnd;
- if( m_d3dEnumeration.AppUsesDepthBuffer )
- {
- m_d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
- m_d3dpp.AutoDepthStencilFormat = m_d3dSettings.DepthStencilBufferFormat();
- }
- else
- {
- m_d3dpp.Flags = 0;
- }
- if ( m_d3dSettings.DeviceClip() )
- m_d3dpp.Flags |= D3DPRESENTFLAG_DEVICECLIP;
- if( m_bWindowed )
- {
- m_d3dpp.BackBufferWidth = m_d3dSettings.Windowed_Width;
- m_d3dpp.BackBufferHeight = m_d3dSettings.Windowed_Height;
- m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
- m_d3dpp.FullScreen_RefreshRateInHz = 0;
- m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
- }
- else
- {
- m_d3dpp.BackBufferWidth = m_d3dSettings.DisplayMode().Width;
- m_d3dpp.BackBufferHeight = m_d3dSettings.DisplayMode().Height;
- m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
- m_d3dpp.FullScreen_RefreshRateInHz = m_d3dSettings.Fullscreen_DisplayMode.RefreshRate;
- m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
- if( m_bAllowDialogBoxMode )
- {
- // Make the back buffers lockable in fullscreen mode
- // so we can show dialog boxes via SetDialogBoxMode()
- // but since lockable back buffers incur a performance cost on
- // some graphics hardware configurations we'll only
- // enable lockable backbuffers where SetDialogBoxMode() would work.
- if ( (m_d3dpp.BackBufferFormat == D3DFMT_X1R5G5B5 || m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5 || m_d3dpp.BackBufferFormat == D3DFMT_X8R8G8B8 ) &&
- ( m_d3dpp.MultiSampleType == D3DMULTISAMPLE_NONE ) &&
- ( m_d3dpp.SwapEffect == D3DSWAPEFFECT_DISCARD ) )
- {
- m_d3dpp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- // Name: Reset3DEnvironment()
- // Desc: Usually this function is not overridden. Here's what this function does:
- // - Sets the windowed flag to be either windowed or fullscreen
- // - Sets parameters for z-buffer depth and back buffer
- // - Creates the D3D device
- // - Sets the window position (if windowed, that is)
- // - Makes some determinations as to the abilites of the driver (HAL, etc)
- // - Sets up some cursor stuff
- // - Calls InitDeviceObjects()
- // - Calls RestoreDeviceObjects()
- // - If all goes well, m_bActive is set to TRUE, and the function returns
- // - Otherwise, initialization is reattempted using the reference device
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::Reset3DEnvironment()
- {
- HRESULT hr;
- // Release all vidmem objects
- if( m_bDeviceObjectsRestored )
- {
- m_bDeviceObjectsRestored = false;
- InvalidateDeviceObjects();
- }
- // Reset the device
- if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
- return hr;
- // Store render target surface desc
- LPDIRECT3DSURFACE9 pBackBuffer;
- m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
- pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
- pBackBuffer->Release();
- // Set up the fullscreen cursor
- if( m_bShowCursorWhenFullscreen && !m_bWindowed )
- {
- HCURSOR hCursor;
- #ifdef _WIN64
- hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
- #else
- hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
- #endif
- D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
- m_pd3dDevice->ShowCursor( true );
- }
- // Confine cursor to fullscreen window
- if( m_bClipCursorWhenFullscreen )
- {
- if (!m_bWindowed )
- {
- RECT rcWindow;
- GetWindowRect( m_hWnd, &rcWindow );
- ClipCursor( &rcWindow );
- }
- else
- {
- ClipCursor( NULL );
- }
- }
- // Initialize the app's device-dependent objects
- hr = RestoreDeviceObjects();
- if( FAILED(hr) )
- {
- InvalidateDeviceObjects();
- return hr;
- }
- m_bDeviceObjectsRestored = true;
- // If the app is paused, trigger the rendering of the current frame
- if( false == m_bFrameMoving )
- {
- m_bSingleStep = true;
- DXUtil_Timer( TIMER_START );
- DXUtil_Timer( TIMER_STOP );
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: ToggleFullScreen()
- // Desc: Called when user toggles between fullscreen mode and windowed mode
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::ToggleFullscreen()
- {
- HRESULT hr;
- int AdapterOrdinalOld = m_d3dSettings.AdapterOrdinal();
- D3DDEVTYPE DevTypeOld = m_d3dSettings.DevType();
- Pause( true );
- m_bIgnoreSizeChange = true;
- // Toggle the windowed state
- m_bWindowed = !m_bWindowed;
- m_d3dSettings.IsWindowed = m_bWindowed;
- // Prepare window for windowed/fullscreen change
- AdjustWindowForChange();
- // If AdapterOrdinal and DevType are the same, we can just do a Reset().
- // If they've changed, we need to do a complete device teardown/rebuild.
- if (m_d3dSettings.AdapterOrdinal() == AdapterOrdinalOld &&
- m_d3dSettings.DevType() == DevTypeOld)
- {
- // Reset the 3D device
- BuildPresentParamsFromSettings();
- hr = Reset3DEnvironment();
- }
- else
- {
- Cleanup3DEnvironment();
- hr = Initialize3DEnvironment();
- }
- if( FAILED( hr ) )
- {
- if( hr != D3DERR_OUTOFVIDEOMEMORY )
- hr = D3DAPPERR_RESETFAILED;
- m_bIgnoreSizeChange = false;
- if( !m_bWindowed )
- {
- // Restore window type to windowed mode
- m_bWindowed = !m_bWindowed;
- m_d3dSettings.IsWindowed = m_bWindowed;
- AdjustWindowForChange();
- SetWindowPos( m_hWnd, HWND_NOTOPMOST,
- m_rcWindowBounds.left, m_rcWindowBounds.top,
- ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
- ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
- SWP_SHOWWINDOW );
- }
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- m_bIgnoreSizeChange = false;
- // When moving from fullscreen to windowed mode, it is important to
- // adjust the window size after resetting the device rather than
- // beforehand to ensure that you get the window size you want. For
- // example, when switching from 640x480 fullscreen to windowed with
- // a 1000x600 window on a 1024x768 desktop, it is impossible to set
- // the window size to 1000x600 until after the display mode has
- // changed to 1024x768, because windows cannot be larger than the
- // desktop.
- if( m_bWindowed )
- {
- SetWindowPos( m_hWnd, HWND_NOTOPMOST,
- m_rcWindowBounds.left, m_rcWindowBounds.top,
- ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
- ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
- SWP_SHOWWINDOW );
- }
- GetClientRect( m_hWnd, &m_rcWindowClient ); // Update our copy
- Pause( false );
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: ForceWindowed()
- // Desc: Switch to a windowed mode, even if that means picking a new device
- // and/or adapter
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::ForceWindowed()
- {
- HRESULT hr;
- if( m_bWindowed )
- return S_OK;
- if( !FindBestWindowedMode(false, false) )
- {
- return E_FAIL;
- }
- m_bWindowed = true;
- // Now destroy the current 3D device objects, then reinitialize
- Pause( true );
- // Release all scene objects that will be re-created for the new device
- Cleanup3DEnvironment();
- // Create the new device
- if( FAILED(hr = Initialize3DEnvironment() ) )
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- Pause( false );
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: AdjustWindowForChange()
- // Desc: Prepare the window for a possible change between windowed mode and
- // fullscreen mode. This function is virtual and thus can be overridden
- // to provide different behavior, such as switching to an entirely
- // different window for fullscreen mode (as in the MFC sample apps).
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::AdjustWindowForChange()
- {
- if( m_bWindowed )
- {
- // Set windowed-mode style
- SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
- if( m_hMenu != NULL )
- {
- SetMenu( m_hWnd, m_hMenu );
- m_hMenu = NULL;
- }
- }
- else
- {
- // Set fullscreen-mode style
- SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
- if( m_hMenu == NULL )
- {
- m_hMenu = GetMenu( m_hWnd );
- SetMenu( m_hWnd, NULL );
- }
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: UserSelectNewDevice()
- // Desc: Displays a dialog so the user can select a new adapter, device, or
- // display mode, and then recreates the 3D environment if needed
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::UserSelectNewDevice()
- {
- HRESULT hr;
- bool bDialogBoxMode = false;
- bool bOldWindowed = m_bWindowed; // Preserve original windowed flag
- if( m_bWindowed == false )
- {
- // See if the current settings comply with the rules
- // for allowing SetDialogBoxMode().
- if( (m_d3dpp.BackBufferFormat == D3DFMT_X1R5G5B5 || m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5 || m_d3dpp.BackBufferFormat == D3DFMT_X8R8G8B8 ) &&
- ( m_d3dpp.MultiSampleType == D3DMULTISAMPLE_NONE ) &&
- ( m_d3dpp.SwapEffect == D3DSWAPEFFECT_DISCARD ) &&
- ( (m_d3dpp.Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) == D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ) &&
- ( (m_dwCreateFlags & D3DCREATE_ADAPTERGROUP_DEVICE) != D3DCREATE_ADAPTERGROUP_DEVICE ) )
- {
- if( SUCCEEDED( m_pd3dDevice->SetDialogBoxMode( true ) ) )
- bDialogBoxMode = true;
- }
- // If SetDialogBoxMode(true) didn't work then we can't display dialogs
- // in fullscreen mode so we'll go back to windowed mode
- if( FALSE == bDialogBoxMode )
- {
- if( FAILED( ToggleFullscreen() ) )
- {
- DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
- return E_FAIL;
- }
- }
- }
- // The dialog should use the mode the sample runs in, not
- // the mode that the dialog runs in.
- CD3DSettings tempSettings = m_d3dSettings;
- tempSettings.IsWindowed = bOldWindowed;
- CD3DSettingsDialog settingsDialog( &m_d3dEnumeration, &tempSettings);
- INT_PTR nResult = settingsDialog.ShowDialog( m_hWnd );
- // Before creating the device, switch back to SetDialogBoxMode(false)
- // mode to allow the user to pick multisampling or backbuffer formats
- // not supported by SetDialogBoxMode(true) but typical apps wouldn't
- // need to switch back.
- if( bDialogBoxMode )
- m_pd3dDevice->SetDialogBoxMode( false );
- if( nResult != IDOK )
- {
- // If we had to switch mode to display the dialog, we
- // need to go back to the original mode the sample
- // was running in.
- if( bOldWindowed != m_bWindowed && FAILED( ToggleFullscreen() ) )
- {
- DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
- return E_FAIL;
- }
- return S_OK;
- }
- settingsDialog.GetFinalSettings( &m_d3dSettings );
- m_bWindowed = m_d3dSettings.IsWindowed;
- // Release all scene objects that will be re-created for the new device
- Cleanup3DEnvironment();
- // Inform the display class of the change. It will internally
- // re-create valid surfaces, a d3ddevice, etc.
- if( FAILED( hr = Initialize3DEnvironment() ) )
- {
- if( hr != D3DERR_OUTOFVIDEOMEMORY )
- hr = D3DAPPERR_RESETFAILED;
- if( !m_bWindowed )
- {
- // Restore window type to windowed mode
- m_bWindowed = !m_bWindowed;
- m_d3dSettings.IsWindowed = m_bWindowed;
- AdjustWindowForChange();
- SetWindowPos( m_hWnd, HWND_NOTOPMOST,
- m_rcWindowBounds.left, m_rcWindowBounds.top,
- ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
- ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
- SWP_SHOWWINDOW );
- }
- return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- // If the app is paused, trigger the rendering of the current frame
- if( false == m_bFrameMoving )
- {
- m_bSingleStep = true;
- DXUtil_Timer( TIMER_START );
- DXUtil_Timer( TIMER_STOP );
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: Run()
- // Desc: Here's what this function does:
- // - Runs through the message loop. If no messages are waiting, then
- // it calls Render3DEnvironment().
- // - Messages are forwarded (through WndProc) to CD3DApplication::MsgProc()
- //-----------------------------------------------------------------------------
- INT CD3DApplication::Run()
- {
- // Load keyboard accelerators
- HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
- // Now we're ready to recieve and process Windows messages.
- HRESULT hr;
- bool bGotMsg;
- MSG msg;
- msg.message = WM_NULL;
- PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
- while( WM_QUIT != msg.message )
- {
- // Use PeekMessage() if the app is active, so we can use idle time to
- // render the scene. Else, use GetMessage() to avoid eating CPU time.
- if( m_bActive )
- bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
- else
- bGotMsg = ( GetMessage( &msg, NULL, 0U, 0U ) != 0 );
- if( bGotMsg )
- {
- // Translate and dispatch the message
- if( hAccel == NULL || m_hWnd == NULL ||
- 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
- {
- TranslateMessage( &msg );
- DispatchMessage( &msg );
- }
- }
- else
- {
- if( m_bDeviceLost )
- {
- // Yield some CPU time to other processes
- Sleep( 100 ); // 100 milliseconds
- }
- // Render a frame during idle time (no messages are waiting)
- if( m_bActive )
- {
- if( FAILED( hr = Render3DEnvironment() ) )
- DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
- }
- }
- }
- if( hAccel != NULL )
- DestroyAcceleratorTable( hAccel );
- return (INT)msg.wParam;
- }
- //-----------------------------------------------------------------------------
- // Name: Render3DEnvironment()
- // Desc: Here's what this function does:
- // - Checks to make sure app is still active (if fullscreen, etc)
- // - Checks to see if it is time to draw with DXUtil_Timer, if not, it just returns S_OK
- // - Calls FrameMove() to recalculate new positions
- // - Calls Render() to draw the new frame
- // - Updates some frame count statistics
- // - Calls m_pd3dDevice->Present() to display the rendered frame.
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::Render3DEnvironment()
- {
- HRESULT hr;
- if( m_bDeviceLost )
- {
- // Test the cooperative level to see if it's okay to render
- if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
- {
- // If the device was lost, do not render until we get it back
- if( D3DERR_DEVICELOST == hr )
- return S_OK;
- // Check if the device needs to be reset.
- if( D3DERR_DEVICENOTRESET == hr )
- {
- // If we are windowed, read the desktop mode and use the same format for
- // the back buffer
- if( m_bWindowed )
- {
- D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
- m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &m_d3dSettings.Windowed_DisplayMode );
- m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
- }
- if( FAILED( hr = Reset3DEnvironment() ) )
- return DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
- }
- return hr;
- }
- m_bDeviceLost = false;
- }
- // Get the app's time, in seconds. Skip rendering if no time elapsed
- FLOAT fAppTime = DXUtil_Timer( TIMER_GETAPPTIME );
- FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
- if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
- return S_OK;
- // FrameMove (animate) the scene
- if( m_bFrameMoving || m_bSingleStep )
- {
- // Store the time for the app
- m_fTime = fAppTime;
- m_fElapsedTime = fElapsedAppTime;
- // Frame move the scene
- if( FAILED( hr = FrameMove() ) )
- return hr;
- m_bSingleStep = false;
- } else
- m_fElapsedTime = fElapsedAppTime;
- // Render the scene as normal
- if( FAILED( hr = Render() ) )
- return hr;
- UpdateStats();
- // Show the frame on the primary surface.
- hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
- if( D3DERR_DEVICELOST == hr )
- m_bDeviceLost = true;
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: UpdateStats()
- // Desc:
- //-----------------------------------------------------------------------------
- void CD3DApplication::UpdateStats()
- {
- // Keep track of the frame count
- static FLOAT fLastTime = 0.0f;
- static DWORD dwFrames = 0;
- FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
- ++dwFrames;
- // Update the scene stats once per second
- if( fTime - fLastTime > 1.0f )
- {
- m_fFPS = dwFrames / (fTime - fLastTime);
- fLastTime = fTime;
- dwFrames = 0;
- TCHAR strFmt[100];
- D3DFORMAT fmtAdapter = m_d3dSettings.DisplayMode().Format;
- if( fmtAdapter == m_d3dsdBackBuffer.Format )
- {
- lstrcpyn( strFmt, D3DUtil_D3DFormatToString( fmtAdapter, false ), 100 );
- }
- else
- {
- _sntprintf( strFmt, 100, TEXT("backbuf %s, adapter %s"),
- D3DUtil_D3DFormatToString( m_d3dsdBackBuffer.Format, false ),
- D3DUtil_D3DFormatToString( fmtAdapter, false ) );
- }
- strFmt[99] = TEXT(' ');
- TCHAR strDepthFmt[100];
- if( m_d3dEnumeration.AppUsesDepthBuffer )
- {
- _sntprintf( strDepthFmt, 100, TEXT(" (%s)"),
- D3DUtil_D3DFormatToString( m_d3dSettings.DepthStencilBufferFormat(), false ) );
- strDepthFmt[99] = TEXT(' ');
- }
- else
- {
- // No depth buffer
- strDepthFmt[0] = TEXT(' ');
- }
- TCHAR* pstrMultiSample;
- switch( m_d3dSettings.MultisampleType() )
- {
- case D3DMULTISAMPLE_NONMASKABLE: pstrMultiSample = TEXT(" (Nonmaskable Multisample)"); break;
- case D3DMULTISAMPLE_2_SAMPLES: pstrMultiSample = TEXT(" (2x Multisample)"); break;
- case D3DMULTISAMPLE_3_SAMPLES: pstrMultiSample = TEXT(" (3x Multisample)"); break;
- case D3DMULTISAMPLE_4_SAMPLES: pstrMultiSample = TEXT(" (4x Multisample)"); break;
- case D3DMULTISAMPLE_5_SAMPLES: pstrMultiSample = TEXT(" (5x Multisample)"); break;
- case D3DMULTISAMPLE_6_SAMPLES: pstrMultiSample = TEXT(" (6x Multisample)"); break;
- case D3DMULTISAMPLE_7_SAMPLES: pstrMultiSample = TEXT(" (7x Multisample)"); break;
- case D3DMULTISAMPLE_8_SAMPLES: pstrMultiSample = TEXT(" (8x Multisample)"); break;
- case D3DMULTISAMPLE_9_SAMPLES: pstrMultiSample = TEXT(" (9x Multisample)"); break;
- case D3DMULTISAMPLE_10_SAMPLES: pstrMultiSample = TEXT(" (10x Multisample)"); break;
- case D3DMULTISAMPLE_11_SAMPLES: pstrMultiSample = TEXT(" (11x Multisample)"); break;
- case D3DMULTISAMPLE_12_SAMPLES: pstrMultiSample = TEXT(" (12x Multisample)"); break;
- case D3DMULTISAMPLE_13_SAMPLES: pstrMultiSample = TEXT(" (13x Multisample)"); break;
- case D3DMULTISAMPLE_14_SAMPLES: pstrMultiSample = TEXT(" (14x Multisample)"); break;
- case D3DMULTISAMPLE_15_SAMPLES: pstrMultiSample = TEXT(" (15x Multisample)"); break;
- case D3DMULTISAMPLE_16_SAMPLES: pstrMultiSample = TEXT(" (16x Multisample)"); break;
- default: pstrMultiSample = TEXT(""); break;
- }
- const int cchMaxFrameStats = sizeof(m_strFrameStats) / sizeof(TCHAR);
- _sntprintf( m_strFrameStats, cchMaxFrameStats, _T("%.02f fps (%dx%d), %s%s%s"), m_fFPS,
- m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
- strFmt, strDepthFmt, pstrMultiSample );
- m_strFrameStats[cchMaxFrameStats - 1] = TEXT(' ');
- }
- }
- //-----------------------------------------------------------------------------
- // Name: Pause()
- // Desc: Called in to toggle the pause state of the app.
- //-----------------------------------------------------------------------------
- void CD3DApplication::Pause( bool bPause )
- {
- static DWORD dwAppPausedCount = 0;
- dwAppPausedCount += ( bPause ? +1 : -1 );
- m_bActive = ( dwAppPausedCount ? false : true );
- // Handle the first pause request (of many, nestable pause requests)
- if( bPause && ( 1 == dwAppPausedCount ) )
- {
- // Stop the scene from animating
- if( m_bFrameMoving )
- DXUtil_Timer( TIMER_STOP );
- }
- if( 0 == dwAppPausedCount )
- {
- // Restart the timers
- if( m_bFrameMoving )
- DXUtil_Timer( TIMER_START );
- }
- }
- //-----------------------------------------------------------------------------
- // Name: Cleanup3DEnvironment()
- // Desc: Cleanup scene objects
- //-----------------------------------------------------------------------------
- void CD3DApplication::Cleanup3DEnvironment()
- {
- if( m_pd3dDevice != NULL )
- {
- if( m_bDeviceObjectsRestored )
- {
- m_bDeviceObjectsRestored = false;
- InvalidateDeviceObjects();
- }
- if( m_bDeviceObjectsInited )
- {
- m_bDeviceObjectsInited = false;
- DeleteDeviceObjects();
- }
- if( m_pd3dDevice->Release() > 0 )
- DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
- m_pd3dDevice = NULL;
- }
- }
- //-----------------------------------------------------------------------------
- // Name: DisplayErrorMsg()
- // Desc: Displays error messages in a message box
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
- {
- static bool s_bFatalErrorReported = false;
- TCHAR strMsg[512];
- // If a fatal error message has already been reported, the app
- // is already shutting down, so don't show more error messages.
- if( s_bFatalErrorReported )
- return hr;
- switch( hr )
- {
- case D3DAPPERR_NODIRECT3D:
- _tcscpy( strMsg, _T("Could not initialize Direct3D. You mayn")
- _T("want to check that the latest version ofn")
- _T("DirectX is correctly installed on yourn")
- _T("system. Also make sure that this programn")
- _T("was compiled with header files that matchn")
- _T("the installed DirectX DLLs.") );
- break;
- case D3DAPPERR_NOCOMPATIBLEDEVICES:
- _tcscpy( strMsg, _T("Could not find any compatible Direct3Dn")
- _T("devices.") );
- break;
- case D3DAPPERR_NOWINDOWABLEDEVICES:
- _tcscpy( strMsg, _T("This sample cannot run in a desktopn")
- _T("window with the current display settings.n")
- _T("Please change your desktop settings to an")
- _T("16- or 32-bit display mode and re-run thisn")
- _T("sample.") );
- break;
- case D3DAPPERR_NOHARDWAREDEVICE:
- _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devicesn")
- _T("were found.") );
- break;
- case D3DAPPERR_HALNOTCOMPATIBLE:
- _tcscpy( strMsg, _T("This sample requires functionality that isn")
- _T("not available on your Direct3D hardwaren")
- _T("accelerator.") );
- break;
- case D3DAPPERR_NOWINDOWEDHAL:
- _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannotn")
- _T("render into a window.n")
- _T("Press F2 while the app is running to see an")
- _T("list of available devices and modes.") );
- break;
- case D3DAPPERR_NODESKTOPHAL:
- _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannotn")
- _T("render into a window with the currentn")
- _T("desktop display settings.n")
- _T("Press F2 while the app is running to see an")
- _T("list of available devices and modes.") );
- break;
- case D3DAPPERR_NOHALTHISMODE:
- _tcscpy( strMsg, _T("This sample requires functionality that isn")
- _T("not available on your Direct3D hardwaren")
- _T("accelerator with the current desktop displayn")
- _T("settings.n")
- _T("Press F2 while the app is running to see an")
- _T("list of available devices and modes.") );
- break;
- case D3DAPPERR_MEDIANOTFOUND:
- case 0x80070002: // HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
- _tcscpy( strMsg, _T("Could not load required media." ) );
- break;
- case D3DAPPERR_RESETFAILED:
- _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
- break;
- case D3DAPPERR_NONZEROREFCOUNT:
- _tcscpy( strMsg, _T("A D3D object has a non-zero referencen")
- _T("count (meaning things were not properlyn")
- _T("cleaned up).") );
- break;
- case D3DAPPERR_NULLREFDEVICE:
- _tcscpy( strMsg, _T("Warning: Nothing will be rendered.n")
- _T("The reference rendering device was selected, but yourn")
- _T("computer only has a reduced-functionality reference devicen")
- _T("installed. Install the DirectX SDK to get the fulln")
- _T("reference device.n") );
- break;
- case E_OUTOFMEMORY:
- _tcscpy( strMsg, _T("Not enough memory.") );
- break;
- case D3DERR_OUTOFVIDEOMEMORY:
- _tcscpy( strMsg, _T("Not enough video memory.") );
- break;
- case D3DERR_DRIVERINTERNALERROR:
- _tcscpy( strMsg, _T("A serious problem occured inside the display driver.") );
- dwType = MSGERR_APPMUSTEXIT;
- break;
- default:
- _tcscpy( strMsg, _T("Generic application error. Enablen")
- _T("debug output for detailed information.") );
- }
- if( MSGERR_APPMUSTEXIT == dwType )
- {
- s_bFatalErrorReported = true;
- _tcscat( strMsg, _T("nnThis sample will now exit.") );
- MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
- // Close the window, which shuts down the app
- if( m_hWnd )
- SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
- }
- else
- {
- if( MSGWARN_SWITCHEDTOREF == dwType )
- _tcscat( strMsg, _T("nnSwitching to the reference rasterizer,n")
- _T("a software device that implements the entiren")
- _T("Direct3D feature set, but runs very slowly.") );
- MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
- }
- return hr;
- }
- //-----------------------------------------------------------------------------
- // Name: LaunchReadme()
- // Desc: Ensures the app is windowed, and launches the readme.txt
- // in the default text editor
- //-----------------------------------------------------------------------------
- HRESULT CD3DApplication::LaunchReadme()
- {
- // Switch to windowed if launching the readme.txt
- if( m_bWindowed == false )
- {
- if( FAILED( ToggleFullscreen() ) )
- {
- DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
- return E_FAIL;
- }
- }
- DXUtil_LaunchReadme( m_hWnd );
- return S_OK;
- }