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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - mhn2

Pages: [1]
1
I found that the QOpenGLWidget has a function called defaultFramebufferObject that returns the FBO of the widget, if there is a way to connect this to a sf::RenderTexture the problem should be mostly solved. The event handling will be able to be done using QtEvents.

So currently the question is, how can I draw on a OpenGL framebuffer object using SFML?

2
General / Re: Sprites turn into white boxes when deleting objects
« on: August 24, 2022, 02:04:27 pm »
The problem was you were using a vector. In vectors if you remove any item except the last item, some of the items will get moved around in memory, which was causing the white box problem for you because you didn't overload the assignment operator.

To fix your issue there are 4 solutions:
1- Overload the assignment operator
2- Keep pointers to the platforms inside the vector instead, be careful about memory leaks
3- Use a list instead of a vector
4- Keep the texture in a static member so all of the platforms use the same texture

Also note that if you aren't planning to move the texture to a static member, then there is no need to keep it as a pointer, since white box problem happens if the texture has been deleted before the sprites that were using it, but if you aren't using a static member and you aren't keeping it as a pointer, it will never happen on accident in your case. Just be sure that in both the copy constructor and assignment operator you are copying the texture or reloading it properly.

In the code below I did a mix of the solutions 1 & 3 & 4. Hopefully this will help you with your problem.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <list>

class Platform
{
private:
    // Since all of the platforms load the same file, I moved the texture to a static member so all of the platforms can use the same texture.
    static sf::Texture* m_texture;
    sf::Sprite m_sprite;

public:
    Platform()
    {
        m_sprite.setTexture(*m_texture);
        m_sprite.setPosition(100, 1080);
    }

    Platform(const Platform &copy)
    {
        // Just to be sure the sprite is pointing at the currect texture.
        m_sprite.setTexture(*m_texture);
        m_sprite.setPosition(copy.m_sprite.getPosition());
    }

    sf::Sprite getSprite()
    {
        return m_sprite;
    }

    void moveUp()
    {
        m_sprite.move(0, -10.f);
    }

    // It's how you should overload the assignment operator
    Platform& operator= (const Platform& copy)
    {
        // Just to be sure the sprite is pointing at the currect texture.
        m_sprite.setTexture(*m_texture);
        m_sprite.setPosition(copy.m_sprite.getPosition());
        return *this;
    }

    // Since there is no need to reload the texture on every constructor, I moved the loading action to a static function.
    // An alternative can be to have a static variable that counts how many platform objects currently exist, then load the texture if the value previously was 0 in the constructor, and unload the texture if the value was 1 in the deconstructor.
    // But that approach might cause rapid loading and unloading which can bring your game's fps down.
    static void loadTexture()
    {
        if (m_texture == nullptr) // prevents memory leak
        {
            m_texture = new sf::Texture;
            if (!m_texture->loadFromFile("textures/platform.png"))
                throw "image not found";
        }
    }

    // I also moved the unloading to a static function.
    static void unloadTexture()
    {
        if (m_texture != nullptr) // prevents memory leak
        {
            delete m_texture;
            m_texture = nullptr;
        }
    }
};

// Nothing special here, it's the way static members work in c++.
// We need this line to make sure its initial value is `nullptr` and to prevent the "Undefined reference to..." error
sf::Texture* Platform::m_texture = nullptr;

int main()
{
    sf::RenderWindow window(sf::VideoMode(1920, 1080), "SFML works!", sf::Style::Fullscreen);
    window.setFramerateLimit(60);

    Platform::loadTexture(); // loading the platform texture here, since we are going to use platforms now

    // I changed the vector to list, since in vectors, if you delete something from anywhere other the end of the vector, it will move every object inside it in the memory, which was the reason you where experiencing the white box error.
    // On the other hand, you can delete anything in a list without having to move other elements, but in return you can't access a random element of it outside of a loop.
    // Check https://cplusplus.com/reference/list/list/ to understand how it works.
    std::list<Platform> platforms;
    int timer = 0;

    while (window.isOpen())
    {
        sf::Event evnt;
        while (window.pollEvent(evnt))
        {
            if (evnt.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        // Spawn platforms every second
        timer++;
        if (timer >= 60)
        {
            platforms.push_back(Platform());
            timer = 0;
        }

        // Erase platforms that go off screen

        // It's how you can iterate through members of a list
        for (auto it = platforms.begin(); it != platforms.end()
        {
            it->moveUp();
            if (it->getSprite().getPosition().y < 0)
                it = platforms.erase(it);
            else
                it++;
        }

        // Draw
        window.clear();

        // It's how you can iterate through members of a list
        for (auto it = platforms.begin(); it != platforms.end(); it++)
            window.draw(it->getSprite());

        window.display();
    }

    Platform::unloadTexture();

    return 0;
}

3
Hi, after reading this topic on this forum, it seems like connecting an sf::RenderWindow to a QWidget will not work reliably anymore. But "binary1248" also stated:
Quote
If you are willing to pull off some really weird looking (platform-specific) stuff, you can get SFML and Qt to share their OpenGL contexts with each other. This would let you use an sf::RenderTexture's texture to draw a "full-screen" textured quad in Qt and do the actual drawing in SFML itself. This is a bit tricky to pull off, but entirely possible.
I lack enough knowledge about SFML, Qt and OpenGL to be able to figure out how to do this myself.
Can anyone help me find a way to make an sf::RenderTexture and a Qt 6 widget share their OpenGL contexts?
Qt also has a widget called QOpenGLWidget which might be able to help with the problem, but I don't know how.
I will appreciate any help.

Pages: [1]
anything