www.pudn.com > promptshaderey.zip > D3DApplication.cpp


// -------------------------------------------------------------------------- 
// Dingus project - a collection of subsystems for game/graphics applications 
// -------------------------------------------------------------------------- 
#include "stdafx.h" 
 
#include  
#include "D3DApplication.h" 
#include "DXUtil.h" 
#include "D3DUtil.h" 
#include "resource.h" 
#include  
 
using namespace dingus; 
 
 
//--------------------------------------------------------------------------- 
// global access to the app (needed for the global gWndProc) 
 
static CD3DApplication* gD3DApp = NULL; 
 
//--------------------------------------------------------------------------- 
// Static msg handler which passes messages to the application class. 
 
LRESULT CALLBACK gWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
	return gD3DApp->msgProc( hWnd, uMsg, wParam, lParam ); 
} 
 
 
//--------------------------------------------------------------------------- 
// CD3DApplication 
//--------------------------------------------------------------------------- 
 
CD3DApplication::CD3DApplication() 
:	mD3D(NULL), mD3DDevice(NULL), 
	mHWnd(NULL), mHWndFocus(NULL), mHMenu(NULL), 
	mWindowed(true), mActive(false), mDeviceLost(false), 
	mMinimized(false), mMaximized(false), mIgnoreSizeChange(false), 
	mDeviceObjectsInited(false), mDeviceObjectsRestored(false), 
	mCreateFlags(0), 
	mFrameMoving(true), mSingleStep(false), 
	mTime(0.0), mElapsedTime(0.0), mFPS(0.0f), 
	mWindowTitle( _T("D3D9 Application")), 
	mCreationWidth(400), 
	mCreationHeight(300), 
	mShowCursorWhenFullscreen(false), mStartFullscreen(false), mVSyncFullscreen(true), 
	mSelectDeviceAtStartup(false), 
	mDebugTimer(false), 
 
	mSSInStartingPause(false), 
	mSSCheckingPassword(false), 
	mSSIsWin9x(false), 
	mSSMouseMoveCount(0), 
	mSSHwndParent(0), mSSPasswordDLL(0), mSSVerifyPasswordProc(0) 
{ 
	gD3DApp 		  = this; 
	 
	mDeviceStats[0] = _T('\0'); 
	mFrameStats[0]	= _T('\0'); 
	mSSRegistryPath[0] = _T('\0'); 
	 
	pause( true ); // pause until we're ready to render 
	 
	// When mClipCursorWhenFullscreen 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) 
	mClipCursorWhenFullscreen = false; 
#else 
	mClipCursorWhenFullscreen = true; 
#endif 
} 
 
 
 
/** 
 *  Static function used by D3DEnumeration 
 */ 
bool CD3DApplication::checkDeviceHelper( const D3DCAPS9& caps, eVertexProcessing vertexProc, D3DFORMAT backBufferFormat ) 
{ 
	DWORD behavior; 
	if( vertexProc == SOFTWARE_VP ) 
		behavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING; 
	else if( vertexProc == MIXED_VP ) 
		behavior = D3DCREATE_MIXED_VERTEXPROCESSING; 
	else if( vertexProc == HARDWARE_VP ) 
		behavior = D3DCREATE_HARDWARE_VERTEXPROCESSING; 
	else if( vertexProc == PURE_HARDWARE_VP ) 
		behavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE; 
	else 
		behavior = 0; // TODO: throw exception 
	 
	return SUCCEEDED( gD3DApp->checkDevice( caps, behavior, backBufferFormat ) ); 
} 
 
 
HRESULT CD3DApplication::create( HINSTANCE hInstance, bool screenSaverMode ) 
{ 
	HRESULT hr; 
 
	// if we're screensaver - set low priority and parse cmd line 
	if( screenSaverMode ) { 
		SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE ); 
		mSSMode = ssParseCmdLine( GetCommandLine() ); 
		// force windowed in preview mode 
		if( mSSMode == SM_PREVIEW ) 
			mStartFullscreen = false; 
	} else { 
		mSSMode = SM_NONE; 
		mSSHwndParent = NULL; 
	} 
	 
	mHInstance = hInstance; 
	 
	// 
	// setup d3d object, enumerate possible options, etc. 
 
	// create the Direct3D object 
	mD3D = Direct3DCreate9( D3D_SDK_VERSION ); 
	if( mD3D == NULL ) 
		return displayErrorMsg( (HRESULT)NODIRECT3D, APPMUSTEXIT ); 
	 
	// Build a list of Direct3D adapters, modes and devices. The 
	// checkDevice() callback is used to confirm that only devices that 
	// meet the app's requirements are considered. 
	mEnumeration.setDirect3D( *mD3D ); 
	mEnumeration.mConfirmDeviceCallback = checkDeviceHelper; 
 
	if( FAILED( hr = mEnumeration.enumerate() ) ) { 
		safeRelease( mD3D ); 
		return displayErrorMsg( hr, APPMUSTEXIT ); 
	} 
 
	if( FAILED( hr = chooseInitialD3DSettings() ) ) { 
		safeRelease( mD3D ); 
		return displayErrorMsg( hr, APPMUSTEXIT ); 
	} 
	 
	// 
	// manage screensaver running modes 
 
	switch( mSSMode ) { 
	case SM_CONFIG: 
		ssDoConfig(); 
		safeRelease( mD3D ); 
		return S_OK; 
		break; 
	case SM_PASSCHANGE: 
		ssChangePassword(); 
		safeRelease( mD3D ); 
		return S_OK; 
		break; 
	} 
 
	 
	// force no dialog at startup if we're screensaver 
	if( mSSMode != SM_NONE ) 
		mSelectDeviceAtStartup = false; 
 
	if( mSelectDeviceAtStartup ) { 
		bool ok = justShowSettingsDialog(); 
		if( !ok ) { 
			safeRelease( mD3D ); 
			if( mHWnd ) 
				SendMessage( mHWnd, WM_CLOSE, 0, 0 ); 
			return E_FAIL; 
		} 
	} 
 
	// 
	// create main window 
 
	// Unless a substitute hWnd has been specified, create a window to 
	// render into, OR 
	// do the needed thing if we're screensaver 
	if( mSSMode==SM_NONE && mHWnd == NULL || 
		(mSSMode==SM_PREVIEW || mSSMode==SM_TEST || mSSMode==SM_FULL) ) 
	{ 
		// Register the windows class 
		WNDCLASS wndClass = { 0, gWndProc, 0, 0, hInstance, 
			LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ), 
			LoadCursor( NULL, IDC_ARROW ), 
			(HBRUSH)GetStockObject(WHITE_BRUSH), 
			NULL, _T("D3D Window") 
		}; 
		// TBD - need this? 
		//if( screenSaverMode ) 
		//	wndClass.style = CS_VREDRAW | CS_HREDRAW; 
		RegisterClass( &wndClass ); 
		 
		// Set the window's initial style and size 
		RECT rc; 
		if( mSSMode==SM_PREVIEW ) { 
			GetClientRect( mSSHwndParent, &rc ); 
			mWindowStyle = WS_VISIBLE | WS_CHILD; 
			AdjustWindowRect( &rc, mWindowStyle, false ); 
			// create the render window 
			mHWnd = CreateWindow( _T("D3D Window"), mWindowTitle, mWindowStyle, 
				CW_USEDEFAULT, CW_USEDEFAULT, 
				(rc.right-rc.left), (rc.bottom-rc.top), mSSHwndParent, 
				NULL, hInstance, 0 ); 
		} else { 
			mWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |  
				WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE; 
			SetRect( &rc, 0, 0, mCreationWidth, mCreationHeight ); 
			AdjustWindowRect( &rc, mWindowStyle, true ); 
			// create the render window 
			mHWnd = CreateWindow( _T("D3D Window"), mWindowTitle, mWindowStyle, 
				CW_USEDEFAULT, CW_USEDEFAULT, 
				(rc.right-rc.left), (rc.bottom-rc.top), NULL, 
				LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ), 
				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( mHWndFocus == NULL ) 
		mHWndFocus = mHWnd; 
	 
	// Save window properties 
	mWindowStyle = GetWindowLong( mHWnd, GWL_STYLE ); 
	GetWindowRect( mHWnd, &mWindowBounds ); 
	GetClientRect( mHWnd, &mWindowClient ); 
 
	// In screensaver preview mode, "pause" (enter a limited message loop) 
	// briefly before proceeding, so the display control panel knows to 
	// update itself. 
	if( mSSMode == SM_PREVIEW ) { 
		mSSInStartingPause = true; 
		// Post a message to mark the end of the initial group of window messages 
		PostMessage( mHWnd, WM_USER, 0, 0 ); 
		MSG msg; 
		while( mSSInStartingPause ) { 
			if( !GetMessage( &msg, mHWnd, 0, 0 ) ) { 
				PostQuitMessage(0); 
				break; 
			} 
			TranslateMessage( &msg ); 
			DispatchMessage( &msg ); 
		} 
	} 
 
	// read SS settings 
	if( mSSMode != SM_NONE ) 
		ssReadSettings(); 
	 
	 
	// Initialize the application timer 
	dingus::timer( TIMER_START ); 
	 
	// Initialize the app 
	if( FAILED( hr = initialize() ) ) { 
		safeRelease( mD3D ); 
		return displayErrorMsg( hr, APPMUSTEXIT ); 
	} 
	 
	// Initialize the 3D environment for the app 
	if( FAILED( hr = initialize3DEnvironment() ) ) { 
		safeRelease( mD3D ); 
		return displayErrorMsg( hr, APPMUSTEXIT ); 
	} 
	 
	// The app is ready to go 
	pause( false ); 
	 
	return S_OK; 
} 
 
 
 
