Swapping between full-screen and windowed mode?

futnuh

23-05-2007 00:36:05

OpenSceneGraph has this nice feature where the 'f' key toggles between windowed and fullscreen modes. Is this possible in python-ogre?

Game_Ender

23-05-2007 00:40:54

That is a pure Ogre question, and it has nothing to do with the input system as I am sure you know. This boils down to whether the RenderWindow class supports this, and from a quick check of the Docs it doesn't. So if you want the feature, you are going to have to add it to Ogre, and then it will automatically appear in Python-Ogre if you generate your bindings from the patched version.

willism

24-05-2007 16:33:26

I've tried to think of a good way to do this. I was wanting to create a menu with options on changing resolution and fullscreen/window mode.

After the research that I have done, it seems like the only way to switch video modes with Ogre is to somehow save the state of your app, shutdown Ogre, re-initialize ogre with the new video settings (full-screen/windowed, resolution, whatever else), then bring your app back to the state that you saved. I know it's not a very fun idea, but I don't know of any other way to do it.

Does anybody else have a better idea, short of contributing the feature to ogre?

sinbad

25-05-2007 10:14:09

The issue is twofold here. Firstly, that the first window any app creates is 'special' in that it holds the context / device. Secondly, DirectX in particular can't switch modes without destroying and recreating the window - which in turn will destroy the device and lose all your resources of course.

The answer is to create a dummy window just to hold the device. I do this in my editor to prevent lost device issues cropping up whenever I want to resize my main editing panes. Create a small window but don't attach any viewports or cameras - that will initialise the device context and allow you to create subsequent windows which will not be bound by the limitations of keeping that device context intact.

sinbad

25-05-2007 10:28:52

Actually this only works for windowed mode (like my editor), let me take another look at it.

sinbad

25-05-2007 15:45:54

Ok, I've spent some time today implementing this feature. GL was easy, D3D a total pain the ass as expected but I finally got it working properly on both. Only supported on Windows at the moment since I'm not a GLX or OSX guy.

Please grab CVS branch 'v1-4' to get it or use the following patch:

Index: OgreMain/include/OgreRenderWindow.h
===================================================================
RCS file: /cvsroot/ogre/ogrenew/OgreMain/include/OgreRenderWindow.h,v
retrieving revision 1.19
diff -u -r1.19 OgreRenderWindow.h
--- OgreMain/include/OgreRenderWindow.h 19 Aug 2006 11:54:54 -0000 1.19
+++ OgreMain/include/OgreRenderWindow.h 25 May 2007 13:59:14 -0000
@@ -85,6 +85,14 @@
*/
virtual void create(const String& name, unsigned int width, unsigned int height,
bool fullScreen, const NameValuePairList *miscParams) = 0;
+
+ /** Alter fullscreen mode options.
+ @param fullScreen Whether to use fullscreen mode or not. Nothing will happen
+ unless this is different from the current setting.
+ @param width The new width to use
+ @param height The new height to use
+ */
+ virtual void setFullscreen(bool fullScreen, unsigned int width, unsigned int height) {}

/** Destroys the window.
*/
Index: RenderSystems/Direct3D9/include/OgreD3D9RenderWindow.h
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/Direct3D9/include/OgreD3D9RenderWindow.h,v
retrieving revision 1.22
diff -u -r1.22 OgreD3D9RenderWindow.h
--- RenderSystems/Direct3D9/include/OgreD3D9RenderWindow.h 23 Aug 2006 08:18:51 -0000 1.22
+++ RenderSystems/Direct3D9/include/OgreD3D9RenderWindow.h 25 May 2007 13:59:14 -0000
@@ -48,6 +48,7 @@
~D3D9RenderWindow();
void create(const String& name, unsigned int width, unsigned int height,
bool fullScreen, const NameValuePairList *miscParams);
+ void setFullscreen(bool fullScreen, unsigned int width, unsigned int height);
void destroy(void);
bool isVisible() const;
bool isClosed() const { return mClosed; }
@@ -94,6 +95,7 @@
bool mSizing;
bool mClosed;
bool mIsSwapChain; // Is this a secondary window?
+ bool mChangingMode;

