📄 d3dapplication.cpp
字号:
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() ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -