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.
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.