www.pudn.com > sxdl.zip > d3dapp.cpp
//-----------------------------------------------------------------------------
// File: D3DApp.cpp
//
// Desc: Application class for the Direct3D samples framework library.
//-----------------------------------------------------------------------------
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdio.h>
#include <tchar.h>
#include <D3D9.h>
#include "DXUtil.h"
#include "D3DUtil.h"
#include "D3DEnumeration.h"
#include "D3DSettings.h"
#include "D3DApp.h"
#include "resource.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('\0');
m_strFrameStats[0] = _T('\0');
m_strWindowTitle = _T("D3D9 Application");
m_dwCreationWidth = 400;
m_dwCreationHeight = 300;
m_bShowCursorWhenFullscreen = false;
m_bStartFullscreen = 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 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, backBufferFormat ) );
}
//-----------------------------------------------------------------------------
// Name: Create()
// Desc:
//-----------------------------------------------------------------------------
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 ),
// LT Change : Black backgound
(HBRUSH)GetStockObject(BLACK_BRUSH),
NULL, _T("D3D Window") };
RegisterClass( &amt;wndClass );
RECT rc ;
switch ( WindowMode )
{
default :
case 0 : // Window
// Set the window's initial style
if ( CanResize )
m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
else
m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_VISIBLE;
// Set the window's initial width
SetRect( &amt;rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
// LT Change : Window has no menu ( true changed to false )
AdjustWindowRect( &amt;rc, m_dwWindowStyle, false );
break ;
case 1 : // Desktop Window ( fake fullscreen )
case 3 : // Screen Saver : same as Desktop Window ( only difference is how we handle mouse and keyboard )
// Set the window's initial style
m_dwWindowStyle = WS_POPUP | WS_MAXIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS;
// Query the system for current desktop window size
m_dwCreationWidth = GetSystemMetrics ( SM_CXSCREEN ) ;
m_dwCreationHeight = GetSystemMetrics ( SM_CYSCREEN ) ;
// Set the window's initial width
SetRect( &amt;rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
break ;
case 2 : // Fullscreen ( fake fullscreen resolution has already been changed )
// Set the window's initial style
m_dwWindowStyle = WS_POPUP | WS_MAXIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS;
// Set the window's initial width
SetRect( &amt;rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
break ;
} ;
// 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,
// LT Change : No Menu
// dont load the menu
/* LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) )*/ NULL ,
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, &amt;m_rcWindowBounds );
GetClientRect( m_hWnd, &amt;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, &amt;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 &amt;&amt; pDeviceInfo->DevType != D3DDEVTYPE_HAL)
continue;
if (bRequireREF &amt;&amt; 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 &amt;&amt; pDeviceCombo->DevType == D3DDEVTYPE_HAL ||
pDeviceCombo->DevType == D3DDEVTYPE_HAL &amt;&amt; bAdapterMatchesBB )
{
pBestAdapterInfo = pAdapterInfo;
pBestDeviceInfo = pDeviceInfo;
pBestDeviceCombo = pDeviceCombo;
if( pDeviceCombo->DevType == D3DDEVTYPE_HAL &amt;&amt; 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, &amt;adapterDesktopDisplayMode );
for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
{
D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
if (bRequireHAL &amt;&amt; pDeviceInfo->DevType != D3DDEVTYPE_HAL)
continue;
if (bRequireREF &amt;&amt; 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 &amt;&amt; pDeviceInfo->DevType == D3DDEVTYPE_HAL ||
pDeviceCombo->DevType == D3DDEVTYPE_HAL &amt;&amt; pBestDeviceCombo->AdapterFormat != adapterDesktopDisplayMode.Format &amt;&amt; bAdapterMatchesDesktop ||
pDeviceCombo->DevType == D3DDEVTYPE_HAL &amt;&amt; bAdapterMatchesDesktop &amt;&amt; bAdapterMatchesBB )
{
bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
pBestAdapterInfo = pAdapterInfo;
pBestDeviceInfo = pDeviceInfo;
pBestDeviceCombo = pDeviceCombo;
if (pDeviceInfo->DevType == D3DDEVTYPE_HAL &amt;&amt; bAdapterMatchesDesktop &amt;&amt; 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 &amt;&amt;
pdm->Height == bestAdapterDesktopDisplayMode.Height &amt;&amt;
pdm->RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate )
{
// found a perfect match, so stop
bestDisplayMode = *pdm;
break;
}
else if( pdm->Width == bestAdapterDesktopDisplayMode.Width &amt;&amt;
pdm->Height == bestAdapterDesktopDisplayMode.Height &amt;&amt;
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 );
if( m_bStartFullscreen &amt;&amt; bFoundFullscreen )
m_d3dSettings.IsWindowed = false;
if( !bFoundWindowed &amt;&amt; bFoundFullscreen )
m_d3dSettings.IsWindowed = false;
if( !bFoundFullscreen &amt;&amt; !bFoundWindowed )
return D3DAPPERR_NOCOMPATIBLEDEVICES;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: Message handling function.
//-----------------------------------------------------------------------------
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 &amt;&amt; !m_bActive &amt;&amt; m_bWindowed &amt;&amt;
m_bDeviceObjectsInited &amt;&amt; m_bDeviceObjectsRestored )
{
Render();
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
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 &amt;&amt; m_hWnd != NULL )
m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
if( SIZE_MINIMIZED == wParam )
{
if( m_bClipCursorWhenFullscreen &amt;&amt; !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 &amt;&amt; !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_ENTERMENULOOP:
// Pause the app when menus are displayed
// LT Change : Menu removed ( we can now use alt and f10 )
// Pause(true);
break;
case WM_EXITMENULOOP:
// LT Change : Menu removed ( we can now use alt and f10 )
// 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_MONITORPOWER:
if( false == m_bWindowed )
return 1;
break;
case SC_KEYMENU:
// LT Change
// Disable F10 Alt and other sys keys
return 1;
}
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
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_EXIT:
// Recieved key/menu command to exit app
SendMessage( hWnd, WM_CLOSE, 0, 0 );
return 0;
}
break;
case WM_CLOSE:
Cleanup3DEnvironment();
FinalCleanup();
SAFE_RELEASE( m_pD3D );
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, &amt;m_rcWindowBounds );
GetClientRect( m_hWnd, &amt;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;
if( m_pd3dDevice != NULL )
{
// Reset the 3D environment
if( FAILED( hr = Reset3DEnvironment() ) )
{
if( hr != D3DERR_OUTOFVIDEOMEMORY )
hr = D3DAPPERR_RESETFAILED;
DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
}
}
Pause( false );
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: Initialize3DEnvironment()
// Desc:
//-----------------------------------------------------------------------------
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 &amt; 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
behaviorFlags |= D3DCREATE_MULTITHREADED ;
// Create the device
hr = m_pD3D->CreateDevice( m_d3dSettings.AdapterOrdinal(), pDeviceInfo->DevType,
m_hWndFocus, behaviorFlags, &amt;m_d3dpp,
&amt;m_pd3dDevice );
#ifdef _DEBUG
// Make this true to run on the REF
static bool WantREF = false ;
if ( WantREF )
{
hr = E_FAIL ;
WantREF = false ;
} ;
// This will cause bad ref count on exit but we dont care
#endif
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( &amt;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 &amt; D3DCREATE_HARDWARE_VERTEXPROCESSING &amt;&amt;
behaviorFlags &amt; 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 &amt; 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 &amt; 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 &amt; 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, &amt;pBackBuffer );
pBackBuffer->GetDesc( &amt;m_d3dsdBackBuffer );
pBackBuffer->Release();
// Set up the fullscreen cursor
if( m_bShowCursorWhenFullscreen &amt;&amt; !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, &amt;rcWindow );
ClipCursor( &amt;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 &amt;&amt;
hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) &amt;&amt;
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_bWindowed )
{
m_d3dpp.BackBufferWidth = m_rcWindowClient.right - m_rcWindowClient.left;
m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
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();
}
}
//-----------------------------------------------------------------------------
// Name: Reset3DEnvironment()
// Desc:
//-----------------------------------------------------------------------------
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( &amt;m_d3dpp ) ) )
return hr;
// Store render target surface desc
LPDIRECT3DSURFACE9 pBackBuffer;
m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &amt;pBackBuffer );
pBackBuffer->GetDesc( &amt;m_d3dsdBackBuffer );
pBackBuffer->Release();
// Set up the fullscreen cursor
if( m_bShowCursorWhenFullscreen &amt;&amt; !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, &amt;rcWindow );
ClipCursor( &amt;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 &amt;&amt;
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 );
}
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;
// Can't display dialogs in fullscreen mode
if( m_bWindowed == false )
{
if( FAILED( ToggleFullscreen() ) )
{
DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
return E_FAIL;
}
}
CD3DSettingsDialog settingsDialog( &amt;m_d3dEnumeration, &amt;m_d3dSettings);
if( settingsDialog.ShowDialog( m_hWnd ) != IDOK )
return S_OK;
settingsDialog.GetFinalSettings( &amt;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:
//-----------------------------------------------------------------------------
INT CD3DApplication::Run()
{
// LT Change : No Accels
// Dont do that
// // Load keyboard accelerators
// HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
// Now we're ready to recieve and process Windows messages.
bool bGotMsg;
MSG msg;
msg.message = WM_NULL;
PeekMessage( &amt;msg, NULL, 0U, 0U, PM_NOREMOVE );
while( WM_QUIT != msg.message )
{
// do not bog down our PC when minimized
if ( ::IsIconic ( m_hWnd ) )
::Sleep ( 50 ) ;
#if defined( _DEBUG ) || defined( DEBUG )
// do not sleep when debugging
#else
// do not bog down our PC when the window is covered
RECT WindowRectangle ;
HDC DeviceContext = ::GetDC ( m_hWnd ) ;
int Region = ::GetClipBox( DeviceContext, &amt; WindowRectangle );
::ReleaseDC( m_hWnd , DeviceContext );
if ( Region == NULLREGION )
::Sleep ( 50 ) ;
#endif
// 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( &amt;msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
else
bGotMsg = ( GetMessage( &amt;msg, NULL, 0U, 0U ) != 0 );
if( bGotMsg )
{
// Translate and dispatch the message
TranslateMessage( &amt;msg );
DispatchMessage( &amt;msg );
// LT Change : No Accels
/* if( hAccel == NULL || m_hWnd == NULL ||
0 == TranslateAccelerator( m_hWnd, hAccel, &amt;msg ) )
{
TranslateMessage( &amt;msg );
DispatchMessage( &amt;msg );
}
*/
}
else
{
if( m_bDeviceLost )
{
// Yield some CPU time to other processes
// LT Change : change to 10
Sleep( 10 ); // was 100 milliseconds
}
// Render a frame during idle time (no messages are waiting)
if( m_bActive )
{
if( FAILED( Render3DEnvironment() ) )
SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
}
}
}
// LT Change : No Accels
// if( hAccel != NULL )
// DestroyAcceleratorTable( hAccel );
return (INT)msg.wParam;
}
//-----------------------------------------------------------------------------
// Name: Render3DEnvironment()
// Desc: Draws the scene.
//-----------------------------------------------------------------------------
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, &amt;m_d3dSettings.Windowed_DisplayMode );
m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
}
if( FAILED( hr = Reset3DEnvironment() ) )
return hr;
}
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 ) &amt;&amt; 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;
}
// 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('\0');
TCHAR strDepthFmt[100];
if( m_d3dEnumeration.AppUsesDepthBuffer )
{
_sntprintf( strDepthFmt, 100, TEXT(" (>s)"),
D3DUtil_D3DFormatToString( m_d3dSettings.DepthStencilBufferFormat(), false ) );
strDepthFmt[99] = TEXT('\0');
}
else
{
// No depth buffer
strDepthFmt[0] = TEXT('\0');
}
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(">.01f msf, >.01f fps, >dx>d, >s>s>s" ), 1000.0f / m_fFPS, m_fFPS,
m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
strFmt, strDepthFmt, pstrMultiSample );
m_strFrameStats[cchMaxFrameStats - 1] = TEXT('\0');
}
}
//-----------------------------------------------------------------------------
// 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 &amt;&amt; ( 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 Direct Graphics. You may\n")
_T("want to check that the latest version of\n")
_T("DirectX is correctly installed on your\n")
_T("system.") );
break;
case D3DAPPERR_NOCOMPATIBLEDEVICES:
_tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
_T("devices.") );
break;
case D3DAPPERR_NOWINDOWABLEDEVICES:
_tcscpy( strMsg, _T("This game cannot run in a desktop\n")
_T("window with the current display settings.\n")
_T("Please change your desktop settings to a\n")
_T("16- or 32-bit display mode and try to re-run.") );
break;
case D3DAPPERR_NOHARDWAREDEVICE:
_tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices.") );
break;
case D3DAPPERR_NOHALTHISMODE:
case D3DAPPERR_NULLREFDEVICE:
case D3DAPPERR_HALNOTCOMPATIBLE:
_tcscpy( strMsg, _T("This game requires functionality that is\n")
_T("not available on your video board.") );
break;
case D3DAPPERR_NOWINDOWEDHAL:
_tcscpy( strMsg, _T("Your your video board cannot render into a window.") );
break;
case D3DAPPERR_NODESKTOPHAL:
_tcscpy( strMsg, _T("Your video board cannot work with the \n")
_T("current display settings.\n") ) ;
break;
case D3DAPPERR_MEDIANOTFOUND:
case 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:
// Hide this one if we are in release build
//
#ifndef _DEBUG
return S_OK ;
#else
_tcscpy( strMsg, _T("Internal Error: Non-zero reference count.") );
break;
#endif
case E_OUTOFMEMORY:
_tcscpy( strMsg, _T("Not enough system memory.") );
break;
case D3DERR_OUTOFVIDEOMEMORY:
_tcscpy( strMsg, _T("Not enough video memory.") );
break;
default:
_tcscpy( strMsg, _T("Generic application error.") );
}
if ( MSGERR_APPMUSTEXIT == dwType )
{
s_bFatalErrorReported = true;
_tcscat( strMsg, _T("\n\nThis game 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("\n\nSwitching to the reference rasterizer.") );
MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
}
return hr;
}