/** 
 *  Sets up mSettings with best available windowed mode, subject to the 
 *  requireHAL and requireREF constraints. Returns false if no such mode 
 *  can be found. 
 */ 
bool CD3DApplication::findBestWindowedMode( bool requireHAL, bool requireREF ) 
{ 
	// Get display mode of primary adapter (which is assumed to be where the 
	// window will appear) 
	D3DDISPLAYMODE primaryDesktopDM; 
	mD3D->GetAdapterDisplayMode( 0, &primaryDesktopDM ); 
	 
	const SD3DAdapterInfo* bestAdapterInfo = NULL; 
	const SD3DDeviceInfo* bestDeviceInfo = NULL; 
	const SD3DDeviceCombo* bestDeviceCombo = NULL; 
	 
	for( int iai = 0; iai < mEnumeration.mAdapterInfos.size(); ++iai ) { 
		const SD3DAdapterInfo* adInfo = mEnumeration.mAdapterInfos[iai]; 
		for( int idi = 0; idi < adInfo->deviceInfos.size(); ++idi ) { 
			const SD3DDeviceInfo* devInfo = adInfo->deviceInfos[idi]; 
			if( requireHAL && devInfo->deviceType != D3DDEVTYPE_HAL ) 
				continue; 
			if( requireREF && devInfo->deviceType != D3DDEVTYPE_REF ) 
				continue; 
			for( int idc = 0; idc < devInfo->deviceCombos.size(); ++idc ) { 
				const SD3DDeviceCombo* devCombo = devInfo->deviceCombos[idc]; 
				bool matchesBB = (devCombo->backBufferFormat == devCombo->adapterFormat); 
				if( !devCombo->isWindowed ) 
					continue; 
				if( devCombo->adapterFormat != primaryDesktopDM.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( !bestDeviceCombo ||  
					bestDeviceCombo->deviceType != D3DDEVTYPE_HAL && devCombo->deviceType == D3DDEVTYPE_HAL || 
					devCombo->deviceType == D3DDEVTYPE_HAL && matchesBB ) 
				{ 
					bestAdapterInfo = adInfo; 
					bestDeviceInfo = devInfo; 
					bestDeviceCombo = devCombo; 
					if( devCombo->deviceType == D3DDEVTYPE_HAL && matchesBB ) { 
						// This windowed device combo looks great -- take it 
						goto _endComboSearch; 
					} 
					// Otherwise keep looking for better combo 
				} 
			} 
		} 
	} 
 
_endComboSearch: 
	CD3DSettings::SSettings& settings = mSettings.mSettings[CD3DSettings::WINDOWED]; 
	if( bestDeviceCombo == NULL ) { 
		settings.adapterInfo = NULL; 
		settings.deviceInfo = NULL; 
		settings.deviceCombo = NULL; 
		return false; 
	} 
	 
	mSettings.mMode = CD3DSettings::WINDOWED; 
	settings.adapterInfo = bestAdapterInfo; 
	settings.deviceInfo = bestDeviceInfo; 
	settings.deviceCombo = bestDeviceCombo; 
	settings.displayMode = primaryDesktopDM; 
	mSettings.mWindowedWidth = mWindowClient.right - mWindowClient.left; 
	mSettings.mWindowedHeight = mWindowClient.bottom - mWindowClient.top; 
	if( mEnumeration.mUsesDepthBuffer ) 
		settings.depthStencilFormat = (D3DFORMAT)bestDeviceCombo->depthStencilFormats[0]; 
	settings.multisampleType = (D3DMULTISAMPLE_TYPE)bestDeviceCombo->multiSampleTypes[0]; 
	settings.multisampleQuality = 0; 
	settings.vertexProcessing = (eVertexProcessing)bestDeviceCombo->vertexProcessings[0]; 
	settings.presentInterval = bestDeviceCombo->presentIntervals[0]; 
	return true; 
} 
 
 
/** 
 *  Sets up mSettings with best available fullscreen mode, subject to the 
 *  requireHAL and requireREF constraints. Returns false if no such 
 *  mode can be found. 
 */ 
bool CD3DApplication::findBestFullscreenMode( bool requireHAL, bool requireREF ) 
{ 
	// 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 adapterDesktopDM; 
	D3DDISPLAYMODE bestAdapterDesktopDM; 
	D3DDISPLAYMODE bestDM; 
	bestAdapterDesktopDM.Width = 0; 
	bestAdapterDesktopDM.Height = 0; 
	bestAdapterDesktopDM.Format = D3DFMT_UNKNOWN; 
	bestAdapterDesktopDM.RefreshRate = 0; 
	 
	const SD3DAdapterInfo* bestAdapterInfo = NULL; 
	const SD3DDeviceInfo* bestDeviceInfo = NULL; 
	const SD3DDeviceCombo* bestDeviceCombo = NULL; 
	 
	for( int iai = 0; iai < mEnumeration.mAdapterInfos.size(); ++iai ) { 
		const SD3DAdapterInfo* adInfo = mEnumeration.mAdapterInfos[iai]; 
		mD3D->GetAdapterDisplayMode( adInfo->adapterOrdinal, &adapterDesktopDM ); 
		for( int idi = 0; idi < adInfo->deviceInfos.size(); ++idi ) { 
			const SD3DDeviceInfo* devInfo = adInfo->deviceInfos[idi]; 
			if( requireHAL && devInfo->deviceType != D3DDEVTYPE_HAL ) 
				continue; 
			if( requireREF && devInfo->deviceType != D3DDEVTYPE_REF ) 
				continue; 
			for( int idc = 0; idc < devInfo->deviceCombos.size(); ++idc ) { 
				const SD3DDeviceCombo* devCombo = devInfo->deviceCombos[idc]; 
				bool matchesBB = (devCombo->backBufferFormat == devCombo->adapterFormat); 
				bool matchesDesktop = (devCombo->adapterFormat == adapterDesktopDM.Format); 
				if( devCombo->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( !bestDeviceCombo || 
					bestDeviceCombo->deviceType != D3DDEVTYPE_HAL && devInfo->deviceType == D3DDEVTYPE_HAL || 
					devCombo->deviceType == D3DDEVTYPE_HAL && bestDeviceCombo->adapterFormat != adapterDesktopDM.Format && matchesDesktop || 
					devCombo->deviceType == D3DDEVTYPE_HAL && matchesDesktop && matchesBB ) 
				{ 
					bestAdapterDesktopDM = adapterDesktopDM; 
					bestAdapterInfo = adInfo; 
					bestDeviceInfo = devInfo; 
					bestDeviceCombo = devCombo; 
					if( devInfo->deviceType == D3DDEVTYPE_HAL && matchesDesktop && matchesBB ) 
					{ 
						// This fullscreen device combo looks great -- take it 
						goto _endComboSearch; 
					} 
					// Otherwise keep looking for a better combo 
				} 
			} 
		} 
	} 
_endComboSearch: 
	CD3DSettings::SSettings& settings = mSettings.mSettings[CD3DSettings::FULLSCREEN]; 
	if( bestDeviceCombo == NULL ) { 
		settings.adapterInfo = NULL; 
		settings.deviceInfo = NULL; 
		settings.deviceCombo = NULL; 
		return false; 
	} 
	 
	// Need to find a display mode on the best adapter that uses 
	// bestDeviceCombo->adapterFormat and is as close to bestAdapterDesktopDM's 
	// res as possible 
	bestDM.Width = 0; 
	bestDM.Height = 0; 
	bestDM.Format = D3DFMT_UNKNOWN; 
	bestDM.RefreshRate = 0; 
	for( int idm = 0; idm < bestAdapterInfo->displayModes.size(); ++idm ) { 
		const D3DDISPLAYMODE& pdm = bestAdapterInfo->displayModes[idm]; 
		if( pdm.Format != bestDeviceCombo->adapterFormat ) 
			continue; 
		if( pdm.Width == bestAdapterDesktopDM.Width && 
			pdm.Height == bestAdapterDesktopDM.Height &&  
			pdm.RefreshRate == bestAdapterDesktopDM.RefreshRate ) 
		{ 
			// found a perfect match, so stop 
			bestDM = pdm; 
			break; 
		} else if( pdm.Width == bestAdapterDesktopDM.Width && 
			pdm.Height == bestAdapterDesktopDM.Height &&  
			pdm.RefreshRate > bestDM.RefreshRate ) 
		{ 
			// refresh rate doesn't match, but width/height match, so keep this 
			// and keep looking 
			bestDM = pdm; 
		} else if( pdm.Width == bestAdapterDesktopDM.Width ) { 
			// width matches, so keep this and keep looking 
			bestDM = pdm; 
		} else if( bestDM.Width == 0 ) { 
			// we don't have anything better yet, so keep this and keep looking 
			bestDM = pdm; 
		} 
	} 
	 
	mSettings.mMode = CD3DSettings::FULLSCREEN; 
 
	settings.adapterInfo = bestAdapterInfo; 
	settings.deviceInfo = bestDeviceInfo; 
	settings.deviceCombo = bestDeviceCombo; 
	settings.displayMode = bestDM; 
	if( mEnumeration.mUsesDepthBuffer ) 
		settings.depthStencilFormat = (D3DFORMAT)bestDeviceCombo->depthStencilFormats[0]; 
	settings.multisampleType = (D3DMULTISAMPLE_TYPE)bestDeviceCombo->multiSampleTypes[0]; 
	settings.multisampleQuality = 0; 
	settings.vertexProcessing = (eVertexProcessing)bestDeviceCombo->vertexProcessings[0]; 
	settings.presentInterval = mVSyncFullscreen ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; 
 
	return true; 
} 
 
 
HRESULT CD3DApplication::chooseInitialD3DSettings() 
{ 
	bool foundFullscreen = findBestFullscreenMode( false, false ); 
	bool foundWindowed = findBestWindowedMode( false, false ); 
	 
	if( (mStartFullscreen || !foundWindowed || mSSMode==SM_FULL) && foundFullscreen ) 
		mSettings.mMode = CD3DSettings::FULLSCREEN; 
 
	if( !foundFullscreen && (!foundWindowed || mSSMode==SM_FULL) ) 
		return (HRESULT)NOCOMPATIBLEDEVICES; 
	 
	return S_OK; 
} 
 
void CD3DApplication::ssReadSettings() 
{ 
	// TBD 
	/* 
	TCHAR strKey[100]; 
	//DWORD monIdx; 
	SMonitorInfo* monInfo; 
	DWORD adapterIdx; 
	SD3DAdapterInfo* adapterInfo; 
	HKEY hkey; 
	DWORD type = REG_DWORD; 
	DWORD dwLength; 
	GUID guidAdapterID; 
	GUID guidZero; 
	ZeroMemory( &guidAdapterID, sizeof(GUID) ); 
	ZeroMemory( &guidZero, sizeof(GUID) ); 
	 
	dwLength = sizeof(DWORD); 
	for( monIdx = 0; monIdx < mMonitorCount; monIdx++ ) { 
		monInfo = &mMonitors[monIdx]; 
		adapterIdx = monInfo->adapterIdx; 
		if( adapterIdx == NO_ADAPTER ) 
			continue;  
		adapterInfo = mAdapters[adapterIdx]; 
		wsprintf( strKey, TEXT("Screen %d"), monIdx + 1 ); 
		if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,  
			0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) ) 
		{ 
			dwLength = sizeof(GUID); 
			RegQueryValueEx( hkey, TEXT("Adapter ID"), NULL, &type,  
				(BYTE*)&guidAdapterID, &dwLength); 
			 
			dwLength = sizeof(DWORD); 
			RegQueryValueEx( hkey, TEXT("Leave Black"), NULL, &type,  
				(BYTE*)&adapterInfo->leaveBlack, &dwLength); 
			 
			if( guidAdapterID == adapterInfo->adapterID.DeviceIdentifier || 
				guidAdapterID == guidZero ) 
			{ 
				dwLength = sizeof(DWORD); 
				RegQueryValueEx( hkey, TEXT("Disable Hardware"), NULL, &type,  
					(BYTE*)&adapterInfo->disableHAL, &dwLength); 
				dwLength = sizeof(DWORD); 
				RegQueryValueEx( hkey, TEXT("width"), NULL, &type,  
					(BYTE*)&adapterInfo->userPrefWidth, &dwLength); 
				dwLength = sizeof(DWORD); 
				RegQueryValueEx( hkey, TEXT("height"), NULL, &type,  
					(BYTE*)&adapterInfo->userPrefHeight, &dwLength); 
				dwLength = sizeof(DWORD); 
				RegQueryValueEx( hkey, TEXT("Format"), NULL, &type,  
					(BYTE*)&adapterInfo->userPrefFormat, &dwLength); 
			} 
			RegCloseKey( hkey); 
		} 
	} 
	*/ 
} 
 
//  Write the registry settings that affect how the screens are set up and used. 
void CD3DApplication::ssWriteSettings() 
{ 
	// TBD 
	/* 
	TCHAR strKey[100]; 
	//DWORD monIdx; 
	SMonitorInfo* monInfo; 
	DWORD adapterIdx; 
	SD3DAdapterInfo* adapterInfo; 
	HKEY hkey; 
	 
	for( monIdx = 0; monIdx < mMonitorCount; monIdx++ ) { 
		monInfo = &mMonitors[monIdx]; 
		adapterIdx = monInfo->adapterIdx; 
		if( adapterIdx == NO_ADAPTER ) 
			continue;  
		adapterInfo = mAdapters[adapterIdx]; 
		wsprintf( strKey, TEXT("Screen %d"), monIdx + 1 ); 
		if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,  
			0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) ) 
		{ 
			RegSetValueEx( hkey, TEXT("Leave Black"), NULL, REG_DWORD,  
				(BYTE*)&adapterInfo->leaveBlack, sizeof(DWORD) ); 
			RegSetValueEx( hkey, TEXT("Disable Hardware"), NULL, REG_DWORD,  
				(BYTE*)&adapterInfo->disableHAL, sizeof(DWORD) ); 
			RegSetValueEx( hkey, TEXT("width"), NULL, REG_DWORD,  
				(BYTE*)&adapterInfo->userPrefWidth, sizeof(DWORD) ); 
			RegSetValueEx( hkey, TEXT("height"), NULL, REG_DWORD,  
				(BYTE*)&adapterInfo->userPrefHeight, sizeof(DWORD) ); 
			RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD,  
				(BYTE*)&adapterInfo->userPrefFormat, sizeof(DWORD) ); 
			RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY,  
				(BYTE*)&adapterInfo->adapterID.DeviceIdentifier, sizeof(GUID) ); 
			RegCloseKey( hkey); 
		} 
	} 
	*/ 
} 
 
eSaverMode CD3DApplication::ssParseCmdLine(	TCHAR* cmdLine ) 
{ 
	mSSHwndParent = NULL; 
	 
	// Skip the first part of the command line, which is the full path  
	// to the exe.	If it contains spaces, it will be contained in quotes. 
	if( *cmdLine == TEXT('\"') ) { 
		cmdLine++; 
		while( *cmdLine != TEXT('\0') && *cmdLine != TEXT('\"') ) 
			cmdLine++; 
		if( *cmdLine == TEXT('\"') ) 
			cmdLine++; 
	} else { 
		while( *cmdLine != TEXT('\0') && *cmdLine != TEXT(' ') ) 
			cmdLine++; 
		if( *cmdLine == TEXT(' ') ) 
			cmdLine++; 
	} 
	 
	// Skip along to the first option delimiter "/" or "-" 
	while( *cmdLine != TEXT('\0') && *cmdLine != TEXT('/') && *cmdLine != TEXT('-') ) 
		cmdLine++; 
	 
	// If there wasn't one, then must be config mode 
	if( *cmdLine == TEXT('\0') ) 
		return SM_CONFIG; 
	 
	// Otherwise see what the option was 
	switch( *(++cmdLine) ) { 
	case 'c': 
	case 'C': 
		cmdLine++; 
		while ( *cmdLine && !isdigit(*cmdLine) ) 
			cmdLine++; 
		if( isdigit(*cmdLine) ) { 
#ifdef _WIN64 
			CHAR strCommandLine[2048]; 
			convertGenericStringToAnsiCb( strCommandLine, cmdLine, sizeof(strCommandLine) ); 
			mSSHwndParent = (HWND)(_atoi64(strCommandLine)); 
#else 
			mSSHwndParent = (HWND)LongToHandle(_ttol(cmdLine)); 
#endif 
		} else { 
			mSSHwndParent = NULL; 
		} 
		return SM_CONFIG; 
		 
	case 't': 
	case 'T': 
		return SM_TEST; 
		 
	case 'p': 
	case 'P': 
		// Preview-mode, so option is followed by the parent HWND in decimal 
		cmdLine++; 
		while( *cmdLine && !isdigit(*cmdLine) ) 
			cmdLine++; 
		if( isdigit(*cmdLine) ) { 
#ifdef _WIN64 
			CHAR strCommandLine[2048]; 
			convertGenericStringToAnsiCb(strCommandLine, cmdLine, sizeof(strCommandLine)); 
			mSSHwndParent = (HWND)(_atoi64(strCommandLine)); 
#else 
			mSSHwndParent = (HWND)LongToHandle(_ttol(cmdLine)); 
#endif 
		} 
		return SM_PREVIEW; 
		 
	case 'a': 
	case 'A': 
		// Password change mode, so option is followed by parent HWND in decimal 
		cmdLine++; 
		while( *cmdLine && !isdigit(*cmdLine) ) 
			cmdLine++; 
		if ( isdigit(*cmdLine) ) { 
#ifdef _WIN64 
			CHAR strCommandLine[2048]; 
			convertGenericStringToAnsiCb(strCommandLine, cmdLine, sizeof(strCommandLine)); 
			mSSHwndParent = (HWND)(_atoi64(strCommandLine)); 
#else 
			mSSHwndParent = (HWND)LongToHandle(_ttol(cmdLine)); 
#endif 
		} 
		return SM_PASSCHANGE; 
		 
	default: 
		// All other options => run the screensaver (typically this is "/s") 
		return SM_FULL; 
	} 
} 
 
// -------------------------------------------------------------------------- 
 
/** Message handling function. */ 
LRESULT CD3DApplication::msgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
	switch( uMsg ) { 
	case WM_USER: 
		// Screensaver: 
		if( mSSMode != SM_NONE ) { 
			// All initialization messages have gone through.  Allow 
			// 500ms of idle time, then proceed with initialization. 
			SetTimer( hWnd, 1, 500, NULL ); 
		} 
		break; 
	case WM_TIMER: 
		// Screensaver: 
		if( mSSMode != SM_NONE ) { 
			// Initial idle time is done, proceed with initialization. 
			mSSInStartingPause = false; 
			KillTimer( hWnd, 1 ); 
		} 
		break; 
 
	case WM_PAINT: 
		// TBD: saver? 
		 
		// handle paint messages when the app is paused 
		if( mD3DDevice && !mActive && mWindowed && mDeviceObjectsInited && mDeviceObjectsRestored ) { 
			performOneTime(); 
			mD3DDevice->Present( NULL, NULL, NULL, NULL ); 
		} 
		break; 
		 
	case WM_ERASEBKGND: 
		// Erase background if checking password 
		if( mSSMode != SM_NONE && !mSSCheckingPassword ) 
			return true; // don't erase this window 
		break; 
 
	case WM_GETMINMAXINFO: 
		((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; 
		((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; 
		break; 
		 
	case WM_ENTERSIZEMOVE: 
		// halt 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( mWindowed && mHWnd != NULL ) 
			mWindowStyle = GetWindowLong( mHWnd, GWL_STYLE ); 
		 
		if( SIZE_MINIMIZED == wParam ) { 
			if( mClipCursorWhenFullscreen && !mWindowed ) 
				ClipCursor( NULL ); 
			pause( true ); // pause while we're minimized 
			mMinimized = true; 
			mMaximized = false; 
		} else if( SIZE_MAXIMIZED == wParam ) { 
			if( mMinimized ) 
				pause( false ); // unpause since we're no longer minimized 
			mMinimized = false; 
			mMaximized = true; 
			handlePossibleSizeChange(); 
		} else if( SIZE_RESTORED == wParam ) { 
			if( mMaximized ) { 
				mMaximized = false; 
				handlePossibleSizeChange(); 
			} else if( mMinimized ) { 
				pause( false ); // unpause since we're no longer minimized 
				mMinimized = 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: 
		// screensaver 
		if( mSSMode	!= SM_NONE ) { 
			if( mSSMode == SM_FULL && !mSSCheckingPassword ) { 
				// Hide cursor 
				SetCursor( NULL ); 
				return true; 
			} 
		} else { 
			// turn off Windows cursor in fullscreen mode 
			if( mActive && !mWindowed ) { 
				SetCursor( NULL ); 
				if( mShowCursorWhenFullscreen ) 
					mD3DDevice->ShowCursor( true ); 
				return true; 
			} 
		} 
		break; 
		 
	case WM_MOUSEMOVE: 
		if( mSSMode != SM_NONE ) { 
			if( mSSMode != SM_TEST ) { 
				static INT xPrev = -1; 
				static INT yPrev = -1; 
				INT xCur = GET_X_LPARAM(lParam); 
				INT yCur = GET_Y_LPARAM(lParam); 
				if( xCur != xPrev || yCur != yPrev ) 
				{ 
					xPrev = xCur; 
					yPrev = yCur; 
					mSSMouseMoveCount++; 
					if( mSSMouseMoveCount > 5 ) 
						ssInterrupt(); 
				} 
			} 
		} else { 
			if( mActive && mD3DDevice != NULL ) { 
				POINT ptCursor; 
				GetCursorPos( &ptCursor ); 
				if( !mWindowed ) 
					ScreenToClient( mHWnd, &ptCursor ); 
				mD3DDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 ); 
			} 
		} 
		break; 
		 
	case WM_KEYDOWN: 
	case WM_LBUTTONDOWN: 
	case WM_RBUTTONDOWN: 
	case WM_MBUTTONDOWN: 
		if( mSSMode != SM_NONE && mSSMode != SM_TEST ) 
			ssInterrupt(); 
		break; 
 
	case WM_ACTIVATEAPP: 
		if( wParam == FALSE && mSSMode != SM_NONE && mSSMode != SM_TEST ) 
			ssInterrupt(); 
		break; 
 
	case WM_ENTERMENULOOP: 
		// pause the app when menus are displayed 
		pause( true ); 
		break; 
		 
	case WM_EXITMENULOOP: 
		pause( false ); 
		break; 
		 
	case WM_NCHITTEST: 
		// prevent the user from selecting the menu in fullscreen mode 
		if( !mWindowed ) 
			return HTCLIENT; 
		break; 
		 
	case WM_POWERBROADCAST: 
		if( mSSMode != SM_NONE ) { 
			if( wParam == PBT_APMSUSPEND && mSSVerifyPasswordProc == NULL ) 
				ssInterrupt(); 
		} else { 
			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: 
		switch( wParam ) { 
		case SC_NEXTWINDOW: 
		case SC_PREVWINDOW: 
		case SC_SCREENSAVE: 
		case SC_CLOSE: 
			if( mSSMode == SM_FULL ) 
				return FALSE; 
			break; 
		// prevent moving/sizing and power loss in fullscreen mode 
		case SC_MOVE: 
		case SC_SIZE: 
		case SC_MAXIMIZE: 
		case SC_KEYMENU: 
		case SC_MONITORPOWER: 
			if( false == mWindowed ) 
				return 1; 
			break; 
		} 
		break; 
		 
	case WM_COMMAND: 
		if( mSSMode == SM_NONE ) { 
			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( (HRESULT)RESETFAILED, 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: 
		{ 
			static boolean closing = false; 
			if( !closing ) { 
				closing = true; 
				close(); 
				HMENU hMenu = GetMenu(hWnd); 
				if( hMenu != NULL ) 
					DestroyMenu( hMenu ); 
				DestroyWindow( hWnd ); 
				PostQuitMessage(0); 
				mHWnd = NULL; 
			} 
		} 
		return 0; 
	case WM_DESTROY: 
		// TBD: need something? 
		//shutdownSaver(); 
		break; 
	} 
	 
	return DefWindowProc( hWnd, uMsg, wParam, lParam ); 
} 
 
//  A message was received (mouse move, keydown, etc.) that may mean 
//	the screen saver should show the password dialog and/or shut down. 
void CD3DApplication::ssInterrupt() 
{ 
	HRESULT hr; 
	bool passwordOK = false; 
	if( mSSMode == SM_TEST || mSSMode == SM_FULL && !mSSCheckingPassword ) { 
		if( mSSIsWin9x && mSSMode == SM_FULL ) { 
			// If no VerifyPassword function, then no password is set  
			// or we're not on 9x.  
			if( mSSVerifyPasswordProc != NULL ) { 
				// Shut down D3D device so we can show a Windows dialog 
				cleanup3DEnvironment(); 
				 
				// Make sure window covers the whole screen, 
				// even after deleting D3D device (which may have caused 
				// mode changes) 
				ShowWindow( mHWnd, SW_RESTORE ); 
				ShowWindow( mHWnd, SW_MAXIMIZE ); 
				 
				mSSCheckingPassword = true; 
				passwordOK = mSSVerifyPasswordProc( mHWnd ) ? true : false; 
				mSSCheckingPassword = false; 
				 
				if( passwordOK ) { 
					// all ok... 
				} else { 
					// Back to screen saving... 
					SetCursor( NULL ); 
					mSSMouseMoveCount = 0; 
					 
					// Recreate D3D device 
					hr = initialize3DEnvironment(); 
					return; 
				} 
			} 
		} 
		doClose(); 
	} 
} 
 
void CD3DApplication::close() 
{ 
	// Unflag screensaver running if in full on mode 
	if( mSSMode == SM_FULL ) { 
		BOOL bUnused; 
		SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 ); 
	} 
 
	cleanup3DEnvironment(); 
	safeRelease( mD3D ); 
	shutdown(); 
 
	// Unload the password DLL (if we loaded it) 
	if( mSSPasswordDLL != NULL ) { 
		FreeLibrary( mSSPasswordDLL ); 
		mSSPasswordDLL = NULL; 
	} 
} 
 
void CD3DApplication::doClose() 
{ 
	PostMessage( mHWnd, WM_CLOSE, 0, 0 ); 
} 
 
/** Reset the device if the client area size has changed. */ 
HRESULT CD3DApplication::handlePossibleSizeChange() 
{ 
	HRESULT hr = S_OK; 
	RECT clientOld; 
	clientOld = mWindowClient; 
	 
	if( mIgnoreSizeChange ) 
		return S_OK; 
	 
	// update window properties 
	GetWindowRect( mHWnd, &mWindowBounds ); 
	GetClientRect( mHWnd, &mWindowClient ); 
	 
	if( clientOld.right - clientOld.left != mWindowClient.right - mWindowClient.left || 
		clientOld.bottom - clientOld.top != mWindowClient.bottom - mWindowClient.top ) 
	{ 
		// A new window size will require a new backbuffer 
		// size, so the 3D structures must be changed accordingly. 
		pause( true ); 
		 
		mPresentParams.BackBufferWidth  = mWindowClient.right - mWindowClient.left; 
		mPresentParams.BackBufferHeight = mWindowClient.bottom - mWindowClient.top; 
		 
		if( mD3DDevice != NULL ) { 
			// Reset the 3D environment 
			if( FAILED( hr = reset3DEnvironment() ) ) { 
				if( hr != D3DERR_OUTOFVIDEOMEMORY ) 
					hr = (HRESULT)RESETFAILED; 
				displayErrorMsg( hr, APPMUSTEXIT ); 
			} 
		} 
		pause( false ); 
	} 
	return hr; 
} 
 
 
 
HRESULT CD3DApplication::initialize3DEnvironment() 
{ 
	HRESULT hr; 
 
	mSSMouseMoveCount = 0; 
	 
	const SD3DAdapterInfo& adInfo = mSettings.getAdapterInfo(); 
	const SD3DDeviceInfo& devInfo = mSettings.getDeviceInfo(); 
	 
	mWindowed = (mSettings.mMode == CD3DSettings::WINDOWED); 
	 
	// Prepare window for possible windowed/fullscreen change 
	adjustWindowForChange(); 
	 
	// Set up the presentation parameters 
	bool okparams = buildPresentParamsFromSettings(); 
	if( !okparams ) 
		return CANTTOGGLEFULLSCREEN; 
	 
	if( devInfo.caps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE ) { 
		// Warn user about null ref device that can't render anything 
		displayErrorMsg( (HRESULT)NULLREFDEVICE, NONE ); 
	} 
	 
	DWORD behaviorFlags; 
	if( mSettings.getVertexProcessing() == SOFTWARE_VP ) 
		behaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; 
	else if( mSettings.getVertexProcessing() == MIXED_VP ) 
		behaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING; 
	else if( mSettings.getVertexProcessing() == HARDWARE_VP ) 
		behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING; 
	else if( mSettings.getVertexProcessing() == PURE_HARDWARE_VP ) 
		behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE; 
	else 
		behaviorFlags = 0; // TODO: throw exception 
	 
	// Araz: 
	behaviorFlags |= D3DCREATE_FPU_PRESERVE; 
	behaviorFlags |= D3DCREATE_MULTITHREADED; 
	 
	// create the device 
	hr = mD3D->CreateDevice( 
		mSettings.getAdapterOrdinal(), devInfo.deviceType, 
		mHWndFocus, behaviorFlags, &mPresentParams, 
		&mD3DDevice ); 
	 
	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( mWindowed ) { 
			SetWindowPos( mHWnd, HWND_NOTOPMOST, 
				mWindowBounds.left, mWindowBounds.top, 
				( mWindowBounds.right - mWindowBounds.left ), 
				( mWindowBounds.bottom - mWindowBounds.top ), 
				SWP_SHOWWINDOW ); 
		} 
		 
		// Store device Caps 
		mD3DDevice->GetDeviceCaps( &mD3DCaps ); 
		mCreateFlags = behaviorFlags; 
		 
		// Store device description 
		if( devInfo.deviceType == D3DDEVTYPE_REF ) 
			lstrcpy( mDeviceStats, TEXT("REF") ); 
		else if( devInfo.deviceType == D3DDEVTYPE_HAL ) 
			lstrcpy( mDeviceStats, TEXT("HAL") ); 
		else if( devInfo.deviceType == D3DDEVTYPE_SW ) 
			lstrcpy( mDeviceStats, TEXT("SW") ); 
		 
		if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING && behaviorFlags & D3DCREATE_PUREDEVICE ) { 
			if( devInfo.deviceType == D3DDEVTYPE_HAL ) 
				lstrcat( mDeviceStats, TEXT(" (pure hw vp)") ); 
			else 
				lstrcat( mDeviceStats, TEXT(" (simulated pure hw vp)") ); 
		} else if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING ) { 
			if( devInfo.deviceType == D3DDEVTYPE_HAL ) 
				lstrcat( mDeviceStats, TEXT(" (hw vp)") ); 
			else 
				lstrcat( mDeviceStats, TEXT(" (simulated hw vp)") ); 
		} else if( behaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING ) { 
			if( devInfo.deviceType == D3DDEVTYPE_HAL ) 
				lstrcat( mDeviceStats, TEXT(" (mixed vp)") ); 
			else 
				lstrcat( mDeviceStats, TEXT(" (simulated mixed vp)") ); 
		} else if( behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING ) { 
			lstrcat( mDeviceStats, TEXT(" (sw vp)") ); 
		} 
		 
		if( devInfo.deviceType == D3DDEVTYPE_HAL ) { 
			// Be sure not to overflow mDeviceStats 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( mDeviceStats, TEXT(": ") ); 
			const int cchDesc = sizeof(adInfo.adapterID.Description); 
			TCHAR szDescription[cchDesc]; 
			dingus::convertAnsiStringToGenericCch( szDescription,  
				adInfo.adapterID.Description, cchDesc ); 
			int maxAppend = sizeof(mDeviceStats) / sizeof(TCHAR) - 
				lstrlen( mDeviceStats ) - 1; 
			_tcsncat( mDeviceStats, szDescription, maxAppend ); 
		} 
		 
		// Store render target surface desc 
		IDirect3DSurface9* backBuffer = NULL; 
		mD3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer ); 
		backBuffer->GetDesc( &mBackBuffer ); 
		backBuffer->Release(); 
		 
		// Set up the fullscreen cursor 
		if( mShowCursorWhenFullscreen && !mWindowed ) { 
			HCURSOR hCursor; 
#ifdef _WIN64 
			hCursor = (HCURSOR)GetClassLongPtr( mHWnd, GCLP_HCURSOR ); 
#else 
			hCursor = (HCURSOR)ULongToHandle( GetClassLong( mHWnd, GCL_HCURSOR ) ); 
#endif 
			dingus::setDeviceCursor( *mD3DDevice, hCursor ); 
			mD3DDevice->ShowCursor( true ); 
		} 
		 
		// Confine cursor to fullscreen window 
		if( mClipCursorWhenFullscreen ) { 
			if( !mWindowed ) { 
				RECT rcWindow; 
				GetWindowRect( mHWnd, &rcWindow ); 
				ClipCursor( &rcWindow ); 
			} else { 
				ClipCursor( NULL ); 
			} 
		} 
		 
		mSSMouseMoveCount = 0; // make sure all changes don't count as mouse moves 
 
		// Initialize the app's device-dependent objects 
		hr = createDeviceObjects(); 
		if( FAILED(hr) ) { 
			deleteDeviceObjects(); 
		} else { 
			mDeviceObjectsInited = true; 
			hr = activateDeviceObjects(); 
			if( FAILED(hr) ) { 
				passivateDeviceObjects(); 
			} else { 
				mDeviceObjectsRestored = true; 
				return S_OK; 
			} 
		} 
		 
		// Cleanup before we try again 
		cleanup3DEnvironment(); 
	} 
	 
	// If that failed, fall back to the reference rasterizer 
	if( hr != MEDIANOTFOUND &&  
		hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) &&  
		devInfo.deviceType == D3DDEVTYPE_HAL ) 
	{ 
		if( findBestWindowedMode( false, true ) ) { 
			mWindowed = true; 
			adjustWindowForChange(); 
			// Make sure main window isn't topmost, so error message is visible 
			SetWindowPos( mHWnd, HWND_NOTOPMOST, 
				mWindowBounds.left, mWindowBounds.top, 
				( mWindowBounds.right - mWindowBounds.left ), 
				( mWindowBounds.bottom - mWindowBounds.top ), 
				SWP_SHOWWINDOW ); 
			 
			// Let the user know we are switching from HAL to the reference rasterizer 
			displayErrorMsg( hr, SWITCHEDTOREF ); 
			 
			hr = initialize3DEnvironment(); 
			 
			mSSMouseMoveCount = 0; // make sure all changes don't count as mouse moves 
		} 
	} 
	return hr; 
} 
 
 
bool CD3DApplication::buildPresentParamsFromSettings() 
{ 
	if( &mSettings.getDeviceCombo() == NULL ) 
		return false; 
 
	mPresentParams.Windowed				= (mSettings.mMode == CD3DSettings::WINDOWED); 
	mPresentParams.BackBufferCount		= 1; 
	mPresentParams.MultiSampleType		= mSettings.getMultiSampleType(); 
	mPresentParams.MultiSampleQuality	= mSettings.getMultiSampleQuality(); 
	mPresentParams.SwapEffect			= D3DSWAPEFFECT_DISCARD; 
	mPresentParams.EnableAutoDepthStencil = mEnumeration.mUsesDepthBuffer; 
	mPresentParams.hDeviceWindow		= mHWnd; 
	if( mEnumeration.mUsesDepthBuffer ) { 
		//mPresentParams.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL; 
		mPresentParams.Flags = 0; 
		mPresentParams.AutoDepthStencilFormat = mSettings.getDepthStencilFormat(); 
	} else { 
		mPresentParams.Flags = 0; 
	} 
	 
	if( mWindowed ) { 
		mPresentParams.BackBufferWidth  = mWindowClient.right - mWindowClient.left; 
		mPresentParams.BackBufferHeight = mWindowClient.bottom - mWindowClient.top; 
		mPresentParams.BackBufferFormat = mSettings.getDeviceCombo().backBufferFormat; 
		mPresentParams.FullScreen_RefreshRateInHz = 0; 
		mPresentParams.PresentationInterval = mSettings.getPresentInterval(); 
	} else { 
		mPresentParams.BackBufferWidth  = mSettings.getDisplayMode().Width; 
		mPresentParams.BackBufferHeight = mSettings.getDisplayMode().Height; 
		mPresentParams.BackBufferFormat = mSettings.getDeviceCombo().backBufferFormat; 
		mPresentParams.FullScreen_RefreshRateInHz = mSettings.getDisplayMode().RefreshRate; 
		mPresentParams.PresentationInterval = mSettings.getPresentInterval(); 
	} 
	return true; 
} 
 
 
HRESULT CD3DApplication::reset3DEnvironment() 
{ 
	HRESULT hr; 
	 
	// Release all vidmem objects 
	if( mDeviceObjectsRestored ) { 
		mDeviceObjectsRestored = false; 
		passivateDeviceObjects(); 
	} 
	// Reset the device 
	if( FAILED( hr = mD3DDevice->Reset( &mPresentParams ) ) ) 
		return hr; 
	 
	// Store render target surface desc 
	IDirect3DSurface9* backBuffer; 
	mD3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer ); 
	backBuffer->GetDesc( &mBackBuffer ); 
	backBuffer->Release(); 
	 
	// Set up the fullscreen cursor 
	if( mShowCursorWhenFullscreen && !mWindowed ) { 
		HCURSOR hCursor; 
#ifdef _WIN64 
		hCursor = (HCURSOR)GetClassLongPtr( mHWnd, GCLP_HCURSOR ); 
#else 
		hCursor = (HCURSOR)ULongToHandle( GetClassLong( mHWnd, GCL_HCURSOR ) ); 
#endif 
		dingus::setDeviceCursor( *mD3DDevice, hCursor ); 
		mD3DDevice->ShowCursor( true ); 
	} 
	 
	// Confine cursor to fullscreen window 
	if( mClipCursorWhenFullscreen ) { 
		if( !mWindowed ) { 
			RECT rcWindow; 
			GetWindowRect( mHWnd, &rcWindow ); 
			ClipCursor( &rcWindow ); 
		} else { 
			ClipCursor( NULL ); 
		} 
	} 
	 
	// Initialize the app's device-dependent objects 
	hr = activateDeviceObjects(); 
	if( FAILED(hr) ) { 
		passivateDeviceObjects(); 
		return hr; 
	} 
	mDeviceObjectsRestored = true; 
	 
	// If the app is paused, trigger the rendering of the current frame 
	if( !mFrameMoving ) { 
		mSingleStep = true; 
		dingus::timer( TIMER_START ); 
		dingus::timer( TIMER_STOP ); 
	} 
	 
	return S_OK; 
} 
 
 
/** Called when user toggles between fullscreen mode and windowed mode. */ 
HRESULT CD3DApplication::toggleFullscreen() 
{ 
	HRESULT hr; 
	int adOrdinalOld = mSettings.getAdapterOrdinal(); 
	D3DDEVTYPE devTypeOld = mSettings.getDevType(); 
	 
	pause( true ); 
	mIgnoreSizeChange = true; 
	 
	// Toggle the windowed state 
	mWindowed = !mWindowed; 
	mSettings.mMode = (mSettings.mMode==CD3DSettings::WINDOWED) ? (CD3DSettings::FULLSCREEN) : (CD3DSettings::WINDOWED); 
	 
	// Prepare window for windowed/fullscreen change 
	adjustWindowForChange(); 
	 
	// If adapterOrdinal and deviceType are the same, we can just do a Reset(). 
	// If they've changed, we need to do a complete device teardown/rebuild. 
	if( mSettings.getAdapterOrdinal() == adOrdinalOld && mSettings.getDevType() == devTypeOld ) { 
		// Reset the 3D device 
		bool okparams = buildPresentParamsFromSettings(); 
		if( okparams ) 
			hr = reset3DEnvironment(); 
		else 
			hr = CANTTOGGLEFULLSCREEN; 
	} else { 
		cleanup3DEnvironment(); 
		hr = initialize3DEnvironment(); 
	} 
	 
	if( FAILED( hr ) ) { 
		if( hr != D3DERR_OUTOFVIDEOMEMORY ) 
			hr = RESETFAILED; 
		mIgnoreSizeChange = false; 
		if( !mWindowed ) { 
			// Restore window type to windowed mode 
			mWindowed = !mWindowed; 
			mSettings.mMode = CD3DSettings::WINDOWED; 
			adjustWindowForChange(); 
			SetWindowPos( mHWnd, HWND_NOTOPMOST, 
				mWindowBounds.left, mWindowBounds.top, 
				( mWindowBounds.right - mWindowBounds.left ), 
				( mWindowBounds.bottom - mWindowBounds.top ), 
				SWP_SHOWWINDOW ); 
		} 
		return displayErrorMsg( hr, APPMUSTEXIT ); 
	} 
	 
	mIgnoreSizeChange = 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( mWindowed ) { 
		SetWindowPos( mHWnd, HWND_NOTOPMOST, 
			mWindowBounds.left, mWindowBounds.top, 
			( mWindowBounds.right - mWindowBounds.left ), 
			( mWindowBounds.bottom - mWindowBounds.top ), 
			SWP_SHOWWINDOW ); 
	} 
	 
	pause( false ); 
	return S_OK; 
} 
 
 
/** Switch to a windowed mode, even if that means picking a new device and/or adapter. */ 
HRESULT CD3DApplication::forceWindowed() 
{ 
	HRESULT hr; 
	 
	if( mWindowed ) 
		return S_OK; 
	 
	if( !findBestWindowedMode( false, false ) ) 
		return E_FAIL; 
 
	mWindowed = 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, APPMUSTEXIT ); 
	 
	pause( false ); 
	return S_OK; 
} 
 
 
/** 
 *  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( mWindowed ) { 
		// Set windowed-mode style 
		SetWindowLong( mHWnd, GWL_STYLE, mWindowStyle ); 
		if( mHMenu != NULL ) { 
			SetMenu( mHWnd, mHMenu ); 
			mHMenu = NULL; 
		} 
	} else { 
		// Set fullscreen-mode style 
		SetWindowLong( mHWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE ); 
		if( mHMenu == NULL ) { 
			mHMenu = GetMenu( mHWnd ); 
			SetMenu( mHWnd, NULL ); 
		} 
	} 
	return S_OK; 
} 
 
 
/** 
 *  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( mWindowed == false ) { 
		if( FAILED( toggleFullscreen() ) ) { 
			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 ); 
}