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

Author Topic: waitEvent - loop.  (Read 847 times)

0 Members and 1 Guest are viewing this topic.

MrGarrison

  • Newbie
  • *
  • Posts: 6
    • View Profile
waitEvent - loop.
« on: June 23, 2023, 10:55:14 am »
Is it possible to make simple example, that is something like :

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

int main()
{
        sf::RenderWindow window(sf::VideoMode(300, 300), "SFML Works");

        sf::RectangleShape shape(sf::Vector2f(150,150));

        shape.setFillColor(sf::Color::Blue);

        while (window.isOpen()) {

                sf::Event event;
                while (window.pollEvent(event)) {

                        if (event.type == sf::Event::Closed) {
                                window.close();
                        }

                }

                window.clear();
                window.draw(shape);
                window.display();
        }

        return 0;
}

To be done using waitEvent in gameloop instead of pollEvent, and make this basic example work?

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: waitEvent - loop.
« Reply #1 on: June 23, 2023, 10:04:49 pm »
I don't expect changing just pollEvent for waitEvent directly to actually have any noticeable effect in that code; it should perform - visually - the same.

Note, of course, that the loop doesn't run unless events are present so updates in that loop would not change until an event happens.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10821
    • View Profile
    • development blog
    • Email
Re: waitEvent - loop.
« Reply #2 on: June 24, 2023, 11:27:28 am »
Here's a simple example that uses waitEvent.
Warning: The rectangle will flash rapidly

#include <SFML/Graphics.hpp>

int main()
{
    auto window = sf::RenderWindow{{1920u, 1080u}, "Wait Event"};
    window.setFramerateLimit(144);

    auto rectangle = sf::RectangleShape{{100.f, 100.f}};
    rectangle.setFillColor(sf::Color::Red);
    rectangle.setPosition({200.f, 200.f});

    while (window.isOpen())
    {
        if (rectangle.getFillColor() == sf::Color::Red)
        {
            rectangle.setFillColor(sf::Color::Green);
        }
        else
        {
            rectangle.setFillColor(sf::Color::Red);
        }

        window.clear();
        window.draw(rectangle);
        window.display();

        auto event = sf::Event{};
        if (window.waitEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }
    }
}

Now don't move your mouse over the window and you'll see that the color remains the same, until you press a key of move the mouse again.
The "problem" this code nice demonstrates is, that the rendering loop will pause for as long as there's no event. If you have a UI application where nothing happens when the user does no input, this can work, but if you say render a game or a simulation, then you want to continuously render something, even if there's no user input happening right now.

And here is a much more complicated example that uses a second thread for rendering.
This is a bit unsafe, as discussed in the other thread, because there's no way to properly protect shared access on the window, as waitEvent blocks. It should generally work, but there's no guarantee.
Important to note is that events always have to be processed in the thread, which created the window, which is why I'm using a rendering thread.
Second note is that you need to disable the OpenGL context on the event thread and enable it on the rendering thread.

As you see it's much more complex and in the end, you're not doing anything special here, we just do a way more complicated pollEvent, as we push the events from the event thread into a queue that is processed in the rendering thread, but hey, we're using waitEvent, which was the whole requirement... ;D

#include <mutex>
#include <string>
#include <thread>
#include <queue>

#include <SFML/Graphics.hpp>

class Application
{
    sf::RenderWindow m_window;
    std::queue<sf::Event> m_eventQueue;
    std::mutex m_sharedAccess;

    void renderGame()
    {
        // Set OpenGL Context active on the current thread
        m_window.setActive(true);

        auto rectangle = sf::RectangleShape{{100.f, 100.f}};
        rectangle.setFillColor(sf::Color::Red);
        rectangle.setPosition({200.f, 200.f});

        auto clock = sf::Clock{};
        auto accumulator = sf::Time::Zero;

        while (m_window.isOpen())
        {
            {
                auto lock = std::unique_lock<std::mutex>{m_sharedAccess};
                while (!m_eventQueue.empty())
                {
                    auto event = sf::Event{};
                    event = m_eventQueue.back();
                    m_eventQueue.pop();

                    if (event.type == sf::Event::Closed)
                    {
                        m_window.close();
                    }
                }
            }

            if (rectangle.getFillColor() == sf::Color::Red)
            {
                rectangle.setFillColor(sf::Color::Green);
            }
            else
            {
                rectangle.setFillColor(sf::Color::Red);
            }

            auto frameTime = clock.restart();
            accumulator += frameTime;

            if (accumulator >= sf::seconds(1.f))
            {
                m_window.setTitle(std::to_string(1.f / frameTime.asSeconds()));
                accumulator = sf::Time::Zero;
            }

            m_window.clear();
            m_window.draw(rectangle);
            m_window.display();
        }
    }

public:
    Application() : m_window{{1920u, 1080u}, "Wait Event"}
    {
        m_window.setFramerateLimit(144);
    }

    void run()
    {
        // Set OpenGL Context inactive on the current thread
        m_window.setActive(false);

        auto renderThread = std::thread{&Application::renderGame, this};

        // Handle events on the same thread the window was created on
        auto event = sf::Event{};
        while (m_window.waitEvent(event))
        {
            {
                auto lock = std::unique_lock<std::mutex>{m_sharedAccess};
                m_eventQueue.push(event);
            }

            if (event.type == sf::Event::Closed)
            {
                break;
            }
        }

        renderThread.join();
    }
};

int main()
{
    auto app = Application{};
    app.run();
}
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

MrGarrison

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: waitEvent - loop.
« Reply #3 on: June 26, 2023, 01:00:35 pm »
I don't expect changing just pollEvent for waitEvent directly to actually have any noticeable effect in that code; it should perform - visually - the same.


That's what i have done at first - just made it "look" like it is working for basic render.

Quote
Note, of course, that the loop doesn't run unless events are present so updates in that loop would not change until an event happens.

Yes, i understand that, that's why i have whole conflict - it won't be good/complete solution because of that.

@eXpl0it3r

The first example that you have posted here is something that i have chosen in this version, ofcourse, without this coloring stuff that demonstrates whole problem - because that would expose problem (i hope it won't be visible at the first glance) ;D

The second one is something that is a bit familiar with codesnippet that i have posted in other topic ( but yours is more smooth, which can be useful for me if it needs :D ).

And you are right - it is just overcomplicated pollEvent that is not 100% safe, but as you said - we're using waitEvent, woohoo !  ;D

I hope that it won't be necessary to use second aproach, since it will be hard to embed that into basic tutorial/presentation about using SFML... We will see.

Thank you guys for fast reponses, time, and effort that you've put in helping me. I really appreciate it !