Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Fullscreen Rendering between Game States  (Read 10284 times)

0 Members and 2 Guests are viewing this topic.

gamepopper

  • Newbie
  • *
  • Posts: 35
    • View Profile
    • Email
Fullscreen Rendering between Game States
« on: March 05, 2016, 01:41:25 am »
Short Version: Changing from one state to another on fullscreen has unusual rendering behaviour, while the same action in window mode does not show the same behaviour.

So I'm using SFML 2.3 in my framework and I've come across an issue that's mainly specific to when I'm rendering in fullscreen mode. I use a Game State Manager class so I can render different screens in separate classes, as well as store multiple states that I can push and pop out of in a stack:

VState* VStateManager::CurrentState()
{
        return states.back();
}

void VStateManager::ChangeState(VState* state)
{
        if (states.size())
        {
                states.back()->Cleanup();
                delete states.back();
                states.pop_back();
        }

        state->Initialise();
        states.push_back(state);
}

void VStateManager::PushState(VState* state)
{
        if (states.size())
        {
                states.back()->Pause();
        }

        state->Initialise();
        states.push_back(state);
}

void VStateManager::PopState()
{
        if (states.size())
        {
                states.back()->Cleanup();
                delete states.back();
                states.pop_back();
        }

        if (!states.empty())
        {
                states.back()->Resume();
        }
}

When you want to change a state from either the ChangeState or PushState functions, the switch doesn't occur straight away to avoid any errors from continuing a state function after it has been destroyed. Instead the new state is saved until the start next game loop iteration, I do this by calling the function and passing in NULL.

//Start of loop
if (stateManager->IfChangedState)
{
        stateManager->ChangeState(NULL);
}

if (stateManager->IfPushedState)
{
        stateManager->PushState(NULL);
}

HandleEvents();
if (focused)
{
        Update(dt * timeScale);
}

if (focused && !stateManager->IfChangedState && !stateManager->IfPushedState)
{
        PreRender();
        for (unsigned int c = 0; c < CurrentState()->Cameras.size(); c++)
        {
                currentView = c;
                Render();
        }
        PostRender();
}

Now onto the SFML specific stuff.  :P

So when I run my game in Windowed mode, and change the state, the screen might pause for a short amount of time, but it'll render the next scene without any problems like below:


However, if I try running the same scene again in fullscreen mode, for some reason it renders the last state for a short amount of time before starting the next state. It was very difficult for me to capture (neither FRAPS or GifCam could capture the fullscreen rendering, but OBS could capture this), what you don't see below is the very short lasting white screen going to black.


This is the code I use to switch between window mode and fullscreen. I initially thought it might be because the previous sf::RenderWindow (App) wasn't being destroyed, but I think that's already handled in create.

void VGame::SetFullscreen(bool set)
{
        if (set && !fullscreen)
        {
                App.create(sf::VideoMode::getDesktopMode(), Title, sf::Style::Fullscreen);
                App.setMouseCursorVisible(set);
                fullscreen = true;
        }
        else if (!set && fullscreen)
        {
                App.create(sf::VideoMode(WindowWidth, WindowHeight), Title, WindowStyle);
                App.setMouseCursorVisible(set);
                fullscreen = false;
        }
}

As for rendering, I use an sf::RenderTexture (called RenderTarget) to render the scene, and then I could apply post process effects before setting the texture to a sf::Sprite, which is positioned, scaled and then rendered to the sf::RenderWindow. I separated it into three functions so I could organise each part of the rendering.

void VGame::PreRender()
{
        RenderTarget.clear(BackgroundColor);
}

void VGame::Render()
{
        RenderTarget.setView(CurrentState()->Cameras[currentView]->GetView());

        if (CurrentState()->visible)
                CurrentState()->Draw(RenderTarget);

        if (CurrentState()->SubState)
        {
                CurrentState()->SubState->Draw(RenderTarget);
        }

        CurrentState()->Cameras[currentView]->Render(RenderTarget);
}

void VGame::PostRender()
{
        RenderTarget.display();
        if (RenderTarget.isSmooth() != Antialiasing)
        {
                RenderTarget.setSmooth(Antialiasing);
        }
        App.setVerticalSyncEnabled(VSync);

        App.clear();

        if (PostProcess == NULL || !VPostEffectBase::isSupported())
        {
                RenderSprite.setTexture(RenderTarget.getTexture());
                App.draw(RenderSprite, RenderState);
        }
        else
        {
                PostProcess->Apply(RenderTarget, App);
        }

        App.display();
}
 

All I could gather from debugging was that after the ChangeState function is called, the rendering functions are skipped for one frame, the states are changed and then the next render is called, and the window outputs what you see above.

Sorry about this being very long-winded. I've tried my best to cut out some parts of the code that might not be relevant, however I'm not sure if I could reproduce this issue with something much smaller.
« Last Edit: March 05, 2016, 01:43:09 am by gamepopper »

Mr_Blame

  • Full Member
  • ***
  • Posts: 192
    • View Profile
    • Email
Re: Fullscreen Rendering between Game States
« Reply #1 on: March 07, 2016, 04:33:32 pm »
It is better to post code in zip archieve instead of some hard-to-understand pieces.  :)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Fullscreen Rendering between Game States
« Reply #2 on: March 07, 2016, 05:14:10 pm »
How do you create fading to black effect? Do you at some point break the rendering cycle, i.e. don't update the screen for a second or so?

