📄 d3dapplication.cpp
字号:
displayErrorMsg( RESETFAILED, APPMUSTEXIT );
return E_FAIL;
}
}
bool dlgok = justShowSettingsDialog();
if( !dlgok )
return S_OK;
// 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 = RESETFAILED;
if( !mWindowed ) {
// Restore window type to windowed mode
mWindowed = !mWindowed;
mSettings.mMode = mWindowed ? (CD3DSettings::WINDOWED) : (CD3DSettings::FULLSCREEN);
adjustWindowForChange();
SetWindowPos( mHWnd, HWND_NOTOPMOST,
mWindowBounds.left, mWindowBounds.top,
( mWindowBounds.right - mWindowBounds.left ),
( mWindowBounds.bottom - mWindowBounds.top ),
SWP_SHOWWINDOW );
}
return displayErrorMsg( hr, APPMUSTEXIT );
}
// If the app is paused, trigger the rendering of the current frame
if( false == mFrameMoving ) {
mSingleStep = true;
dingus::timer( TIMER_START );
dingus::timer( TIMER_STOP );
}
return S_OK;
}
bool CD3DApplication::justShowSettingsDialog()
{
CD3DSettingsDialog settingsDialog( mEnumeration, mSettings );
if( settingsDialog.showDialog( mHInstance, mHWnd, *this ) != IDOK )
return false;
settingsDialog.getFinalSettings( mSettings );
mWindowed = (mSettings.mMode == CD3DSettings::WINDOWED);
return true;
}
int CD3DApplication::run()
{
// First manage screensaver running modes
if( mSSMode == SM_CONFIG || mSSMode == SM_PASSCHANGE )
return 0; // done already
//
// some stuff for screensavers
// Figure out if we're on Win9x
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx( &osvi );
mSSIsWin9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
// If we're in full mode, and on 9x, then need to load the password DLL
if( mSSMode == SM_FULL && mSSIsWin9x ) {
// Only do this if the password is set - check registry:
HKEY hKey;
if( RegCreateKeyEx( HKEY_CURRENT_USER, REGSTR_PATH_SCREENSAVE, 0, NULL, 0, KEY_READ, NULL, &hKey, NULL ) == ERROR_SUCCESS ) {
DWORD dwVal;
DWORD dwSize = sizeof(dwVal);
if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL,
(BYTE*)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal )
{
mSSPasswordDLL = LoadLibrary( TEXT("PASSWORD.CPL") );
if( mSSPasswordDLL )
mSSVerifyPasswordProc = (SSVERIFYPASSWORDPROC)GetProcAddress( mSSPasswordDLL, "VerifyScreenSavePwd" );
RegCloseKey( hKey );
}
}
}
// Flag as screensaver running if in full on mode
if( mSSMode == SM_FULL ) {
bool bUnused;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 );
}
//
// message pump
// Load keyboard accelerators
HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
// Now we're ready to recieve and process Windows messages.
bool gotMsg;
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( mActive )
gotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
else
gotMsg = ( GetMessage( &msg, NULL, 0U, 0U ) != 0 );
if( gotMsg ) {
// Translate and dispatch the message
if( hAccel == NULL || mHWnd == NULL || 0 == TranslateAccelerator( mHWnd, hAccel, &msg ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
} else {
if( mDeviceLost ) {
// Yield some CPU time to other processes
Sleep( 100 ); // 100 milliseconds
}
// render a frame during idle time (no messages are waiting)
if( mActive ) {
// some sleep if in screensaver mode
if( mSSMode == SM_FULL || mSSMode == SM_PREVIEW )
Sleep( 2 );
if( FAILED( render3DEnvironment() ) )
SendMessage( mHWnd, WM_CLOSE, 0, 0 );
}
}
}
if( hAccel != NULL )
DestroyAcceleratorTable( hAccel );
return (INT)msg.wParam;
}
/** Draws the scene. */
HRESULT CD3DApplication::render3DEnvironment()
{
HRESULT hr;
if( mDeviceLost ) {
// Test the cooperative level to see if it's okay to render
if( FAILED( hr = mD3DDevice->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( mWindowed ) {
const SD3DAdapterInfo& adInfo = mSettings.getAdapterInfo();
mD3D->GetAdapterDisplayMode( adInfo.adapterOrdinal, &mSettings.getDisplayMode() );
mPresentParams.BackBufferFormat = mSettings.getDisplayMode().Format;
}
if( FAILED( hr = reset3DEnvironment() ) )
return hr;
}
return hr;
}
mDeviceLost = false;
}
// Timer
// For debugging - so we get reproducable behaviour
if( mDebugTimer ) {
mElapsedTime = 1.0f / 60.0f; // emulate 60FPS
mTime += mElapsedTime;
} else {
double appTime = dingus::timer( TIMER_GETAPPTIME );
double elapsedTime = dingus::timer( TIMER_GETELAPSEDTIME );
mTime = appTime;
mElapsedTime = elapsedTime;
}
// perform
if( FAILED( hr = performOneTime() ) )
return hr;
mSingleStep = false;
updateStats();
// Show the frame on the primary surface.
hr = mD3DDevice->Present( NULL, NULL, NULL, NULL );
if( D3DERR_DEVICELOST == hr )
mDeviceLost = true;
return S_OK;
}
void CD3DApplication::updateStats()
{
// Keep track of the frame count
static double lastTime = 0.0f;
static int frameCount = 0;
double time = dingus::timer( TIMER_GETABSOLUTETIME );
++frameCount;
// Update the scene stats once per second
if( time - lastTime > 1.0 ) {
mFPS = (float)(frameCount / (time - lastTime));
lastTime = time;
frameCount = 0;
TCHAR strFmt[100];
D3DFORMAT fmtAdapter = mSettings.getDisplayMode().Format;
if( fmtAdapter == mBackBuffer.Format ) {
lstrcpyn( strFmt, dingus::convertD3DFormatToString( fmtAdapter ), 100 );
} else {
_sntprintf( strFmt, 100, TEXT("backbuf %s, adapter %s"),
dingus::convertD3DFormatToString( mBackBuffer.Format ),
dingus::convertD3DFormatToString( fmtAdapter ) );
}
strFmt[99] = TEXT('\0');
TCHAR strDepthFmt[100];
if( mEnumeration.mUsesDepthBuffer ) {
_sntprintf( strDepthFmt, 100, TEXT(" (%s)"),
dingus::convertD3DFormatToString( mSettings.getDepthStencilFormat() ) );
strDepthFmt[99] = TEXT('\0');
} else {
// No depth buffer
strDepthFmt[0] = TEXT('\0');
}
TCHAR* pstrMultiSample;
switch( mSettings.getMultiSampleType() ) {
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(mFrameStats) / sizeof(TCHAR);
_sntprintf( mFrameStats, cchMaxFrameStats, _T("%.02f fps (%dx%d), %s%s%s"), mFPS,
mBackBuffer.Width, mBackBuffer.Height,
strFmt, strDepthFmt, pstrMultiSample );
mFrameStats[cchMaxFrameStats - 1] = TEXT('\0');
}
}
/** Called in to toggle the pause state of the app. */
void CD3DApplication::pause( bool pause )
{
static DWORD pausedCount = 0;
pausedCount += (pause ? +1 : -1);
mActive = (pausedCount ? false : true);
// Handle the first pause request (of many, nestable pause requests)
if( pause && ( 1 == pausedCount ) ) {
// Stop the scene from animating
if( mFrameMoving )
dingus::timer( TIMER_STOP );
}
if( 0 == pausedCount ) {
// Restart the timers
if( mFrameMoving )
dingus::timer( TIMER_START );
}
}
/** Cleanup scene objects. */
void CD3DApplication::cleanup3DEnvironment()
{
if( mD3DDevice != NULL ) {
if( mDeviceObjectsRestored ) {
mDeviceObjectsRestored = false;
passivateDeviceObjects();
}
if( mDeviceObjectsInited ) {
mDeviceObjectsInited = false;
deleteDeviceObjects();
}
if( mD3DDevice->Release() > 0 )
displayErrorMsg( NONZEROREFCOUNT, APPMUSTEXIT );
mD3DDevice = NULL;
}
}
void CD3DApplication::ssChangePassword()
{
// Load the password change DLL
HINSTANCE mpr = LoadLibrary( TEXT("MPR.DLL") );
if( mpr != NULL ) {
// Grab the password change function from it
typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID );
PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" );
// Do the password change
if ( pwd != NULL )
pwd( "SCRSAVE", mSSHwndParent, 0, NULL );
// Free the library
FreeLibrary( mpr );
}
}
/** Displays error messages in a message box. */
HRESULT CD3DApplication::displayErrorMsg( HRESULT hr, eAppMsg type )
{
static bool fatalErrorReported = 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( fatalErrorReported )
return hr;
switch( hr ) {
case CANTTOGGLEFULLSCREEN:
_tcscpy( strMsg,
_T("Could not toggle fullscreen mode.\n")
_T("Your Direct3D device or desktop settings\n")
_T("might not support required video mode.\n")
_T("Try increasing desktop bit depth.\n") );
break;
case 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 NOCOMPATIBLEDEVICES:
_tcscpy( strMsg,
_T("Could not find any compatible Direct3D\n")
_T("devices.") );
break;
case NOWINDOWABLEDEVICES:
_tcscpy( strMsg,
_T("This program 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("program.") );
break;
case NOHARDWAREDEVICE:
_tcscpy( strMsg,
_T("No hardware-accelerated Direct3D devices\n")
_T("were found.") );
break;
case HALNOTCOMPATIBLE:
_tcscpy( strMsg,
_T("This program requires functionality that is\n")
_T("not available on your Direct3D hardware\n")
_T("accelerator.") );
break;
case 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 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 NOHALTHISMODE:
_tcscpy( strMsg,
_T("This program 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 MEDIANOTFOUND:
case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
_tcscpy( strMsg, _T("Could not load required media." ) );
break;
case RESETFAILED:
_tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
break;
case 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 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( APPMUSTEXIT == type ) {
fatalErrorReported = true;
_tcscat( strMsg, _T("\n\nThis program will now exit.") );
MessageBox( NULL, strMsg, mWindowTitle, MB_ICONERROR|MB_OK );
// Close the window, which shuts down the app
if( mHWnd )
SendMessage( mHWnd, WM_CLOSE, 0, 0 );
} else {
if( SWITCHEDTOREF == type )
_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, mWindowTitle, MB_ICONWARNING|MB_OK );
}
return hr;
}
// --------------------------------------------------------------------------
static INT_PTR CALLBACK gScreenSettingsDlgProcStub( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
// TBD
//return gD3DApp->ssScreenSettingsDlgProc( hwnd, msg, wParam, lParam );
}
void CD3DApplication::ssScreenSettingsDlg( HWND hwndParent )
{
// TBD
//LPCTSTR pstrTemplate = MAKEINTRESOURCE( IDD_SINGLEMONITORSETTINGS );
//DialogBox(mInstance, pstrTemplate, hwndParent, screenSettingsDlgProcStub );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -