mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
update fullscreen, alt-tab, error handling
This commit is contained in:
parent
13918eb201
commit
bfc5300e57
@ -306,6 +306,9 @@ init_dx( LPDIRECTDRAW7 context,
|
||||
_d3d = pD3D;
|
||||
_d3dDevice = pDevice;
|
||||
_view_rect = viewrect;
|
||||
|
||||
_last_testcooplevel_result = S_OK;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if(dx_show_fps_meter) {
|
||||
@ -567,8 +570,7 @@ clear(const RenderBuffer &buffer) {
|
||||
HRESULT hr = _d3dDevice->Clear(0, NULL, flags, clear_colr,
|
||||
(D3DVALUE) _depth_clear_value, (DWORD)_stencil_clear_value);
|
||||
if (hr != DD_OK)
|
||||
dxgsg_cat.error()
|
||||
<< "dxGSG::clear_buffer failed: Clear returned " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.error() << "clear_buffer failed: Clear returned " << ConvD3DErrorToString(hr) << endl;
|
||||
/* The following line will cause the background to always clear to a medium red
|
||||
_color_clear_value[0] = .5;
|
||||
/* The following lines will cause the background color to cycle from black to red.
|
||||
@ -653,15 +655,14 @@ prepare_display_region() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: set_clipper
|
||||
// Access:
|
||||
// Description: Useless in DX at the present time
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian::set_clipper(RECT cliprect) {
|
||||
#if 0
|
||||
|
||||
LPDIRECTDRAWCLIPPER Clipper;
|
||||
HRESULT result;
|
||||
|
||||
@ -699,8 +700,8 @@ void DXGraphicsStateGuardian::set_clipper(RECT cliprect) {
|
||||
}
|
||||
free(rgn_data);
|
||||
DeleteObject(hrgn);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian::render_frame
|
||||
@ -711,7 +712,8 @@ void DXGraphicsStateGuardian::set_clipper(RECT cliprect) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian::
|
||||
render_frame(const AllAttributesWrapper &initial_state) {
|
||||
if (!_dx_ready) return;
|
||||
if (!_dx_ready)
|
||||
return;
|
||||
|
||||
_win->begin_frame();
|
||||
_lighting_enabled_this_frame = false;
|
||||
@ -730,7 +732,20 @@ render_frame(const AllAttributesWrapper &initial_state) {
|
||||
set_state(state, false);
|
||||
#endif
|
||||
|
||||
_d3dDevice->BeginScene();
|
||||
HRESULT hr = _d3dDevice->BeginScene();
|
||||
|
||||
if(FAILED(hr)) {
|
||||
if((hr==DDERR_SURFACELOST)||(hr==DDERR_SURFACEBUSY)) {
|
||||
if(dxgsg_cat.is_debug())
|
||||
dxgsg_cat.debug() << "BeginScene returns " << ConvD3DErrorToString(hr) << endl;
|
||||
|
||||
CheckCooperativeLevel();
|
||||
} else {
|
||||
dxgsg_cat.error() << "BeginScene failed, unhandled error hr == " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* _d3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &matIdentity); */
|
||||
|
||||
@ -780,7 +795,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
|
||||
|
||||
// Now we're done with the frame processing. Clean up.
|
||||
|
||||
_d3dDevice->EndScene(); // FPS meter drawing MUST occur after EndScene, since it uses GDI
|
||||
hr = _d3dDevice->EndScene(); // FPS meter drawing MUST occur after EndScene, since it uses GDI
|
||||
|
||||
if (_lighting_enabled_this_frame) {
|
||||
// Let's turn off all the lights we had on, and clear the light
|
||||
@ -805,6 +820,19 @@ render_frame(const AllAttributesWrapper &initial_state) {
|
||||
// at all?
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
if((hr==DDERR_SURFACELOST)||(hr==DDERR_SURFACEBUSY)) {
|
||||
if(dxgsg_cat.is_debug())
|
||||
dxgsg_cat.debug() << "EndScene returns " << ConvD3DErrorToString(hr) << endl;
|
||||
|
||||
CheckCooperativeLevel();
|
||||
} else {
|
||||
dxgsg_cat.error() << "EndScene failed, unhandled error hr == " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(dx_show_fps_meter) {
|
||||
DO_PSTATS_STUFF(PStatTimer timer(_win->_show_fps_pcollector));
|
||||
|
||||
@ -1056,7 +1084,7 @@ render_subgraph(RenderTraverser *traverser,
|
||||
// We infer the modelview matrix by doing a wrt on the projection
|
||||
// node.
|
||||
LMatrix4f modelview_mat;
|
||||
get_rel_mat(subgraph, _current_projection_node, modelview_mat); // reversed from GL
|
||||
get_rel_mat(subgraph, _current_projection_node, modelview_mat); //needs reversal from glgsg, probably due D3D LH coordsys
|
||||
// get_rel_mat(_current_projection_node, subgraph, modelview_mat);
|
||||
|
||||
if (_coordinate_system != CS_yup_left) {
|
||||
@ -5488,17 +5516,18 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) {
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = _pDD->CreateSurface( &ddsd, &_pri, NULL ))) {
|
||||
dxgsg_cat.fatal() << "DXGraphicsStateGuardian::resize() - CreateSurface failed for primary : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.fatal() << "resize() - CreateSurface failed for primary : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!dx_full_screen) {
|
||||
// Create a clipper object which handles all our clipping for cases when
|
||||
// our window is partially obscured by other windows.
|
||||
LPDIRECTDRAWCLIPPER Clipper;
|
||||
|
||||
if (FAILED(hr = _pDD->CreateClipper( 0, &Clipper, NULL ))) {
|
||||
dxgsg_cat.fatal()
|
||||
<< "dxgsg - CreateClipper after resize failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
<< "CreateClipper after resize failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
// Associate the clipper with our window. Note that, afterwards, the
|
||||
@ -5507,6 +5536,7 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) {
|
||||
Clipper->SetHWnd( 0, mwindow );
|
||||
_pri->SetClipper( Clipper );
|
||||
Clipper->Release();
|
||||
}
|
||||
|
||||
// Recreate the backbuffer. (might want to handle failure due to running out of video memory)
|
||||
|
||||
@ -5516,7 +5546,7 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) {
|
||||
PRINTVIDMEM(_pDD,&ddsd_back.ddsCaps,"resize backbuffer surf");
|
||||
|
||||
if (FAILED(hr = _pDD->CreateSurface( &ddsd_back, &_back, NULL ))) {
|
||||
dxgsg_cat.fatal() << "DXGraphicsStateGuardian::resize() - CreateSurface failed for backbuffer : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.fatal() << "resize() - CreateSurface failed for backbuffer : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -5524,20 +5554,20 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) {
|
||||
|
||||
// Recreate and attach a z-buffer.
|
||||
if (FAILED(hr = _pDD->CreateSurface( &ddsd_zbuf, &_zbuf, NULL ))) {
|
||||
dxgsg_cat.fatal() << "DXGraphicsStateGuardian::resize() - CreateSurface failed for Z buffer: result = " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.fatal() << "resize() - CreateSurface failed for Z buffer: result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Attach the z-buffer to the back buffer.
|
||||
if ((hr = _back->AddAttachedSurface( _zbuf ) ) != DD_OK) {
|
||||
dxgsg_cat.fatal()
|
||||
<< "DXGraphicsStateGuardian::resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
<< "resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((hr = _d3dDevice->SetRenderTarget(_back,0x0) ) != DD_OK) {
|
||||
dxgsg_cat.fatal()
|
||||
<< "DXGraphicsStateGuardian::resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
<< "resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -5546,7 +5576,7 @@ dx_setup_after_resize(RECT viewrect, HWND mwindow) {
|
||||
hr = _d3dDevice->SetViewport( &vp );
|
||||
if (hr != DD_OK) {
|
||||
dxgsg_cat.fatal()
|
||||
<< "DXGraphicsStateGuardian:: SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
<< "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -5571,13 +5601,15 @@ HRESULT DXGraphicsStateGuardian::RestoreAllVideoSurfaces(void) {
|
||||
// note: could go through and just restore surfs that return IsLost() true
|
||||
// apparently that isnt as reliable w/some drivers tho
|
||||
if (FAILED(hr = _pDD->RestoreAllSurfaces() )) {
|
||||
dxgsg_cat.fatal()
|
||||
<< "DXGraphicsStateGuardian:: RestoreAllSurfs failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
return hr;
|
||||
dxgsg_cat.fatal() << "RestoreAllSurfs failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
|
||||
traverse_prepared_textures(refill_tex_callback,this);
|
||||
|
||||
if(dxgsg_cat.is_debug())
|
||||
dxgsg_cat.debug() << "restore and refill of video surfaces complete...\n";
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -5627,58 +5659,17 @@ void DXGraphicsStateGuardian::show_full_screen_frame(void) {
|
||||
// waiting for vsync?
|
||||
hr = _pri->Flip( NULL, dwFlipFlags);
|
||||
|
||||
if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
|
||||
//full screen app has been switched away
|
||||
HRESULT hr;
|
||||
|
||||
// TestCooperativeLevel returns DD_OK: If the current mode is same as the one which the App set.
|
||||
// The following error is returned only for exclusivemode apps.
|
||||
// DDERR_NOEXCLUSIVEMODE: Some other app took exclusive mode.
|
||||
hr = _pDD->TestCooperativeLevel();
|
||||
|
||||
while(hr == DDERR_NOEXCLUSIVEMODE) {
|
||||
// This means that mode changes had taken place, surfaces
|
||||
// were lost but still we are in the original mode, so we
|
||||
// simply restore all surfaces and keep going.
|
||||
|
||||
#ifdef _DEBUG
|
||||
if(dxgsg_cat.is_spam() && _dx_ready) {
|
||||
dxgsg_cat.spam() << "DXGraphicsStateGuardian:: no exclusive mode, waiting...\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
_dx_ready = FALSE;
|
||||
_win->update(); // sleep in here, and check for window events
|
||||
|
||||
hr = _pDD->TestCooperativeLevel();
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian::unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
dxgsg_cat.debug() << "DXGraphicsStateGuardian:: regained exclusive mode, refilling surfs...\n";
|
||||
#endif
|
||||
|
||||
RestoreAllVideoSurfaces();
|
||||
|
||||
#ifdef _DEBUG
|
||||
dxgsg_cat.debug() << "DXGraphicsStateGuardian:: refill done...\n";
|
||||
#endif
|
||||
|
||||
_dx_ready = TRUE;
|
||||
|
||||
return; // need to re-render scene before we can display it
|
||||
}
|
||||
|
||||
if(hr != DD_OK) {
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian::show_frame() - Flip failed w/unexpected error code: " << ConvD3DErrorToString(hr) << endl;
|
||||
if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
|
||||
CheckCooperativeLevel();
|
||||
} else {
|
||||
dxgsg_cat.error() << "show_frame() - Flip failed w/unexpected error code: " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: show_windowed_frame
|
||||
// Access: Public
|
||||
@ -5688,6 +5679,8 @@ void DXGraphicsStateGuardian::show_full_screen_frame(void) {
|
||||
void DXGraphicsStateGuardian::show_windowed_frame(void) {
|
||||
HRESULT hr;
|
||||
|
||||
DX_DECLARE_CLEAN(DDBLTFX, bltfx);
|
||||
|
||||
if (dx_sync_video) {
|
||||
// Wait for the video refresh *before* we blt the rendered image
|
||||
// onto the window. This will (a) prevent the "tearing" of the
|
||||
@ -5704,77 +5697,109 @@ void DXGraphicsStateGuardian::show_windowed_frame(void) {
|
||||
// this behavior; thus, we allow the user to avoid this wait,
|
||||
// based on the Config settings.
|
||||
|
||||
hr = _pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
|
||||
bltfx.dwDDFX |= DDBLTFX_NOTEARING; // hmm, does any driver actually recognize this flag?
|
||||
}
|
||||
|
||||
hr = _pri->Blt( &_view_rect, _back, NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx );
|
||||
|
||||
if (dx_sync_video) {
|
||||
HRESULT hr = _pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
|
||||
if(hr != DD_OK) {
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian::WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.error() << "WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
DX_DECLARE_CLEAN(DDBLTFX, bltfx);
|
||||
|
||||
bltfx.dwDDFX |= DDBLTFX_NOTEARING;
|
||||
hr = _pri->Blt( &_view_rect, _back, NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx );
|
||||
|
||||
if(FAILED(hr)) {
|
||||
if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
|
||||
if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
|
||||
CheckCooperativeLevel();
|
||||
} else {
|
||||
dxgsg_cat.error() << "show_frame() - Blt failed : " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DXGraphicsStateGuardian::CheckCooperativeLevel(bool bDoReactivateWindow) {
|
||||
|
||||
HRESULT hr = _pDD->TestCooperativeLevel();
|
||||
|
||||
if(SUCCEEDED(_last_testcooplevel_result)) {
|
||||
if(SUCCEEDED(hr)) // this means this was just a safety check, dont need to restore surfs
|
||||
return true;
|
||||
|
||||
// otherwise something just went wrong
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// TestCooperativeLevel returns DD_OK: If the current mode is
|
||||
// same as the one which the App set. The following two errors
|
||||
// are returned to NORMALMODE (windowed)apps only.
|
||||
//
|
||||
// DDERR_WRONGMODE: If the App is a windowed app and the current mode is
|
||||
// not the same as the one in which the app was created.
|
||||
// DDERR_EXCLUSIVEMODEALREADYSET: If another app took exclusivemode access
|
||||
// TestCooperativeLevel returns DD_OK: If the current mode is same as the one which the App set.
|
||||
// The following error is returned only for exclusivemode apps.
|
||||
// DDERR_NOEXCLUSIVEMODE: Some other app took exclusive mode.
|
||||
|
||||
hr = _pDD->TestCooperativeLevel();
|
||||
while(hr == DDERR_EXCLUSIVEMODEALREADYSET) {
|
||||
|
||||
HRESULT expected_error = (dx_full_screen ? DDERR_NOEXCLUSIVEMODE : DDERR_EXCLUSIVEMODEALREADYSET);
|
||||
|
||||
if(hr == expected_error) {
|
||||
// This means that mode changes had taken place, surfaces
|
||||
// were lost but still we are in the original mode, so we
|
||||
// simply restore all surfaces and keep going.
|
||||
|
||||
_dx_ready = FALSE;
|
||||
|
||||
#ifdef _DEBUG
|
||||
dxgsg_cat.spam() << "DXGraphicsStateGuardian:: another app has exclusive mode, waiting...\n";
|
||||
#endif
|
||||
|
||||
Sleep( 500 ); // Dont consume CPU.
|
||||
throw_event("PandaPaused"); // throw panda event to invoke network-only processing
|
||||
|
||||
hr = _pDD->TestCooperativeLevel();
|
||||
if(dxgsg_cat.is_debug()) {
|
||||
if(dx_full_screen)
|
||||
dxgsg_cat.debug() << "Lost access to DDRAW exclusive mode, waiting to regain it...\n";
|
||||
else dxgsg_cat.debug() << "Another app has DDRAW exclusive mode, waiting...\n";
|
||||
}
|
||||
|
||||
if(hr==DDERR_WRONGMODE) {
|
||||
if(_dx_ready) {
|
||||
_win->deactivate_window();
|
||||
_dx_ready = FALSE;
|
||||
}
|
||||
} else if(hr==DDERR_WRONGMODE) {
|
||||
// This means that the desktop mode has changed
|
||||
// need to destroy all of dx stuff and recreate everything
|
||||
// back again, which is a big hit
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian:: detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet. " << ConvD3DErrorToString(hr) << endl;
|
||||
dxgsg_cat.error() << "detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet. hr == " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
return;
|
||||
} else if(FAILED(hr)) {
|
||||
dxgsg_cat.error() << "unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
// testcooplvl was failing, handle case where it now succeeds
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
if(_last_testcooplevel_result == DDERR_EXCLUSIVEMODEALREADYSET) {
|
||||
if(dxgsg_cat.is_debug())
|
||||
dxgsg_cat.debug() << "other app relinquished exclusive mode, refilling surfs...\n";
|
||||
} else if(_last_testcooplevel_result == DDERR_NOEXCLUSIVEMODE) {
|
||||
if(dxgsg_cat.is_debug())
|
||||
dxgsg_cat.debug() << "regained exclusive mode, refilling surfs...\n";
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian::unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
|
||||
return;
|
||||
}
|
||||
if(bDoReactivateWindow)
|
||||
_win->reactivate_window(); //must reactivate window before you can restore surfaces (otherwise you are in WRONGVIDEOMODE, and DDraw RestoreAllSurfaces fails)
|
||||
|
||||
#ifdef _DEBUG
|
||||
dxgsg_cat.debug() << "DXGraphicsStateGuardian:: other app relinquished exclusive mode, refilling surfs...\n";
|
||||
#endif
|
||||
RestoreAllVideoSurfaces();
|
||||
#ifdef _DEBUG
|
||||
dxgsg_cat.debug() << "DXGraphicsStateGuardian:: refill done...\n";
|
||||
#endif
|
||||
|
||||
_dx_ready = TRUE;
|
||||
return; // need to re-render scene before we can display it
|
||||
} else {
|
||||
dxgsg_cat.error() << "DXGraphicsStateGuardian::show_frame() - Blt failed : " << ConvD3DErrorToString(hr) << endl;
|
||||
|
||||
} else if(hr==DDERR_WRONGMODE) {
|
||||
// This means that the desktop mode has changed
|
||||
// need to destroy all of dx stuff and recreate everything
|
||||
// back again, which is a big hit
|
||||
dxgsg_cat.error() << "detected desktop display mode change in TestCoopLevel, must recreate all DDraw surfaces & D3D devices, this is not handled yet. " << ConvD3DErrorToString(hr) << endl;
|
||||
_win->close_window();
|
||||
exit(1);
|
||||
} else if((hr!=DDERR_NOEXCLUSIVEMODE) && (hr!=DDERR_EXCLUSIVEMODEALREADYSET)) {
|
||||
dxgsg_cat.error() << "unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
_last_testcooplevel_result = hr;
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -203,6 +203,7 @@ protected:
|
||||
WORD *_index_buf; // base of malloced array
|
||||
|
||||
bool _dx_ready;
|
||||
HRESULT _last_testcooplevel_result;
|
||||
bool _bIsTNLDevice;
|
||||
LPDIRECTDRAWSURFACE7 _back;
|
||||
LPDIRECTDRAWSURFACE7 _zbuf;
|
||||
@ -226,7 +227,6 @@ protected:
|
||||
|
||||
D3DDEVICEDESC7 _D3DDevDesc;
|
||||
|
||||
void set_clipper(RECT cliprect);
|
||||
void GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
|
||||
void *pIndexSpace,DWORD dwIndexSpaceByteSize,
|
||||
D3DVECTOR *pCenter, float fRadius,
|
||||
@ -414,6 +414,9 @@ public:
|
||||
|
||||
void dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
|
||||
|
||||
#define DO_REACTIVATE_WINDOW true
|
||||
bool CheckCooperativeLevel(bool bDoReactivateWindow = false);
|
||||
|
||||
void dx_setup_after_resize(RECT viewrect,HWND mwindow) ;
|
||||
void show_frame();
|
||||
void show_full_screen_frame();
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include <keyboardButton.h>
|
||||
#include <mouseButton.h>
|
||||
#include <throw_event.h>
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
#include <pStatTimer.h>
|
||||
@ -57,7 +56,7 @@ extern bool dx_full_screen_antialiasing; // defined in dxgsg_config.cxx
|
||||
|
||||
#define MOUSE_ENTERED 0
|
||||
#define MOUSE_EXITED 1
|
||||
|
||||
#define PAUSED_TIMER_ID 7 // completely arbitrary choice
|
||||
#define DXREADY ((_dxgsg!=NULL)&&(_dxgsg->GetDXReady()))
|
||||
|
||||
LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam,LPARAM lparam);
|
||||
@ -277,33 +276,16 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_ACTIVATE: {
|
||||
if (_props._fullscreen && (!_exiting_window)) {
|
||||
// handle switching out of fullscreen mode differently than windowed mode.
|
||||
// here we want to suspend all gfx and execution, switch display modes and minimize ourself
|
||||
// until we are switched back to
|
||||
case WM_ACTIVATEAPP: {
|
||||
#ifdef _DEBUG
|
||||
wdxdisplay_cat.spam() << "WM_ACTIVATEAPP(" << (bool)(wparam!=0) <<") received\n";
|
||||
#endif
|
||||
|
||||
if(LOWORD(wparam)==WA_INACTIVE) {
|
||||
if(wdxdisplay_cat.is_spam())
|
||||
wdxdisplay_cat.spam() << "WDX window deactivated...\n";
|
||||
_window_inactive = true;
|
||||
|
||||
if(HIWORD(wparam)==0x0) // otherwise window already minimized
|
||||
ShowWindow(_mwindow, SW_MINIMIZE);
|
||||
} else {
|
||||
if(_window_inactive) {
|
||||
if(wdxdisplay_cat.is_spam())
|
||||
wdxdisplay_cat.spam() << "WDX window re-activated...\n";
|
||||
_window_inactive = false;
|
||||
|
||||
// move window to top of zorder,
|
||||
SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
|
||||
if(HIWORD(wparam)!=0x0) // window minimized, need to unminimize
|
||||
ShowWindow(_mwindow, SW_RESTORE);
|
||||
}
|
||||
}
|
||||
if((!wparam) && _props._fullscreen) {
|
||||
deactivate_window();
|
||||
return 0;
|
||||
} else break;
|
||||
} // dont want to reactivate until window is actually un-minimized (see WM_SIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_PAINT: {
|
||||
@ -401,19 +383,18 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
handle_window_move(LOWORD(lparam), HIWORD(lparam) );
|
||||
return 0;
|
||||
|
||||
|
||||
case WM_EXITSIZEMOVE:
|
||||
#ifdef _DEBUG
|
||||
wdxdisplay_cat.spam() << "WM_EXITSIZEMOVE received" << endl;
|
||||
#endif
|
||||
if(_dxgsg==NULL)
|
||||
break;
|
||||
|
||||
if(_WindowAdjustingType==Resizing) {
|
||||
_dxgsg->SetDXReady(false); // disable rendering whilst we mess with surfs
|
||||
|
||||
GdiFlush();
|
||||
|
||||
if(_dxgsg!=NULL) {
|
||||
_dxgsg->SetDXReady(false); // disable rendering whilst we mess with surfs
|
||||
|
||||
// Want to change rendertarget size without destroying d3d device. To save vid memory
|
||||
// (and make resizing work on memory-starved 4MB cards), we need to construct
|
||||
// a temporary mini-sized render target for the d3d device (it cannot point to a
|
||||
@ -439,8 +420,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
PRINTVIDMEM(pDD,&ddsd.ddsCaps,"dummy backbuf");
|
||||
|
||||
if(FAILED( hr = pDD->CreateSurface( &ddsd, &pddsDummy, NULL ) )) {
|
||||
wdxdisplay_cat.fatal()
|
||||
<< "Resize CreateSurface for temp backbuf failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
wdxdisplay_cat.fatal() << "Resize CreateSurface for temp backbuf failed : result = " << ConvD3DErrorToString(hr) << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -468,27 +448,20 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
}
|
||||
RELEASE(pddsDummyZ);
|
||||
RELEASE(pddsDummy);
|
||||
}
|
||||
|
||||
RECT view_rect;
|
||||
GetClientRect( _mwindow, &view_rect );
|
||||
ClientToScreen( _mwindow, (POINT*)&view_rect.left );
|
||||
ClientToScreen( _mwindow, (POINT*)&view_rect.right );
|
||||
|
||||
_dxgsg->dx_setup_after_resize(view_rect,_mwindow); // create the new resized rendertargets
|
||||
|
||||
// change _props xsize,ysize
|
||||
resized((view_rect.right - view_rect.left),(view_rect.bottom - view_rect.top));
|
||||
_props._xorg = view_rect.left; // _props origin should reflect view rectangle
|
||||
_props._yorg = view_rect.top;
|
||||
handle_reshape(true);
|
||||
|
||||
if(_dxgsg!=NULL) {
|
||||
_dxgsg->SetDXReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
_WindowAdjustingType = NotAdjusting;
|
||||
return 0;
|
||||
|
||||
case WM_ENTERSIZEMOVE: {
|
||||
if(_dxgsg==NULL)
|
||||
break;
|
||||
_dxgsg->SetDXReady(true); // dont disable here because I want to see pic as I resize
|
||||
_WindowAdjustingType = MovingOrResizing;
|
||||
}
|
||||
@ -500,9 +473,18 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
DWORD newbitdepth=wparam;
|
||||
wdxdisplay_cat.spam() <<"WM_DISPLAYCHANGE received with width:" << width << " height: " << height << " bpp: " << wparam<< endl;
|
||||
#endif
|
||||
// Note: TestCoopLevel in dxgsg will return WRONGMODE if there is a problem after a displaymode change
|
||||
// so we dont need to abort here
|
||||
|
||||
// unfortunately this doesnt seem to work because RestoreAllSurfaces doesn't
|
||||
// seem to think we're back in the original displaymode even after I've received
|
||||
// the WM_DISPLAYCHANGE msg, and returns WRONGMODE error. So the only way I can
|
||||
// think of to make this work is to have the timer periodically check for restored
|
||||
// coop level
|
||||
|
||||
// if(_props._fullscreen && _window_inactive) {
|
||||
// if(_dxgsg!=NULL)
|
||||
// _dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW);
|
||||
// else reactivate_window();
|
||||
// }
|
||||
}
|
||||
break;
|
||||
|
||||
@ -523,7 +505,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
|
||||
width = LOWORD(lparam); height = HIWORD(lparam);
|
||||
|
||||
if(_props._xsize != width || _props._ysize != height) {
|
||||
if((_props._xsize != width) || (_props._ysize != height)) {
|
||||
_WindowAdjustingType = Resizing;
|
||||
|
||||
// for maximized,unmaximize, need to call resize code artificially
|
||||
@ -532,7 +514,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
_bSizeIsMaximized=TRUE;
|
||||
window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0);
|
||||
} else if((wparam==SIZE_RESTORED) && _bSizeIsMaximized) {
|
||||
_bSizeIsMaximized=FALSE;
|
||||
_bSizeIsMaximized=FALSE; // only want to reinit dx if restoring from maximized state
|
||||
window_proc(hwnd, WM_EXITSIZEMOVE, 0x0,0x0);
|
||||
}
|
||||
}
|
||||
@ -570,12 +552,129 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
if(_WindowAdjustingType)
|
||||
break;
|
||||
return 0; // dont let GDI waste time redrawing the deflt background
|
||||
|
||||
case WM_TIMER:
|
||||
// 2 cases of app deactivation:
|
||||
//
|
||||
// 1) user has switched out of fullscreen mode
|
||||
// this is first signalled when ACTIVATEAPP returns false
|
||||
// for this case, we dont wake up until WM_SIZE returns restore or maximize
|
||||
// and WM_TIMER just periodically reawakens app for idle processing
|
||||
|
||||
// unfortunately this doesnt seem to work because RestoreAllSurfaces doesn't
|
||||
// seem to think we're back in the original displaymode even after I've received
|
||||
// the WM_DISPLAYCHANGE msg, and returns WRONGMODE error. So the only way I can
|
||||
// think of to make this work is to have the timer periodically check for restored
|
||||
// coop level, as it does in case 2)
|
||||
|
||||
//
|
||||
// 2) windowed app has lost access to dx because another app has taken dx exclusive mode
|
||||
// here we rely on WM_TIMER to periodically check if it is ok to reawaken app.
|
||||
// windowed apps currently run regardless of if its window is in the foreground
|
||||
// so we cannot rely on window messages to reawaken app
|
||||
|
||||
|
||||
if((wparam==_PandaPausedTimer) && _window_inactive) {
|
||||
assert(_dxgsg!=NULL);
|
||||
_dxgsg->CheckCooperativeLevel(DO_REACTIVATE_WINDOW);
|
||||
|
||||
// wdxdisplay_cat.spam() << "periodic return of control to app\n";
|
||||
_return_control_to_app = true;
|
||||
// throw_event("PandaPaused");
|
||||
// do we still need to do this since I return control to app periodically using timer msgs?
|
||||
// does app need to know to avoid major computation?
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: handle_reshape
|
||||
// Access:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void wdxGraphicsWindow::handle_reshape(bool bDoDxReset) {
|
||||
RECT view_rect;
|
||||
GetClientRect( _mwindow, &view_rect );
|
||||
ClientToScreen( _mwindow, (POINT*)&view_rect.left ); // translates top,left pnt
|
||||
ClientToScreen( _mwindow, (POINT*)&view_rect.right ); // translates right,bottom pnt
|
||||
|
||||
// change _props xsize,ysize
|
||||
resized((view_rect.right - view_rect.left),(view_rect.bottom - view_rect.top));
|
||||
|
||||
_props._xorg = view_rect.left; // _props origin should reflect upper left of view rectangle
|
||||
_props._yorg = view_rect.top;
|
||||
|
||||
if(wdxdisplay_cat.is_spam()) {
|
||||
wdxdisplay_cat.spam() << "reshape to origin: (" << _props._xorg << "," << _props._yorg << "), size: (" << _props._xsize << "," << _props._ysize << ")\n";
|
||||
}
|
||||
|
||||
if((_dxgsg!=NULL) && bDoDxReset) {
|
||||
_dxgsg->dx_setup_after_resize(view_rect,_mwindow); // create the new resized rendertargets
|
||||
}
|
||||
}
|
||||
|
||||
void wdxGraphicsWindow::deactivate_window(void) {
|
||||
// current policy is to suspend minimized or deactivated fullscreen windows, but leave
|
||||
// regular windows running normally
|
||||
|
||||
if(_window_inactive || _exiting_window)
|
||||
return;
|
||||
|
||||
if(wdxdisplay_cat.is_spam())
|
||||
wdxdisplay_cat.spam() << "WDX window deactivated, waiting...\n";
|
||||
_window_inactive = true;
|
||||
|
||||
if(_props._fullscreen) {
|
||||
// make sure window is minimized
|
||||
|
||||
WINDOWPLACEMENT wndpl;
|
||||
wndpl.length=sizeof(WINDOWPLACEMENT);
|
||||
|
||||
if(!GetWindowPlacement(_mwindow,&wndpl)) {
|
||||
wdxdisplay_cat.error() << "GetWindowPlacement failed!\n";
|
||||
return;
|
||||
}
|
||||
if((wndpl.showCmd!=SW_MINIMIZE)&&(wndpl.showCmd!=SW_SHOWMINIMIZED)) {
|
||||
ShowWindow(_mwindow, SW_MINIMIZE);
|
||||
}
|
||||
}
|
||||
|
||||
_PandaPausedTimer = SetTimer(_mwindow,PAUSED_TIMER_ID,500,NULL);
|
||||
if(_PandaPausedTimer!=PAUSED_TIMER_ID) {
|
||||
wdxdisplay_cat.error() << "Error in SetTimer!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void wdxGraphicsWindow::reactivate_window(void) {
|
||||
if(!_window_inactive)
|
||||
return;
|
||||
|
||||
// first see if dx cooperative level is OK for reactivation
|
||||
// if(!_dxgsg->CheckCooperativeLevel())
|
||||
// return;
|
||||
|
||||
if(wdxdisplay_cat.is_spam())
|
||||
wdxdisplay_cat.spam() << "WDX window re-activated...\n";
|
||||
|
||||
_window_inactive = false;
|
||||
|
||||
if(_PandaPausedTimer!=NULL) {
|
||||
KillTimer(_mwindow,_PandaPausedTimer);
|
||||
_PandaPausedTimer = NULL;
|
||||
}
|
||||
|
||||
// move window to top of zorder
|
||||
// if(_props._fullscreen)
|
||||
// SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
|
||||
GdiFlush();
|
||||
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Constructor
|
||||
@ -613,6 +712,7 @@ void wdxGraphicsWindow::config(void) {
|
||||
_gsg = _dxgsg = NULL;
|
||||
_exiting_window = false;
|
||||
_window_inactive = false;
|
||||
_return_control_to_app = false;
|
||||
|
||||
_hOldForegroundWindow=GetForegroundWindow();
|
||||
|
||||
@ -662,24 +762,23 @@ void wdxGraphicsWindow::config(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DWORD window_style = WS_POPUP | WS_SYSMENU; // for CreateWindow
|
||||
|
||||
// rect now contains the coords for the entire window, not the client
|
||||
if(dx_full_screen) {
|
||||
|
||||
_mwindow = CreateWindow(WDX_WINDOWCLASSNAME, _props._title.c_str(),
|
||||
WS_POPUP, 0, 0, _props._xsize,_props._ysize,
|
||||
window_style, 0, 0, _props._xsize,_props._ysize,
|
||||
NULL, NULL, hinstance, 0);
|
||||
} else {
|
||||
int style;
|
||||
RECT win_rect;
|
||||
SetRect(&win_rect, _props._xorg, _props._yorg, _props._xorg + _props._xsize,
|
||||
_props._yorg + _props._ysize);
|
||||
|
||||
if(_props._border)
|
||||
style = WS_OVERLAPPEDWINDOW;
|
||||
else
|
||||
style = WS_POPUP | WS_MAXIMIZE;
|
||||
window_style |= WS_OVERLAPPEDWINDOW; // should we just use WS_THICKFRAME instead?
|
||||
|
||||
AdjustWindowRect(&win_rect, style, FALSE); //compute window size based on desired client area size
|
||||
AdjustWindowRect(&win_rect, window_style, FALSE); //compute window size based on desired client area size
|
||||
|
||||
// make sure origin is on screen
|
||||
if(win_rect.left < 0) {
|
||||
@ -690,13 +789,13 @@ void wdxGraphicsWindow::config(void) {
|
||||
}
|
||||
|
||||
_mwindow = CreateWindow(WDX_WINDOWCLASSNAME, _props._title.c_str(),
|
||||
style, win_rect.left, win_rect.top, win_rect.right-win_rect.left,
|
||||
window_style, win_rect.left, win_rect.top, win_rect.right-win_rect.left,
|
||||
win_rect.bottom-win_rect.top,
|
||||
NULL, NULL, hinstance, 0);
|
||||
}
|
||||
|
||||
if(!_mwindow) {
|
||||
wdxdisplay_cat.fatal() << "config() - failed to create Mwindow" << endl;
|
||||
wdxdisplay_cat.fatal() << "config() - failed to create window" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -1063,7 +1162,6 @@ dx_setup() {
|
||||
}
|
||||
|
||||
SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight);
|
||||
|
||||
} // end create full screen buffers
|
||||
|
||||
else { // CREATE WINDOWED BUFFERS
|
||||
@ -1480,10 +1578,9 @@ supports_update() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void INLINE wdxGraphicsWindow::process_events(void) {
|
||||
void INLINE process_1_event(void) {
|
||||
MSG msg;
|
||||
|
||||
while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
if(!GetMessage(&msg, NULL, 0, 0)) {
|
||||
// WM_QUIT received
|
||||
DestroyAllWindows(false);
|
||||
@ -1495,6 +1592,25 @@ void INLINE wdxGraphicsWindow::process_events(void) {
|
||||
// Call window_proc
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
void INLINE wdxGraphicsWindow::process_events(void) {
|
||||
if(_window_inactive) {
|
||||
// Get 1 msg at a time until no more are left and we block and sleep,
|
||||
// or message changes _return_control_to_app or _window_inactive status
|
||||
|
||||
while(_window_inactive && (!_return_control_to_app)) {
|
||||
process_1_event();
|
||||
}
|
||||
_return_control_to_app = false;
|
||||
|
||||
} else {
|
||||
MSG msg;
|
||||
|
||||
// handle all msgs on queue in a row
|
||||
while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
process_1_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1504,8 +1620,9 @@ void INLINE wdxGraphicsWindow::process_events(void) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void wdxGraphicsWindow::update(void) {
|
||||
#ifdef DO_PSTATS
|
||||
if(!_window_inactive) {
|
||||
_show_code_pcollector.stop();
|
||||
|
||||
if(!_window_inactive) {
|
||||
PStatClient::main_tick();
|
||||
}
|
||||
#endif
|
||||
@ -1513,8 +1630,9 @@ void wdxGraphicsWindow::update(void) {
|
||||
process_events();
|
||||
|
||||
if(_window_inactive) {
|
||||
Sleep( 500 ); // Dont consume CPU.
|
||||
throw_event("PandaPaused"); // throw panda event to invoke network-only processing
|
||||
// note _window_inactive must be checked after process_events is called, to avoid draw_callback being called
|
||||
if(_idle_callback)
|
||||
call_idle_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ protected:
|
||||
public:
|
||||
HWND _mwindow;
|
||||
HWND _hOldForegroundWindow;
|
||||
UINT_PTR _PandaPausedTimer;
|
||||
|
||||
private:
|
||||
HDC _hdc;
|
||||
@ -107,6 +108,7 @@ private:
|
||||
bool _ignore_key_repeat;
|
||||
bool _exiting_window;
|
||||
bool _window_inactive;
|
||||
bool _return_control_to_app;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type(void);
|
||||
@ -116,6 +118,9 @@ public:
|
||||
|
||||
void DestroyMe(bool bAtExitFnCalled);
|
||||
virtual void do_close_window();
|
||||
void deactivate_window(void);
|
||||
void reactivate_window(void);
|
||||
void handle_reshape(bool bDoDXReset);
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
Loading…
x
Reference in New Issue
Block a user