It is better to post code in zip archieve instead of some hard-to-understand pieces.  :)
I disagree. Having to download some tiny files that would've easily fitted into a post, is way worse.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

gamepopper

  • Newbie
  • *
  • Posts: 35
    • View Profile
    • Email
Re: Fullscreen Rendering between Game States
« Reply #3 on: March 07, 2016, 07:47:07 pm »
How do you create fading to black effect? Do you at some point break the rendering cycle, i.e. don't update the screen for a second or so?

The fade to black is done using an overlay, an sf::RectangleShape object, rendered in the camera object (hence why there is a render call in the camera object).

CurrentState()->Cameras[currentView]->Render(RenderTarget);

Once the fade is completed, I use a callback function (an std::function<T> pointer) to change the state, this callback function is passed in when I want the camera to fade.

//Called once in an event handled input
Cameras[0]->Fade(sf::Color::Black, 1.0f, false, std::bind(&TitleState::ToMenu, this));

//Some code later...
void TitleState::ToMenu()
{
        VGame::ChangeState(new CharacterSelectState());
}
 

To answer the second question, I do break the rendering cycle for one frame in the game loop, before successfully changing the state. This is what the IfChangedState and IfPushedState variables are for, they only are set true if the ChangeState or PushedState functions are called with a new game state class passed in.

Again, sorry for the large amount of code. It was either this or provide a download link to the files, and the latter option had the issue of not being sure which files to include.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Fullscreen Rendering between Game States
« Reply #4 on: March 08, 2016, 08:29:00 am »
Could it be that the rectangle shape's color fading wraps around?

To make sure it's not your code you should try a minimal example.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Fullscreen Rendering between Game States
« Reply #5 on: March 08, 2016, 05:15:02 pm »
This thread has frozen my browser on two occasions.
I assume it's the animations but I can't understand why they freeze the browser. Did you hide some sort of mind-altering substance into the post?  ;D
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

gamepopper

  • Newbie
  • *
  • Posts: 35
    • View Profile
    • Email
Re: AW: Fullscreen Rendering between Game States
« Reply #6 on: March 08, 2016, 08:10:49 pm »
Could it be that the rectangle shape's color fading wraps around?
To make sure it's not your code you should try a minimal example.

Well to test it out, I made sure that the maximum value for the alpha of the rectangle is 255. I set the colour using the sf::Color variable fadeColour and I use a linear interpolation function:

float fadePercentage = fadeFlashTimer / fadeTime;
fadePercentage = fadePercentage > 1.0f ? 1.0f : fadePercentage;

if (fadeIn)
{
        fadeColour.a = static_cast<unsigned int>(VInterpolate::Float(255, 0, fadePercentage));
}
else
{
        fadeColour.a = static_cast<unsigned int>(VInterpolate::Float(0, 255, fadePercentage));
}

Despite adding this, the issue above still occurs in fullscreen mode. It doesn't occur when I use Windowed mode (I've even tried maximising the window, so the graphics are scaled up, however that didn't make a difference).

Fortunately I do have a much more simpler example that I use to test out the framework that I've built. It has very few graphic objects per states (although you get to see the post process effects I've done :P).

This is how it should look, windowed mode (albeit with GIF quality dithering :P):


Now I couldn't capture what;s occuring on fullscreen at all for this, and I have no external capture devices so instead here's a video recording of what happens:


Considering that the Gemstone Keeper game above doesn't use the post process shaders when transitioning from the title screen, I don't think it's a cause. Once again this only occurs in fullscreen mode.

This thread has frozen my browser on two occasions.
I assume it's the animations but I can't understand why they freeze the browser. Did you hide some sort of mind-altering substance into the post?  ;D

Might be because of the gifs, I don't think they have any browser-freezing stuff unless that's hidden in GifCam or Photoshop.

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: AW: Fullscreen Rendering between Game States
« Reply #7 on: March 09, 2016, 03:55:49 pm »
Fortunately I do have a much more simpler example that I use to test out the framework that I've built. It has very few graphic objects per states (although you get to see the post process effects I've done :P).

If this is really an issue with SFML and not your own code then you should be able to reproduce it without your entire code base (less than 200 lines).
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

gamepopper

  • Newbie
  • *
  • Posts: 35
    • View Profile
    • Email
Re: AW: Fullscreen Rendering between Game States
« Reply #8 on: March 14, 2016, 12:58:12 am »
If this is really an issue with SFML and not your own code then you should be able to reproduce it without your entire code base (less than 200 lines).

I have tried to write a project that just contained a basic game loop, my game state management and how I handle resolution, all in a single cpp file, but it'll exceeds 200 lines.

So instead I figure I try it out on one of the SFML example projects. I got the Shader example project and changed the RenderWindow parameter to open in sf::Style::Fullscreen. It's the only change I did to the Shader.cpp file.

////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Shader",
                            sf::Style::Fullscreen);
    window.setVerticalSyncEnabled(true);

   

Good thing is that it worked, ran fullscreen at a low resolution, but when I cycled through the effects I noticed that when it entered into the Post Edge Effect screen it went black briefly with a white box at the corner (I have as proof of this as well  :P), in this case, the difference in what happens is that the issue only occurs once while running, if I switch back it doesn't happen again.

I also tried running the example in fullscreen on my laptop, however I do not get this issue. The laptop uses Intel's HD Graphics while my desktop uses an AMD HD Radeon.

« Last Edit: March 14, 2016, 07:54:26 pm by gamepopper »