Archived

This topic is now archived and is closed to further replies.

James Gregory

Yet another alt tab question

Recommended Posts

James Gregory    128
I''ve been reading all the previous stuff on this forum about alt-tab issues, and as my game is no Half-Life I quite like the sound of simply reszing the desktop to match my desired resolution and then running in windowed mode. However, I don''t know how I would go about doing such a thing. Can anyone help? Thanks.

Share this post


Link to post
Share on other sites
JoeyBlow2    100
You will still run into the same problems running in windows mode (alt-tab is no different than clicking off a window then clicking back onto it.) I suggest learning about alt-tab and put the correct code into your software. Its not very hard. You just release all DEFAULT pool objects, then call the Device->Reset() function, the re-create all DEFAULT pool objects. Not much harder than that.

PS. I''d suggest never resizing someones desktop on them... Thats not very user friendly and you might receive death threats if you do so. =)

Share this post


Link to post
Share on other sites
James Gregory    128
I''m using DirectDraw, not Direct3D, so I can''t call CheckIfDeviceIsStillFineAndDandy() or whatever the Direct3D function is called.

And WM_Activate isn''t caught in full screen mode, I think because the window isn''t actually your program, it''s just something to keep Window happy. Plus it requires reloading all the bitmaps.




Share this post


Link to post
Share on other sites
hl_mark    122
I''ve used the IsLost() member function to check if I still have my surface. If I do not then RestoreAllSurfaces() else proceed to render image.

Share this post


Link to post
Share on other sites
slip    140
quote:
Original post by JoeyBlow2
PS. I''d suggest never resizing someones desktop on them... Thats not very user friendly and you might receive death threats if you do so. =)


Speaking oh which... Does anyone know of some way you can prevent all the windows being resized when any application goes fullscreen? I seem to have that problem a lot. Some things that run in fullscreen don''t do it but most do... Its really annoying...

Share this post


Link to post
Share on other sites
James Gregory    128
I'm afraid I can't help you there, but in case someone else searches the forum archives some time with the same problem as me, and doesn't want to waste hours of their life:

If you want to make a pseudo-fullscreen application (i.e. it looks full screen, but is actually in a window), here's how you do it:

1. At the beginning of your program, save the person's current screen settings in a global, and then change the screen settings to what you want them to be. E.g.:


//globals

DEVMODE oldDispSettings;
.
.
.
//at the very beginning of the program


//save the person's old settings

EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &oldDispSettings);
oldDispSettings.dmSize = sizeof(DEVMODE);
oldDispSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;

//set up the new ones

DEVMODE newDispSettings;

newDispSettings.dmSize = sizeof(DEVMODE);
newDispSettings.dmBitsPerPel = screenBPP;
newDispSettings.dmPelsWidth = screenWidth;
newDispSettings.dmPelsHeight = screenHeight;
newDispSettings.dmDisplayFrequency = oldDispSettings.dmDisplayFrequency;
newDispSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;

ChangeDisplaySettings(&newDispSettings, 0);


This should come right at the very beginning, before you even create a window. Your game's main window size should obviously be equal to the size you just set for the monitor size.

2. If the person alt tabs or otherwise deactivates your game, you want to do 2 things:

a) Pause the game so it doesn't eat up all their system resources. You need some sort of global boolean "paused" variable.

b) Minimize your window such that your game's display doesn't interfere with whatever the person is doing.

You could use the global old settings DEVMODE to restore their old settings whenever they alt tab, but I think this invalidates all your surfaces so it would probably require reloading everything in the same way that real full screen games have to.

Anyway, in my Windows call back function I have the following:


case WM_ACTIVATE:
{
WORD fActive = LOWORD(wParam);

if (fActive == WA_ACTIVE || fActive == WA_CLICKACTIVE)
{
//if MSWIN it means the window has just been created

if (gsCurrent != MSWIN)
gsCurrent = gsTo;
}
else //must be WA_INACTIVE

{
gsCurrent = DEACTIVATED;

//this minimizes your game's window

WINDOWPLACEMENT tempPlacer;
tempPlacer.length = sizeof(WINDOWPLACEMENT);
tempPlacer.showCmd = SW_MINIMIZE;

SetWindowPlacement(mainWindowHandle, &tempPlacer);
}
}


The "gsCurrent" and "gsTo" stuff is perculiar to my game, you could just have a global boolean called "paused" or whatever, but bear in mind you'll get an activated message when your program first starts.

Then at the beginning of my main game loop I have a switch on the current game state, with a simple:


case DEACTIVATED:
return 1;
break;


for the case of being paused. I cut out the whole main game loop when deactivated, if you're making a game that is real time and multiplayer, you'll probably just want to pause out your DrawWorld() part.

3. When the program shuts down, restore the person's old settings again.


ChangeDisplaySettings(&oldDispSettings, 0);


Note I set the valid fields on the oldDispSettings structure at start up, you could leave it until shutdown, but whatever, you have to do it some time.

www.hcstreet.f2s.com/galaxyhack

