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

Author Topic: window.display() alone toggles between the last and current buffer displayed  (Read 2993 times)

0 Members and 1 Guest are viewing this topic.

rogeriodec

  • Newbie
  • *
  • Posts: 42
    • View Profile
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?

kennyrkun

  • Newbie
  • *
  • Posts: 9
  • a pretty mediocre programmer
    • View Profile
    • mehsowb
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();
 
it's probably terrible.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Because of double buffering and clear-dispaly is non-optional
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

rogeriodec

  • Newbie
  • *
  • Posts: 42
    • View Profile
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?

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
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.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Elro444

  • Newbie
  • *
  • Posts: 5
    • View Profile
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 ... */
                }

        }
}