SFML community forums

Help => General => Topic started by: rogeriodec on May 26, 2018, 06:27:50 am

Title: window.display() alone toggles between the last and current buffer displayed
Post by: rogeriodec on May 26, 2018, 06:27:50 am
I made this code that shows a timer and pauses when you press spacebar:

#include <SFML/Graphics.hpp>
#include <iostream>

using namespace sf;
using namespace std;
void events();

bool pause, exitPause;
char key;
double timeFrame, timeTot = 0;
Clock timer;
Text text;
Font font;

RenderWindow window(VideoMode(800, 600), "Window", Style::Close);

int main()
{
        font.loadFromFile("C:/Windows/Fonts/arial.ttf");
        text.setFont(font);
        text.setCharacterSize(15);
        window.setFramerateLimit(120);
        while (window.isOpen())
        {
                for (Event event; window.pollEvent(event);) {
                        if (event.type == Event::Closed)
                                window.close();
                        if (event.type == Event::TextEntered) {
                                key = std::tolower(static_cast<char>(event.text.unicode));
                                if (key == ' ') {
                                        pause = !pause;
                                        if (!pause) {
                                                timer.restart();
                                        }
                                }
                        }
                }
                if (!pause) {
                        timeFrame = timer.restart().asSeconds();
                        timeTot += timeFrame;
                        text.setString(to_string(timeTot));
                        window.clear();
                        window.draw(text);
                }
                window.display();
        }
}
 

If you test, you will see something curious. When pausing by pressing the spacebar, window.display () alternates between the last and the current displayed number.

But if I put window.clear and window.draw together with window.display, the problem does not happen.


                if (!pause) {
                        timeFrame = timer.restart().asSeconds();
                        timeTot += timeFrame;
                        text.setString(to_string(timeTot));
                }
                window.clear();
                window.draw(text);
                window.display();

I thought windows.display, alone, would only show the last buffer.
What is the problem?
Title: Re: window.display() alone toggles between the last and current buffer displayed
Post by: kennyrkun on May 26, 2018, 07:33:47 am
I'm not sure why that happens, but here's how to make it not happen:

if (!pause)
{
        timeFrame = timer.restart().asSeconds();
        timeTot += timeFrame;
        text.setString(to_string(timeTot));
}
               
window.clear();
window.draw(text);
window.display();
 
Title: Re: window.display() alone toggles between the last and current buffer displayed
Post by: eXpl0it3r on May 26, 2018, 09:10:11 am
Because of double buffering and clear-dispaly is non-optional
Title: Re: window.display() alone toggles between the last and current buffer displayed
Post by: rogeriodec on May 26, 2018, 05:47:47 pm
Because of double buffering and clear-dispaly is non-optional

I learned it is necessary to put window.display inside the loop to avoid processor overload since it inserts the necessary breaks within the frame rate limit. Still, it would be more logical to have a command just for that, not window.display, which is constantly rendering something repeated, unnecessarily.
Now, I realize that the loop needs to consistently send the clear, the draw, and the display (even when the program is paused). Does not this burden the gpu unnecessarily?
Is not there a better way?
Title: Re: window.display() alone toggles between the last and current buffer displayed
Post by: Hapax on May 28, 2018, 08:21:16 pm
Is not there a better way?
If you're willing to put in a bit of extra work, you should be able to do something with it, yes.

When your game pauses, you can switch the event loop to a completely different one that uses waitEvent instead of pollEvent and update the clear/draw/display after events since the events should include the operating system telling your game when it needs it to update its window.
Title: Re: window.display() alone toggles between the last and current buffer displayed
Post by: Elro444 on July 01, 2018, 11:32:52 am
A bit late, but in case someone else will come by..
You could also use callbacks to swap between waitEvent and pollEvent, allowing you to use the same event handling loop:


sf::Window window;
//An array of callbacks, in which we store both functions:
bool (sf::Window::*windowEventCallbacks[])(sf::Event&) = {
        &sf::Window::pollEvent,
        &sf::Window::waitEvent
};
unsigned currentCallbackIndex = 0;

while (window.isOpen)
{
        sf::Event e;
        //use the right callback, using the current index:
        while (  (window.*windowEventCallbacks[currentCallbackIndex])(e)  )
        {
                switch (e.type)
                {
                case sf::Event::KeyPressed:
                        if (e.key.code == sf::Keyboard::Escape)
                        {
                                //pause game - swap callbacks, to use waitEvent:
                                currentCallbackIndex++;
                                currentCallbackIndex %= 2; //to loop back when it is greater than 1.
                        }
                        break;
                        /* ... handle events ... */
                }

        }
}