Changing resolution at runtime?
  • PhoenixPhoenix January 2008
    Hello, HGE users!

    I'm having a bit of a trouble; I've managed to make my game resolution independent, and it works like a charm.
    However, I'd like to allow the user to change the resolution of the HGE window in an options menu whilst the game is running, but I've yet to find a way to change the screen size after System_Initiate() has been called. I've also found out that calling System_Initiate() twice gives me an error.

    Any ideas on how to allow resolution changing?

    Thanks,
    Martin
  • ProfEclipseProfEclipse January 2008
    That scenario isn't supported in HGE. You'd have to modify the engine source code to get that to work.
  • PhoenixPhoenix January 2008
    Aww, damn. Well, you can't get it all, can you? I'll stick to the set-resolution-at-startup-method.
  • DrewDrew January 2008
    Actually it's doable with a bit of trickery with vanilla hge. I don't have the code I tried it with to hand, however the general idea is: (in pseudocode)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    	// game init
     
    if(hge->System_Initiate())
    {
    bool NoErrors = true;
     
    while (flag_gameQuitCode == GAME_RUNNING && NoErrors)
    {
    hge->System_Start();
     
    if (flag_gameQuitCode == GAME_RUNNING && flag_resChange == CHANGE_RESOLUTION)
    {
    hge->System_Shutdown();
    hge->System_SetState(HGE_SCREENWIDTH, ScreenWidth);
    hge->System_SetState(HGE_SCREENHEIGHT, ScreenHeight);
    hge->System_SetState(HGE_SCREENBPP, BitDepth);
    // start up HGE again
    if (!hge->System_Initiate())
    {
    NoErrors = false;
    }
     
    }
    else
    {
    flag_gameQuitCode = GAME_QUIT;
    }
    }
    }
     
    hge->System_Shutdown();
    hge->Release();


    In the rest of your code you will have to set up the GAME_RUNNING & CHANGE_RESOLUTION values, as well as the flag_gameQuitCode & flag_resChange variables.

    Here's how it works:
    Whenever the user requests a screen resolution change set the flag_resChange flag to CHANGE_RESOLUTION, flag_gameQuitCode to GAME_RUNNING & store the new screen res somewhere (for simplicity I'm using ScreenWidth, ScreenHeight & BitDepth to store this).
    Now return an exit code from your FrameFunc().
    At this point HGE will "quit", but now we set the new screen resolution & call System_Start() again.

    If the user wants to quit then set the flag_gameQuitCode flag to something other than GAME_RUNNING.


    Now this isn't perfect - in fact it's downright hacky. If memory serves me right I had problems with occasional crashes, there may be other issues too. However technically it does work :)
  • ProfEclipseProfEclipse January 2008
    That solution effectively requires the game to quit and restart to get the resolution changed. It works, but it's not really what Phoenix was asking for. There's not really any way for this to work in-game without adding a bunch of code to save the current state of the game before the change and restore it afterward. Not really worth the effort.
  • painkillerpainkiller June 2012

    That scenario isn't supported in HGE. You'd have to modify the engine source code to get that to work.



    Do you have an idea what one would have to do to implement this - changing the resolution without restarting the HGE? I tried doing the same thing as setting the HGE_WINDOWED flag does, which is basically adjusting d3dpp, and calling _GfxRestore() and _AdjustWindow(). Unfortunately, that doesn't work correctly. Especially not when in fullscreen mode.
    I would LOVE to get this working, and I really hope you or anyone else can help me.
    Thanks.
  • That should be all you need to do. What doesn't work right?
  • painkillerpainkiller June 2012
    Ok, first I should probably mention that my code in the game is currently setup to work with 800x600. That is, I haven't made it resolution-independent yet (although I don't think that's relevant for this issue).

    1) When I start the game with 800x600 and windowed, it works almost just like it should! However, there is some issue with moving the cursor out of the window. It doesn't pop out at the right place, and it pops out before the cursor has even reached the end of the visible back buffer.

    2) When I start the game at a different resolution and I change the resolution in the game, the back buffer is not fully stretched to the whole window...

    2) Fullscreen mode doesn't work at all. The game doesn't crash, but it never fully succeeds in restoring the window, it seems. Part of the screen is filled with a black box, and I can partially see the desktop.

    Here's the function I implemented in graphics.cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    void CALL HGE_Impl::Gfx_SetDisplayMode(int width, int height, int bpp)
    {
    nScreenWidth = width;
    d3dppFS.BackBufferWidth = width;
    d3dppW.BackBufferWidth = width;
    // d3dpp->BackBufferWidth = width;
     
    nScreenHeight = height;
    d3dppFS.BackBufferWidth = height;
    d3dppW.BackBufferWidth = height;
    // d3dpp->BackBufferHeight = height;
     
    nScreenBPP = bpp;
     
    // Choose appropriate back buffer format
    UINT nModes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT);
    D3DDISPLAYMODE Mode;
    for (int i = 0; i < nModes; ++i)
    {
    pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, i, &Mode);
     
    if (Mode.Width != (UINT)nScreenWidth || Mode.Height != (UINT)nScreenHeight)
    continue;
    if (bpp == 16 && (_format_id(Mode.Format) > _format_id(D3DFMT_A1R5G5B5)))
    continue;
    if (_format_id(Mode.Format) > _format_id(d3dpp->BackBufferFormat))
    {
    d3dppFS.BackBufferFormat = Mode.Format;
    d3dppW.BackBufferFormat = Mode.Format;
    // d3dpp->BackBufferFormat = Mode.Format;
    }
    }
     
    // Adjust windowed/fullscreen rects, necessary before calling _AdjustWindow()
    int wndWidth = nScreenWidth + GetSystemMetrics(SM_CXFIXEDFRAME)*2;
    int wndHeight = nScreenHeight + GetSystemMetrics(SM_CYFIXEDFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
     
    rectW.left = (GetSystemMetrics(SM_CXSCREEN)-wndWidth)/2;
    rectW.top = (GetSystemMetrics(SM_CYSCREEN)-wndHeight)/2;
    rectW.right = rectW.left + wndWidth;
    rectW.bottom = rectW.top + wndHeight;
     
    rectFS.left = 0;
    rectFS.top = 0;
    rectFS.right = nScreenWidth;
    rectFS.bottom = nScreenHeight;
     
    _GfxRestore();
    _AdjustWindow();
    }
  • The only things I noticed is that you didn't call _SetProjectionMatrix() and you should probably call _AdjustWindow() before calling GfxRestore().

    Other than that, I don't see any obvious problems with your code.
  • painkillerpainkiller June 2012
    Including the call to _SetProjectionMatrix() actually fixed the cursor problem, thanks. Although the dt/FPS text looks a bit blurry when changing resolutions. And it's still not possible to change resolutions in fullscreen mode.

    What I also tried was this: I started the game fullscreen, switched to windowed, changed the resolution (successfully), and then switched back to fullscreen (just toggling fullscreen has always worked). But that didn't work either.

    Btw, I'm using the original HGE which uses DirectX 8. Maybe there's a slightly different procedure for changing resolutions between DX8 and DX9?
  • Changing resolution in DX8 and DX9 should work the same.

    I don't have a PC to test your code on, so I really don't have any other suggestions.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In Apply for Membership

In this Discussion

Who's Online (2)