// -------------------------------------------------------
// DirectX-specific
Index: RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp,v
retrieving revision 1.178.2.4
diff -u -r1.178.2.4 OgreD3D9RenderSystem.cpp
--- RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp 28 Apr 2007 14:40:07 -0000 1.178.2.4
+++ RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp 25 May 2007 14:36:22 -0000
@@ -3217,9 +3217,9 @@
(*sw)->destroyD3DResources();
}

+ D3DPRESENT_PARAMETERS* presParams = mPrimaryWindow->getPresentationParameters();
// Reset the device, using the primary window presentation params
- HRESULT hr = mpD3DDevice->Reset(
- mPrimaryWindow->getPresentationParameters());
+ HRESULT hr = mpD3DDevice->Reset(presParams);

if (hr == D3DERR_DEVICELOST)
{
@@ -3233,6 +3233,29 @@
"D3D9RenderWindow::restoreLostDevice" );
}

+ StringUtil::StrStreamType str;
+ str << "Reset device ok w:" << presParams->BackBufferWidth
+ << " h:" << presParams->BackBufferHeight;
+ LogManager::getSingleton().logMessage(str.str());
+ // If windowed, we have to reset the size here
+ // since a fullscreen switch may have occurred
+ if (presParams->Windowed)
+ {
+ RECT rc;
+ SetRect(&rc, 0, 0, presParams->BackBufferWidth, presParams->BackBufferHeight);
+ AdjustWindowRect(&rc, GetWindowLong(mPrimaryWindow->getWindowHandle(), GWL_STYLE), false);
+ unsigned int winWidth = rc.right - rc.left;
+ unsigned int winHeight = rc.bottom - rc.top;
+ int screenw = GetSystemMetrics(SM_CXSCREEN);
+ int screenh = GetSystemMetrics(SM_CYSCREEN);
+ int left = (screenw - winWidth) / 2;
+ int top = (screenh - winHeight) / 2;
+ SetWindowPos(mPrimaryWindow->getWindowHandle(), HWND_NOTOPMOST, left, top, winWidth, winHeight,
+ SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
+
+ }
+
+
// will have lost basic states
mBasicStatesInitialised = false;
mVertexProgramBound = false;
Index: RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp,v
retrieving revision 1.59
diff -u -r1.59 OgreD3D9RenderWindow.cpp
--- RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp 14 Mar 2007 17:52:49 -0000 1.59
+++ RenderSystems/Direct3D9/src/OgreD3D9RenderWindow.cpp 25 May 2007 13:59:14 -0000
@@ -47,6 +47,7 @@
D3D9RenderWindow::D3D9RenderWindow(HINSTANCE instance, D3D9Driver *driver, LPDIRECT3DDEVICE9 deviceIfSwapChain)
: mInstance(instance)
, mDriver(driver)
+ , mChangingMode(false)
, mpRenderSurface(0)
{
mIsFullScreen = false;
@@ -268,6 +269,61 @@
mClosed = false;
}

+ void D3D9RenderWindow::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
+ {
+ if (fullScreen != mIsFullScreen)
+ {
+ mIsFullScreen = fullScreen;
+
+ DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+
+ if (fullScreen)
+ {
+ dwStyle |= WS_POPUP;
+
+ mTop = mLeft = 0;
+ mWidth = width;
+ mHeight = height;
+ // need different ordering here
+ md3dpp.Windowed = !fullScreen;
+ md3dpp.FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
+ md3dpp.BackBufferHeight = height;
+ md3dpp.BackBufferWidth = width;
+ MoveWindow(mHWnd, mLeft, mTop, mWidth, mHeight, FALSE);
+ SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
+
+ }
+ else
+ {
+ dwStyle |= WS_OVERLAPPEDWINDOW;
+ // Calculate window dimensions required
+ // to get the requested client area
+ RECT rc;
+ SetRect(&rc, 0, 0, width, height);
+ AdjustWindowRect(&rc, dwStyle, false);
+ md3dpp.Windowed = !fullScreen;
+ md3dpp.FullScreen_RefreshRateInHz = mIsFullScreen ? mDisplayFrequency : 0;
+ unsigned int winWidth = rc.right - rc.left;
+ unsigned int winHeight = rc.bottom - rc.top;
+
+ md3dpp.BackBufferHeight = height;
+ md3dpp.BackBufferWidth = width;
+
+ SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
+ SetWindowPos(mHWnd, HWND_NOTOPMOST, 0, 0, winWidth, winHeight,
+ SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE);
+
+ // Note that we also set the position in the restoreLostDevice method
+
+
+ }
+
+
+ }
+
+ }
+
void D3D9RenderWindow::createD3DResources(void)
{
// access device via driver
@@ -854,6 +910,9 @@
//-----------------------------------------------------------------------------
void D3D9RenderWindow::update(bool swap)
{
+ if (mChangingMode)
+ return;
+
D3D9RenderSystem* rs = static_cast<D3D9RenderSystem*>(
Root::getSingleton().getRenderSystem());

Index: RenderSystems/GL/include/OgreWin32Window.h
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/GL/include/OgreWin32Window.h,v
retrieving revision 1.19
diff -u -r1.19 OgreWin32Window.h
--- RenderSystems/GL/include/OgreWin32Window.h 26 Feb 2007 14:50:33 -0000 1.19
+++ RenderSystems/GL/include/OgreWin32Window.h 25 May 2007 14:11:16 -0000
@@ -42,6 +42,7 @@

void create(const String& name, unsigned int width, unsigned int height,
bool fullScreen, const NameValuePairList *miscParams);
+ void setFullscreen(bool fullScreen, unsigned int width, unsigned int height);
void destroy(void);
bool isVisible() const;
bool isClosed(void) const;
Index: RenderSystems/GL/src/OgreGLHardwareIndexBuffer.cpp
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/GL/src/OgreGLHardwareIndexBuffer.cpp,v
retrieving revision 1.19
diff -u -r1.19 OgreGLHardwareIndexBuffer.cpp
--- RenderSystems/GL/src/OgreGLHardwareIndexBuffer.cpp 17 Mar 2007 16:00:31 -0000 1.19
+++ RenderSystems/GL/src/OgreGLHardwareIndexBuffer.cpp 23 May 2007 14:56:56 -0000
@@ -140,7 +140,8 @@
if (mScratchUploadOnUnlock)
{
// have to write the data back to vertex buffer
- writeData(mScratchOffset, mScratchSize, mScratchPtr, true);
+ writeData(mScratchOffset, mScratchSize, mScratchPtr,
+ mScratchOffset == 0 && mScratchSize == getSizeInBytes());
}

// deallocate from scratch buffer
Index: RenderSystems/GL/src/OgreGLHardwareVertexBuffer.cpp
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/GL/src/OgreGLHardwareVertexBuffer.cpp,v
retrieving revision 1.22
diff -u -r1.22 OgreGLHardwareVertexBuffer.cpp
--- RenderSystems/GL/src/OgreGLHardwareVertexBuffer.cpp 17 Mar 2007 16:00:31 -0000 1.22
+++ RenderSystems/GL/src/OgreGLHardwareVertexBuffer.cpp 23 May 2007 13:22:56 -0000
@@ -143,7 +143,8 @@
if (mScratchUploadOnUnlock)
{
// have to write the data back to vertex buffer
- writeData(mScratchOffset, mScratchSize, mScratchPtr, true);
+ writeData(mScratchOffset, mScratchSize, mScratchPtr,
+ mScratchOffset == 0 && mScratchSize == getSizeInBytes());
}

// deallocate from scratch buffer
Index: RenderSystems/GL/src/OgreWin32Window.cpp
===================================================================
RCS file: /cvsroot/ogre/ogrenew/RenderSystems/GL/src/OgreWin32Window.cpp,v
retrieving revision 1.45.2.1
diff -u -r1.45.2.1 OgreWin32Window.cpp
--- RenderSystems/GL/src/OgreWin32Window.cpp 17 Apr 2007 11:57:19 -0000 1.45.2.1
+++ RenderSystems/GL/src/OgreWin32Window.cpp 25 May 2007 14:37:22 -0000
@@ -138,20 +138,15 @@
if(opt != miscParams->end())
outerSize = StringConverter::parseBool(opt->second);

- if (mIsFullScreen)
- {
- // only available with fullscreen
- if ((opt = miscParams->find("displayFrequency")) != end)
- mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
- if ((opt = miscParams->find("colourDepth")) != end)
- mColourDepth = StringConverter::parseUnsignedInt(opt->second);
- }
- else
- {
- // incompatible with fullscreen
- if ((opt = miscParams->find("parentWindowHandle")) != end)
- parent = (HWND)StringConverter::parseUnsignedInt(opt->second);
- }
+ // only available with fullscreen
+ if ((opt = miscParams->find("displayFrequency")) != end)
+ mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
+ if ((opt = miscParams->find("colourDepth")) != end)
+ mColourDepth = StringConverter::parseUnsignedInt(opt->second);
+
+ // incompatible with fullscreen
+ if ((opt = miscParams->find("parentWindowHandle")) != end)
+ parent = (HWND)StringConverter::parseUnsignedInt(opt->second);
}

if (!mIsExternal)
@@ -312,6 +307,89 @@
mActive = true;
}

+ void Win32Window::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
+ {
+ if (mIsFullScreen != fullScreen)
+ {
+ mIsFullScreen = fullScreen;
+ DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+
+ if (mIsFullScreen)
+ {
+ dwStyle |= WS_POPUP;
+
+ DEVMODE dm;
+ dm.dmSize = sizeof(DEVMODE);
+ dm.dmBitsPerPel = mColourDepth;
+ dm.dmPelsWidth = width;
+ dm.dmPelsHeight = height;
+ dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+ if (mDisplayFrequency)
+ {
+ dm.dmDisplayFrequency = mDisplayFrequency;
+ dm.dmFields |= DM_DISPLAYFREQUENCY;
+ if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
+ {
+ LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
+ dm.dmFields ^= DM_DISPLAYFREQUENCY;
+ }
+ }
+ else
+ {
+ // try a few
+ dm.dmDisplayFrequency = 100;
+ dm.dmFields |= DM_DISPLAYFREQUENCY;
+ if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
+ {
+ dm.dmDisplayFrequency = 75;
+ if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
+ {
+ dm.dmFields ^= DM_DISPLAYFREQUENCY;
+ }
+ }
+
+ }
+ if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
+ LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
+
+ SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
+ SetWindowPos(mHWnd, HWND_TOPMOST, 0, 0, width, height,
+ SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
+ mWidth = width;
+ mHeight = height;
+
+
+ }
+ else
+ {
+ dwStyle |= WS_OVERLAPPEDWINDOW;
+
+ // drop out of fullscreen
+ ChangeDisplaySettings(NULL, 0);
+
+ // calculate overall dimensions for requested client area
+ RECT rc = { 0, 0, width, height };
+ AdjustWindowRect(&rc, dwStyle, false);
+ unsigned int winWidth = rc.right - rc.left;
+ unsigned int winHeight = rc.bottom - rc.top;
+
+ int screenw = GetSystemMetrics(SM_CXSCREEN);
+ int screenh = GetSystemMetrics(SM_CYSCREEN);
+ int left = (screenw - winWidth) / 2;
+ int top = (screenh - winHeight) / 2;
+
+
+ SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
+ SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
+ SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
+ mWidth = width;
+ mHeight = height;
+
+ }
+
+ }
+ }
+
void Win32Window::destroy(void)
{
if (!mHWnd)

andy

26-05-2007 00:30:14

I'm going to build the next Python-Ogre SnapShot (expect it in a couple of days) against the Ogre CVS version so this will be supported..

Andy

saladin

28-05-2007 16:29:10

I'm going to build the next Python-Ogre SnapShot (expect it in a couple of days) against the Ogre CVS version so this will be supported..

Andy


Thumb up. :twisted: :twisted: :twisted:

futnuh

31-05-2007 01:05:27

Thanks Steve. Will this patch get merged into the next version of Ogre or is it Eihort only? (Aside: it might be worth changing Dagon to Eihort in the "update to latest stable release" CVS instructions. I realize the CVS listed commands are only illustrative but someone will likely follow them explicitly and grab an old version ... ahem.)