Advertisement

Frustrating problems with alt-tabbing and fullscreen

Started by July 18, 2004 07:08 PM
6 comments, last by comservlant 20 years, 4 months ago
I've spent most of the last 2 days coding up a storm finishing my new basecode, and as far as I can tell, there's one major glitch left: alt-tabbing out, then back in, from fullscreen mode. Whenever I'm in fullscreen mode (usually testing in 640x480x32) and I alt tab out, then tab back in, the viewport seems messed up and/or offset. In the tests I've done, I've simply drawn a colored triangle right in the center of the screen. When testing alt-tabbing, tabbing back in usually shows the triangle suddenly drawing much lower on the screen. I've logged calls to my viewport function and the resolution parameters passed to it seem fine. The modelview matrix couldn't be messed up since I reset that as well. This is seriously boggling my mind. Oddly enough, once I tab back in, then toggle fullscreen mode switch to windowed mode, then back again, the viewport/drawing lines up correctly again. I've also noticed that things seem fine when the resolution of the fullscreen app is the same as the desktop resolution. I've played around with various windows messages (WM_etc), but I'm fairly convinced at this point there's a small yet crucial thing I'm doing wrong in processing these. I still don't entirely understand the perfect way to process window messages 'cause there are so many :( Here are the relevant window messages that I'm processing and some related functions: for detecting when the window loses focus, I'm using WM_ACTIVATEAPP and for resizing (including restoration from minimized states) I process WM_SIZE.

// I process this message to determine whenever the window loses focus.
// If it does and I'm fullscreen, I change display settings and use
// ShowWindow() to minimize the app -- is that flawed?
	case WM_ACTIVATEAPP:
		{
			// Window is reactivating
			if (wParam)
			{
				pWindow->isActive = true;
				pWindow->isVisible = true;

				// If we're operating in fullscreen, restore the game's display
				// settings.
				if (pWindow->isFullScreen)
				{
					ZeroMemory(&screenSettings, sizeof(screenSettings));
					screenSettings.dmSize = sizeof(screenSettings);
					screenSettings.dmPelsWidth = pWindow->width;
					screenSettings.dmPelsHeight = pWindow->height;
					screenSettings.dmBitsPerPel = pWindow->colorDepth;
					screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
					ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN);
				}

				ShowWindow(hWnd, SW_RESTORE);
				UpdateWindow(hWnd);  // needed?
			}
			// Window is deactivating
			else
			{
				pWindow->isActive = false;
				pWindow->isVisible = false;

				// If we're in fullscreen, change display settings and minimize
				// the window.
				if (pWindow->isFullScreen)
				{
					ChangeDisplaySettings(NULL, 0);
				}

				ShowWindow(hWnd, SW_MINIMIZE);
				UpdateWindow(hWnd);
			}
			return 0;  // should I return here or break and let DefaultWindowProc ALSO process it?
		}

// Then I decided to process WM_SIZE since it seemed the viewport
// needed resetting each time I'm tabbing in/out or changing the
// window's dimensions.  For safety at least? o_O

	case WM_SIZE:
		{
                        // If the window is maximized or restored (from a minimized state?) I use SetViewport()
			if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
                                // If this is windowed mode, I use the message params to set 
                                // the new size (seems to work fine)
				if (!pWindow->isFullScreen && pWindow->isActive)
				{
        				pWindow->SetViewport(LOWORD(lParam), HIWORD(lParam));
				}
                                // If it's fullscreen, however, I (re)set the viewport to the 
                                //current dimensions of the fullscreen resolution
				else if (pWindow->isActive)
					pWindow->SetViewport(pWindow->width, pWindow->height);
			return 0;  // should I return here or break and let DefaultWindowProc ALSO process it?
		}

// And the SetViewport function itself.  It resets the projection
// and modelview matrices.  It doesn't seem wrong (?!)
void CWindow::SetViewport(int width, int height)
{
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (double)width / (double)height, 1.0, 500.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

If anyone has some sample code that works with fullscreen/windowed mode toggling and alt-tabbing under Win98 (yea, yea, I know!), I'd love some help. And yes, I've done quite a bit of browsing through MSDN, the MSDN website, google, and whatever else I can find to give me information about processing those two window messages, before coming here. Perhaps I should process some others? I'm lost. Thanks
when you change resolution, even if from 640->desktop->640, generally you always must recreate the window and reload textures, etc... so when you tab back in try recreating the window from scratch...
Advertisement
I *could* do that. When toggling between fullscreen and windowed mode, I do recreate the window, but are you sure it's necessary when I'm changing display settings? The window's properties really don't change, so I'm wondering what else occurs. Plus, in addition to recreating the window (not a big chore), you suggest I reload textures?

I'm curious, though, how I've seen a number of modern day 3D games handle alt-tabbing with what seems to be little overhead (take Diablo 2 for instance, it switches from alt-tab and back again rather quickly). For now, whatever I'll be testing while I tweak the basecode doesn't require a bunch of preparation time, so reinitializing the entire "game" isn't unreasonable, but wouldn't a large 3D game go through quite a bit of reloading to faciliate a simple feature? It makes me think it's possible without recreating the window. I will test it though.

Thanks for the input!
Also, a related question, if someone could :) : if I create a window, create a rendering context, make some openGL setup calls and load some textures (let's say), then I decide to free the context and dc and destroy the window, etc, then recreate the window again, is the state of openGL preserved between those operations? i.e. will textures still be loaded, matrices still set, etc? I've never had the perception of openGL "initializing" anywhere, I just started making calls to it after a window and rendering context was made. Does it then "deinitialize" once the rendering context is freed and the window destroyed?
Quote:


I'm curious, though, how I've seen a number of modern day 3D games handle alt-tabbing with what seems to be little overhead (take Diablo 2 for instance, it switches from alt-tab and back again rather quickly).



It depends if the game uses OpenGL/D3D or not (Diablo 2 doesn't).. and D3D handles alt-tabbing quite nicly (all the example applications are setup to handle it correctly) - there really arn't any good examples for OpenGL.
Quake 3 does it pretty efficiently.
The nehe basecode allso preforms reasonably well, exept that it reloads textures models and such, so currently in working on making a fullscreen/windowed transition that doesn't need reloading
Advertisement
I downloaded the "Nehe latest" basecode and ran the sample. Alt-tabbing out doesn't work properly at all for me. The task list shows up, but selecting another app doesn't minimize the window, it just blinks a moment then continues rendering fullscreen (though I think it loses input focus). Maybe my videocard and OS setup just sucks :(


How does Quake3 do it? :P
Quote: Original post by chawk
(though I think it loses input focus). Maybe my videocard and OS setup just sucks :(


Yeah, I hadn't tried it 'till I read your post but my stuff does the same thing.

I'm running a child OGL window in a dialog, tied to it's parent's location through WM_MOVE messages.

When I go fullscreen, I just maximize the OGL window (it's a borderless popup) and it covers taskbar and all with no system resolution changes (I do a MoveWindow() set to the desktop res).

But, I think what might be part of the reason is the way the rendering loop is called, it's not part of the winproc message handler or the child window's message handler, it just uses the winmain message pump also OGL is set up for OWN_DC, might have something to do with it.

I'll mess with it a little now that I've seen your post.

This topic is closed to new replies.

Advertisement