www.pudn.com > d3d_grass.rar > d3dapp.cpp
//----------------------------------------------------------------------------- // File: D3DApp.cpp // // Desc: Application class for the Direct3D samples framework library. // // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #define STRICT #include#include #include #include #include #include #include #include "D3DApp.h" #include "D3DUtil.h" #include "DXUtil.h" #include "D3DRes.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_dwNumAdapters = 0; m_dwAdapter = 0L; m_pD3D = NULL; m_pd3dDevice = NULL; m_hWnd = NULL; m_hWndFocus = NULL; m_hMenu = NULL; m_bActive = FALSE; m_bReady = FALSE; m_bHasFocus = FALSE; m_dwCreateFlags = 0L; m_bFrameMoving = TRUE; m_bSingleStep = FALSE; m_fFPS = 0.0f; m_strDeviceStats[0] = _T('\0'); m_strFrameStats[0] = _T('\0'); m_strWindowTitle = _T("D3D8 Application"); m_dwCreationWidth = 400; m_dwCreationHeight = 300; m_bUseDepthBuffer = FALSE; m_dwMinDepthBits = 16; m_dwMinStencilBits = 0; m_bShowCursorWhenFullscreen = FALSE; // 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: Create() // Desc: //----------------------------------------------------------------------------- HRESULT CD3DApplication::Create( HINSTANCE hInstance ) { HRESULT hr; // Create the Direct3D object m_pD3D = Direct3DCreate8( 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. if( FAILED( hr = BuildDeviceList() ) ) { 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_VISIBLE; // Set the window's initial width RECT rc; SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight ); AdjustWindowRect( &rc, m_dwWindowStyle, TRUE ); // 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), 0L, LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ), hInstance, 0L ); } // 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 ); // 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 m_bReady = TRUE; return S_OK; } //----------------------------------------------------------------------------- // Name: SortModesCallback() // Desc: Callback function for sorting display modes (used by BuildDeviceList). //----------------------------------------------------------------------------- static int SortModesCallback( const VOID* arg1, const VOID* arg2 ) { D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1; D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2; if( p1->Format > p2->Format ) return -1; if( p1->Format < p2->Format ) return +1; if( p1->Width < p2->Width ) return -1; if( p1->Width > p2->Width ) return +1; if( p1->Height < p2->Height ) return -1; if( p1->Height > p2->Height ) return +1; return 0; } //----------------------------------------------------------------------------- // Name: BuildDeviceList() // Desc: //----------------------------------------------------------------------------- HRESULT CD3DApplication::BuildDeviceList() { const DWORD dwNumDeviceTypes = 2; const TCHAR* strDeviceDescs[] = { _T("HAL"), _T("REF") }; const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_REF }; BOOL bHALExists = FALSE; BOOL bHALIsWindowedCompatible = FALSE; BOOL bHALIsDesktopCompatible = FALSE; BOOL bHALIsSampleCompatible = FALSE; // Loop through all the adapters on the system (usually, there's just one // unless more than one graphics card is present). for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ ) { // Fill in adapter info D3DAdapterInfo* pAdapter = &m_Adapters[m_dwNumAdapters]; m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier ); m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop ); pAdapter->dwNumDevices = 0; pAdapter->dwCurrentDevice = 0; // Enumerate all display modes on this adapter D3DDISPLAYMODE modes[100]; D3DFORMAT formats[20]; DWORD dwNumFormats = 0; DWORD dwNumModes = 0; DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter ); // Add the adapter's current desktop format to the list of formats formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format; for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ ) { // Get the display mode attributes D3DDISPLAYMODE DisplayMode; m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode ); // Filter out low-resolution modes if( DisplayMode.Width < 640 || DisplayMode.Height < 400 ) continue; // Check if the mode already exists (to filter out refresh rates) for( DWORD m=0L; m devices[pAdapter->dwNumDevices]; pDevice->DeviceType = DeviceTypes[iDevice]; m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps ); pDevice->strDesc = strDeviceDescs[iDevice]; pDevice->dwNumModes = 0; pDevice->dwCurrentMode = 0; pDevice->bCanDoWindowed = FALSE; pDevice->bWindowed = FALSE; pDevice->MultiSampleTypeFullscreen = D3DMULTISAMPLE_NONE; pDevice->MultiSampleTypeWindowed = D3DMULTISAMPLE_NONE; // Examine each format supported by the adapter to see if it will // work with this device and meets the needs of the application. BOOL bFormatConfirmed[20]; DWORD dwBehavior[20]; D3DFORMAT fmtDepthStencil[20]; for( DWORD f=0; f CheckDeviceType( iAdapter, pDevice->DeviceType, formats[f], formats[f], FALSE ) ) ) continue; if( pDevice->DeviceType == D3DDEVTYPE_HAL ) { // This system has a HAL device bHALExists = TRUE; if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED ) { // HAL can run in a window for some mode bHALIsWindowedCompatible = TRUE; if( f == 0 ) { // HAL can run in a window for the current desktop mode bHALIsDesktopCompatible = TRUE; } } } // Confirm the device/format for HW vertex processing if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT ) { if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE ) { dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } if ( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } if ( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } } // Confirm the device/format for SW vertex processing if( FALSE == bFormatConfirmed[f] ) { dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING; if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f], formats[f] ) ) ) bFormatConfirmed[f] = TRUE; } // Find a suitable depth/stencil buffer format for this device/format if( bFormatConfirmed[f] && m_bUseDepthBuffer ) { if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType, formats[f], &fmtDepthStencil[f] ) ) { bFormatConfirmed[f] = FALSE; } } } // Add all enumerated display modes with confirmed formats to the // device's list of valid modes for( DWORD m=0L; m modes[pDevice->dwNumModes].Width = modes[m].Width; pDevice->modes[pDevice->dwNumModes].Height = modes[m].Height; pDevice->modes[pDevice->dwNumModes].Format = modes[m].Format; pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f]; pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f]; pDevice->dwNumModes++; if( pDevice->DeviceType == D3DDEVTYPE_HAL ) bHALIsSampleCompatible = TRUE; } } } } // Select any 640x480 mode for default (but prefer a 16-bit mode) for( m=0; m dwNumModes; m++ ) { if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 ) { pDevice->dwCurrentMode = m; if( pDevice->modes[m].Format == D3DFMT_R5G6B5 || pDevice->modes[m].Format == D3DFMT_X1R5G5B5 || pDevice->modes[m].Format == D3DFMT_A1R5G5B5 ) { break; } } } // Check if the device is compatible with the desktop display mode // (which was added initially as formats[0]) if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) ) { pDevice->bCanDoWindowed = TRUE; pDevice->bWindowed = TRUE; } // If valid modes were found, keep this device if( pDevice->dwNumModes > 0 ) pAdapter->dwNumDevices++; } // If valid devices were found, keep this adapter if( pAdapter->dwNumDevices > 0 ) m_dwNumAdapters++; } // Return an error if no compatible devices were found if( 0L == m_dwNumAdapters ) return D3DAPPERR_NOCOMPATIBLEDEVICES; // Pick a default device that can render into a window // (This code assumes that the HAL device comes before the REF // device in the device array). for( DWORD a=0; a CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D16 ) ) ) { *pDepthStencilFormat = D3DFMT_D16; return TRUE; } } } if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) ) { *pDepthStencilFormat = D3DFMT_D15S1; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) ) { *pDepthStencilFormat = D3DFMT_D24X8; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) ) { *pDepthStencilFormat = D3DFMT_D24S8; return TRUE; } } } if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) ) { *pDepthStencilFormat = D3DFMT_D24X4S4; return TRUE; } } } if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 ) { if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType, TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) ) { if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType, TargetFormat, TargetFormat, D3DFMT_D32 ) ) ) { *pDepthStencilFormat = D3DFMT_D32; return TRUE; } } } return FALSE; } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: Message handling function. //----------------------------------------------------------------------------- LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { HRESULT hr; switch( uMsg ) { case WM_PAINT: // Handle paint messages when the app is not ready if( m_pd3dDevice && !m_bReady ) { if( m_bWindowed ) { Render(); m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } } break; case WM_ACTIVATEAPP: m_bHasFocus = (BOOL) wParam; 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: // Check to see if we are losing our window... if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam ) { if( m_bClipCursorWhenFullscreen && !m_bWindowed ) ClipCursor( NULL ); m_bActive = FALSE; } else { m_bActive = TRUE; } break; case WM_EXITSIZEMOVE: Pause( FALSE ); if( m_bActive && m_bWindowed ) { RECT rcClientOld; rcClientOld = m_rcWindowClient; // 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. m_bReady = FALSE; m_d3dpp.BackBufferWidth = m_rcWindowClient.right - m_rcWindowClient.left; m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top; // Resize the 3D environment if( FAILED( hr = Resize3DEnvironment() ) ) { DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT ); return 0; } m_bReady = TRUE; } } break; case WM_SETCURSOR: // Turn off Windows cursor in fullscreen mode if( m_bActive && m_bReady && !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_bReady && m_pd3dDevice != NULL ) { POINT ptCursor; GetCursorPos( &ptCursor ); if( !m_bWindowed ) ScreenToClient( m_hWnd, &ptCursor ); m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0L ); } break; case WM_ENTERMENULOOP: // Pause the app when menus are displayed Pause(TRUE); break; case WM_EXITMENULOOP: Pause(FALSE); break; case WM_CONTEXTMENU: // No context menus allowed in fullscreen mode if( m_bWindowed == FALSE ) break; // Handle the app's context menu (via right mouse click) TrackPopupMenuEx( GetSubMenu( LoadMenu( 0, MAKEINTRESOURCE(IDR_POPUP) ), 0 ), TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL ); 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 if( m_bActive && m_bReady ) { Pause(TRUE); if( FAILED( hr = UserSelectNewDevice() ) ) return 0; Pause(FALSE); } return 0; case IDM_TOGGLEFULLSCREEN: // Toggle the fullscreen/window mode if( m_bActive && m_bReady ) { Pause( TRUE ); if( FAILED( ToggleFullscreen() ) ) { DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT ); return 0; } 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(); DestroyMenu( GetMenu(hWnd) ); DestroyWindow( hWnd ); PostQuitMessage(0); return 0; } return DefWindowProc( hWnd, uMsg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: Initialize3DEnvironment() // Desc: //----------------------------------------------------------------------------- HRESULT CD3DApplication::Initialize3DEnvironment() { HRESULT hr; D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter]; D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice]; D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode]; // Prepare window for possible windowed/fullscreen change AdjustWindowForChange(); // Set up the presentation parameters ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) ); m_d3dpp.Windowed = pDeviceInfo->bWindowed; m_d3dpp.BackBufferCount = 1; if( pDeviceInfo->bWindowed ) m_d3dpp.MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed; else m_d3dpp.MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen; m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; m_d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer; m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat; m_d3dpp.hDeviceWindow = m_hWnd; if( m_bWindowed ) { m_d3dpp.BackBufferWidth = m_rcWindowClient.right - m_rcWindowClient.left; m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top; m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format; } else { m_d3dpp.BackBufferWidth = pModeInfo->Width; m_d3dpp.BackBufferHeight = pModeInfo->Height; m_d3dpp.BackBufferFormat = pModeInfo->Format; } if( pDeviceInfo->d3dCaps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE ) { // Warn user about null ref device that can't render anything DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 ); } // Create the device hr = m_pD3D->CreateDevice( m_dwAdapter, pDeviceInfo->DeviceType, m_hWndFocus, pModeInfo->dwBehavior, &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 = pModeInfo->dwBehavior; // Store device description if( pDeviceInfo->DeviceType == D3DDEVTYPE_REF ) lstrcpy( m_strDeviceStats, TEXT("REF") ); else if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) lstrcpy( m_strDeviceStats, TEXT("HAL") ); else if( pDeviceInfo->DeviceType == D3DDEVTYPE_SW ) lstrcpy( m_strDeviceStats, TEXT("SW") ); if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING && pModeInfo->dwBehavior & D3DCREATE_PUREDEVICE ) { if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") ); else lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") ); } else if( pModeInfo->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) { if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) lstrcat( m_strDeviceStats, TEXT(" (hw vp)") ); else lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") ); } else if( pModeInfo->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) { if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") ); else lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") ); } else if( pModeInfo->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING ) { lstrcat( m_strDeviceStats, TEXT(" (sw vp)") ); } if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) { lstrcat( m_strDeviceStats, TEXT(": ") ); lstrcat( m_strDeviceStats, pAdapterInfo->d3dAdapterIdentifier.Description ); } // Store render target surface desc LPDIRECT3DSURFACE8 pBackBuffer; m_pd3dDevice->GetBackBuffer( 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)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( SUCCEEDED(hr) ) { hr = RestoreDeviceObjects(); if( SUCCEEDED(hr) ) { m_bActive = TRUE; return S_OK; } } // Cleanup before we try again InvalidateDeviceObjects(); DeleteDeviceObjects(); SAFE_RELEASE( m_pd3dDevice ); } // If that failed, fall back to the reference rasterizer if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL ) { // Select the default adapter m_dwAdapter = 0L; pAdapterInfo = &m_Adapters[m_dwAdapter]; // Look for a software device for( UINT i=0L; i dwNumDevices; i++ ) { if( pAdapterInfo->devices[i].DeviceType == D3DDEVTYPE_REF ) { pAdapterInfo->dwCurrentDevice = i; pDeviceInfo = &pAdapterInfo->devices[i]; m_bWindowed = pDeviceInfo->bWindowed; break; } } // Try again, this time with the reference rasterizer if( pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice].DeviceType == D3DDEVTYPE_REF ) { // 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 ); AdjustWindowForChange(); // Let the user know we are switching from HAL to the reference rasterizer DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF ); hr = Initialize3DEnvironment(); } } return hr; } //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CD3DApplication::Resize3DEnvironment() { HRESULT hr; // Release all vidmem objects if( FAILED( hr = InvalidateDeviceObjects() ) ) return hr; // Reset the device if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) ) return hr; // Store render target surface desc LPDIRECT3DSURFACE8 pBackBuffer; m_pd3dDevice->GetBackBuffer( 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)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) ) return hr; // 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() { // Get access to current adapter, device, and mode D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter]; D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice]; D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode]; // Need device change if going windowed and the current device // can only be fullscreen if( !m_bWindowed && !pDeviceInfo->bCanDoWindowed ) return ForceWindowed(); m_bReady = FALSE; // Toggle the windowed state m_bWindowed = !m_bWindowed; pDeviceInfo->bWindowed = m_bWindowed; // Prepare window for windowed/fullscreen change AdjustWindowForChange(); // Set up the presentation parameters m_d3dpp.Windowed = pDeviceInfo->bWindowed; if( m_bWindowed ) m_d3dpp.MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed; else m_d3dpp.MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen; m_d3dpp.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat; m_d3dpp.hDeviceWindow = m_hWnd; if( m_bWindowed ) { m_d3dpp.BackBufferWidth = m_rcWindowClient.right - m_rcWindowClient.left; m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top; m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format; } else { m_d3dpp.BackBufferWidth = pModeInfo->Width; m_d3dpp.BackBufferHeight = pModeInfo->Height; m_d3dpp.BackBufferFormat = pModeInfo->Format; } // Resize the 3D device if( FAILED( Resize3DEnvironment() ) ) { if( m_bWindowed ) return ForceWindowed(); else return E_FAIL; } // 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 ); } m_bReady = TRUE; 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; D3DAdapterInfo* pAdapterInfoCur = &m_Adapters[m_dwAdapter]; D3DDeviceInfo* pDeviceInfoCur = &pAdapterInfoCur->devices[pAdapterInfoCur->dwCurrentDevice]; BOOL bFoundDevice = FALSE; if( pDeviceInfoCur->bCanDoWindowed ) { bFoundDevice = TRUE; } else { // Look for a windowable device on any adapter D3DAdapterInfo* pAdapterInfo; DWORD dwAdapter; D3DDeviceInfo* pDeviceInfo; DWORD dwDevice; for( dwAdapter = 0; dwAdapter < m_dwNumAdapters; dwAdapter++ ) { pAdapterInfo = &m_Adapters[dwAdapter]; for( dwDevice = 0; dwDevice < pAdapterInfo->dwNumDevices; dwDevice++ ) { pDeviceInfo = &pAdapterInfo->devices[dwDevice]; if( pDeviceInfo->bCanDoWindowed ) { m_dwAdapter = dwAdapter; pDeviceInfoCur = pDeviceInfo; pAdapterInfo->dwCurrentDevice = dwDevice; bFoundDevice = TRUE; break; } } if( bFoundDevice ) break; } } if( !bFoundDevice ) return E_FAIL; pDeviceInfoCur->bWindowed = TRUE; m_bWindowed = TRUE; // Now destroy the current 3D device objects, then reinitialize m_bReady = FALSE; // Release all scene objects that will be re-created for the new device InvalidateDeviceObjects(); DeleteDeviceObjects(); // Release display objects, so a new device can be created if( m_pd3dDevice->Release() > 0L ) return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT ); // Create the new device if( FAILED( hr = Initialize3DEnvironment() ) ) return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT ); m_bReady = TRUE; 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 ); } else { // Set fullscreen-mode style SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE ); m_hMenu = (HMENU)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_RESIZEFAILED, MSGERR_APPMUSTEXIT ); return E_FAIL; } } // Prompt the user to change the mode if( IDOK != DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SELECTDEVICE), m_hWnd, SelectDeviceProc, (LPARAM)this ) ) return S_OK; // Get access to the newly selected adapter, device, and mode DWORD dwDevice; dwDevice = m_Adapters[m_dwAdapter].dwCurrentDevice; m_bWindowed = m_Adapters[m_dwAdapter].devices[dwDevice].bWindowed; // Release all scene objects that will be re-created for the new device InvalidateDeviceObjects(); DeleteDeviceObjects(); // Release display objects, so a new device can be created if( m_pd3dDevice->Release() > 0L ) return DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT ); // Inform the display class of the change. It will internally // re-create valid surfaces, a d3ddevice, etc. if( FAILED( hr = Initialize3DEnvironment() ) ) 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: SelectDeviceProc() // Desc: Windows message handling function for the device select dialog //----------------------------------------------------------------------------- INT_PTR CALLBACK CD3DApplication::SelectDeviceProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) { // Get access to the UI controls HWND hwndAdapterList = GetDlgItem( hDlg, IDC_ADAPTER_COMBO ); HWND hwndDeviceList = GetDlgItem( hDlg, IDC_DEVICE_COMBO ); HWND hwndFullscreenModeList = GetDlgItem( hDlg, IDC_FULLSCREENMODES_COMBO ); HWND hwndWindowedRadio = GetDlgItem( hDlg, IDC_WINDOW ); HWND hwndFullscreenRadio = GetDlgItem( hDlg, IDC_FULLSCREEN ); HWND hwndMultiSampleList = GetDlgItem( hDlg, IDC_MULTISAMPLE_COMBO ); BOOL bUpdateDlgControls = FALSE; // Static state for adapter/device/mode selection static CD3DApplication* pd3dApp; static DWORD dwOldAdapter, dwNewAdapter; static DWORD dwOldDevice, dwNewDevice; static DWORD dwOldMode, dwNewMode; static BOOL bOldWindowed, bNewWindowed; static D3DMULTISAMPLE_TYPE OldMultiSampleTypeWindowed, NewMultiSampleTypeWindowed; static D3DMULTISAMPLE_TYPE OldMultiSampleTypeFullscreen, NewMultiSampleTypeFullscreen; // Working variables D3DAdapterInfo* pAdapter; D3DDeviceInfo* pDevice; // Handle the initialization message if( WM_INITDIALOG == msg ) { // Old state pd3dApp = (CD3DApplication*)lParam; dwOldAdapter = pd3dApp->m_dwAdapter; pAdapter = &pd3dApp->m_Adapters[dwOldAdapter]; dwOldDevice = pAdapter->dwCurrentDevice; pDevice = &pAdapter->devices[dwOldDevice]; dwOldMode = pDevice->dwCurrentMode; bOldWindowed = pDevice->bWindowed; OldMultiSampleTypeWindowed = pDevice->MultiSampleTypeWindowed; OldMultiSampleTypeFullscreen = pDevice->MultiSampleTypeFullscreen; // New state is initially the same as the old state dwNewAdapter = dwOldAdapter; dwNewDevice = dwOldDevice; dwNewMode = dwOldMode; bNewWindowed = bOldWindowed; NewMultiSampleTypeWindowed = OldMultiSampleTypeWindowed; NewMultiSampleTypeFullscreen = OldMultiSampleTypeFullscreen; // Set flag to update dialog controls below bUpdateDlgControls = TRUE; } if( WM_COMMAND == msg ) { // Get current UI state bNewWindowed = Button_GetCheck( hwndWindowedRadio ); if( IDOK == LOWORD(wParam) ) { // Handle the case when the user hits the OK button. Check if any // of the options were changed if( dwNewAdapter != dwOldAdapter || dwNewDevice != dwOldDevice || dwNewMode != dwOldMode || bNewWindowed != bOldWindowed || NewMultiSampleTypeWindowed != OldMultiSampleTypeWindowed || NewMultiSampleTypeFullscreen != OldMultiSampleTypeFullscreen ) { pd3dApp->m_dwAdapter = dwNewAdapter; pAdapter = &pd3dApp->m_Adapters[dwNewAdapter]; pAdapter->dwCurrentDevice = dwNewDevice; pAdapter->devices[dwNewDevice].dwCurrentMode = dwNewMode; pAdapter->devices[dwNewDevice].bWindowed = bNewWindowed; pAdapter->devices[dwNewDevice].MultiSampleTypeWindowed = NewMultiSampleTypeWindowed; pAdapter->devices[dwNewDevice].MultiSampleTypeFullscreen = NewMultiSampleTypeFullscreen; EndDialog( hDlg, IDOK ); } else EndDialog( hDlg, IDCANCEL ); return TRUE; } else if( IDCANCEL == LOWORD(wParam) ) { // Handle the case when the user hits the Cancel button EndDialog( hDlg, IDCANCEL ); return TRUE; } else if( CBN_SELENDOK == HIWORD(wParam) ) { if( LOWORD(wParam) == IDC_ADAPTER_COMBO ) { dwNewAdapter = ComboBox_GetCurSel( hwndAdapterList ); pAdapter = &pd3dApp->m_Adapters[dwNewAdapter]; dwNewDevice = pAdapter->dwCurrentDevice; dwNewMode = pAdapter->devices[dwNewDevice].dwCurrentMode; bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed; } else if( LOWORD(wParam) == IDC_DEVICE_COMBO ) { pAdapter = &pd3dApp->m_Adapters[dwNewAdapter]; dwNewDevice = ComboBox_GetCurSel( hwndDeviceList ); dwNewMode = pAdapter->devices[dwNewDevice].dwCurrentMode; bNewWindowed = pAdapter->devices[dwNewDevice].bWindowed; } else if( LOWORD(wParam) == IDC_FULLSCREENMODES_COMBO ) { dwNewMode = ComboBox_GetCurSel( hwndFullscreenModeList ); } else if( LOWORD(wParam) == IDC_MULTISAMPLE_COMBO ) { DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList ); if( bNewWindowed ) NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem ); else NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem ); } } // Keep the UI current bUpdateDlgControls = TRUE; } // Update the dialog controls if( bUpdateDlgControls ) { // Reset the content in each of the combo boxes ComboBox_ResetContent( hwndAdapterList ); ComboBox_ResetContent( hwndDeviceList ); ComboBox_ResetContent( hwndFullscreenModeList ); ComboBox_ResetContent( hwndMultiSampleList ); pAdapter = &pd3dApp->m_Adapters[dwNewAdapter]; pDevice = &pAdapter->devices[dwNewDevice]; // Add a list of adapters to the adapter combo box for( DWORD a=0; a < pd3dApp->m_dwNumAdapters; a++ ) { // Add device name to the combo box DWORD dwItem = ComboBox_AddString( hwndAdapterList, pd3dApp->m_Adapters[a].d3dAdapterIdentifier.Description ); // Set the item data to identify this adapter ComboBox_SetItemData( hwndAdapterList, dwItem, a ); // Set the combobox selection on the current adapater if( a == dwNewAdapter ) ComboBox_SetCurSel( hwndAdapterList, dwItem ); } // Add a list of devices to the device combo box for( DWORD d=0; d < pAdapter->dwNumDevices; d++ ) { // Add device name to the combo box DWORD dwItem = ComboBox_AddString( hwndDeviceList, pAdapter->devices[d].strDesc ); // Set the item data to identify this device ComboBox_SetItemData( hwndDeviceList, dwItem, d ); // Set the combobox selection on the current device if( d == dwNewDevice ) ComboBox_SetCurSel( hwndDeviceList, dwItem ); } // Add a list of modes to the mode combo box for( DWORD m=0; m < pDevice->dwNumModes; m++ ) { DWORD BitDepth = 16; if( pDevice->modes[m].Format == D3DFMT_X8R8G8B8 || pDevice->modes[m].Format == D3DFMT_A8R8G8B8 || pDevice->modes[m].Format == D3DFMT_R8G8B8 ) { BitDepth = 32; } // Add mode desc to the combo box TCHAR strMode[80]; _stprintf( strMode, _T("%ld x %ld x %ld"), pDevice->modes[m].Width, pDevice->modes[m].Height, BitDepth ); DWORD dwItem = ComboBox_AddString( hwndFullscreenModeList, strMode ); // Set the item data to identify this mode ComboBox_SetItemData( hwndFullscreenModeList, dwItem, m ); // Set the combobox selection on the current mode if( m == dwNewMode ) ComboBox_SetCurSel( hwndFullscreenModeList, dwItem ); } // Add a list of multisample modes to the multisample combo box for( m=0; m <= 16; m++ ) { TCHAR strDesc[50]; D3DFORMAT fmt; if( bNewWindowed ) fmt = pd3dApp->m_Adapters[dwNewAdapter].d3ddmDesktop.Format; else fmt = pDevice->modes[dwNewMode].Format; if ( m == 1 ) // 1 is not a valid multisample type continue; if( SUCCEEDED( pd3dApp->m_pD3D->CheckDeviceMultiSampleType( dwNewAdapter, pDevice->DeviceType, fmt, bNewWindowed, (D3DMULTISAMPLE_TYPE)m ) ) ) { if( m == 0 ) lstrcpy( strDesc, _T("none") ); else wsprintf( strDesc, _T("%d samples"), m ); // Add device name to the combo box DWORD dwItem = ComboBox_AddString( hwndMultiSampleList, strDesc ); // Set the item data to identify this multisample type ComboBox_SetItemData( hwndMultiSampleList, dwItem, m ); // Set the combobox selection on the current multisample type if( bNewWindowed ) { if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeWindowed || m == 0 ) ComboBox_SetCurSel( hwndMultiSampleList, dwItem ); } else { if( (D3DMULTISAMPLE_TYPE)m == NewMultiSampleTypeFullscreen || m == 0 ) ComboBox_SetCurSel( hwndMultiSampleList, dwItem ); } } } DWORD dwItem = ComboBox_GetCurSel( hwndMultiSampleList ); if( bNewWindowed ) NewMultiSampleTypeWindowed = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem ); else NewMultiSampleTypeFullscreen = (D3DMULTISAMPLE_TYPE)ComboBox_GetItemData( hwndMultiSampleList, dwItem ); EnableWindow( hwndMultiSampleList, ComboBox_GetCount( hwndMultiSampleList ) > 1); EnableWindow( hwndWindowedRadio, pDevice->bCanDoWindowed ); if( bNewWindowed ) { Button_SetCheck( hwndWindowedRadio, TRUE ); Button_SetCheck( hwndFullscreenRadio, FALSE ); EnableWindow( hwndFullscreenModeList, FALSE ); } else { Button_SetCheck( hwndWindowedRadio, FALSE ); Button_SetCheck( hwndFullscreenRadio, TRUE ); EnableWindow( hwndFullscreenModeList, TRUE ); } return TRUE; } return FALSE; } //----------------------------------------------------------------------------- // Name: Run() // Desc: //----------------------------------------------------------------------------- INT CD3DApplication::Run() { // 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( &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 ); else bGotMsg = GetMessage( &msg, NULL, 0U, 0U ); if( bGotMsg ) { // Translate and dispatch the message if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } else { // Render a frame during idle time (no messages are waiting) if( m_bActive && m_bReady ) { if( FAILED( Render3DEnvironment() ) ) SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); } } } return (INT)msg.wParam; } //----------------------------------------------------------------------------- // Name: Render3DEnvironment() // Desc: Draws the scene. //----------------------------------------------------------------------------- HRESULT CD3DApplication::Render3DEnvironment() { HRESULT hr; // 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 resized. 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_Adapters[m_dwAdapter]; m_pD3D->GetAdapterDisplayMode( m_dwAdapter, &pAdapterInfo->d3ddmDesktop ); m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format; } if( FAILED( hr = Resize3DEnvironment() ) ) return hr; } return hr; } // 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; } // Render the scene as normal if( FAILED( hr = Render() ) ) return hr; // Keep track of the frame count { static FLOAT fLastTime = 0.0f; static DWORD dwFrames = 0L; 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 = 0L; // Get adapter's current mode so we can report // bit depth (back buffer depth may be unknown) D3DDISPLAYMODE mode; m_pD3D->GetAdapterDisplayMode(m_dwAdapter, &mode); _stprintf( m_strFrameStats, _T("%.02f fps (%dx%dx%d)"), m_fFPS, m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, mode.Format==D3DFMT_X8R8G8B8?32:16 ); D3DAdapterInfo* pAdapterInfo = &m_Adapters[m_dwAdapter]; D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice]; D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode]; if( m_bUseDepthBuffer ) { switch( pModeInfo->DepthStencilFormat ) { case D3DFMT_D16: lstrcat( m_strFrameStats, _T(" (D16)") ); break; case D3DFMT_D15S1: lstrcat( m_strFrameStats, _T(" (D15S1)") ); break; case D3DFMT_D24X8: lstrcat( m_strFrameStats, _T(" (D24X8)") ); break; case D3DFMT_D24S8: lstrcat( m_strFrameStats, _T(" (D24S8)") ); break; case D3DFMT_D24X4S4: lstrcat( m_strFrameStats, _T(" (D24X4S4)") ); break; case D3DFMT_D32: lstrcat( m_strFrameStats, _T(" (D32)") ); break; } } D3DMULTISAMPLE_TYPE MultiSampleType; if( m_bWindowed ) MultiSampleType = pDeviceInfo->MultiSampleTypeWindowed; else MultiSampleType = pDeviceInfo->MultiSampleTypeFullscreen; switch( MultiSampleType ) { case D3DMULTISAMPLE_2_SAMPLES: lstrcat( m_strFrameStats, _T(" (2x Multisample)") ); break; case D3DMULTISAMPLE_3_SAMPLES: lstrcat( m_strFrameStats, _T(" (3x Multisample)") ); break; case D3DMULTISAMPLE_4_SAMPLES: lstrcat( m_strFrameStats, _T(" (4x Multisample)") ); break; case D3DMULTISAMPLE_5_SAMPLES: lstrcat( m_strFrameStats, _T(" (5x Multisample)") ); break; case D3DMULTISAMPLE_6_SAMPLES: lstrcat( m_strFrameStats, _T(" (6x Multisample)") ); break; case D3DMULTISAMPLE_7_SAMPLES: lstrcat( m_strFrameStats, _T(" (7x Multisample)") ); break; case D3DMULTISAMPLE_8_SAMPLES: lstrcat( m_strFrameStats, _T(" (8x Multisample)") ); break; case D3DMULTISAMPLE_9_SAMPLES: lstrcat( m_strFrameStats, _T(" (9x Multisample)") ); break; case D3DMULTISAMPLE_10_SAMPLES: lstrcat( m_strFrameStats, _T(" (10x Multisample)") ); break; case D3DMULTISAMPLE_11_SAMPLES: lstrcat( m_strFrameStats, _T(" (11x Multisample)") ); break; case D3DMULTISAMPLE_12_SAMPLES: lstrcat( m_strFrameStats, _T(" (12x Multisample)") ); break; case D3DMULTISAMPLE_13_SAMPLES: lstrcat( m_strFrameStats, _T(" (13x Multisample)") ); break; case D3DMULTISAMPLE_14_SAMPLES: lstrcat( m_strFrameStats, _T(" (14x Multisample)") ); break; case D3DMULTISAMPLE_15_SAMPLES: lstrcat( m_strFrameStats, _T(" (15x Multisample)") ); break; case D3DMULTISAMPLE_16_SAMPLES: lstrcat( m_strFrameStats, _T(" (16x Multisample)") ); break; } } } // Show the frame on the primary surface. m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); return S_OK; } //----------------------------------------------------------------------------- // Name: Pause() // Desc: Called in to toggle the pause state of the app. //----------------------------------------------------------------------------- VOID CD3DApplication::Pause( BOOL bPause ) { static DWORD dwAppPausedCount = 0L; dwAppPausedCount += ( bPause ? +1 : -1 ); m_bReady = ( 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() { m_bActive = FALSE; m_bReady = FALSE; if( m_pd3dDevice ) { InvalidateDeviceObjects(); DeleteDeviceObjects(); m_pd3dDevice->Release(); m_pD3D->Release(); m_pd3dDevice = NULL; m_pD3D = NULL; } FinalCleanup(); } //----------------------------------------------------------------------------- // Name: DisplayErrorMsg() // Desc: Displays error messages in a message box //----------------------------------------------------------------------------- HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType ) { TCHAR strMsg[512]; switch( hr ) { case D3DAPPERR_NODIRECT3D: _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n") _T("want to check that the latest version of\n") _T("DirectX is correctly installed on your\n") _T("system. Also make sure that this program\n") _T("was compiled with header files that match\n") _T("the installed DirectX DLLs.") ); break; case D3DAPPERR_NOCOMPATIBLEDEVICES: _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n") _T("devices.") ); break; case D3DAPPERR_NOWINDOWABLEDEVICES: _tcscpy( strMsg, _T("This sample 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 re-run this\n") _T("sample.") ); break; case D3DAPPERR_NOHARDWAREDEVICE: _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n") _T("were found.") ); break; case D3DAPPERR_HALNOTCOMPATIBLE: _tcscpy( strMsg, _T("This sample requires functionality that is\n") _T("not available on your Direct3D hardware\n") _T("accelerator.") ); break; case D3DAPPERR_NOWINDOWEDHAL: _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n") _T("render into a window.\n") _T("Press F2 while the app is running to see a\n") _T("list of available devices and modes.") ); break; case D3DAPPERR_NODESKTOPHAL: _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n") _T("render into a window with the current\n") _T("desktop display settings.\n") _T("Press F2 while the app is running to see a\n") _T("list of available devices and modes.") ); break; case D3DAPPERR_NOHALTHISMODE: _tcscpy( strMsg, _T("This sample requires functionality that is\n") _T("not available on your Direct3D hardware\n") _T("accelerator with the current desktop display\n") _T("settings.\n") _T("Press F2 while the app is running to see a\n") _T("list of available devices and modes.") ); break; case D3DAPPERR_MEDIANOTFOUND: _tcscpy( strMsg, _T("Could not load required media." ) ); break; case D3DAPPERR_RESIZEFAILED: _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) ); break; case D3DAPPERR_NONZEROREFCOUNT: _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n") _T("count (meaning things were not properly\n") _T("cleaned up).") ); break; case D3DAPPERR_NULLREFDEVICE: _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n") _T("The reference rendering device was selected, but your\n") _T("computer only has a reduced-functionality reference device\n") _T("installed. Install the DirectX SDK to get the full\n") _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; default: _tcscpy( strMsg, _T("Generic application error. Enable\n") _T("debug output for detailed information.") ); } if( MSGERR_APPMUSTEXIT == dwType ) { _tcscat( strMsg, _T("\n\nThis 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("\n\nSwitching to the reference rasterizer,\n") _T("a software device that implements the entire\n") _T("Direct3D feature set, but runs very slowly.") ); MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK ); } return hr; }