[edit: why proofread for typos before posting when you know there's an edit button?]

[edited by - James Gregory on January 17, 2004 2:52:36 AM]

Share this post


Link to post
Share on other sites
Atlay    122
For James, and anyone else who finds this post and thinks it''s a good idea, *please* dont do that in your game. The reason is simple: It''s very anti-social to your user base. If your game crashes with some terminal error and is unable to run your shutdown code, you have left your user with their desktop in a FUBAR state.

I''m not into death threats but as a consumer, I will return any game that uses this technique to the store, and hit you in your wallet.

Go on, put some (realtively simple) work into it and do the job properly... you know it makes sense. :D


Atlay

Share this post


Link to post
Share on other sites
James Gregory    128
If it''s so simple, why don''t you explain how it can be done?

I''m utterly fed up with seaching the DirectX documentation/Win32 documentation/MSDN library/google, finding some function call or argument that looks like it might be relevant, compiling, running, quitting, changing it so it''s slightly different, compiling, running, changing it a bit again, searching for more functions a bit more, running again, ad infinitum.

It''s not like it''s a matter of putting a bit of logic or thought or effort into it, or a matter of thinking about what exactly it is you want your program to do, it''s just extremely tedious trial and error.

Share this post


Link to post
Share on other sites
Atlay    122
Sorry, I did not mean to condascend. My intention was just to express that the principle of resizing my windows desktop behind my back has caused me to return several games to the shop and get a refund. It's a horrible thing to do to users (in my opinion).

I said it was 'relatively' simple, although I know full well it's not always trivial to implement. Joey above outlined how you do it (release, reset, recreate). What is hard about it is that the exact code for is intimately linked to how you have structured your scene graph/rendering pipeline. This is why you dont see "copy this code" posts, because that is not possible when everyone designs their own object hierachy.

The best advice I can give (i.e. the approach that worked for me) is to do this:

1. Create a simple application with the Visual C++ DirectX wizard. Strip away (in the wizard) everything except Direct3D support for a single triangle.

2. Compile and run that sample, and see how well it lets you pick your diplay mode, including multiple monitors and alt-tab or alt-enter mode switching.

3. Examine the code path for dealing with the mode selection and switching to glean the *useful* bits, so you can see how to apply the techniques to your own rendering system.

Normally, I hate any MS related DX code, as they bloat it to the point it is really hard to see the useful bits, but in this specific example you can target your reseach to just find the code path relating to lost devices.

One caveat tho... I know you are using DirectDraw, and I described studying the Direct3D wizard generated code. I do not use DirectDraw myself, so I am making an assumption that it uses a similar technique... you mention that it returns SURFACELOST so I think we're on safe ground.

Again, I'm sorry if I offended, but the alternative approach is really not a good idea if you plan on selling your game to me or my kids.


Atlay

[edit: stuff]

[edited by - Atlay on January 17, 2004 7:57:37 AM]

Share this post


Link to post
Share on other sites
chdennis    122
quote:
Original post by Atlay
I said it was ''relatively'' simple, although I know full well it''s not always trivial to implement.


Agreed.

The only time it''s really difficult to implement is when you''ve already written your app without consideration for lost devices/assets. If that''s the case, depending on your code, it can be an absolutely ugly thing to implement.

However, it''s still well worth the effort to implement this - putting a framework in place to reset lost devices and recreate device-dependent assets on demand makes it much easier to do things like resolution-switching and certain other 3D option tweaking from within the game engine.

Share this post


Link to post
Share on other sites
wazoo69    157
James you probably already know this, but the framework the dx appwizard uses is in the /samples/common folders. D3dapp.h/.cpp are the two files that drive everything, so it''s in there that you can look for some examples of the alt+tab stuff.

(ie. you don''t need Visual C++ to see how it''s done)..

And just my 0.02, but I guess I''m more "forgiving" in terms of the game resizing my desktop. I certainly wouldn''t return any of my Tie-Fighter games if/because it did this!

And I''ve also played many a great homebrew game that did this technique...does it mean I wouldn''t buy the game? Heck no!

Besides most homebrew companies *might* actually look into it if you sent them some email about how they''re handling desktop resolution/resizing..

Share this post


Link to post
Share on other sites
James Gregory    128
TestCooperativeLevel() and Present() don't exist in DirectDraw.

You could probably fudge Present() by making a test blit before drawing/rendering the world and checking its return value, though it would seem rather inefficient. But even if you did that the lack of TestCooperativeLevel() means you can't test whether or not you've lost the focus.

I've read some stuff about DirectDraw saying you can use the DDSCL_SETFOCUSWINDOW flag when you set the cooperative level to make it such that your fullscreen application receives the messages from your main window, but it fails to set the cooperative level at all if I set that flag. If I OR that flag with DDSCL_SETDEVICEWINDOW it manages to set the cooperative level but fails to draw half the screen.

The documentation says that thee flags are supported in Windows 98 and Windows NT 5.0 only, though I'd guess this just means that the documentation was written at a time when Windows 98 was the latest version of Windows.

Anyhow, I'm not planning on charging for my game, indeed I'm not really seriously expecting anyone else to play it, so I think I'll just leave it as it is.

[edited by - James Gregory on January 17, 2004 6:41:33 PM]

Share this post


Link to post
Share on other sites
bash_chelik    122
quote:
Original post by James Gregory
And WM_Activate isn't caught in full screen mode, I think because the window isn't actually your program, it's just something to keep Window happy. Plus it requires reloading all the bitmaps.



You can use WM_ACTIVATEAPP. I used it in some DirectDraw apps (along with RestoreAllSurfaces and TestCooperativeLevel methods) to resovle alt-tabing. You'll still have to reload all the bitmaps...

[edited by - bash_chelik on January 18, 2004 2:41:09 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Not to mention you''ll screw up the user''s icons on the desktop!
AND the app runs slower on window mode!

Share this post


Link to post
Share on other sites